From 1ae545bcb5706aafa7831aec639c2534a03aeb03 Mon Sep 17 00:00:00 2001 From: CodeCodon Date: Sat, 17 Oct 2015 12:09:39 -0500 Subject: [PATCH 1/9] Many fixes - first, the bulk of these are fixes to warnings and code issues detected by gcc and clang's linters. Second, you may have to remove some cflags to build this with gcc versions lower than 5.2 - but 5.2 is heavily suggested because it build much more efficient server. Also added is doxygen config file so you can generate class docs in html format (very large!) --- src/CMakeLists.txt | 7 +- src/cmake/linux/FindOracle.cmake | 6 + .../client/application/Miff/src/lex_yy.c | 14 +- .../application/Miff/src/linux/parser.lex | 6 +- .../application/Miff/src/linux/parser.yac | 12 +- .../application/Miff/src/win32/miff.cpp | 1922 +- src/engine/server/application/CMakeLists.txt | 36 +- .../AuctionTransferAPI.cpp | 388 +- .../AuctionTransferGameAPI/Base/linux/Types.h | 90 +- .../src/shared/CentralServer.cpp | 8172 ++-- .../src/shared/ConfigCentralServer.cpp | 330 +- .../ChatServer/src/shared/ChatInterface.cpp | 4 +- .../src/shared/ConfigChatServer.cpp | 296 +- .../src/shared/ConnectionServerConnection.cpp | 2 +- .../CommoditiesServer/src/shared/Auction.cpp | 2914 +- .../src/shared/ConfigCommodityServer.cpp | 144 +- .../src/shared/ClientConnection.cpp | 3380 +- .../src/shared/ConfigConnectionServer.cpp | 332 +- .../shared/ConfigCustomerServiceServer.cpp | 334 +- .../LogServer/src/shared/ConfigLogServer.cpp | 110 +- .../src/shared/ConfigLoginServer.h | 944 +- .../shared/LoginServerRemoteDebugSetup.cpp | 192 +- .../src/shared/ConfigMetricsServer.cpp | 90 +- .../src/shared/ConfigPlanetServer.cpp | 194 +- .../src/shared/ConfigServerConsole.cpp | 136 +- .../src/shared/ConfigTaskManager.cpp | 216 +- .../src/shared/ConfigTransferServer.cpp | 274 +- .../server/library/codegen/package_data.txt | 1228 +- .../src/shared/ConfigServerDatabase.cpp | 272 +- .../src/shared/DatabaseProcess.cpp | 3 - .../serverGame/src/shared/city/CityInfo.h | 4 +- .../src/shared/city/CityStructureInfo.h | 4 +- .../src/shared/command/CommandCppFuncs.cpp | 19746 +++++----- .../console/ConsoleCommandParserCraft.cpp | 386 +- .../console/ConsoleCommandParserSpaceAi.cpp | 3 +- .../console/ConsoleCommandParserSpawner.cpp | 260 +- .../shared/controller/AiShipController.cpp | 2 +- .../serverGame/src/shared/core/Client.cpp | 5010 +-- .../src/shared/core/ConfigServerGame.cpp | 1160 +- .../serverGame/src/shared/core/GameServer.cpp | 12188 +++--- .../src/shared/core/NpcConversation.cpp | 4 +- .../src/shared/core/PreloadManager.cpp | 12 +- .../src/shared/core/ServerWorld.cpp | 34 +- .../src/shared/object/CellPermissions.h | 4 +- .../src/shared/object/CreatureObject.cpp | 31818 ++++++++-------- .../shared/object/DraftSchematicObject.cpp | 1132 +- .../src/shared/object/IntangibleObject.cpp | 14 +- .../src/shared/object/IntangibleObject.h | 2 +- .../src/shared/object/PlayerObject.cpp | 18342 ++++----- .../src/shared/object/PlayerObject.h | 2672 +- .../src/shared/object/ServerObject.cpp | 17126 ++++----- .../src/shared/object/ServerObject.h | 2 +- .../shared/object/ShipObject_Components.cpp | 6844 ++-- .../src/shared/object/TangibleObject.cpp | 12822 +++---- .../ServerCreatureObjectTemplate.cpp | 42 +- .../ServerTangibleObjectTemplate.cpp | 5 +- .../ServerTangibleObjectTemplate.h | 2 +- .../src/shared/region/RegionMaster.cpp | 2510 +- .../ShipInternalDamageOverTimeManager.cpp | 512 +- .../src/shared/ConfigServerMetrics.cpp | 94 +- .../gameGameServer/AiCreatureStateMessage.h | 2 +- .../shared/gameGameServer/AiMovementMessage.h | 2 +- .../serverScript/src/shared/JavaLibrary.cpp | 10 +- .../src/shared/ScriptMethodsCrafting.cpp | 5616 +-- .../src/shared/ScriptMethodsDataTable.cpp | 3182 +- .../src/shared/ScriptMethodsObjectCreate.cpp | 7 +- .../src/shared/ScriptMethodsObjectInfo.cpp | 97 - .../src/shared/ScriptMethodsShip.cpp | 8324 ++-- .../src/shared/ScriptMethodsString.cpp | 406 +- .../src/shared/ScriptParameters.h | 2 +- .../library/serverUtility/src/CMakeLists.txt | 4 - .../serverUtility/src/shared/PopulationList.h | 4 +- .../core/TemplateDefinitionCompiler.cpp | 78 - .../sharedDebug/src/linux/DebugHelp.cpp | 3 +- .../sharedDebug/src/shared/DataLint.cpp | 1814 +- .../sharedDebug/src/shared/PixCounter.cpp | 2 +- .../sharedDebug/src/shared/Profiler.cpp | 1752 +- .../sharedDebug/src/shared/RemoteDebug.cpp | 4 +- .../sharedFile/src/shared/FileManifest.cpp | 2 +- .../library/sharedFoundation/src/linux/Os.cpp | 940 +- .../library/sharedFoundation/src/linux/Os.h | 536 +- .../sharedFoundation/src/shared/ArrayList.h | 16 +- .../sharedFoundation/src/shared/BitArray.h | 4 +- .../sharedFoundation/src/shared/Fatal.h | 2 +- .../shared/dynamicVariable/DynamicVariable.h | 4 +- .../src/shared/core/GameScheduler.cpp | 166 +- .../src/shared/core/LfgCharacterData.cpp | 2 +- .../src/shared/core/WearableEntry.h | 4 +- .../SharedCreatureObjectTemplate.cpp | 18 +- .../src/shared/quest/PlayerQuestData.h | 4 +- .../src/shared/space/NebulaManager.cpp | 2 +- .../src/shared/travel/TravelPoint.h | 4 +- .../sharedLog/src/shared/ConfigSharedLog.cpp | 228 +- .../sharedMath/src/shared/MxCifQuadTree.h | 326 +- .../src/shared/MxCifQuadTreeBounds.h | 1 + .../sharedMath/src/shared/PolySolver.cpp | 638 +- .../src/shared/MemoryManager.cpp | 4478 +-- .../src/linux/NetworkGetHostName.cpp | 282 +- .../shared/UdpLibraryMT/UdpConnectionMT.cpp | 3 + .../src/shared/object/AlterScheduler.cpp | 4 +- .../src/shared/SharedRemoteDebugServer.cpp | 202 +- .../src/shared/SkillManager.h | 124 +- .../src/shared/SkillObject.cpp | 1112 +- .../shared/core/TemplateDefinitionFile.cpp | 1264 +- .../3rd/library/OCI/include/oratypes.h | 618 +- .../boost/boost/asio/detail/wince_thread.hpp | 236 +- .../library/boost/boost/asio/io_service.hpp | 1544 +- .../ssl/old/detail/openssl_stream_service.hpp | 1146 +- .../boost/boost/assign/ptr_list_of.hpp | 382 +- .../boost/boost/config/stdlib/roguewave.hpp | 378 +- .../boost/date_time/gregorian/greg_facet.hpp | 704 +- .../boost/boost/detail/lightweight_thread.hpp | 270 +- .../3rd/library/boost/boost/get_pointer.hpp | 96 +- .../boost/graph/detail/adjacency_list.hpp | 5654 +-- .../library/boost/boost/iostreams/chain.hpp | 1196 +- .../boost/iostreams/filter/symmetric.hpp | 620 +- .../3rd/library/boost/boost/locale/format.hpp | 1030 +- .../library/boost/boost/locale/generator.hpp | 470 +- .../library/boost/boost/locale/hold_ptr.hpp | 186 +- .../boost/locale/localization_backend.hpp | 318 +- .../3rd/library/boost/boost/locale/util.hpp | 418 +- .../distributions/non_central_chi_squared.hpp | 1992 +- .../boost/boost/mpi/python/serialize.hpp | 1078 +- .../boost/boost/multi_index/global_fun.hpp | 354 +- .../boost/boost/multi_index/identity.hpp | 274 +- .../boost/boost/multi_index/mem_fun.hpp | 410 +- .../boost/boost/multi_index/member.hpp | 524 +- .../program_options/options_description.hpp | 556 +- .../detail/associative_ptr_container.hpp | 822 +- .../detail/reversible_ptr_container.hpp | 1504 +- .../boost/boost/ptr_container/ptr_array.hpp | 468 +- .../ptr_container/ptr_circular_buffer.hpp | 1062 +- .../boost/ptr_container/ptr_inserter.hpp | 516 +- .../boost/ptr_container/ptr_map_adapter.hpp | 1748 +- .../ptr_container/ptr_sequence_adapter.hpp | 1550 +- .../boost/ptr_container/ptr_set_adapter.hpp | 1384 +- .../python/converter/arg_from_python.hpp | 672 +- .../converter/as_to_python_function.hpp | 98 +- .../python/detail/copy_ctor_mutates_rhs.hpp | 42 +- .../boost/boost/python/detail/is_auto_ptr.hpp | 60 +- .../boost/boost/python/make_constructor.hpp | 580 +- .../boost/boost/python/object/py_function.hpp | 344 +- .../boost/boost/python/to_python_indirect.hpp | 226 +- .../serialization/detail/shared_count_132.hpp | 1138 +- .../serialization/detail/shared_ptr_132.hpp | 900 +- .../detail/shared_ptr_nmt_132.hpp | 364 +- .../boost/smart_ptr/detail/shared_count.hpp | 1350 +- .../boost/boost/smart_ptr/scoped_ptr.hpp | 314 +- .../boost/boost/smart_ptr/shared_ptr.hpp | 2056 +- .../core/non_terminal/impl/grammar.ipp | 740 +- .../spirit/home/classic/symbols/impl/tst.ipp | 562 +- .../boost/spirit/home/classic/tree/common.hpp | 3170 +- .../home/support/detail/lexer/generator.hpp | 1728 +- .../boost/statechart/processor_container.hpp | 890 +- .../runtime/file/config_file_iterator.cpp | 1370 +- .../boost/thread/detail/thread_group.hpp | 308 +- .../library/boost/boost/typeof/std/memory.hpp | 34 +- .../Session/CommonAPI/CommonAPIStrings.h | 504 +- .../library/platform/utils/Base/Config.cpp | 360 +- .../3rd/library/platform/utils/Base/MD5.cpp | 8 +- .../CSAssistStressTest/test.cpp | 1464 +- .../CSAssistgameapi/CSAssistgameobjects.cpp | 2 +- .../CSAssistgameapi/CSAssistgameobjects.h | 2 +- .../soePlatform/CSAssist/utils/Base/Config.h | 222 +- .../soePlatform/CSAssist/utils/Base/MD5.cpp | 6 +- .../CSAssist/utils/Base/linux/Types.h | 90 +- .../CSAssist/utils/TcpLibrary/Clock.cpp | 2 - .../CTServiceGameAPI/Base/linux/Types.h | 90 +- .../CTCommon/CTServiceCharacter.h | 7 +- .../CTCommon/CTServiceCustomer.h | 8 +- .../CTCommon/CTServiceDBOrder.h | 7 +- .../CTCommon/CTServiceDBTransaction.h | 7 +- .../CTCommon/CTServiceServer.h | 7 +- .../CTCommon/CTServiceWebAPITransaction.h | 7 +- .../CTServiceGameAPI/TcpLibrary/Clock.cpp | 5 +- .../ChatAPI/projects/ChatAPI/Response.cpp | 124 +- .../soePlatform/ChatAPI/utils/Base/Base64.cpp | 2 +- .../soePlatform/ChatAPI/utils/Base/Base64.h | 2 +- .../soePlatform/ChatAPI/utils/Base/MD5.cpp | 6 +- .../ChatAPI/utils/Base/ccspanutil.cpp | 1 - .../ChatAPI/utils/UdpLibrary/UdpHashTable.h | 2 +- .../ChatAPI/utils/UdpLibrary/UdpPriority.h | 2 +- .../VChatAPI/utils2.0/utils/Base/Base64.cpp | 8 +- .../VChatAPI/utils2.0/utils/Base/Base64.h | 2 +- .../VChatAPI/utils2.0/utils/Base/MD5.cpp | 6 +- .../utils2.0/utils/Base/hashtable.hpp | 2 +- .../VChatAPI/utils2.0/utils/Base/pid.cpp | 6 - .../VChatAPI/utils2.0/utils/Base/priority.hpp | 2 +- .../utils/Base/serializeStringVector.h | 3 - .../utils2.0/utils/Base/serializeTemplates.h | 3 +- .../VChatAPI/utils2.0/utils/Base/utf8.cpp | 2 +- .../utils2.0/utils/TcpLibrary/Clock.cpp | 2 - .../3rd/library/udplibrary/hashtable.hpp | 2 +- .../3rd/library/udplibrary/priority.hpp | 2 +- .../crypto/src/shared/original/cryptlib.cpp | 6 +- .../crypto/src/shared/original/filters.cpp | 848 +- .../fileInterface/src/shared/AbstractFile.h | 3 +- .../src/shared/UnicodeAutoDeltaPackedMap.cpp | 2 - .../src/shared/core/CSHandler.cpp | 2 +- .../SwgGameServer/src/win32/WinMain.cpp | 1108 +- src/swg.doxygen | 2381 ++ 201 files changed, 121212 insertions(+), 119048 deletions(-) create mode 100644 src/swg.doxygen diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d5ba548a..db2930b8d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,10 +47,9 @@ if(WIN32) elseif(UNIX) find_package(Curses REQUIRED) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG -DDEBUG_LEVEL=2 -DPRODUCTION=0 -g -pipe -Wall -Wno-unknown-pragmas -Wno-reorder -O0") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DDEBUG_LEVEL=0 -DPRODUCTION=1 -march=native -pipe -mtune=native -O2 -s") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-write-strings") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG -DDEBUG_LEVEL=2 -DPRODUCTION=0 -g -pipe -O0 -Wall -Wno-overloaded-virtual -Wno-missing-braces -Wno-unused-private-field -Wno-format -Wno-unused-but-set-variable -Wno-write-strings -Wno-unknown-pragmas -Wno-uninitialized -Wno-reorder -Wno-unused-const-variable -Wno-unknown-warning-option") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DDEBUG_LEVEL=0 -DPRODUCTION=1 -march=native -pipe -mtune=native -O2 -Wno-overloaded-virtual -Wno-missing-braces -Wno-unused-private-field -Wno-format -Wno-unused-but-set-variable -Wno-write-strings -Wno-unknown-pragmas -Wno-uninitialized -Wno-reorder -Wno-unused-const-variable -Wno-unknown-warning-option") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0") add_definitions(-DLINUX -D_REENTRANT -Dlinux -D_USING_STL -D__STL_NO_BAD_ALLOC -D_GNU_SOURCE -D_XOPEN_SOURCE=500) endif() diff --git a/src/cmake/linux/FindOracle.cmake b/src/cmake/linux/FindOracle.cmake index 2d7427d79..1fe3dc033 100644 --- a/src/cmake/linux/FindOracle.cmake +++ b/src/cmake/linux/FindOracle.cmake @@ -34,6 +34,12 @@ if(DEFINED ENV{ORACLE_HOME}) find_path(ORACLE_INCLUDE_DIR NAMES oci.h PATHS + /usr/include/oracle/12.1/client64 + /usr/include/oracle/12.1/client + /usr/lib/oracle/12.1/client64 + /usr/share/oracle/12.1/client64 + /usr/lib/oracle/12.1/client + /usr/share/oracle/12.1/client ${ORACLE_HOME}/rdbms/public ${ORACLE_HOME}/include ${ORACLE_HOME}/sdk/include # Oracle SDK diff --git a/src/engine/client/application/Miff/src/lex_yy.c b/src/engine/client/application/Miff/src/lex_yy.c index 449b767d0..e9bd04364 100644 --- a/src/engine/client/application/Miff/src/lex_yy.c +++ b/src/engine/client/application/Miff/src/lex_yy.c @@ -4520,7 +4520,7 @@ static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ); +static int yy_flex_strnlen (yyconst char * ); #endif #ifndef YY_NO_INPUT @@ -4726,9 +4726,9 @@ YY_RULE_SETUP char *s; // allocate space for string and pass the string pointer rather then yytext count(); - s = MIFFallocString(strlen(yytext) + 1); + s = MIFFallocString(strnlen(yytext) + 1); strcpy(s, yytext+1); /* strip off the double quotes */ - s[strlen(yytext+1)-1] = 0; /* strip off the ending double quotes */ + s[strnlen(yytext+1)-1] = 0; /* strip off the ending double quotes */ yylval.stype = s; return(STR_LIT); } @@ -4977,7 +4977,7 @@ YY_RULE_SETUP char *s; // allocate space for string and pass the string pointer rather then yytext count(); - s = MIFFallocString(strlen(yytext) + 1); + s = MIFFallocString(strnlen(yytext) + 1); strcpy(s, yytext); yylval.stype = s; return(IDENTIFIER); @@ -5915,7 +5915,7 @@ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { - return yy_scan_bytes(yystr,strlen(yystr) ); + return yy_scan_bytes(yystr,strnlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will @@ -6126,7 +6126,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s ) +static int yy_flex_strnlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) @@ -6219,7 +6219,7 @@ void yyerror(char *err) /* called by yyparse() */ **-------------------------*/ int MIFFYYInput(char *buf,int max_size) { - int len = strlen(MIFFInputStream); + int len = strnlen(MIFFInputStream); int n = max_size < len ? max_size : len; if (n > 0) { diff --git a/src/engine/client/application/Miff/src/linux/parser.lex b/src/engine/client/application/Miff/src/linux/parser.lex index 3989ec880..f80c2c9b2 100644 --- a/src/engine/client/application/Miff/src/linux/parser.lex +++ b/src/engine/client/application/Miff/src/linux/parser.lex @@ -39,7 +39,7 @@ int yyparse(); int MIFFYYInput(char *buf,int max_size); void initParser(void); void count(void); -void yyerror(char *err); +int yyerror(char *err); void open_brace(void); void close_brace(void); int count_brace(void); @@ -374,7 +374,7 @@ void initParser(void) /*-------------------------------------------------** ** generate a dialog box to MFC to report an error ** **-------------------------------------------------*/ -void yyerror(char *err) /* called by yyparse() */ +int yyerror(char *err) /* called by yyparse() */ { char myString[256]; @@ -387,7 +387,7 @@ void yyerror(char *err) /* called by yyparse() */ MIFFSetError(); /* set global error flag for shell as well */ yyterminate(); } - + return 0; } /*-------------------------** diff --git a/src/engine/client/application/Miff/src/linux/parser.yac b/src/engine/client/application/Miff/src/linux/parser.yac index 8412cbea6..25feaf7e8 100644 --- a/src/engine/client/application/Miff/src/linux/parser.yac +++ b/src/engine/client/application/Miff/src/linux/parser.yac @@ -27,7 +27,7 @@ #include #include /* for toupper() */ #include /* for wide character (16bit) strings */ - +#include /* for strtoupper and strtolower */ #include /*----------------------------------------------------------------** @@ -823,7 +823,7 @@ void parseESCstring(char *str, char *targetBuffer, int sizeOfTarget) sPtr++; if (numIndex > 3) { - sprintf(err_msg, "Escape sequence Octal numbers greater then\noctal o400 (256 decimal)! [more then 3 digits]", *sPtr); + sprintf(err_msg, "Escape sequence Octal numbers greater then\noctal o400 (256 decimal)! [more then 3 digits]"); yyerror(err_msg); exitParser = 1; } @@ -841,7 +841,7 @@ void parseESCstring(char *str, char *targetBuffer, int sizeOfTarget) if (tempNum > 255) { - sprintf(err_msg, "Escape sequence Octal numbers greater then\noctal o400 (256 decimal)!", tempNum); + sprintf(err_msg, "Escape sequence Octal numbers greater then\noctal o400 (256 decimal)!"); yyerror(err_msg); exitParser = 1; } @@ -865,7 +865,7 @@ void parseESCstring(char *str, char *targetBuffer, int sizeOfTarget) sPtr++; if (numIndex > 3) { - sprintf(err_msg, "Escape sequence HEX numbers greater then 0x100\n(256 decimal)! [more then 3 digits]", *sPtr); + sprintf(err_msg, "Escape sequence HEX numbers greater then 0x100\n(256 decimal)! [more then 3 digits]"); yyerror(err_msg); exitParser = 1; } @@ -883,7 +883,7 @@ void parseESCstring(char *str, char *targetBuffer, int sizeOfTarget) if (tempNum > 255) { - sprintf(err_msg, "Escape sequence HEX numbers greater then 0x100\n(256 decimal)!", *sPtr); + sprintf(err_msg, "Escape sequence HEX numbers greater then 0x100\n(256 decimal)!"); yyerror(err_msg); exitParser = 1; } @@ -985,7 +985,7 @@ void addEnumSymbol(char *symString, long value) if (MAX_SYMCHARS < strlen(symString)) { /* somebody insane decided to use variable longer then max size! */ - sprintf(err_msg, "%s is longer then %d characters! [value: %d]", symString, MAX_SYMCHARS, value); + sprintf(err_msg, "%s is longer then %d characters! [value: %ld]", symString, MAX_SYMCHARS, value); yyerror(err_msg); } else diff --git a/src/engine/client/application/Miff/src/win32/miff.cpp b/src/engine/client/application/Miff/src/win32/miff.cpp index 88d2e6f4b..a935b72db 100644 --- a/src/engine/client/application/Miff/src/win32/miff.cpp +++ b/src/engine/client/application/Miff/src/win32/miff.cpp @@ -1,961 +1,961 @@ -//=========================================================================== -// -// FILENAME: mIFF.cpp [C:\Projects\new\tools\src\miff\src\] -// COPYRIGHT: (C) 1999 BY Bootprint Entertainment -// -// DESCRIPTION: make IFF (Console version) -// AUTHOR: Hideki Ikeda -// DATE: 1/07/99 12:57:20 PM -// -// HISTORY: 1/07/99 [HAI] - File created -// : 1/07/99 [HAI] - v1.0 introductory version -// : 1/12/99 [HAI] - v1.1 switched from DOS to Engine library -// : - first attempt was to setup the main entry -// : point via ConsoleEntryPoint() via callback -// : 1/29/99 [HAI] - changed the parameter in MIFFMessage to allow -// : output even in non-verbose mode (for error -// : message purpose. -// : 05/07/99 [HAI]- added MIFFallocString() and MIFFfreeString() -// : to work with memory manager. they are allocated -// : in the lexical analyzer for IDENTIFIERS and STR_LIT -// : deleted after parser parses the rule. -// -// FUNCTION: main() -// : evaluateArgs() -// : help() -// : handleError() -// : preprocessSource() -// : MIFFMessage() -// : callbackFunction() -// -//=========================================================================== - -//========================================================== include files == -#include "sharedFoundation/FirstSharedFoundation.h" - -#include "sharedCompression/SetupSharedCompression.h" -#include "sharedDebug/SetupSharedDebug.h" -#include "sharedFile/SetupSharedFile.h" -#include "sharedFile/TreeFile.h" -#include "sharedFoundation/CommandLine.h" -#include "sharedFoundation/Crc.h" -#include "sharedFoundation/Os.h" -#include "sharedFoundation/SetupSharedFoundation.h" -#include "sharedMemoryManager/MemoryManager.h" -#include "sharedThread/SetupSharedThread.h" - -#include "InputFileHandler.h" -#include "OutputFileHandler.h" - -#include // for memset() -#include // FILE stuff -#include // for getcwd() -#include // for tolower() -#include // for system() - -//================================================= static vars assignment == -const int entryPointVersion = 1; // constantly check DataEntryPoint.h to see if this value has changed - -OutputFileHandler *outfileHandler = NULL; -const int bufferSize = 16 * 1024 * 1024; -const int maxStringSize = 256; -const char version[] = "1.3 September 18, 2000"; - -// vars set by pragmas or via command line -char drive[8]; // should be no more then 2 char "C:" -char directory[maxStringSize]; -char filename[maxStringSize]; -char extension[8]; // we'll truncate if the extension is more then 8 chars... -char inFileName[512]; - -// switches to be sent to mIFF Compiler -char sourceBuffer[bufferSize]; -char outFileName[512]; // x2 to combine filename, dir, and ext -bool usePragma = false; -bool useCCCP = false; -bool verboseMode = false; // default to non-verbose mode -bool debugMode = false; // set this on and the preprocessed source file (mIFF.$$$) won't be deleted - -static bool runningUnderNT; - -enum errorType { - ERR_FILENOTFOUND = -1, - ERR_ARGSTOOFEW = -2, - ERR_BUFFERTOOSMALL = -3, - ERR_UNKNOWNDIR = -4, - ERR_PREPROCESS = -5, - ERR_MULTIPLEINFILE = -6, - ERR_PARSER = -7, - ERR_ENGINE = -8, - - ERR_HELPREQUEST = -9, - ERR_OPTIONS = -10, - - ERR_WRITEERROR = -11, - - ERR_NONE = 0 - }; -char err_msg[256]; -errorType errorFlag = ERR_NONE; // assume no error (default) - - -// long and short name definitions for command line options - -static const char * const LNAME_HELP = "help"; -static const char * const LNAME_INPUT_FILE = "inputfile"; -static const char * const LNAME_OUTPUT_FILE = "outputfile"; -static const char * const LNAME_PRAGMA_TARGET = "pragmatarget"; -static const char * const LNAME_CCCP = "cccp"; -static const char * const LNAME_VERBOSE = "verbose"; -static const char * const LNAME_DEBUG = "debug"; - -static const char SNAME_HELP = 'h'; -static const char SNAME_INPUT_FILE = 'i'; -static const char SNAME_OUTPUT_FILE = 'o'; -static const char SNAME_PRAGMA_TARGET = 'p'; -static const char SNAME_CCCP = 'c'; -static const char SNAME_VERBOSE = 'v'; -static const char SNAME_DEBUG = 'd'; - -// following is the command line option spec tree needed for command line processing -static CommandLine::OptionSpec optionSpecArray[] = -{ - OP_BEGIN_SWITCH(OP_NODE_REQUIRED), - - // help - OP_SINGLE_SWITCH_NODE(SNAME_HELP, LNAME_HELP, OP_ARG_NONE, OP_MULTIPLE_DENIED), - - // real options - OP_BEGIN_SWITCH_NODE(OP_MULTIPLE_DENIED), - OP_BEGIN_LIST(), - // input filename required - OP_SINGLE_LIST_NODE(SNAME_INPUT_FILE, LNAME_INPUT_FILE, OP_ARG_REQUIRED, OP_MULTIPLE_DENIED, OP_NODE_REQUIRED), - - // optional, mutually exclusive output file specification options - // if none specified, generate derive output filename from input filename - OP_BEGIN_LIST_NODE(OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), - OP_BEGIN_SWITCH(OP_NODE_OPTIONAL), - // specify output filename on command line - OP_SINGLE_SWITCH_NODE(SNAME_OUTPUT_FILE, LNAME_OUTPUT_FILE, OP_ARG_REQUIRED, OP_MULTIPLE_DENIED), - - // use pragma target for output filename - OP_SINGLE_SWITCH_NODE(SNAME_PRAGMA_TARGET, LNAME_PRAGMA_TARGET, OP_ARG_NONE, OP_MULTIPLE_DENIED), - OP_END_SWITCH(), - OP_END_LIST_NODE(), - - // if specified, use cccp instead of cpp - OP_SINGLE_LIST_NODE(SNAME_CCCP, LNAME_CCCP, OP_ARG_NONE, OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), - - // if specified, be verbose - OP_SINGLE_LIST_NODE(SNAME_VERBOSE, LNAME_VERBOSE, OP_ARG_NONE, OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), - - // if specified, enter debug info - OP_SINGLE_LIST_NODE(SNAME_DEBUG, LNAME_DEBUG, OP_ARG_NONE, OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), - OP_END_LIST(), - OP_END_SWITCH_NODE(), - - OP_END_SWITCH() -}; -static const int optionSpecCount = sizeof(optionSpecArray) / sizeof(optionSpecArray[0]); - -//================================================= function prototypes == -int main(int argc, char *argv[]); -static errorType evaluateArgs(void); -static void help(void); -static void handleError(errorType error); -static int preprocessSource(char *sourceName); -static void callbackFunction(void); -static errorType loadInputToBuffer(void *destAddr, int maxBufferSize); - -// functions called by parser.yac and parser.lex -extern "C" void MIFFMessage(char *msg, int forceOut); -extern "C" void MIFFSetError(void); -extern "C" void MIFFSetIFFName(const char *newFileName); -extern "C" void MIFFinsertForm(const char *formName); -extern "C" void MIFFinsertChunk(const char *chunkName); -extern "C" void MIFFinsertChunkData(void * buffer, unsigned bufferSize); -extern "C" int MIFFloadRawData(char *fname, void * buffer, unsigned maxBufferSize); -extern "C" void MIFFexitChunk(void); -extern "C" void MIFFexitForm(void); -extern "C" unsigned long MIFFgetLabelHash(char *inputStream); - -// external functions found in parser.lex file -extern "C" void MIFFCompile(char *inputStream, char *inputFname); -extern "C" void MIFFCompileInit(char *inputStream, char *inputFname); - -//--------------------------------------------------------------------------- -// main entry point from console call -// -// Return Value: -// errorType - see enumeration; 0 if no errors -// -// Remarks: -// -// -// See Also: -// -// -// Revisions and History: -// 1/07/99 [HAI] - created -// -int main( int argc, // number of args in commandline - char * argv[] // list of pointers to strings - ) -{ - memset(sourceBuffer, 0, bufferSize); - - SetupSharedThread::install(); - SetupSharedDebug::install(4096); - - SetupSharedFoundation::Data SetupSharedFoundationData (SetupSharedFoundation::Data::D_console); - SetupSharedFoundationData.useWindowHandle = false; - SetupSharedFoundationData.argc = argc; - SetupSharedFoundationData.argv = argv; - SetupSharedFoundationData.demoMode = false; - SetupSharedFoundation::install (SetupSharedFoundationData); - - SetupSharedCompression::install(); - - SetupSharedFile::install(false); - - TreeFile::addSearchAbsolute(0); - TreeFile::addSearchPath (".", 0); - - SetupSharedFoundation::callbackWithExceptionHandling(callbackFunction); - SetupSharedFoundation::remove(); - - SetupSharedThread::remove(); - return static_cast (errorFlag); -} - -//--------------------------------------------------------------------------- -// callback function for Engine's console entry point -// -// Return Value: -// none -// -// Remarks: -// this is like a substitute of main() -// -// See Also: -// -// -// Revisions and History: -// 1/12/99 [HAI] - created -// -static void callbackFunction(void) -{ - outfileHandler = NULL; - -#ifdef WIN32 - - // check if we're running under NT - OSVERSIONINFO osInfo; - Zero(osInfo); - - osInfo.dwOSVersionInfoSize = sizeof(osInfo); - const BOOL getVersionResult = GetVersionEx(&osInfo); - if (getVersionResult) - runningUnderNT = (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); - if (runningUnderNT) - DEBUG_REPORT_LOG(true, ("MIFF: running under Windows NT platform\n")); - else - DEBUG_REPORT_LOG(true, ("MIFF: running under non-NT Windows platform\n")); - -#endif - - errorFlag = evaluateArgs(); - if (ERR_NONE == errorFlag) - { - outfileHandler = new OutputFileHandler(outFileName); - MIFFCompile(sourceBuffer, inFileName); - } - else - handleError(errorFlag); - - if (outfileHandler) - { - // only write output IF there was no error - if (ERR_NONE == errorFlag) - { - if (!outfileHandler->writeBuffer()) - { - fprintf(stderr, "MIFF: failed to write output file \"%s\"\n", outFileName); - errorFlag = ERR_WRITEERROR; - } - } - delete outfileHandler; - } -} - -//--------------------------------------------------------------------------- -// Evaluates the command line and sets up the environment variables required for mIFF to function -// -// Return Value: -// errorType -// -// Remarks: -// argc's and argv's are substituted with CommandLine::functions() -// -// See Also: -// -// -// Revisions and History: -// 1/07/99 [HAI] - created -// -static errorType evaluateArgs(void) -{ - errorType retVal = ERR_NONE; - - // parse the commandline - const CommandLine::MatchCode mc = CommandLine::parseOptions(optionSpecArray, optionSpecCount); - if (mc != CommandLine::MC_MATCH) - { - // -TF- add call to retrieve command line error buffer for display (as soon as it is written!) - printf("WARNING: usage error detected, printing help.\n"); - help(); - return ERR_OPTIONS; - } - else if (CommandLine::getOccurrenceCount(SNAME_HELP)) - { - // user specified help - help(); - retVal = ERR_HELPREQUEST; - return(retVal); - } - - // at this point, we can assume a valid combination of options has been specified on the commandline - - - // setup input filename - strcpy(inFileName, CommandLine::getOptionString(SNAME_INPUT_FILE)); - - - // handle output filename spec - if (CommandLine::getOccurrenceCount(SNAME_OUTPUT_FILE)) - { - strcpy(outFileName, CommandLine::getOptionString(SNAME_OUTPUT_FILE)); - } - else if (CommandLine::getOccurrenceCount(SNAME_PRAGMA_TARGET)) - { - // use pragma target within iff source for output filename - usePragma = true; - } - else - { - // no output option specified on commandline, derive from input filename - char *terminator; - - // start with input file pathname - strcpy(outFileName, inFileName); - - // try to terminate at rightmost '.' - terminator = strrchr(outFileName, '.'); - if (terminator) - *terminator = 0; - - // append the default iff extension - strcat(outFileName, ".iff"); - } - - - // handle options (get them out of the way, as we use them later) - useCCCP = (CommandLine::getOccurrenceCount(SNAME_CCCP) != 0); - verboseMode = (CommandLine::getOccurrenceCount(SNAME_VERBOSE) != 0); - debugMode = (CommandLine::getOccurrenceCount(SNAME_DEBUG) != 0); - - - // preprocess the input file - if (0 == preprocessSource(inFileName)) - { - if (verboseMode) - { - sprintf(err_msg,"Now compiling %s...\n", inFileName); - MIFFMessage(err_msg, 0); - } - if (ERR_NONE == retVal) - retVal = loadInputToBuffer(sourceBuffer, bufferSize); - } - else - { - // preprocessSource returned an error... - retVal = ERR_PREPROCESS; - } - if (retVal != ERR_NONE) - return retVal; - - return retVal; - -#if 0 - - errorType retVal = ERR_NONE; // assume no error has been found - bool outPathUsed = false; // flag to monitor if -o flag was used, if so, we can ignore -d, -p, -e, -f - bool inFileEntered = false; - int argc = CommandLine::getPlainCount(); - - // get default values from DOS - char currentDir[maxStringSize]; - if (NULL == getcwd(currentDir, maxStringSize)) // get current working directory - { - retVal = ERR_UNKNOWNDIR; - return(retVal); - } - drive[0] = currentDir[0]; // drive letter - drive[1] = 0; // and null terminate it - strcpy(extension, "IFF"); // default to uppercase .IFF - strcpy(directory, ¤tDir[2]); // get everything after the Drive: including the first backslash - filename[0] = 0; - - // see specs.txt for requests - // scan for any argv's that has '-' in the argv[n][0]'s character - for (int index = 0; index < argc; index++) // note: if using argv[] rather then CommandLine::getPlainString() then start with 1 rather then 0 - { - if ('-' == CommandLine::getPlainString(index)[0]) - { - // we've found a parameter switch - switch (tolower(CommandLine::getPlainString(index)[1])) // assume non case sensitive switches - { - case 'i': // install via #pragma - { - usePragma = true; - break; - } - - case 'c': // use CCCP instead of CPP - useCCCP = true; - break; - - case 'v': // don't show any debug message - verboseMode = true; - break; - - case '$': - debugMode = true; - break; - - case 'o': // target output file name and path (complete path) - { - index++; // next param - outPathUsed = true; - strcpy(outFileName, CommandLine::getPlainString(index)); - break; - - } - - case 'd': // target drive letter (-p must be present) - { - if (!outPathUsed) - { - index++; // next param - strcpy(drive, CommandLine::getPlainString(index)); - } - else - index++; // skip the drive letter arg that SHOULD follow the -d option - break; - } - - case 'p': // target pathname - { - if (!outPathUsed) - { - index++; // next param - strcpy(directory, CommandLine::getPlainString(index)); - } - else - index++; // skip the pathname arg that follows the -p option - break; - } - - case 'f': // target filename - { - if (!outPathUsed) - { - index++; // next param - strcpy(filename, CommandLine::getPlainString(index)); - } - else - index++; // skip the filename arg that follows the -f - break; - } - - case 'e': // target extension - { - if (!outPathUsed) - { - index++; // next param - strcpy(extension, CommandLine::getPlainString(index)); - } - else - index++; // skip the extension arg that follows the -e - break; - } - - case 'h': // help! - case '?': - { - help(); - index = argc; // force to exit - retVal = ERR_HELPREQUEST; - return(retVal); // special case, ONLY time I call return() in the middle of the function (because I check for argc < 2 at the end of the code) - break; - } - - default: - { - sprintf(err_msg, "\nUnknown parameter %s, use -h to seek help...\n", CommandLine::getPlainString(index)); - MIFFMessage(err_msg, 1); - index = argc; // force to exit - break; - } - } - } - else - { - // we found an arg that doesn't start with '-' so let's assume it's a filename - if (!inFileEntered) - { - strcpy(inFileName, CommandLine::getPlainString(index)); - inFileEntered = true; - } - else - { - retVal = ERR_MULTIPLEINFILE; - index = argc; - } - - // now construct the DEFAULT filename for this file by scanning backwards to front and only extracting the filename (no extension, no path) - if (ERR_NONE == retVal) - { - char sourceName[maxStringSize]; - strcpy(sourceName, inFileName); // make a duplicate for us to play with - for (int strIndex = strlen(sourceName); strIndex > 0; strIndex--) - { - if ('.' == sourceName[strIndex]) - sourceName[strIndex] = 0; // put a stopper here... we are assuming that '.' indicates extension! I'm going to assume that the person is just testing me if s/he decides to use filename like "foo.bar.psych" which will truncate to "foo" - if ('\\' == sourceName[strIndex]) - break; // get out, for we've reached the path name... - } - - // ok, by here, strIndex should point to either beginning of the string, or where the first '\' was found scanning backwards - strcpy(filename, &sourceName[strIndex]); // ta-da-! - } - } - } - - if (inFileEntered) - { - if (0 == preprocessSource(inFileName)) - { - if (verboseMode) - { - // using err_msg as my temp buffer... - sprintf(err_msg,"Now compiling %s\n", inFileName); - MIFFMessage(err_msg, 0); - } - - if (ERR_NONE == retVal) - retVal = loadInputToBuffer(sourceBuffer, bufferSize); - } - else // preprocessSource returned an error... - { - retVal = ERR_PREPROCESS; - } - } - else // inFileEntered == false - { - MIFFMessage("Missing input filename in command line!", 1); - } - - // construct a outFileName[] based on drive[], directory[], filename[], and extension[] - if (!outPathUsed && (ERR_NONE == retVal)) - { - if (inFileName[0]) // make sure the user has entered a input filename - sprintf(outFileName,"%s:%s\\%s.%s", drive, directory, filename, extension); - } - - if (argc < 1) - retVal = ERR_ARGSTOOFEW; // we can do this because we know -h was not entered... - - return(retVal); - -#endif - -} - - -//--------------------------------------------------------------------------- -// reads the tmeporary files spit out by CCCP and stuffs the plain text into source buffer -// -// Return Value: -// errorType -// -// Remarks: -// -// -// See Also: -// -// -// Revisions and History: -// 1/14/99 [HAI] - created -// -static errorType loadInputToBuffer( - void * dest, // destination address of where you want the date to be read - int maxBufferSize // maximum destination data pool size - ) -{ - errorType retVal = ERR_NONE; - InputFileHandler *inFileHandler = new InputFileHandler("mIFF.$$$"); - if (inFileHandler) - { - int sizeRead = inFileHandler->read(dest, maxBufferSize); - if (sizeRead >= maxBufferSize) - { - retVal = ERR_BUFFERTOOSMALL; - } - else - { - reinterpret_cast(dest)[sizeRead] = 0; // so stupid... but if you don't zero-terminate at exact spot, YYInput may chokes because of extra grammer that may exist... - } - if (!debugMode) - inFileHandler->deleteFile("mIFF.$$$", true); // no need for temp file now... - - // we've successfully read the file, now close it... - delete inFileHandler; - } - else // inFileName is NULL - { - retVal = ERR_FILENOTFOUND; - } - - return(retVal); -} - -//--------------------------------------------------------------------------- -// help function called by main upon -h switch -// -// Return Value: -// none -// -// Remarks: -// #include's mIFF.dox -// make sure to update the version when modified. -// Notice that help() does NOT go thru MIFFMessage() because we want it to -// print out whether it's verbose mode or not... -// -// See Also: -// mIFF.dox -// -// Revisions and History: -// 1/07/99 [HAI] - created -// -static void help(void) -{ - printf("\nmIFF v%s (DOS version) - Bootprint Ent. (c) 1999\n", version); - printf("Hideki Ikeda\n"); -#include "mIFF.dox" -} - - -//--------------------------------------------------------------------------- -// upon exit from main(), if error has been found, it calls here to inform the user of the type of errors it has encounted. -// -// Return Value: -// none -// -// Remarks: -// use -q switch to suppress error messages - but in shell, return value can be used to determine the handling -// -// See Also: -// -// -// Revisions and History: -// 1/07/99 [HAI] - created -// -static void handleError(errorType error) -{ - if (ERR_NONE == error) - return; - - switch (error) - { - case ERR_NONE: - break; - - case ERR_FILENOTFOUND: - MIFFMessage("ERROR: INPUT File not found!\n", 1); - break; - - case ERR_ARGSTOOFEW: - MIFFMessage("ERROR: Not enough arguments. Use -h for help.\n", 1); - break; - - case ERR_BUFFERTOOSMALL: - MIFFMessage("ERROR: Internally allocated buffer for reading\nsource code is too small, increase buffer and re-compile\n", 1); - break; - - case ERR_UNKNOWNDIR: - MIFFMessage("ERROR: Directory unknown...\n", 1); - break; - - case ERR_PREPROCESS: - MIFFMessage("ERROR: Possible problems running the GNU C Preprocessor.\n", 1); - break; - - case ERR_MULTIPLEINFILE: - MIFFMessage("ERROR: There can only be ONE inputfile name.\nPerhaps you've forgotten the -o option flag\n", 1); - break; - - case ERR_ENGINE: - MIFFMessage("ERROR: Engine returned a non-zero value...\n", 1); - break; - - case ERR_PARSER: - MIFFMessage("ERROR: Parser error\n", 1); - break; - - case ERR_HELPREQUEST: - break; - - case ERR_OPTIONS: - MIFFMessage("ERROR: Failed to handle command line options\n", 1); - break; - - default: - MIFFMessage("ERROR: Unknown error, you suck!\n", 1); - break; - } -} - - -///////////////////////////////////////////////////////////////////////////// -// gotta write all these externs because you can't call C++ class based non-static -// functions from C... So we will use here as the bridge between the two -// languages - - -//--------------------------------------------------------------------------- -// Message output handler called by ALL external "C" functions -// -// Return Value: -// none -// -// Remarks: -// all the messages that are displayed are channeled thru this function. Note the -q quiet mode suppresses all messages. -// this is an extern "C" function -// -// See Also: -// yyerror() -// -// Revisions and History: -// 1/07/99 [] - created -// -extern "C" void MIFFMessage(char *message, // null terminated string to be displayed - int forceOutput) // if non-zero, it will print out even in quiet mode (for ERRORs) -{ - if (forceOutput) - fprintf(stdout, "%s\n", message); - else if (verboseMode) - fprintf(stdout, "%s\n", message); - OutputDebugString(message); - OutputDebugString("\n"); -} - -// Only call this via parser!!! -extern "C" void MIFFSetError(void) -{ - errorFlag = ERR_PARSER; -} - -//--------------------------------------------------------------------------- -// validation of the filename passed are legal. -// -// Return Value: -// bool usePragma - whether #pragma is ignored or not -// -// Remarks: -// if -i switch is used then #pragma's are expected -// this is an extern "C" function -// -// See Also: -// -// -// Revisions and History: -// 1/07/99 [ ] - created -// -extern "C" int validateTargetFilename( char *targetFileName, // pointer to where we can store the string filename - unsigned maxTargetBufSize // size of the filename string buffer - ) -{ - if (strlen(outFileName) > maxTargetBufSize) - MIFFMessage("Internal error, increase string buffer size in parser.yac and recompile!", 1); - - strcpy(targetFileName, outFileName); - - return(usePragma); -} - - -//--------------------------------------------------------------------------- -// function calls CCCP or CPP via shell to preprocess the source code for #include's and #define's via C-Compatible Compiler Preprocessor -// -// Return Value: -// shell return value (4DOS is very generous on returning different values, while DOS just returns 0 all the time) -// -// Remarks: -// use -c switch to use CCCP rather then CPP in your search path -// -// See Also: -// -// -// Revisions and History: -// 1/07/99 [ ] - created -// -static int preprocessSource(char *sourceName) -{ - char shellCommand[512]; - int retVal = 0; - - memset(shellCommand, 0, sizeof(shellCommand)); - -// if (!runningUnderNT) - { - - if (verboseMode) - MIFFMessage("Preprocessing... via CCCP", 0); - - // CCCP parameters: - // -nostdinc -nostdinc++ - do NOT search for standard include directory; without this, your - // puter would be just twiddling its thumb because CCCP can't find it... - // -pedantic - issue warnings (use pedantic-errors if you want it as errors) - // required by the ANSI C standard in certain cases such as comments that - // follow the #else/#endif - // -dD - output #defines (for the purpose of error msg I parse) - // -H - display the name of the header/included files (verbose mode) - // -P - originally, I had this... so it won't show the # line_num "filename" ??? - if (!useCCCP && verboseMode) - { - sprintf(shellCommand, "cpp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD -H %s mIFF.$$$", sourceName); - } - else if (!useCCCP && !verboseMode) - { - sprintf(shellCommand, "cpp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD %s mIFF.$$$", sourceName); - } - else if (useCCCP && verboseMode) - { - sprintf(shellCommand, "cccp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD -H %s mIFF.$$$", sourceName); - } - else - sprintf(shellCommand, "cccp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD %s mIFF.$$$", sourceName); - } -// else - { - // running under NT. Use the MSVC cl since it deals with long filenames on fat16/fat32 partitions correctly - // and ccp and cccp don't -// sprintf(shellCommand, "cl /nologo /W4 /EP %s > mIFF.$$$", sourceName); - } - - retVal = system(shellCommand); - if (2 == retVal) // actually, I think 4DOS reports 2 for cannot find file, but DOS returns a 0... - { - REPORT_LOG(true, ("failed to execute following shell command (%d):\n", retVal)); - REPORT_LOG(true, (" %s\n", shellCommand)); - MIFFMessage("\n\nERROR: Cannot find preprocessor (either CCCP.EXE, CPP.EXE or CL.EXE (under NT) in the search path...\n", 1); - MIFFMessage("Please make sure the preprocessor is in your search path!\n", 1); - } - return(retVal); -} - -extern "C" void MIFFSetIFFName(const char *newFileName) -{ - if (ERR_NONE != errorFlag) - return; - - if (outfileHandler) - outfileHandler->setCurrentFilename(newFileName); -} - -extern "C" void MIFFinsertForm(const char *formName) -{ - if (ERR_NONE != errorFlag) - return; - - if (outfileHandler) - outfileHandler->insertForm(formName); -} - -extern "C" void MIFFinsertChunk(const char *chunkName) -{ - if (ERR_NONE != errorFlag) - return; - - if (outfileHandler) - outfileHandler->insertChunk(chunkName); -} - -extern "C" void MIFFinsertChunkData(void * buffer, unsigned bufferSize) -{ - if (ERR_NONE != errorFlag) - return; - - if (outfileHandler) - outfileHandler->insertChunkData(buffer, bufferSize); -} - -extern "C" int MIFFloadRawData(char *fname, void * buffer, unsigned maxBufferSize) -{ - int sizeRead = -1; - - if (ERR_NONE != errorFlag) - return(sizeRead); // should be -1 - - InputFileHandler * inFileName = new InputFileHandler(fname); - if (inFileName) - { - sizeRead = inFileName->read(buffer, maxBufferSize); - if (static_cast(sizeRead) >= maxBufferSize) - { - handleError(ERR_BUFFERTOOSMALL); - sizeRead = -1; - } - delete inFileName; - } - - return(sizeRead); -} - -extern "C" void MIFFexitChunk(void) -{ - if (ERR_NONE != errorFlag) - return; - - if (outfileHandler) - outfileHandler->exitChunk(); -} -extern "C" void MIFFexitForm(void) -{ - if (ERR_NONE != errorFlag) - return; - - if (outfileHandler) - outfileHandler->exitForm(); -} - -extern "C" char * MIFFallocString(int sizeOfString) -{ - return(new char[sizeOfString]); -} - -extern "C" void MIFFfreeString(char * pointer) -{ - delete [] pointer; -} - -extern "C" unsigned long MIFFgetLabelHash(char * inputStream) -{ - return (unsigned long)Crc::calculate(inputStream); -} - -//=========================================================================== -//============================================================ End-of-file == -//=========================================================================== - +//=========================================================================== +// +// FILENAME: mIFF.cpp [C:\Projects\new\tools\src\miff\src\] +// COPYRIGHT: (C) 1999 BY Bootprint Entertainment +// +// DESCRIPTION: make IFF (Console version) +// AUTHOR: Hideki Ikeda +// DATE: 1/07/99 12:57:20 PM +// +// HISTORY: 1/07/99 [HAI] - File created +// : 1/07/99 [HAI] - v1.0 introductory version +// : 1/12/99 [HAI] - v1.1 switched from DOS to Engine library +// : - first attempt was to setup the main entry +// : point via ConsoleEntryPoint() via callback +// : 1/29/99 [HAI] - changed the parameter in MIFFMessage to allow +// : output even in non-verbose mode (for error +// : message purpose. +// : 05/07/99 [HAI]- added MIFFallocString() and MIFFfreeString() +// : to work with memory manager. they are allocated +// : in the lexical analyzer for IDENTIFIERS and STR_LIT +// : deleted after parser parses the rule. +// +// FUNCTION: main() +// : evaluateArgs() +// : help() +// : handleError() +// : preprocessSource() +// : MIFFMessage() +// : callbackFunction() +// +//=========================================================================== + +//========================================================== include files == +#include "sharedFoundation/FirstSharedFoundation.h" + +#include "sharedCompression/SetupSharedCompression.h" +#include "sharedDebug/SetupSharedDebug.h" +#include "sharedFile/SetupSharedFile.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/CommandLine.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/SetupSharedFoundation.h" +#include "sharedMemoryManager/MemoryManager.h" +#include "sharedThread/SetupSharedThread.h" + +#include "InputFileHandler.h" +#include "OutputFileHandler.h" + +#include // for memset() +#include // FILE stuff +#include // for getcwd() +#include // for tolower() +#include // for system() + +//================================================= static vars assignment == +const int entryPointVersion = 1; // constantly check DataEntryPoint.h to see if this value has changed + +OutputFileHandler *outfileHandler = NULL; +const int bufferSize = 16 * 1024 * 1024; +const int maxStringSize = 256; +const char version[] = "1.3 September 18, 2000"; + +// vars set by pragmas or via command line +char drive[8]; // should be no more then 2 char "C:" +char directory[maxStringSize]; +char filename[maxStringSize]; +char extension[8]; // we'll truncate if the extension is more then 8 chars... +char inFileName[512]; + +// switches to be sent to mIFF Compiler +char sourceBuffer[bufferSize]; +char outFileName[512]; // x2 to combine filename, dir, and ext +bool usePragma = false; +bool useCCCP = false; +bool verboseMode = false; // default to non-verbose mode +bool debugMode = false; // set this on and the preprocessed source file (mIFF.$$$) won't be deleted + +static bool runningUnderNT; + +enum errorType { + ERR_FILENOTFOUND = -1, + ERR_ARGSTOOFEW = -2, + ERR_BUFFERTOOSMALL = -3, + ERR_UNKNOWNDIR = -4, + ERR_PREPROCESS = -5, + ERR_MULTIPLEINFILE = -6, + ERR_PARSER = -7, + ERR_ENGINE = -8, + + ERR_HELPREQUEST = -9, + ERR_OPTIONS = -10, + + ERR_WRITEERROR = -11, + + ERR_NONE = 0 + }; +char err_msg[256]; +errorType errorFlag = ERR_NONE; // assume no error (default) + + +// long and short name definitions for command line options + +static const char * const LNAME_HELP = "help"; +static const char * const LNAME_INPUT_FILE = "inputfile"; +static const char * const LNAME_OUTPUT_FILE = "outputfile"; +static const char * const LNAME_PRAGMA_TARGET = "pragmatarget"; +static const char * const LNAME_CCCP = "cccp"; +static const char * const LNAME_VERBOSE = "verbose"; +static const char * const LNAME_DEBUG = "debug"; + +static const char SNAME_HELP = 'h'; +static const char SNAME_INPUT_FILE = 'i'; +static const char SNAME_OUTPUT_FILE = 'o'; +static const char SNAME_PRAGMA_TARGET = 'p'; +static const char SNAME_CCCP = 'c'; +static const char SNAME_VERBOSE = 'v'; +static const char SNAME_DEBUG = 'd'; + +// following is the command line option spec tree needed for command line processing +static CommandLine::OptionSpec optionSpecArray[] = +{ + OP_BEGIN_SWITCH(OP_NODE_REQUIRED), + + // help + OP_SINGLE_SWITCH_NODE(SNAME_HELP, LNAME_HELP, OP_ARG_NONE, OP_MULTIPLE_DENIED), + + // real options + OP_BEGIN_SWITCH_NODE(OP_MULTIPLE_DENIED), + OP_BEGIN_LIST(), + // input filename required + OP_SINGLE_LIST_NODE(SNAME_INPUT_FILE, LNAME_INPUT_FILE, OP_ARG_REQUIRED, OP_MULTIPLE_DENIED, OP_NODE_REQUIRED), + + // optional, mutually exclusive output file specification options + // if none specified, generate derive output filename from input filename + OP_BEGIN_LIST_NODE(OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), + OP_BEGIN_SWITCH(OP_NODE_OPTIONAL), + // specify output filename on command line + OP_SINGLE_SWITCH_NODE(SNAME_OUTPUT_FILE, LNAME_OUTPUT_FILE, OP_ARG_REQUIRED, OP_MULTIPLE_DENIED), + + // use pragma target for output filename + OP_SINGLE_SWITCH_NODE(SNAME_PRAGMA_TARGET, LNAME_PRAGMA_TARGET, OP_ARG_NONE, OP_MULTIPLE_DENIED), + OP_END_SWITCH(), + OP_END_LIST_NODE(), + + // if specified, use cccp instead of cpp + OP_SINGLE_LIST_NODE(SNAME_CCCP, LNAME_CCCP, OP_ARG_NONE, OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), + + // if specified, be verbose + OP_SINGLE_LIST_NODE(SNAME_VERBOSE, LNAME_VERBOSE, OP_ARG_NONE, OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), + + // if specified, enter debug info + OP_SINGLE_LIST_NODE(SNAME_DEBUG, LNAME_DEBUG, OP_ARG_NONE, OP_MULTIPLE_DENIED, OP_NODE_OPTIONAL), + OP_END_LIST(), + OP_END_SWITCH_NODE(), + + OP_END_SWITCH() +}; +static const int optionSpecCount = sizeof(optionSpecArray) / sizeof(optionSpecArray[0]); + +//================================================= function prototypes == +int main(int argc, char *argv[]); +static errorType evaluateArgs(void); +static void help(void); +static void handleError(errorType error); +static int preprocessSource(char *sourceName); +static void callbackFunction(void); +static errorType loadInputToBuffer(void *destAddr, int maxBufferSize); + +// functions called by parser.yac and parser.lex +extern "C" void MIFFMessage(char *msg, int forceOut); +extern "C" void MIFFSetError(void); +extern "C" void MIFFSetIFFName(const char *newFileName); +extern "C" void MIFFinsertForm(const char *formName); +extern "C" void MIFFinsertChunk(const char *chunkName); +extern "C" void MIFFinsertChunkData(void * buffer, unsigned bufferSize); +extern "C" int MIFFloadRawData(char *fname, void * buffer, unsigned maxBufferSize); +extern "C" void MIFFexitChunk(void); +extern "C" void MIFFexitForm(void); +extern "C" unsigned long MIFFgetLabelHash(char *inputStream); + +// external functions found in parser.lex file +extern "C" void MIFFCompile(char *inputStream, char *inputFname); +extern "C" void MIFFCompileInit(char *inputStream, char *inputFname); + +//--------------------------------------------------------------------------- +// main entry point from console call +// +// Return Value: +// errorType - see enumeration; 0 if no errors +// +// Remarks: +// +// +// See Also: +// +// +// Revisions and History: +// 1/07/99 [HAI] - created +// +int main( int argc, // number of args in commandline + char * argv[] // list of pointers to strings + ) +{ + memset(sourceBuffer, 0, bufferSize); + + SetupSharedThread::install(); + SetupSharedDebug::install(4096); + + SetupSharedFoundation::Data SetupSharedFoundationData (SetupSharedFoundation::Data::D_console); + SetupSharedFoundationData.useWindowHandle = false; + SetupSharedFoundationData.argc = argc; + SetupSharedFoundationData.argv = argv; + SetupSharedFoundationData.demoMode = false; + SetupSharedFoundation::install (SetupSharedFoundationData); + + SetupSharedCompression::install(); + + SetupSharedFile::install(false); + + TreeFile::addSearchAbsolute(0); + TreeFile::addSearchPath (".", 0); + + SetupSharedFoundation::callbackWithExceptionHandling(callbackFunction); + SetupSharedFoundation::remove(); + + SetupSharedThread::remove(); + return static_cast (errorFlag); +} + +//--------------------------------------------------------------------------- +// callback function for Engine's console entry point +// +// Return Value: +// none +// +// Remarks: +// this is like a substitute of main() +// +// See Also: +// +// +// Revisions and History: +// 1/12/99 [HAI] - created +// +static void callbackFunction(void) +{ + outfileHandler = NULL; + +#ifdef WIN32 + + // check if we're running under NT + OSVERSIONINFO osInfo; + Zero(osInfo); + + osInfo.dwOSVersionInfoSize = sizeof(osInfo); + const BOOL getVersionResult = GetVersionEx(&osInfo); + if (getVersionResult) + runningUnderNT = (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); + if (runningUnderNT) + DEBUG_REPORT_LOG(true, ("MIFF: running under Windows NT platform\n")); + else + DEBUG_REPORT_LOG(true, ("MIFF: running under non-NT Windows platform\n")); + +#endif + + errorFlag = evaluateArgs(); + if (ERR_NONE == errorFlag) + { + outfileHandler = new OutputFileHandler(outFileName); + MIFFCompile(sourceBuffer, inFileName); + } + else + handleError(errorFlag); + + if (outfileHandler) + { + // only write output IF there was no error + if (ERR_NONE == errorFlag) + { + if (!outfileHandler->writeBuffer()) + { + fprintf(stderr, "MIFF: failed to write output file \"%s\"\n", outFileName); + errorFlag = ERR_WRITEERROR; + } + } + delete outfileHandler; + } +} + +//--------------------------------------------------------------------------- +// Evaluates the command line and sets up the environment variables required for mIFF to function +// +// Return Value: +// errorType +// +// Remarks: +// argc's and argv's are substituted with CommandLine::functions() +// +// See Also: +// +// +// Revisions and History: +// 1/07/99 [HAI] - created +// +static errorType evaluateArgs(void) +{ + errorType retVal = ERR_NONE; + + // parse the commandline + const CommandLine::MatchCode mc = CommandLine::parseOptions(optionSpecArray, optionSpecCount); + if (mc != CommandLine::MC_MATCH) + { + // -TF- add call to retrieve command line error buffer for display (as soon as it is written!) + printf("WARNING: usage error detected, printing help.\n"); + help(); + return ERR_OPTIONS; + } + else if (CommandLine::getOccurrenceCount(SNAME_HELP)) + { + // user specified help + help(); + retVal = ERR_HELPREQUEST; + return(retVal); + } + + // at this point, we can assume a valid combination of options has been specified on the commandline + + + // setup input filename + strcpy(inFileName, CommandLine::getOptionString(SNAME_INPUT_FILE)); + + + // handle output filename spec + if (CommandLine::getOccurrenceCount(SNAME_OUTPUT_FILE)) + { + strcpy(outFileName, CommandLine::getOptionString(SNAME_OUTPUT_FILE)); + } + else if (CommandLine::getOccurrenceCount(SNAME_PRAGMA_TARGET)) + { + // use pragma target within iff source for output filename + usePragma = true; + } + else + { + // no output option specified on commandline, derive from input filename + char *terminator; + + // start with input file pathname + strcpy(outFileName, inFileName); + + // try to terminate at rightmost '.' + terminator = strrchr(outFileName, '.'); + if (terminator) + *terminator = 0; + + // append the default iff extension + strcat(outFileName, ".iff"); + } + + + // handle options (get them out of the way, as we use them later) + useCCCP = (CommandLine::getOccurrenceCount(SNAME_CCCP) != 0); + verboseMode = (CommandLine::getOccurrenceCount(SNAME_VERBOSE) != 0); + debugMode = (CommandLine::getOccurrenceCount(SNAME_DEBUG) != 0); + + + // preprocess the input file + if (0 == preprocessSource(inFileName)) + { + if (verboseMode) + { + sprintf(err_msg,"Now compiling %s...\n", inFileName); + MIFFMessage(err_msg, 0); + } + if (ERR_NONE == retVal) + retVal = loadInputToBuffer(sourceBuffer, bufferSize); + } + else + { + // preprocessSource returned an error... + retVal = ERR_PREPROCESS; + } + if (retVal != ERR_NONE) + return retVal; + + return retVal; + +#if 0 + + errorType retVal = ERR_NONE; // assume no error has been found + bool outPathUsed = false; // flag to monitor if -o flag was used, if so, we can ignore -d, -p, -e, -f + bool inFileEntered = false; + int argc = CommandLine::getPlainCount(); + + // get default values from DOS + char currentDir[maxStringSize]; + if (NULL == getcwd(currentDir, maxStringSize)) // get current working directory + { + retVal = ERR_UNKNOWNDIR; + return(retVal); + } + drive[0] = currentDir[0]; // drive letter + drive[1] = 0; // and null terminate it + strcpy(extension, "IFF"); // default to uppercase .IFF + strcpy(directory, ¤tDir[2]); // get everything after the Drive: including the first backslash + filename[0] = 0; + + // see specs.txt for requests + // scan for any argv's that has '-' in the argv[n][0]'s character + for (int index = 0; index < argc; index++) // note: if using argv[] rather then CommandLine::getPlainString() then start with 1 rather then 0 + { + if ('-' == CommandLine::getPlainString(index)[0]) + { + // we've found a parameter switch + switch (tolower(CommandLine::getPlainString(index)[1])) // assume non case sensitive switches + { + case 'i': // install via #pragma + { + usePragma = true; + break; + } + + case 'c': // use CCCP instead of CPP + useCCCP = true; + break; + + case 'v': // don't show any debug message + verboseMode = true; + break; + + case '$': + debugMode = true; + break; + + case 'o': // target output file name and path (complete path) + { + index++; // next param + outPathUsed = true; + strcpy(outFileName, CommandLine::getPlainString(index)); + break; + + } + + case 'd': // target drive letter (-p must be present) + { + if (!outPathUsed) + { + index++; // next param + strcpy(drive, CommandLine::getPlainString(index)); + } + else + index++; // skip the drive letter arg that SHOULD follow the -d option + break; + } + + case 'p': // target pathname + { + if (!outPathUsed) + { + index++; // next param + strcpy(directory, CommandLine::getPlainString(index)); + } + else + index++; // skip the pathname arg that follows the -p option + break; + } + + case 'f': // target filename + { + if (!outPathUsed) + { + index++; // next param + strcpy(filename, CommandLine::getPlainString(index)); + } + else + index++; // skip the filename arg that follows the -f + break; + } + + case 'e': // target extension + { + if (!outPathUsed) + { + index++; // next param + strcpy(extension, CommandLine::getPlainString(index)); + } + else + index++; // skip the extension arg that follows the -e + break; + } + + case 'h': // help! + case '?': + { + help(); + index = argc; // force to exit + retVal = ERR_HELPREQUEST; + return(retVal); // special case, ONLY time I call return() in the middle of the function (because I check for argc < 2 at the end of the code) + break; + } + + default: + { + sprintf(err_msg, "\nUnknown parameter %s, use -h to seek help...\n", CommandLine::getPlainString(index)); + MIFFMessage(err_msg, 1); + index = argc; // force to exit + break; + } + } + } + else + { + // we found an arg that doesn't start with '-' so let's assume it's a filename + if (!inFileEntered) + { + strcpy(inFileName, CommandLine::getPlainString(index)); + inFileEntered = true; + } + else + { + retVal = ERR_MULTIPLEINFILE; + index = argc; + } + + // now construct the DEFAULT filename for this file by scanning backwards to front and only extracting the filename (no extension, no path) + if (ERR_NONE == retVal) + { + char sourceName[maxStringSize]; + strcpy(sourceName, inFileName); // make a duplicate for us to play with + for (int strIndex = strlen(sourceName); strIndex > 0; strIndex--) + { + if ('.' == sourceName[strIndex]) + sourceName[strIndex] = 0; // put a stopper here... we are assuming that '.' indicates extension! I'm going to assume that the person is just testing me if s/he decides to use filename like "foo.bar.psych" which will truncate to "foo" + if ('\\' == sourceName[strIndex]) + break; // get out, for we've reached the path name... + } + + // ok, by here, strIndex should point to either beginning of the string, or where the first '\' was found scanning backwards + strcpy(filename, &sourceName[strIndex]); // ta-da-! + } + } + } + + if (inFileEntered) + { + if (0 == preprocessSource(inFileName)) + { + if (verboseMode) + { + // using err_msg as my temp buffer... + sprintf(err_msg,"Now compiling %s\n", inFileName); + MIFFMessage(err_msg, 0); + } + + if (ERR_NONE == retVal) + retVal = loadInputToBuffer(sourceBuffer, bufferSize); + } + else // preprocessSource returned an error... + { + retVal = ERR_PREPROCESS; + } + } + else // inFileEntered == false + { + MIFFMessage("Missing input filename in command line!", 1); + } + + // construct a outFileName[] based on drive[], directory[], filename[], and extension[] + if (!outPathUsed && (ERR_NONE == retVal)) + { + if (inFileName[0]) // make sure the user has entered a input filename + sprintf(outFileName,"%s:%s\\%s.%s", drive, directory, filename, extension); + } + + if (argc < 1) + retVal = ERR_ARGSTOOFEW; // we can do this because we know -h was not entered... + + return(retVal); + +#endif + +} + + +//--------------------------------------------------------------------------- +// reads the tmeporary files spit out by CCCP and stuffs the plain text into source buffer +// +// Return Value: +// errorType +// +// Remarks: +// +// +// See Also: +// +// +// Revisions and History: +// 1/14/99 [HAI] - created +// +static errorType loadInputToBuffer( + void * dest, // destination address of where you want the date to be read + int maxBufferSize // maximum destination data pool size + ) +{ + errorType retVal = ERR_NONE; + InputFileHandler *inFileHandler = new InputFileHandler("mIFF.$$$"); + if (inFileHandler) + { + int sizeRead = inFileHandler->read(dest, maxBufferSize); + if (sizeRead >= maxBufferSize) + { + retVal = ERR_BUFFERTOOSMALL; + } + else + { + reinterpret_cast(dest)[sizeRead] = 0; // so stupid... but if you don't zero-terminate at exact spot, YYInput may chokes because of extra grammer that may exist... + } + if (!debugMode) + inFileHandler->deleteFile("mIFF.$$$", true); // no need for temp file now... + + // we've successfully read the file, now close it... + delete inFileHandler; + } + else // inFileName is NULL + { + retVal = ERR_FILENOTFOUND; + } + + return(retVal); +} + +//--------------------------------------------------------------------------- +// help function called by main upon -h switch +// +// Return Value: +// none +// +// Remarks: +// #include's mIFF.dox +// make sure to update the version when modified. +// Notice that help() does NOT go thru MIFFMessage() because we want it to +// print out whether it's verbose mode or not... +// +// See Also: +// mIFF.dox +// +// Revisions and History: +// 1/07/99 [HAI] - created +// +static void help(void) +{ + printf("\nmIFF v%s (DOS version) - Bootprint Ent. (c) 1999\n", version); + printf("Hideki Ikeda\n"); +#include "mIFF.dox" +} + + +//--------------------------------------------------------------------------- +// upon exit from main(), if error has been found, it calls here to inform the user of the type of errors it has encounted. +// +// Return Value: +// none +// +// Remarks: +// use -q switch to suppress error messages - but in shell, return value can be used to determine the handling +// +// See Also: +// +// +// Revisions and History: +// 1/07/99 [HAI] - created +// +static void handleError(errorType error) +{ + if (ERR_NONE == error) + return; + + switch (error) + { + case ERR_NONE: + break; + + case ERR_FILENOTFOUND: + MIFFMessage("ERROR: INPUT File not found!\n", 1); + break; + + case ERR_ARGSTOOFEW: + MIFFMessage("ERROR: Not enough arguments. Use -h for help.\n", 1); + break; + + case ERR_BUFFERTOOSMALL: + MIFFMessage("ERROR: Internally allocated buffer for reading\nsource code is too small, increase buffer and re-compile\n", 1); + break; + + case ERR_UNKNOWNDIR: + MIFFMessage("ERROR: Directory unknown...\n", 1); + break; + + case ERR_PREPROCESS: + MIFFMessage("ERROR: Possible problems running the GNU C Preprocessor.\n", 1); + break; + + case ERR_MULTIPLEINFILE: + MIFFMessage("ERROR: There can only be ONE inputfile name.\nPerhaps you've forgotten the -o option flag\n", 1); + break; + + case ERR_ENGINE: + MIFFMessage("ERROR: Engine returned a non-zero value...\n", 1); + break; + + case ERR_PARSER: + MIFFMessage("ERROR: Parser error\n", 1); + break; + + case ERR_HELPREQUEST: + break; + + case ERR_OPTIONS: + MIFFMessage("ERROR: Failed to handle command line options\n", 1); + break; + + default: + MIFFMessage("ERROR: Unknown error, you suck!\n", 1); + break; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// gotta write all these externs because you can't call C++ class based non-static +// functions from C... So we will use here as the bridge between the two +// languages + + +//--------------------------------------------------------------------------- +// Message output handler called by ALL external "C" functions +// +// Return Value: +// none +// +// Remarks: +// all the messages that are displayed are channeled thru this function. Note the -q quiet mode suppresses all messages. +// this is an extern "C" function +// +// See Also: +// yyerror() +// +// Revisions and History: +// 1/07/99 [] - created +// +extern "C" void MIFFMessage(char *message, // null terminated string to be displayed + int forceOutput) // if non-zero, it will print out even in quiet mode (for ERRORs) +{ + if (forceOutput) + fprintf(stdout, "%s\n", message); + else if (verboseMode) + fprintf(stdout, "%s\n", message); + OutputDebugString(message); + OutputDebugString("\n"); +} + +// Only call this via parser!!! +extern "C" void MIFFSetError(void) +{ + errorFlag = ERR_PARSER; +} + +//--------------------------------------------------------------------------- +// validation of the filename passed are legal. +// +// Return Value: +// bool usePragma - whether #pragma is ignored or not +// +// Remarks: +// if -i switch is used then #pragma's are expected +// this is an extern "C" function +// +// See Also: +// +// +// Revisions and History: +// 1/07/99 [ ] - created +// +extern "C" int validateTargetFilename( char *targetFileName, // pointer to where we can store the string filename + unsigned maxTargetBufSize // size of the filename string buffer + ) +{ + if (strlen(outFileName) > maxTargetBufSize) + MIFFMessage("Internal error, increase string buffer size in parser.yac and recompile!", 1); + + strcpy(targetFileName, outFileName); + + return(usePragma); +} + + +//--------------------------------------------------------------------------- +// function calls CCCP or CPP via shell to preprocess the source code for #include's and #define's via C-Compatible Compiler Preprocessor +// +// Return Value: +// shell return value (4DOS is very generous on returning different values, while DOS just returns 0 all the time) +// +// Remarks: +// use -c switch to use CCCP rather then CPP in your search path +// +// See Also: +// +// +// Revisions and History: +// 1/07/99 [ ] - created +// +static int preprocessSource(char *sourceName) +{ + char shellCommand[512]; + int retVal = 0; + + memset(shellCommand, 0, sizeof(shellCommand)); + +// if (!runningUnderNT) + { + + if (verboseMode) + MIFFMessage("Preprocessing... via CCCP", 0); + + // CCCP parameters: + // -nostdinc -nostdinc++ - do NOT search for standard include directory; without this, your + // puter would be just twiddling its thumb because CCCP can't find it... + // -pedantic - issue warnings (use pedantic-errors if you want it as errors) + // required by the ANSI C standard in certain cases such as comments that + // follow the #else/#endif + // -dD - output #defines (for the purpose of error msg I parse) + // -H - display the name of the header/included files (verbose mode) + // -P - originally, I had this... so it won't show the # line_num "filename" ??? + if (!useCCCP && verboseMode) + { + sprintf(shellCommand, "cpp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD -H %s mIFF.$$$", sourceName); + } + else if (!useCCCP && !verboseMode) + { + sprintf(shellCommand, "cpp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD %s mIFF.$$$", sourceName); + } + else if (useCCCP && verboseMode) + { + sprintf(shellCommand, "cccp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD -H %s mIFF.$$$", sourceName); + } + else + sprintf(shellCommand, "cccp.exe -nostdinc -nostdinc++ -x c++ -pedantic -Wall -dD %s mIFF.$$$", sourceName); + } +// else + { + // running under NT. Use the MSVC cl since it deals with long filenames on fat16/fat32 partitions correctly + // and ccp and cccp don't +// sprintf(shellCommand, "cl /nologo /W4 /EP %s > mIFF.$$$", sourceName); + } + + retVal = system(shellCommand); + if (2 == retVal) // actually, I think 4DOS reports 2 for cannot find file, but DOS returns a 0... + { + REPORT_LOG(true, ("failed to execute following shell command (%d):\n", retVal)); + REPORT_LOG(true, (" %s\n", shellCommand)); + MIFFMessage("\n\nERROR: Cannot find preprocessor (either CCCP.EXE, CPP.EXE or CL.EXE (under NT) in the search path...\n", 1); + MIFFMessage("Please make sure the preprocessor is in your search path!\n", 1); + } + return(retVal); +} + +extern "C" void MIFFSetIFFName(const char *newFileName) +{ + if (ERR_NONE != errorFlag) + return; + + if (outfileHandler) + outfileHandler->setCurrentFilename(newFileName); +} + +extern "C" void MIFFinsertForm(const char *formName) +{ + if (ERR_NONE != errorFlag) + return; + + if (outfileHandler) + outfileHandler->insertForm(formName); +} + +extern "C" void MIFFinsertChunk(const char *chunkName) +{ + if (ERR_NONE != errorFlag) + return; + + if (outfileHandler) + outfileHandler->insertChunk(chunkName); +} + +extern "C" void MIFFinsertChunkData(void * buffer, unsigned bufferSize) +{ + if (ERR_NONE != errorFlag) + return; + + if (outfileHandler) + outfileHandler->insertChunkData(buffer, bufferSize); +} + +extern "C" int MIFFloadRawData(char *fname, void * buffer, unsigned maxBufferSize) +{ + int sizeRead = -1; + + if (ERR_NONE != errorFlag) + return(sizeRead); // should be -1 + + InputFileHandler * inFileName = new InputFileHandler(fname); + if (inFileName) + { + sizeRead = inFileName->read(buffer, maxBufferSize); + if (static_cast(sizeRead) >= maxBufferSize) + { + handleError(ERR_BUFFERTOOSMALL); + sizeRead = -1; + } + delete inFileName; + } + + return(sizeRead); +} + +extern "C" void MIFFexitChunk(void) +{ + if (ERR_NONE != errorFlag) + return; + + if (outfileHandler) + outfileHandler->exitChunk(); +} +extern "C" void MIFFexitForm(void) +{ + if (ERR_NONE != errorFlag) + return; + + if (outfileHandler) + outfileHandler->exitForm(); +} + +extern "C" char * MIFFallocString(int sizeOfString) +{ + return(new char[sizeOfString]); +} + +extern "C" void MIFFfreeString(char * pointer) +{ + delete [] pointer; +} + +extern "C" unsigned long MIFFgetLabelHash(char * inputStream) +{ + return (unsigned long)Crc::calculate(inputStream); +} + +//=========================================================================== +//============================================================ End-of-file == +//=========================================================================== + diff --git a/src/engine/server/application/CMakeLists.txt b/src/engine/server/application/CMakeLists.txt index eccc95935..350d0aba6 100644 --- a/src/engine/server/application/CMakeLists.txt +++ b/src/engine/server/application/CMakeLists.txt @@ -1,18 +1,18 @@ - -add_subdirectory(CentralServer) -add_subdirectory(ChatServer) -add_subdirectory(ConnectionServer) -add_subdirectory(LogServer) -add_subdirectory(LoginServer) -add_subdirectory(MetricsServer) -add_subdirectory(PlanetServer) -add_subdirectory(ServerConsole) -add_subdirectory(TaskManager) -add_subdirectory(TransferServer) -add_subdirectory(CommoditiesServer) - -if(NOT WIN32) - add_subdirectory(CustomerServiceServer) - add_subdirectory(LoginPing) - add_subdirectory(StationPlayersCollector) -endif() + +add_subdirectory(CentralServer) +add_subdirectory(ChatServer) +add_subdirectory(ConnectionServer) +add_subdirectory(LogServer) +add_subdirectory(LoginServer) +add_subdirectory(MetricsServer) +add_subdirectory(PlanetServer) +add_subdirectory(ServerConsole) +add_subdirectory(TaskManager) +add_subdirectory(TransferServer) +add_subdirectory(CommoditiesServer) + +if(NOT WIN32) + add_subdirectory(CustomerServiceServer) + add_subdirectory(LoginPing) + add_subdirectory(StationPlayersCollector) +endif() diff --git a/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/AuctionTransferAPI.cpp b/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/AuctionTransferAPI.cpp index ffbae4102..e75c66d51 100644 --- a/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/AuctionTransferAPI.cpp +++ b/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/AuctionTransferAPI.cpp @@ -1,194 +1,194 @@ -#include "AuctionTransferAPI.h" -#include "AuctionTransferAPICore.h" -#include "Request.h" -#include "Response.h" -#include "zip/GZipHelper.h" - -#define DEFAULT_HOST "localhost" -#define DEFAULT_PORT 5901 -#define DEFAULT_IDENTIFIER "GAME+UNKNOWN" -////////////////////////////////////////////////////////////////////////////////////// -namespace AuctionTransfer -{ - -////////////////////////////////////////////////////////////////////////////////////// -AuctionTransferAPI::AuctionTransferAPI(const char *hostName[], const short port[], int count, const char *identifier[], unsigned identifierCount, unsigned reqTimeout, unsigned maxRecvMessageSizeInKB) -{ - m_apiCore = new AuctionTransferAPICore(hostName, port, count, this, identifier, identifierCount, reqTimeout, maxRecvMessageSizeInKB); -} - -////////////////////////////////////////////////////////////////////////////////////// -AuctionTransferAPI::AuctionTransferAPI(const char *hostNames, const char *identifiers) -{ - std::vector hostArray; - std::vector identifierArray; - std::vector portArray; - char hostConfig[4096]; - char identifierConfig[4096]; - if (hostNames == NULL) - hostNames = DEFAULT_HOST; - if(identifiers == NULL) - identifiers = DEFAULT_IDENTIFIER; - - // parse the hosts and ports out : - strncpy(hostConfig, hostNames, 4096); hostConfig[4095] = 0; - char *ptr; - if ((ptr = strtok(hostConfig, " ")) != 0) - { - do - { - char * host = ptr; - char * portStr = strchr(host, ':'); - unsigned short port = DEFAULT_PORT; - if (portStr) - { - *portStr++ = 0; - port = (short)atoi(portStr); - } - - if (::strlen(host) && port) - { - hostArray.push_back(host); - portArray.push_back(port); - } - } - while ((ptr = strtok(NULL, " ")) != NULL); - } - - strncpy(identifierConfig, identifiers, 4096); identifierConfig[4095] = 0; - // parse the identifiers out - if ((ptr = strtok(identifierConfig, ";")) != 0) - { - do - { - char * identifier = ptr; - if (::strlen(identifier)) - { - identifierArray.push_back(identifier); - } - } - while ((ptr = strtok(NULL, ";")) != NULL); - } - - if (hostArray.empty()) - { - hostArray.push_back(DEFAULT_HOST); - portArray.push_back(DEFAULT_PORT); - } - if(identifierArray.empty()) - identifierArray.push_back(DEFAULT_IDENTIFIER); - - m_apiCore = new AuctionTransferAPICore(&hostArray[0], &portArray[0], hostArray.size(), this, &identifierArray[0], identifierArray.size()); -} - -////////////////////////////////////////////////////////////////////////////////////// -AuctionTransferAPI::~AuctionTransferAPI() -{ - if( m_apiCore) - delete m_apiCore; -} - -////////////////////////////////////////////////////////////////////////////////////// -void AuctionTransferAPI::process() -{ - m_apiCore->process(); -} - -////////////////////////////////////////////////////////////////////////////////////// -// Calls and replies -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::replyReceiveAbortTransaction(unsigned trackingNumber, unsigned responseCode, void *user) -{ - ReplyRequest *req = new ReplyRequest( GAME_REPLY_RECEIVE_ABORT, trackingNumber, responseCode ); - return m_apiCore->submitRequest( req, new CommonResponse( GAME_REPLY_RECEIVE_ABORT, user )); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::replyReceiveCommitTransaction(unsigned trackingNumber, unsigned responseCode, void *user) -{ - ReplyRequest *req = new ReplyRequest( GAME_REPLY_RECEIVE_COMMIT, trackingNumber, responseCode ); - return m_apiCore->submitRequest( req, new CommonResponse( GAME_REPLY_RECEIVE_COMMIT, user )); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::replyReceivePrepareTransaction(unsigned trackingNumber, unsigned responseCode, void *user) -{ - ReplyRequest *req = new ReplyRequest( GAME_REPLY_RECEIVE_PREPARE_TRANSACTION, trackingNumber, responseCode ); - return m_apiCore->submitRequest( req, new CommonResponse( GAME_REPLY_RECEIVE_PREPARE_TRANSACTION, user )); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::sendAbortTransaction(long long transactionID, void *user) -{ - CommonRequest *req = new CommonRequest( GAME_REQUEST_SEND_ABORT, 0, transactionID ); - return m_apiCore->submitRequest( req, new CommonResponse( GAME_REQUEST_SEND_ABORT, user )); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::sendCommitTransaction(long long transactionID, void *user) -{ - CommonRequest *req = new CommonRequest( GAME_REQUEST_SEND_COMMIT, 0, transactionID ); - return m_apiCore->submitRequest( req, new CommonResponse( GAME_REQUEST_SEND_COMMIT, user )); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::sendPrepareTransaction(const char *serverIdentifier, long long transactionID, unsigned stationID, unsigned characterID, long long assetID, const char *xmlAsset, void *user, bool compress) -{ - RequestTypes requestEnum = GAME_REQUEST_SEND_PREPARE_TRANSACTION; - GenericRequest *req = NULL; - if( compress ) - { - requestEnum = GAME_REQUEST_SEND_PREPARE_TRANSACTION_COMPRESSED; - // compress and create the request here - char *data = (char *)xmlAsset; - CA2GZIP zippedData(data, strlen(xmlAsset)); - req = new SendPrepareCompressedRequest( requestEnum, 0, serverIdentifier, transactionID, stationID, characterID, assetID, zippedData.pgzip, zippedData.Length ); - } - else - { - req = new SendPrepareRequest( requestEnum, 0, serverIdentifier, transactionID, stationID, characterID, assetID, xmlAsset ); - } - - return m_apiCore->submitRequest( req, new CommonResponse( requestEnum, user )); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::sendPrepareTransactionCompressed (const char *serverIdentifier, long long transactionID, unsigned stationID, unsigned characterID, long long assetID, const unsigned char *zippedXmlAsset, unsigned length, void *user) -{ - SendPrepareCompressedRequest *req = new SendPrepareCompressedRequest( GAME_REQUEST_SEND_PREPARE_TRANSACTION_COMPRESSED, 0, serverIdentifier, transactionID, stationID, characterID, assetID, zippedXmlAsset, length ); - - return m_apiCore->submitRequest( req, new CommonResponse( GAME_REQUEST_SEND_PREPARE_TRANSACTION_COMPRESSED, user )); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::replyReceiveGetCharacterList(unsigned trackingNumber, unsigned responseCode, const Character characters[], unsigned numCharacters, void *user) -{ - ReplyGetCharacterListRequest *req = new ReplyGetCharacterListRequest(GAME_REPLY_RECEIVE_GET_CHARACTER_LIST, trackingNumber, responseCode, characters, numCharacters); - return m_apiCore->submitRequest(req, new CommonResponse(GAME_REPLY_RECEIVE_GET_CHARACTER_LIST, user)); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::identifyHost( const char *serverID[], unsigned idCount, void *user) -{ - IdentifyServerRequest *req = new IdentifyServerRequest(REQUEST_SET_SERVER_LIST, 0, serverID, idCount); - return m_apiCore->submitRequest( req, new CommonResponse(REQUEST_SET_SERVER_LIST, user)); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::sendAuditAssetTransfer(const char *gameCode, const char *serverCode, long long inGameAssetID, unsigned stationID, const char *event, const char *message, void *user) -{ - SendAuditRequest *req = new SendAuditRequest( GAME_SEND_AUDIT_MESSAGE, 0, gameCode, serverCode, inGameAssetID, stationID, event, message ); - return m_apiCore->submitRequest(req, new CommonResponse(GAME_SEND_AUDIT_MESSAGE, user)); -} - -////////////////////////////////////////////////////////////////////////////////////// -unsigned AuctionTransferAPI::getNewTransactionID(void *user) -{ - GetIDRequest *req = new GetIDRequest( GAME_REQUEST_GET_TRANSACTION_ID, 0); - return m_apiCore->submitRequest(req, new GetIDResponse( GAME_REQUEST_GET_TRANSACTION_ID, user)); -} - -}; // namespace -////////////////////////////////////////////////////////////////////////////////////// - - +#include "AuctionTransferAPI.h" +#include "AuctionTransferAPICore.h" +#include "Request.h" +#include "Response.h" +#include "zip/GZipHelper.h" + +#define DEFAULT_HOST "localhost" +#define DEFAULT_PORT 5901 +#define DEFAULT_IDENTIFIER "GAME+UNKNOWN" +////////////////////////////////////////////////////////////////////////////////////// +namespace AuctionTransfer +{ + +////////////////////////////////////////////////////////////////////////////////////// +AuctionTransferAPI::AuctionTransferAPI(const char *hostName[], const short port[], int count, const char *identifier[], unsigned identifierCount, unsigned reqTimeout, unsigned maxRecvMessageSizeInKB) +{ + m_apiCore = new AuctionTransferAPICore(hostName, port, count, this, identifier, identifierCount, reqTimeout, maxRecvMessageSizeInKB); +} + +////////////////////////////////////////////////////////////////////////////////////// +AuctionTransferAPI::AuctionTransferAPI(const char *hostNames, const char *identifiers) +{ + std::vector hostArray; + std::vector identifierArray; + std::vector portArray; + char hostConfig[4096]; + char identifierConfig[4096]; + if (hostNames == NULL) + hostNames = DEFAULT_HOST; + if(identifiers == NULL) + identifiers = DEFAULT_IDENTIFIER; + + // parse the hosts and ports out : + strncpy(hostConfig, hostNames, 4096); hostConfig[4095] = 0; + char *ptr; + if ((ptr = strtok(hostConfig, " ")) != 0) + { + do + { + char * host = ptr; + char * portStr = strchr(host, ':'); + unsigned short port = DEFAULT_PORT; + if (portStr) + { + *portStr++ = 0; + port = (short)atoi(portStr); + } + + if (::strlen(host) && port) + { + hostArray.push_back(host); + portArray.push_back(port); + } + } + while ((ptr = strtok(NULL, " ")) != NULL); + } + + strncpy(identifierConfig, identifiers, 4096); identifierConfig[4095] = 0; + // parse the identifiers out + if ((ptr = strtok(identifierConfig, ";")) != 0) + { + do + { + char * identifier = ptr; + if (::strlen(identifier)) + { + identifierArray.push_back(identifier); + } + } + while ((ptr = strtok(NULL, ";")) != NULL); + } + + if (hostArray.empty()) + { + hostArray.push_back(DEFAULT_HOST); + portArray.push_back(DEFAULT_PORT); + } + if(identifierArray.empty()) + identifierArray.push_back(DEFAULT_IDENTIFIER); + + m_apiCore = new AuctionTransferAPICore(&hostArray[0], &portArray[0], hostArray.size(), this, &identifierArray[0], identifierArray.size()); +} + +////////////////////////////////////////////////////////////////////////////////////// +AuctionTransferAPI::~AuctionTransferAPI() +{ + if( m_apiCore) + delete m_apiCore; +} + +////////////////////////////////////////////////////////////////////////////////////// +void AuctionTransferAPI::process() +{ + m_apiCore->process(); +} + +////////////////////////////////////////////////////////////////////////////////////// +// Calls and replies +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::replyReceiveAbortTransaction(unsigned trackingNumber, unsigned responseCode, void *user) +{ + ReplyRequest *req = new ReplyRequest( GAME_REPLY_RECEIVE_ABORT, trackingNumber, responseCode ); + return m_apiCore->submitRequest( req, new CommonResponse( GAME_REPLY_RECEIVE_ABORT, user )); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::replyReceiveCommitTransaction(unsigned trackingNumber, unsigned responseCode, void *user) +{ + ReplyRequest *req = new ReplyRequest( GAME_REPLY_RECEIVE_COMMIT, trackingNumber, responseCode ); + return m_apiCore->submitRequest( req, new CommonResponse( GAME_REPLY_RECEIVE_COMMIT, user )); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::replyReceivePrepareTransaction(unsigned trackingNumber, unsigned responseCode, void *user) +{ + ReplyRequest *req = new ReplyRequest( GAME_REPLY_RECEIVE_PREPARE_TRANSACTION, trackingNumber, responseCode ); + return m_apiCore->submitRequest( req, new CommonResponse( GAME_REPLY_RECEIVE_PREPARE_TRANSACTION, user )); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::sendAbortTransaction(long long transactionID, void *user) +{ + CommonRequest *req = new CommonRequest( GAME_REQUEST_SEND_ABORT, 0, transactionID ); + return m_apiCore->submitRequest( req, new CommonResponse( GAME_REQUEST_SEND_ABORT, user )); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::sendCommitTransaction(long long transactionID, void *user) +{ + CommonRequest *req = new CommonRequest( GAME_REQUEST_SEND_COMMIT, 0, transactionID ); + return m_apiCore->submitRequest( req, new CommonResponse( GAME_REQUEST_SEND_COMMIT, user )); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::sendPrepareTransaction(const char *serverIdentifier, long long transactionID, unsigned stationID, unsigned characterID, long long assetID, const char *xmlAsset, void *user, bool compress) +{ + RequestTypes requestEnum = GAME_REQUEST_SEND_PREPARE_TRANSACTION; + GenericRequest *req = NULL; + if( compress ) + { + requestEnum = GAME_REQUEST_SEND_PREPARE_TRANSACTION_COMPRESSED; + // compress and create the request here + char *data = (char *)xmlAsset; + CA2GZIP zippedData(data, strlen(xmlAsset)); + req = new SendPrepareCompressedRequest( requestEnum, 0, serverIdentifier, transactionID, stationID, characterID, assetID, zippedData.pgzip, zippedData.Length ); + } + else + { + req = new SendPrepareRequest( requestEnum, 0, serverIdentifier, transactionID, stationID, characterID, assetID, xmlAsset ); + } + + return m_apiCore->submitRequest( req, new CommonResponse( requestEnum, user )); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::sendPrepareTransactionCompressed (const char *serverIdentifier, long long transactionID, unsigned stationID, unsigned characterID, long long assetID, const unsigned char *zippedXmlAsset, unsigned length, void *user) +{ + SendPrepareCompressedRequest *req = new SendPrepareCompressedRequest( GAME_REQUEST_SEND_PREPARE_TRANSACTION_COMPRESSED, 0, serverIdentifier, transactionID, stationID, characterID, assetID, zippedXmlAsset, length ); + + return m_apiCore->submitRequest( req, new CommonResponse( GAME_REQUEST_SEND_PREPARE_TRANSACTION_COMPRESSED, user )); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::replyReceiveGetCharacterList(unsigned trackingNumber, unsigned responseCode, const Character characters[], unsigned numCharacters, void *user) +{ + ReplyGetCharacterListRequest *req = new ReplyGetCharacterListRequest(GAME_REPLY_RECEIVE_GET_CHARACTER_LIST, trackingNumber, responseCode, characters, numCharacters); + return m_apiCore->submitRequest(req, new CommonResponse(GAME_REPLY_RECEIVE_GET_CHARACTER_LIST, user)); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::identifyHost( const char *serverID[], unsigned idCount, void *user) +{ + IdentifyServerRequest *req = new IdentifyServerRequest(REQUEST_SET_SERVER_LIST, 0, serverID, idCount); + return m_apiCore->submitRequest( req, new CommonResponse(REQUEST_SET_SERVER_LIST, user)); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::sendAuditAssetTransfer(const char *gameCode, const char *serverCode, long long inGameAssetID, unsigned stationID, const char *event, const char *message, void *user) +{ + SendAuditRequest *req = new SendAuditRequest( GAME_SEND_AUDIT_MESSAGE, 0, gameCode, serverCode, inGameAssetID, stationID, event, message ); + return m_apiCore->submitRequest(req, new CommonResponse(GAME_SEND_AUDIT_MESSAGE, user)); +} + +////////////////////////////////////////////////////////////////////////////////////// +unsigned AuctionTransferAPI::getNewTransactionID(void *user) +{ + GetIDRequest *req = new GetIDRequest( GAME_REQUEST_GET_TRANSACTION_ID, 0); + return m_apiCore->submitRequest(req, new GetIDResponse( GAME_REQUEST_GET_TRANSACTION_ID, user)); +} + +}; // namespace +////////////////////////////////////////////////////////////////////////////////////// + + diff --git a/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/Base/linux/Types.h b/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/Base/linux/Types.h index 4ff7adc36..69419a0fc 100644 --- a/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/Base/linux/Types.h +++ b/src/engine/server/application/CentralServer/src/shared/AuctionTransferGameAPI/Base/linux/Types.h @@ -1,45 +1,45 @@ -//////////////////////////////////////// -// Types.h -// -// Purpose: -// 1. Define integer types that are unambiguous with respect to size -// -// Revisions: -// 07/10/2001 Created -// - -#ifndef BASE_LINUX_TYPES_H -#define BASE_LINUX_TYPES_H - -#include - -#ifdef EXTERNAL_DISTRO -namespace NAMESPACE -{ - -#endif - -namespace Base -{ - -#ifndef INT32_MAX -#define INT32_MAX 0x7FFFFFFF -#define INT32_MIN 0x80000000 -#define UINT32_MAX 0xFFFFFFFF -#endif - -typedef signed char int8; -typedef unsigned char uint8; -typedef signed short int16; -typedef unsigned short uint16; - -typedef int32_t int32; -typedef u_int32_t uint32; -typedef int64_t int64; -typedef u_int64_t uint64; -} -#ifdef EXTERNAL_DISTRO -}; -#endif -#endif // BASE_LINUX_TYPES_H - +//////////////////////////////////////// +// Types.h +// +// Purpose: +// 1. Define integer types that are unambiguous with respect to size +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_TYPES_H +#define BASE_LINUX_TYPES_H + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif + +namespace Base +{ + +#ifndef INT32_MAX +#define INT32_MAX 0x7FFFFFFF +#define INT32_MIN 0x80000000 +#define UINT32_MAX 0xFFFFFFFF +#endif + +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; + +typedef int32_t int32; +typedef u_int32_t uint32; +typedef int64_t int64; +typedef u_int64_t uint64; +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // BASE_LINUX_TYPES_H + diff --git a/src/engine/server/application/CentralServer/src/shared/CentralServer.cpp b/src/engine/server/application/CentralServer/src/shared/CentralServer.cpp index 6b1ec4e12..ec59cdf1f 100644 --- a/src/engine/server/application/CentralServer/src/shared/CentralServer.cpp +++ b/src/engine/server/application/CentralServer/src/shared/CentralServer.cpp @@ -1,4086 +1,4086 @@ -// CentralServer.cpp -// copyright 2000 Verant Interactive -// Author: Justin Randall - -//----------------------------------------------------------------------- - -#include "FirstCentralServer.h" -#include "CentralServer.h" - -#include "CentralCSHandler.h" -#include "CentralServerMetricsData.h" -#include "CharacterCreationTracker.h" -#include "ChatServerConnection.h" -#include "ConfigCentralServer.h" -#include "ConnectionServerConnection.h" -#include "ConsoleConnection.h" -#include "ConsoleManager.h" -#include "CustomerServiceConnection.h" -#include "fileInterface/StdioFile.h" -#include "GameServerConnection.h" -#include "LoginServerConnection.h" -#include "PlanetManager.h" -#include "PlanetServerConnection.h" -#include "TaskConnection.h" -#include "UnicodeUtils.h" -#include "UniverseManager.h" -#include "serverKeyShare/KeyShare.h" -#include "serverMetrics/MetricsManager.h" -#include "serverNetworkMessages/AccountFeatureIdResponse.h" -#include "serverNetworkMessages/AddCharacterMessage.h" -#include "serverNetworkMessages/AddObjectIdBlockMessage.h" -#include "serverNetworkMessages/AdjustAccountFeatureIdResponse.h" -#include "serverNetworkMessages/CentralConnectionServerMessages.h" -#include "serverNetworkMessages/CentralGameServerMessages.h" -#include "serverNetworkMessages/CentralPingMessage.h" -#include "serverNetworkMessages/CentralPlanetServerConnect.h" -#include "serverNetworkMessages/CentralTaskMessages.h" -#include "serverNetworkMessages/CharacterListMessage.h" -#include "serverNetworkMessages/ChatServerOnline.h" -#include "serverNetworkMessages/ChunkObjectListMessage.h" -#include "serverNetworkMessages/ClaimRewardsMessage.h" -#include "serverNetworkMessages/ClaimRewardsReplyMessage.h" -#include "serverNetworkMessages/ConnectionServerDown.h" -#include "serverNetworkMessages/CreateNewObjectMessage.h" -#include "serverNetworkMessages/EnumerateServers.h" -#include "serverNetworkMessages/ExchangeListCreditsMessage.h" -#include "serverNetworkMessages/ExcommunicateGameServerMessage.h" -#include "serverNetworkMessages/FailedToLoadObjectMessage.h" -#include "serverNetworkMessages/FeatureIdTransactionResponse.h" -#include "serverNetworkMessages/ForceUnloadObjectMessage.h" -#include "serverNetworkMessages/GameServerForLoginMessage.h" -#include "serverNetworkMessages/GameServerReadyMessage.h" -#include "serverNetworkMessages/GameServerUniverseLoadedMessage.h" -#include "serverNetworkMessages/GameTaskManagerMessages.h" -#include "serverNetworkMessages/LoadObjectMessage.h" -#include "serverNetworkMessages/LocateStructureMessage.h" -#include "serverNetworkMessages/LoginConnectionServerAddress.h" -#include "serverNetworkMessages/LoginCreateCharacterAckMessage.h" -#include "serverNetworkMessages/LoginCreateCharacterMessage.h" -#include "serverNetworkMessages/LoginKeyPush.h" -#include "serverNetworkMessages/LoginRestoreCharacterMessage.h" -#include "serverNetworkMessages/LoginUpgradeAccountMessage.h" -#include "serverNetworkMessages/MessageToAckMessage.h" -#include "serverNetworkMessages/MessageToMessage.h" -#include "serverNetworkMessages/PlanetLoadCharacterMessage.h" -#include "serverNetworkMessages/PopulationListMessage.h" -#include "serverNetworkMessages/PreloadFinishedMessage.h" -#include "serverNetworkMessages/PreloadRequestCompleteMessage.h" -#include "serverNetworkMessages/ProfilerOperationMessage.h" -#include "serverNetworkMessages/RandomName.h" -#include "serverNetworkMessages/ReleaseAuthoritativeMessage.h" -#include "serverNetworkMessages/RenameCharacterMessage.h" -#include "serverNetworkMessages/RequestChunkMessage.h" -#include "serverNetworkMessages/RequestGameServerForLoginMessage.h" -#include "serverNetworkMessages/RequestObjectIdsMessage.h" -#include "serverNetworkMessages/RequestObjectMessage.h" -#include "serverNetworkMessages/RestartServerMessage.h" -#include "serverNetworkMessages/SceneTransferMessages.h" -#include "serverNetworkMessages/ServerDeleteCharacterMessage.h" -#include "serverNetworkMessages/SetConnectionServerPublic.h" -#include "serverNetworkMessages/SetObjectPositionMessage.h" -#include "serverNetworkMessages/TaskProcessDiedMessage.h" -#include "serverNetworkMessages/TaskSpawnProcess.h" -#include "serverNetworkMessages/TransferCharacterData.h" -#include "serverNetworkMessages/TransferCharacterDataArchive.h" -#include "serverNetworkMessages/UnloadObjectMessage.h" -#include "serverNetworkMessages/UpdateLoginConnectionServerStatus.h" -#include "serverNetworkMessages/UpdatePlayerCountMessage.h" -#include "serverNetworkMessages/ValidateAccountMessage.h" -#include "serverNetworkMessages/ValidateAccountReplyMessage.h" -#include "serverNetworkMessages/ValidateCharacterForLoginMessage.h" -#include "serverNetworkMessages/ValidateCharacterForLoginReplyMessage.h" -#include "serverNetworkMessages/VerifyAndLockName.h" -#include "sharedNetworkMessages/ConsoleChannelMessages.h" -#include "serverUtility/ClusterWideDataManagerList.h" -#include "serverUtility/ServerClock.h" -#include "serverUtility/SetupServerUtility.h" -#include "sharedDebug/Profiler.h" -#include "sharedFile/Iff.h" -#include "sharedFoundation/ApplicationVersion.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/Clock.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/Os.h" -#include "sharedFoundation/Timer.h" -#include "sharedLog/Log.h" -#include "sharedLog/SetupSharedLog.h" -#include "sharedMathArchive/VectorArchive.h" -#include "sharedNetwork/Connection.h" -#include "sharedNetwork/NetworkSetupData.h" -#include "sharedNetwork/Service.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/NameErrors.h" -#include "sharedNetworkMessages/NetworkStringIds.h" -#include "sharedUtility/SetupSharedUtility.h" -#include "sharedUtility/StartingLocationData.h" -#include "sharedUtility/StartingLocationManager.h" -#include "TransferServerConnection.h" -#include "StationPlayersCollectorConnection.h" -#include "AuctionTransferClient.h" -#include "unicodeArchive/UnicodeArchive.h" -#include - - -namespace CentralServerNamespace -{ - bool gs_connectionServersPublic=false; - bool gs_clusterIsLocked=false; - bool gs_clusterIsSecret=false; - - std::map ms_sceneToHostMap; - - // every connection server started on the cluster will - // have a entry in this vector which contains the node - // on which to start that particular connection server; - // every connection server that is started will be assigned - // a 1-based number, which corresponds to its position - // in this vector; that is, the connection server assigned - // number 1 will be at position 0 in this vector - std::vector s_connectionServerHostList; - - std::pair s_customerServiceServerChatServerServiceAddress; - std::pair s_customerServiceServerGameServerServiceAddress; - Service * s_commodityServerService = 0; - bool s_retryTransferServerConnection = false; - bool s_retryStationPlayersCollectorConnection = false; - - std::map m_purgeAccountToLoginServerMap; - std::map > s_pendingRenameCharacter; -} - -using namespace CentralServerNamespace; - -// ====================================================================== - -CentralServer::CentralObject::CentralObject() : -m_sceneId(), -m_authoritativeProcess(0), -m_proxyProcessList() -{ - -} - -//----------------------------------------------------------------------- - -CentralServer::CentralObject::CentralObject(const CentralServer::SceneId & sceneId, uint32 authProcess) : -m_sceneId(sceneId), -m_authoritativeProcess(authProcess), -m_proxyProcessList() -{ - -} - -//----------------------------------------------------------------------- - -CentralServer::CentralServer() : -Singleton(), -MessageDispatch::Receiver(), -m_connectionServerConnections(), -m_chatServerConnections(), -m_csServerConnections(), -m_gameServers(), -m_accountConnectionMap(), -m_dbProcessServerProcessId(0), -m_done(false), -m_gameService(0), -m_chatService(0), -m_connService(0), -m_csService(0), -m_planetService(0), -m_consoleService(0), -m_transferServerConnection(0), -m_stationPlayersCollectorConnection(0), -m_gameServerConnections(), -m_gameServerConnectionsList(), -m_playerSceneMap(), -m_loginServerConnectionMap(), -m_loginServerKeys(0), -m_loginService(0), -m_pAuctionTransferClient(0), -m_messagesWaitingForPlanetServer(), -m_pendingLoadingObjects(), -m_pendingNewObjects(), -m_nextFreeProcessId(0), -m_taskManager(0), -m_taskService(0), -m_commandLine(), -m_pendingTransfers(), -m_totalPlayerCount(0), -m_totalFreeTrialCount(0), -m_totalEmptySceneCount(0), -m_totalTutorialSceneCount(0), -m_totalFalconSceneCount(0), -m_metricsData(0), -m_pendingPlanetServers(), -m_planetsWaitingForPreload(), -m_planetServers(), -m_nextPlanetWatcherPort(ConfigCentralServer::getFirstPlanetWatcherPort()), -m_databaseBacklogged(false), -m_lastLoadingStateTime(0), -m_timeClusterStarted(time(0)), -m_clusterStartupTime(-1), -m_timeClusterWentIntoLoadingState(time(0)), -m_clusterId(0), -m_serverPings(), -m_shutdownTotalTime(0), -m_shutdownMaxTime(0), -m_shutdownSystemMessage(Unicode::narrowToWide("")), -m_shutdownPhase(0), -m_shutdownHaveDatabaseSaveStart(false), -m_shutdownHaveDatabaseComplete(false), -m_curTime(0), -m_lastTimeSystemTimeMismatchNotification(0), -m_lastTimeSystemTimeMismatchNotificationDescription(), -m_disconnectedTaskManagerList(), -m_populationStatistics(), -m_timePopulationStatisticsRefresh(0), -m_timePopulationStatisticsNextRefresh(0), -m_gcwScoreStatistics(), -m_timeGcwScoreStatisticsRefresh(0), -m_timeGcwScoreStatisticsNextRefresh(0), -m_lastLoginTimeStatistics(), -m_createTimeStatistics(), -m_timeLastLoginTimeStatisticsRefresh(0), -m_timeLastLoginTimeStatisticsNextRefresh(0), -m_numberOfCharacterMatchRequests(0), -m_numberOfCharacterMatchResults(0), -m_timeSpentOnCharacterMatchRequestsMs(0), -m_timeCharacterMatchStatisticsNextRefresh(0) -{ - m_curTime = static_cast(time(0)); - m_loginServerKeys = new KeyServer(20); - - connectToMessage("LoginKeyPush"); - - //Connection Messages - connectToMessage("ClientConnectionClosed"); // from connection server - connectToMessage("ConnectionOpened"); - connectToMessage("RequestClusterShutdown"); - connectToMessage("GameConnectionClosed"); - connectToMessage("CentralGameServerConnect"); - connectToMessage("CentralGameServerDbProcessServerProcessId"); - connectToMessage("LoginConnectionOpened"); - connectToMessage("LoginConnectionClosed"); - connectToMessage("ClusterId"); - connectToMessage("GameServerReadyMessage"); - connectToMessage("GameServerUniverseLoadedMessage"); - connectToMessage("ConnectionServerConnectionClosed"); - connectToMessage("ConnectionServerConnectionOpened"); - connectToMessage("TaskConnectionClosed"); - connectToMessage("TaskConnectionOpened"); - connectToMessage("RandomNameRequest"); // from connection server - connectToMessage("RandomNameResponse"); // from game server - connectToMessage("VerifyAndLockNameRequest"); // from connection server - connectToMessage("VerifyAndLockNameResponse"); // from game server - - //Object Messages - connectToMessage("RequestObjectMessage"); - connectToMessage("RequestChunkMessage"); - connectToMessage("ChunkObjectListMessage"); - connectToMessage("CreateNewObjectMessage"); - connectToMessage("SetObjectPositionMessage"); - connectToMessage("FailedToLoadObjectMessage"); - connectToMessage("ReleaseAuthoritativeMessage"); - connectToMessage("ForceUnloadObjectMessage"); - connectToMessage("RequestUnloadObjectMessage"); - connectToMessage("MessageToMessage"); - connectToMessage("MessageToAckMessage"); - connectToMessage("LocateStructureMessage"); - - //Create character messages - connectToMessage("ConnectionCreateCharacter"); - connectToMessage("DatabaseCreateCharacterSuccess"); - connectToMessage("GameCreateCharacterFailed"); - connectToMessage("RequestGameServerForLoginMessage"); - connectToMessage("GameServerForLoginMessage"); - connectToMessage("LoginCreateCharacterAckMessage"); - connectToMessage("LoginUpgradeAccountMessage"); - connectToMessage("LoginRestoreCharacterMessage"); - connectToMessage("NewCharacterCreated"); - - connectToMessage("ServerDeleteCharacterMessage"); - connectToMessage("ValidateCharacterForLoginMessage"); - connectToMessage("ValidateCharacterForLoginReplyMessage"); - connectToMessage("EnableCharacterMessage"); - connectToMessage("EnableCharacterReplyMessage"); - connectToMessage("DisableCharacterMessage"); - connectToMessage("DisableCharacterReplyMessage"); - - connectToMessage("RequestOIDsMessage"); - connectToMessage("AddOIDBlockMessage"); - connectToMessage("CharacterListMessage"); - connectToMessage("LoggedInMessage"); - connectToMessage("CentralPlanetServerConnect"); - connectToMessage("PlanetCreateProxy"); - connectToMessage("PlanetRemoveProxy"); - - connectToMessage("RequestSceneTransfer"); - connectToMessage("SceneTransferMessage"); - connectToMessage("PlanetLoadCharacterMessage"); - - connectToMessage("ConnSrvDropDupeConns"); - connectToMessage("CntrlSrvDropDupeConns"); - - connectToMessage("PlayerDroppedFromGameServerCrash"); - - // Station exchange messages - connectToMessage("ExchangeListCreditsMessage"); - - // Chat Server messages - connectToMessage("ChatServerConnectionOpened"); - connectToMessage("ChatServerConnectionClosed"); - connectToMessage("ChatServerOnline"); - - // Chat Server messages - connectToMessage("CustomerServiceConnectionOpened"); - connectToMessage("CustomerServiceConnectionClosed"); - - connectToMessage("ValidateAccountMessage"); - connectToMessage("ValidateAccountReplyMessage"); - - connectToMessage("RequestPreloadListMessage"); - connectToMessage("PreloadListMessage"); - connectToMessage("PreloadRequestCompleteMessage"); - connectToMessage("PreloadFinishedMessage"); - connectToMessage("DatabaseBackloggedMessage"); - - connectToMessage("UpdatePlayerCountMessage"); - connectToMessage("RenameCharacterMessageEx"); - connectToMessage("PlayerRenameRequestSubmitted"); - connectToMessage("PlayerRenameRequestCompleted"); - connectToMessage("PopulationListMessage"); - - connectToMessage("SetConnectionServerPublic"); - - connectToMessage("ProfilerOperationMessage"); - connectToMessage("CentralPingMessage"); - - connectToMessage("DatabaseSaveStart"); - connectToMessage("DatabaseSaveComplete"); - connectToMessage("ShutdownCluster"); - connectToMessage("AbortShutdown"); - connectToMessage("SetSceneForPlayer"); - connectToMessage("DatabaseConsoleReplyMessage"); - connectToMessage("TaskProcessDiedMessage"); - connectToMessage("SystemTimeMismatchNotification"); - connectToMessage("DisconnectedTaskManagerMessage"); - connectToMessage("TransferServerConnectionClosed"); - connectToMessage("PlanetRequestSave"); - connectToMessage("TransferReplyLoginLocationData"); - connectToMessage("CustomerServiceServerChatServerServiceAddress"); - connectToMessage("CustomerServiceServerGameServerServiceAddress"); - connectToMessage("ChatClosedConnectionWithGameServer"); - - connectToMessage("ReconnectToTransferServer"); - connectToMessage("ClaimRewardsMessage"); - connectToMessage("ClaimRewardsReplyMessage"); - connectToMessage("PurgeStructuresForAccountMessage"); - connectToMessage("WarnStructuresAboutPurgeMessage"); - connectToMessage("PurgeCompleteMessage"); - connectToMessage("RestartServerMessage"); - connectToMessage("RestartServerByRoleMessage"); - connectToMessage("ExcommunicateGameServerMessage"); - connectToMessage("RestartPlanetMessage"); - - // Cluster state - connectToMessage("UpdateClusterLockedAndSecretState"); - - // Population statistics - connectToMessage("PopStatRsp"); - connectToMessage("LLTStatRsp"); - - // GCW score statistics - connectToMessage("GcwScoreStatRsp"); - - // Character Search statistics - connectToMessage("LfgStatRsp"); - - // Account feature Id management - connectToMessage("AdjustAccountFeatureIdResponse"); - connectToMessage("AccountFeatureIdResponse"); - connectToMessage("FeatureIdTransactionResponse"); - - // Unlocked Slot management - connectToMessage("OccupyUnlockedSlotRsp"); - connectToMessage("VacateUnlockedSlotRsp"); - connectToMessage("SwapUnlockedSlotRsp"); - - // Cluster wide data manager - ClusterWideDataManagerList::install(); - ClusterWideDataManagerList::registerMessage(*this); - ClusterWideDataManagerList::setLockTimeoutValue(ConfigCentralServer::getClusterWideDataLockTimeout()); - - CentralCSHandler::install(); - - gs_connectionServersPublic = ConfigCentralServer::getStartPublic(); - - m_metricsData = new CentralServerMetricsData; - MetricsManager::install(m_metricsData, false, "CentralServer", "", 0); - ConsoleManager::install(); - CharacterCreationTracker::install(); - - IGNORE_RETURN(UniverseManager::getInstance()); //make sure it's constructed -} - -//----------------------------------------------------------------------- - -CentralServer::~CentralServer() -{ - ConsoleManager::remove(); - - CentralCSHandler::remove(); - - ms_sceneToHostMap.clear(); - - // released during CentralServer::remove() - m_gameService = 0; - m_chatService = 0; - m_connService = 0; - m_csService = 0; - m_planetService = 0; - m_consoleService = 0; - m_transferServerConnection = 0; - m_stationPlayersCollectorConnection = 0; - m_loginServerKeys = 0; //lint !e423 : leak - m_loginService = 0; - m_taskManager = 0; - m_taskService = 0; - m_metricsData = 0; //lint !e423 : leak -} - -//----------------------------------------------------------------------- -void CentralServer::addGameServer(GameServerConnection * newGameServer) -{ - uint32 pid = newGameServer->getProcessId(); - - LOG("ServerStartup", ("Adding server %lu for scene %s", pid, newGameServer->getSceneId().c_str())); - - IGNORE_RETURN(m_gameServers.insert(SceneGameMap::value_type( - newGameServer->getSceneId(), newGameServer))); - m_gameServerConnections[pid] = newGameServer; - - if (newGameServer->getSceneId() != "database") - { - m_gameServerConnectionsList.push_back(newGameServer); - - if (ConfigCentralServer::getGameServerConnectionPendingAllocatedSizeLimit() != 0) - newGameServer->setTcpClientPendingSendAllocatedSizeLimit(ConfigCentralServer::getGameServerConnectionPendingAllocatedSizeLimit()); - - PlanetManager::addGameServerForScene(newGameServer->getSceneId(), newGameServer); - - // Have the new game server connect to the db and notify it of what game servers exist - std::vector serverList; - - GameServerConnection const * const databaseProcessConnection = CentralServer::getInstance().getGameServer(CentralServer::getInstance().getDbProcessServerProcessId()); - - FATAL(!databaseProcessConnection, ("Tried to add a game server without a database process connection?")); - - for (std::map::iterator i = m_gameServerConnections.begin(); i != m_gameServerConnections.end(); ++i) - { - GameServerConnection const * const g = (*i).second; - if (g != databaseProcessConnection && g->getProcessId() != pid) - serverList.push_back(g->getProcessId()); - } - - GenericValueTypeMessage, std::pair > > > const setupMessage( - "GameServerSetupMessage", - std::make_pair( - serverList, - std::make_pair( - databaseProcessConnection->getProcessId(), - std::make_pair( - databaseProcessConnection->getGameServiceAddress(), - databaseProcessConnection->getGameServicePort())))); - - newGameServer->send(setupMessage, true); - } -} - -//----------------------------------------------------------------------- - -void CentralServer::broadcastToChatServers(const GameNetworkMessage & message) const -{ - for (std::set::const_iterator i = m_chatServerConnections.begin(); i != m_chatServerConnections.end(); ++i) - (*i)->send(message, true); -} - -//----------------------------------------------------------------------- - -void CentralServer::broadcastToCustomerServiceServers(const GameNetworkMessage & message) const -{ - for (std::set::const_iterator i = m_csServerConnections.begin(); i != m_csServerConnections.end(); ++i) - (*i)->send(message, true); -} - -//----------------------------------------------------------------------- - -void CentralServer::broadcastToGameServers(const GameNetworkMessage & message) const -{ - for (SceneGameMap::const_iterator i = m_gameServers.begin(); i != m_gameServers.end(); ++i) - (*i).second->send(message, true); -} - -//----------------------------------------------------------------------- -// /** -// * Clears the object process map for an object. -// * -// * @param objectId id of object we want to clear -// */ -// void CentralServer::clearObjectMap(const NetworkId & objectId) -// { -// IGNORE_RETURN(m_centralObjectMap.erase(objectId)); -// } - -//----------------------------------------------------------------------- - -bool CentralServer::getIsClusterPublic() const -{ - return gs_connectionServersPublic; -} - -//----------------------------------------------------------------------- - -bool CentralServer::getIsClusterLocked() const -{ - return gs_clusterIsLocked; -} - -//----------------------------------------------------------------------- - -bool CentralServer::getIsClusterSecret() const -{ - return gs_clusterIsSecret; -} - -//----------------------------------------------------------------------- - -const std::string& CentralServer::getHostForScene(const std::string& scene) const -{ - static std::string anyString = "any"; - std::map::iterator i = ms_sceneToHostMap.find(scene); - if (i != ms_sceneToHostMap.end()) - { - return i->second; - } - return anyString; -} - -// ---------------------------------------------------------------------- - -/** - * Get the list of game servers that are ready - */ -void CentralServer::getReadyGameServers(std::vector &theList) -{ - std::map::const_iterator i; - for (i = m_gameServerConnections.begin(); i!=m_gameServerConnections.end(); ++i) - { - if ((*i).second->getProcessId()!=getDbProcessServerProcessId() && i->second->getReady()) - theList.push_back(i->second->getProcessId()); - } -} - -//------------------------------------------------------------- - -GameServerConnection * CentralServer::getRandomGameServer(void) -{ - if (m_gameServerConnectionsList.empty()) - return NULL; - - // m_gameServerConnectionsList ***DOES NOT*** contain the DB server so - // we don't have to worry about checking for and excluding the DB server - size_t const listSize = m_gameServerConnectionsList.size(); - size_t const indexChosenGameServer = (::rand() % listSize); - if (m_gameServerConnectionsList[indexChosenGameServer]->getReady()) - return m_gameServerConnectionsList[indexChosenGameServer]; - - // randomly chosen game server is not ready, find next ready game server - size_t indexNextGameServer = (indexChosenGameServer + 1); - if (indexNextGameServer == listSize) - indexNextGameServer = 0; - - while (indexNextGameServer != indexChosenGameServer) - { - if (m_gameServerConnectionsList[indexNextGameServer]->getReady()) - return m_gameServerConnectionsList[indexNextGameServer]; - - ++indexNextGameServer; - if (indexNextGameServer == listSize) - indexNextGameServer = 0; - } - - return NULL; -} - -//----------------------------------------------------------------------- - -/** -* Returns a game server that is handling a scene. -* -* @param scene the scene -* -* @return a game server connection for that scene -*/ -GameServerConnection * CentralServer::getGameServer(const SceneId &scene) const -{ - // @todo: we should pick a gameserver based on load - - CentralServer::ServersList range = getGameServers(scene); - SceneGameMap::const_iterator iter = range.first; - while (iter != range.second) - { - if (iter->second->getReady()) - return iter->second; - ++iter; - } - return 0; -} - -//----------------------------------------------------------------------- - -/** -* Returns the game server for a given process id. -* -* @param processId the process id -* -* @return the game server connection -*/ -GameServerConnection * CentralServer::getGameServer(const uint32 processId) const -{ - GameServerConnection * result = 0; - std::map::const_iterator i = m_gameServerConnections.find(processId); - if(i != m_gameServerConnections.end()) - result = (*i).second; - return result; -} - -//----------------------------------------------------------------------- - -/** -* Returns a list of game servers that are handling a scene. -* -* @param scene the scene -* -* @return an iterator pair for a range of GameServerConnections -*/ -const CentralServer::ServersList CentralServer::getGameServers(const SceneId &scene) const -{ - return m_gameServers.equal_range(scene); //lint !e64 //Type mismatch -} - -//----------------------------------------------------------------------- - -void CentralServer::pushAllKeys(ConnectionServerConnection * targetConnectionServer) const -{ - DEBUG_FATAL(static_cast(m_loginServerKeys->getKeyCount()) < 0, ("Invalid number of keys (uint overflow) in CentralServer.h")); - - for(int i = static_cast(m_loginServerKeys->getKeyCount()) - 1; i >= 0 ; i --) - { - ConnectionKeyPush pk(m_loginServerKeys->getKey(static_cast(i))); - targetConnectionServer->send(pk, true); - } -} - -//----------------------------------------------------------------------- - -void CentralServer::launchStartingProcesses() const -{ - static bool startingProcessesLaunched = false; - if (startingProcessesLaunched) - return; - - // we can only launch starting processes once we have a connection to the - // TaskManager *AND* have received our cluster id from the LoginServer - if (!m_taskManager || !m_taskManager->isConnected() || (m_clusterId == 0)) - { - if (!m_taskManager) - REPORT_LOG(true, ("CentralServer not launching starting processes because m_taskManager is NULL\n")); - else if (!m_taskManager->isConnected()) - REPORT_LOG(true, ("CentralServer not launching starting processes because m_taskManager->isConnected() is false\n")); - - if (m_clusterId == 0) - REPORT_LOG(true, ("CentralServer not launching starting processes because m_clusterId is 0, meaning hasn't received the cluster Id from the LoginServer yet\n")); - - return; - } - - REPORT_LOG(true, ("CentralServer now launching starting processes because has a connection to the TaskManager *AND* has received cluster Id (%u) from the LoginServer\n", m_clusterId)); - - startingProcessesLaunched = true; - - // spawn a connection server - launchStartingConnectionServers(); - - std::string options = "-s dbProcess centralServerAddress="; - if(getGameService()) - { - options += getGameService()->getBindAddress(); - } - else - { - options += NetworkHandler::getHostName(); - } - - TaskSpawnProcess pd(ConfigCentralServer::getDbServerHost(), "SwgDatabaseServer", options); - m_taskManager->send(pd, true); - - options = "-s ChatServer centralServerAddress="; - if(getChatService()) - { - options += getChatService()->getBindAddress(); - } - else - { - options += NetworkHandler::getHostName(); - } - options += " clusterName="; - options += ConfigCentralServer::getClusterName(); - TaskSpawnProcess pc(ConfigCentralServer::getChatServerHost(), "ChatServer", options); - m_taskManager->send(pc, true); - - options = "-s CustomerServiceServer centralServerAddress="; - if(getCustomerService()) - { - options += getCustomerService()->getBindAddress(); - } - else - { - options += NetworkHandler::getHostName(); - } - - options += " clusterName="; - options += ConfigCentralServer::getClusterName(); - TaskSpawnProcess pcs("any", "CustomerServiceServer", options); - m_taskManager->send(pcs, true); -} - -//----------------------------------------------------------------------- - -void CentralServer::launchStartingConnectionServers() const -{ - // if there are several planets listed explicitly in the config file/command line, - // spawn them - - int i = 0; - - // check for nesteds - int const numberOfStartingConnectionServers = ConfigCentralServer::getNumberOfStartingConnectionServers(); - for (i = 0; i < numberOfStartingConnectionServers; ++i) - { - char const * const host = ConfigCentralServer::getStartingConnectionServer(i); - if (host) - { - char const * listenAddress = strchr(host,':'); - DEBUG_FATAL(!listenAddress, ("Could not start up connection server because string %s has no listen address", host)); - std::string hostString(host, static_cast(listenAddress - host)); - ++listenAddress; - - char const * publicPort = strchr(listenAddress,':'); - DEBUG_FATAL(!publicPort, ("Could not start up connection server because string %s has no public port", host)); - std::string listenString(listenAddress, static_cast(publicPort - listenAddress)); - ++publicPort; - - char const * privatePort = strchr(publicPort,':'); - DEBUG_FATAL(!privatePort, ("Could not start up connection server because string %s has no private port", host)); - std::string publicPortString(publicPort, static_cast(privatePort - publicPort)); - ++privatePort; - std::string privatePortString(privatePort); - - DEBUG_REPORT_LOG(true, ("Spawning Connection Server on %s listen:%s public:%s priv:%s\n", hostString.c_str(), listenString.c_str(), publicPortString.c_str(), privatePortString.c_str())); - - // must update s_connectionServerHostList before calling startConnectionServer() - s_connectionServerHostList.push_back(hostString); - startConnectionServer(s_connectionServerHostList.size(), listenString, &publicPortString, &privatePortString, 0); - } - } - - // if there were none specified, use defaults - if(i == 0) - { - // must update s_connectionServerHostList before calling startConnectionServer() - s_connectionServerHostList.push_back("node0"); - startConnectionServer(s_connectionServerHostList.size(), NetworkHandler::getHostName(), 0, 0, 0); - } - -} - -//----------------------------------------------------------------------- - -void CentralServer::launchStartingPlanetServers() -{ - // if there are several planets listed explicitly in the config file/command line, - // spawn them - int i = 0; - int const numberOfStartPlanets = ConfigCentralServer::getNumberOfStartPlanets(); - - for (i = 0; i < numberOfStartPlanets ; ++i) - { - char const * const p = ConfigCentralServer::getStartPlanet(i); - if (p) - { - FATAL(!*p, ("CentralServer::launchStartingPlanetServers: ConfigCentralServer::getStartPlanet(%d) specified a non-null but empty planet name", i)); - - std::string planetName; - std::string hostName; - char const * planet = p; - NOT_NULL(planet); - char const * host = strchr(planet,':'); - - if (host) - { - planetName = std::string(planet, static_cast(host - planet) ); - ++host; - hostName = host; - } - else - { - planetName = planet; - } - - startPlanetServer(hostName, planetName, 0); - ms_sceneToHostMap[planetName] = hostName; - } - } - - // if there were no planets specified, get the configfile default and - // start that planet - if(i == 0) - { - startPlanetServer("any", ConfigCentralServer::getStartPlanet(), 0); - } -} - -//----------------------------------------------------------------------- - -void CentralServer::launchCommoditiesServer() -{ - std::string options; - TaskSpawnProcess csp("any", "CommoditiesServer", options); - CentralServer::getInstance().sendTaskMessage(csp); -} - -//----------------------------------------------------------------------- - -void CentralServer::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) -{ - if(message.isType("LoginKeyPush")) - { - // receiving another key - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const LoginKeyPush k(ri); - m_loginServerKeys->pushKey(k.getKey()); - DEBUG_REPORT_LOG(true, ("Received session key.\n")); - ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); - for (;i != m_connectionServerConnections.end(); ++i) - { - (*i)->send(k, true); - } - } - else if (message.isType("RequestClusterShutdown")) - { - REPORT_LOG(true, ("An admin requested we shutdown the entire cluster\n")); - m_done = true; - } - else if (message.isType("ClientConnectionClosed")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - ConnectionServerSUIDMap::iterator i = m_accountConnectionMap.find(msg.getValue()); - if ((i != m_accountConnectionMap.end()) && (i->second == &source)) - { - // Erase the entry - m_accountConnectionMap.erase(i); - } - } - else if(message.isType("ConnectionOpened")) - { - if (!dynamic_cast(&source)) - { - ServerConnection *newServer = const_cast(safe_cast(&source)); - uint32 pid = newServer->getProcessId(); - - CentralGameServerSetProcessId pidMessage(pid, ServerClock::getInstance().getSubtractInterval(), ConfigCentralServer::getClusterName()); - newServer->send(pidMessage, true); - } - } - else if(message.isType("ConnectionServerConnectionClosed")) - { - DEBUG_REPORT_LOG(true,("Handling connection server crash.\n")); - ConnectionServerConnection const *c = safe_cast(&source); - removeFromAccountConnectionMap(c->getId()); - } - else if(message.isType("GameConnectionClosed")) - { - DEBUG_REPORT_LOG(true, ("Game server closed connection\n")); - GameServerConnection const *g = safe_cast(&source); - removeGameServer(g); - } - - else if (message.isType("LoginConnectionOpened")) - { - LoginServerConnection *l = const_cast(safe_cast(&source)); - m_loginServerConnectionMap[l->getProcessId()] = l; - //Send connection server data - ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); - for(; i != m_connectionServerConnections.end(); ++i) - { - const ConnectionServerConnection * const csc = *i; - if ( (csc->getClientServicePortPrivate() != 0) || (csc->getClientServicePortPublic() != 0) ) - { - const LoginConnectionServerAddress csa(csc->getId(), csc->getClientServiceAddress(), csc->getClientServicePortPrivate(), csc->getClientServicePortPublic(), csc->getPlayerCount(), csc->getPingPort ()); - l->send(csa, true); - } - } - - // send preload is finished, if it is - PreloadFinishedMessage msg(isPreloadFinished()); - l->send(msg, true); - - CharacterCreationTracker::getInstance().retryLoginServerCreates(); - } - - else if(message.isType("LoginConnectionClosed")) - { - LoginServerConnection const *l = safe_cast(&source); - LoginServerConnectionMapType::iterator i=m_loginServerConnectionMap.find(l->getProcessId()); - if (i!=m_loginServerConnectionMap.end()) - m_loginServerConnectionMap.erase(i); - - // In development mode, try to reconnect to the login server if we aren't shutting down - if (ConfigCentralServer::getDevelopmentMode() && !m_done) - connectToLoginServer(); - - CharacterCreationTracker::getInstance().onLoginServerDisconnect(l->getProcessId()); - } - - else if(message.isType("ClusterId")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - if (m_clusterId == 0) - { - FATAL(((msg.getValue() < 1) || (msg.getValue() > 255)),("Cluster Id (%lu) must be between 1 and 255 inclusive", msg.getValue())); - - m_clusterId = static_cast(msg.getValue()); - - // start launching processes - launchStartingProcesses(); - } - } - - else if(message.isType("CentralGameServerConnect")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - CentralGameServerConnect c(ri); - - GameServerConnection *g = const_cast(safe_cast(&source)); - - FATAL(ConfigCentralServer::getValidateBuildVersionNumber() && strcmp(ApplicationVersion::getInternalVersion(), c.getBuildVersionNumber().c_str()), - ("Build version number mismatch: central server (%s), remote server %s (%s)", ApplicationVersion::getInternalVersion(), g->getRemoteAddress().c_str(), c.getBuildVersionNumber().c_str()) - ); - - // a game server (or db process) has connected... - addGameServer(g); - - //Send connection server data - ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); - for(; i != m_connectionServerConnections.end(); ++i) - { - if ((*i)->getGameServicePort() != 0) - { - ConnectionServerAddress csa((*i)->getGameServiceAddress(), (*i)->getGameServicePort()); - g->send(csa, true); - } - } - - std::set::const_iterator chatIter; - for(chatIter = m_chatServerConnections.begin(); chatIter != m_chatServerConnections.end(); ++chatIter) - { - if((*chatIter)->getGameServicePort()) - { - ChatServerOnline cso((*chatIter)->getRemoteAddress(), (*chatIter)->getGameServicePort()); - g->send(cso, true); - } - } - - if (g != NULL) - { - //DEBUG_REPORT_LOG(true, ("CentralServer: Sending CustomerServiceServerGameServerServiceAddress to game server (%s:%d) pid(%i)\n", g->getRemoteAddress().c_str(), g->getRemotePort(), g->getProcessId())); - const GenericValueTypeMessage > address("CustomerServiceServerGameServerServiceAddress", std::make_pair(s_customerServiceServerGameServerServiceAddress.first, s_customerServiceServerGameServerServiceAddress.second)); - - g->send(address, true); - } - } - else if (message.isType("ChatClosedConnectionWithGameServer")) - { - GameServerConnection *g = const_cast(safe_cast(&source)); - std::set::const_iterator chatIter; - for(chatIter = m_chatServerConnections.begin(); chatIter != m_chatServerConnections.end(); ++chatIter) - { - if((*chatIter)->getGameServicePort()) - { - ChatServerOnline cso((*chatIter)->getRemoteAddress(), (*chatIter)->getGameServicePort()); - g->send(cso, true); - } - } - } - else if (message.isType("CustomerServiceServerGameServerServiceAddress")) - { - //DEBUG_REPORT_LOG(true, ("CentralServer::receiveMessage(CustomerServiceServerGameServerServiceAddress)\n")); - - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const GenericValueTypeMessage > address(ri); - s_customerServiceServerGameServerServiceAddress.first = address.getValue().first; - s_customerServiceServerGameServerServiceAddress.second = address.getValue().second; - - broadcastToGameServers(address); - } - else if(message.isType("TaskConnectionClosed")) - { - // Net::getInstance().connect(Network::Address("127.0.0.1", ConfigCentralServer::getTaskManagerPort()), TaskConnection()); - } - else if(message.isType("TaskConnectionOpened")) - { - DEBUG_REPORT_LOG(true, ("Task manager connection opened\n")); - } - - else if(message.isType("CentralGameServerDbProcessServerProcessId")) - { - DEBUG_REPORT_LOG(true, ("dbProcess connected\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - CentralGameServerDbProcessServerProcessId d(ri); - m_dbProcessServerProcessId = d.getServerProcessId(); - ServerClock::getInstance().setSubtractInterval(d.getSubtractInterval()); - - launchCommoditiesServer(); - launchStartingPlanetServers(); - } - - else if(message.isType("RequestChunkMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RequestChunkMessage t(ri); - - // Forward this message to the dbProcess - sendToGameServer(m_dbProcessServerProcessId, t, true); - } - else if(message.isType("ChunkObjectListMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ChunkObjectListMessage t(ri); - - DEBUG_FATAL(true,("Got ChunkObjectListMessage. Thought it was deprecated.\n")); - // handleChunkList(t.getProcess(), t.getIds()); - } - else if(message.isType("LocateStructureMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LocateStructureMessage t(ri); - sendToPlanetServer(t.getSceneId(), t, true); - } - else if(message.isType("RequestObjectMessage")) - { - DEBUG_FATAL(true,("Got RequestObjectMessage. Thought this went away.")); - - // Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - // RequestObjectMessage t(ri); - // // tell the authoritative object to create a proxy - // const GameServerConnection *gameServer = getGameServer(t.getProcess()); - // NOT_NULL(gameServer); - // uint32 authId = sendToAuthoritativeServer(t.getId(), - // LoadObjectMessage(t.getId(), t.getProcess(), gameServer->getGameServiceAddress(), gameServer->getGameServicePort(), false), - // true); - // // if we sent the message to the database process, mark it as being - // // authoritative for this object - // if (authId == m_dbProcessServerProcessId) - // { - // addObjectToMap(t.getId(), authId, gameServer->getSceneId(), true); - // m_pendingLoadingObjects[t.getId()] = t.getProcess(); - // } - } - else if(message.isType("CreateNewObjectMessage")) - { - DEBUG_FATAL(true,("Ain't this supposed to be deprecated or something?")); - } - else if(message.isType("SetObjectPositionMessage")) - { - //@todo remove this message from the library - DEBUG_FATAL(true,("Got SetObjectPositionMessage. Thought this went away")); - } - else if(message.isType("FailedToLoadObjectMessage")) - { - //@todo remove this message from the library - DEBUG_FATAL(true,("Received Failed To Load Object Message. Thought it was depricated\n")); - } - else if(message.isType("ReleaseAuthoritativeMessage")) - { - //@todo remove this message from the library - DEBUG_FATAL(true, ("Received ReleaseAuthoritative for. Thought it was deprecated.")); - } - else if(message.isType("ForceUnloadObjectMessage")) - { - //N.B. This message can come from a game server or from the planet server. - DEBUG_WARNING(true, ("Received ForceUnloadObject. Need to implement this\n")); - - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ForceUnloadObjectMessage t(ri); - - //@todo: figure out some way to handle this (such as forwarding to PlanetServers), or remove every case where it's sent - // forceUnload(t.getId(),t.getPermaDelete()); - } - //Character Creation Messages - else if(message.isType("ConnectionCreateCharacter")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ConnectionCreateCharacter c(ri); - - LOG("TraceCharacterCreation", ("%d received ConnectionCreateCharacter", c.getStationId())); - CharacterCreationTracker::getInstance().handleCreateNewCharacter(c); - } - else if(message.isType("GameCreateCharacterFailed")) - { - DEBUG_REPORT_LOG(true, ("Game server advises central that character creation failed\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GameCreateCharacterFailed f(ri); - CharacterCreationTracker::getInstance().handleGameCreateCharacterFailed(f.getStationId(), f.getName(), f.getErrorMessage(), f.getOptionalDetailedErrorMessage()); - } - else if(message.isType("DatabaseCreateCharacterSuccess")) - { - DEBUG_REPORT_LOG(true, ("Database Process advises central that character creation succeeded\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - DatabaseCreateCharacterSuccess s(ri); - CharacterCreationTracker::getInstance().handleDatabaseCreateCharacterSuccess(s.getStationId(), s.getCharacterName(), s.getObjectId(), s.getTemplateId(), s.getJedi()); - } - else if(message.isType("LoginCreateCharacterAckMessage")) - { - DEBUG_REPORT_LOG(true, ("Login Server advises central that character creation succeeded\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginCreateCharacterAckMessage s(ri); - CharacterCreationTracker::getInstance().handleLoginCreateCharacterAck(s.getStationId()); - } - else if(message.isType("LoginRestoreCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginRestoreCharacterMessage msg(ri); - - IGNORE_RETURN(sendToArbitraryLoginServer(msg)); - } - else if(message.isType("NewCharacterCreated")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const ncc(ri); - - CentralServer::getInstance().sendToAllConnectionServers(ncc, true); - } - else if(message.isType("DatabaseConsoleReplyMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > msg(ri); - - IGNORE_RETURN(sendToRandomGameServer(msg)); - } - else if(message.isType("LoginRestoreCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginRestoreCharacterMessage msg(ri); - - IGNORE_RETURN(sendToArbitraryLoginServer(msg)); - } - else if(message.isType("DatabaseConsoleReplyMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > msg(ri); - - IGNORE_RETURN(sendToRandomGameServer(msg)); - } - else if(message.isType("LoginUpgradeAccountMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginUpgradeAccountMessage msg(ri); - - if (msg.getIsAck()) - { - MessageToMessage const reply( - MessageToPayload(msg.getReplyToObject(), NetworkId::cms_invalid, msg.getReplyMessage(), msg.getPackedMessageData(), 0, false, MessageToPayload::DT_c,NetworkId::cms_invalid,std::string(), 0), - 0); - sendToAllGameServers (reply,true); - } - else - { - IGNORE_RETURN(sendToArbitraryLoginServer(msg)); - } - } - else if (message.isType("RandomNameRequest")) - { - GameServerConnection * gameServer = getRandomGameServer(); - if(gameServer) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RandomNameRequest crnr(ri); - gameServer->send(crnr, true); - } - } - else if (message.isType("RandomNameResponse")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RandomNameResponse crnr(ri); - ConnectionServerConnection * conn = getConnectionServerForAccount(crnr.getStationId()); - if (conn) - { - conn->send(crnr, true); - } - else - { - DEBUG_REPORT_LOG(true,("Could not send name to client because unable to determine which connection server to use.\n")); - } - } - else if (message.isType("VerifyAndLockNameRequest")) - { - GameServerConnection * gameServer = getRandomGameServer(); - if(gameServer) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - VerifyAndLockNameRequest valnr(ri); - gameServer->send(valnr, true); - } - } - else if (message.isType("VerifyAndLockNameResponse")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - VerifyAndLockNameResponse valnr(ri); - ConnectionServerConnection * conn = getConnectionServerForAccount(valnr.getStationId()); - if (conn) - { - conn->send(valnr, true); - } - else - { - DEBUG_REPORT_LOG(true,("Could not send name lock response to client because unable to determine which connection server to use.\n")); - } - } - else if (message.isType("RequestOIDsMessage")) - { - DEBUG_REPORT_LOG(true,("Got RequestOIDsMessage.\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RequestOIDsMessage m(ri); - - if (m.getLogRequest()) - LOG("ObjectIdManager", ("Requesting %lu more object ids for pid %lu", m.getHowMany(), m.getServerId())); - - sendToGameServer(m_dbProcessServerProcessId, m, true); - } - else if (message.isType("AddOIDBlockMessage")) - { - DEBUG_REPORT_LOG(true,("Got AddOIDBlockMessage.\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AddOIDBlockMessage m(ri); - - if (m.getLogRequest()) - LOG("ObjectIdManager", ("Returning object ids (%s - %s) for pid %lu", m.getStart().getValueString().c_str(), m.getEnd().getValueString().c_str(), m.getServerId())); - - sendToGameServer(m.getServerId(), m, true); - } - else if (message.isType("LoggedInMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoggedInMessage m (ri); - DEBUG_REPORT_LOG(true, ("Pending character %lu is logging in or dropping\n", m.getAccountNumber())); - - // Once they're logged in, Central doesn't need to know about them anymore: - removeFromAccountConnectionMap(m.getAccountNumber()); - } - - else if (message.isType("CharacterListMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - CharacterListMessage m(ri); - - // Find the client connection and send the character to it. - DEBUG_REPORT_LOG(true,("Got CharacterListMessage for %lu.\n",m.getAccountNumber())); - ConnectionServerConnection *conn = getConnectionServerForAccount(m.getAccountNumber()); - - if (conn) - { - conn->send(m, true); - } - else - { - DEBUG_REPORT_LOG(true,("Warning: received CharacterListMessage for client that is not connected.")); - } - } - else if (message.isType("ValidateCharacterForLoginMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ValidateCharacterForLoginMessage m(ri); - - // ask DBProcess to check whether the character is valid - //pendingCharactersLogin[m.getSuid()] = safe_cast(&source); - if (hasDBConnection()) - sendToDBProcess(m, true); - } - else if (message.isType("ValidateCharacterForLoginReplyMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ValidateCharacterForLoginReplyMessage msg(ri); - - ConnectionServerConnection *conn = getConnectionServerForAccount(msg.getSuid()); - if(conn) - conn->send(msg,true); - else - DEBUG_REPORT_LOG(true,("Trying to handle ValidateCharacterForLoginReplyMessage for account %lu, but could not determine which connection server to use.\n",msg.getSuid())); - } - else if (message.isType("EnableCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::string> > msg(ri); - - LOG("CustomerService", ("EnableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); - // forward this request to LoginServer - IGNORE_RETURN(sendToArbitraryLoginServer(msg)); - } - else if (message.isType("EnableCharacterReplyMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > msg(ri); - GenericValueTypeMessage > reply("DatabaseConsoleReplyMessage", std::make_pair(msg.getValue().first, msg.getValue().second)); - getRandomGameServer()->send(reply, true); - } - else if (message.isType("DisableCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::string> > msg(ri); - - LOG("CustomerService", ("DisableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); - // forward this request to LoginServer - IGNORE_RETURN(sendToArbitraryLoginServer(msg)); - } - else if (message.isType("DisableCharacterReplyMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > msg(ri); - GenericValueTypeMessage > reply("DatabaseConsoleReplyMessage", std::make_pair(msg.getValue().first, msg.getValue().second)); - getRandomGameServer()->send(reply, true); - } - else if(message.isType("TransferReplyLoginLocationData")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage reply(ri); - // If this request has a CS Tool Id associated with it, it is an admin request for the CSTool, - // and so we should send it directly to the connection server, and not depend on a - // transfer server existing. - - if(reply.getValue().getCSToolId() > 0) - { - GenericValueTypeMessage loginMessage("TransferLoginCharacterToSourceServer", reply.getValue()); - ConnectionServerConnection * conn = getAnyConnectionServer(); - if(conn) - { - conn->send(loginMessage, true); - } - return; - } - - LOG("CustomerService", ("CharacterTransfer: Received TransferReplyLoginLocationData from database for character %s\n", reply.getValue().getSourceCharacterName().c_str())); - - if(reply.getValue().getTransferRequestSource() == TransferRequestMoveValidation::TRS_transfer_server) - { - CentralServer::getInstance().sendToTransferServer(reply); - } - else - { - // send character to ConnectionServer for login to a game server - ConnectionServerConnection * connectionServer = CentralServer::getInstance().getAnyConnectionServer(); - if(connectionServer) - { - const GenericValueTypeMessage login("TransferLoginCharacterToSourceServer", reply.getValue()); - connectionServer->send(login, true); - - LOG("CustomerService", ("CharacterTransfer: Sending TransferLoginCharacterToSourceServer to ConnectionServer : %s", login.getValue().toString().c_str())); - } - } - } - else if (message.isType("CentralPlanetServerConnect")) - { - PlanetServerConnection *g = const_cast(safe_cast(&source)); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - CentralPlanetServerConnect msg(ri); - g->setGameServerConnectionData(msg.getConnectionAddress(), msg.getGameServerPort()); - PlanetManager::addServer(msg.getSceneId(), g); - - std::map, time_t> >::iterator f = m_pendingPlanetServers.find(msg.getSceneId()); - if(f != m_pendingPlanetServers.end()) - m_pendingPlanetServers.erase(f); - - IGNORE_RETURN(m_planetServers.insert(std::make_pair(msg.getSceneId(), g))); - - if (isPreloadFinished()) - m_timeClusterWentIntoLoadingState = 0; - else if (m_timeClusterWentIntoLoadingState <= 0) - m_timeClusterWentIntoLoadingState = time(0); - - // handle planet transfers and logins for planet server that aren't up yet - std::vector::iterator t; - for(t = m_messagesWaitingForPlanetServer.begin(); t != m_messagesWaitingForPlanetServer.end();) - { - Archive::ReadIterator tri = t->begin(); - const GameNetworkMessage gnm(tri); - tri = t->begin(); - if(gnm.isType("RequestGameServerForLoginMessage")) - { - const RequestGameServerForLoginMessage loginMessage(tri); - if (loginMessage.getScene() == msg.getSceneId()) - { - t = m_messagesWaitingForPlanetServer.erase(t); - handleRequestGameServerForLoginMessage(loginMessage); - } - } - else if(gnm.isType("RequestSceneTransfer")) - { - const RequestSceneTransfer sceneMessage(tri); - if (sceneMessage.getSceneName() == msg.getSceneId()) - { - t = m_messagesWaitingForPlanetServer.erase(t); - handleRequestSceneTransfer(sceneMessage); - } - } - else - { - t = m_messagesWaitingForPlanetServer.erase(t); - WARNING_STRICT_FATAL(true, ("Unknown message type waiting for planet server")); - } - } - } - else if (message.isType("RequestSceneTransfer")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const RequestSceneTransfer msg (ri); - - handleRequestSceneTransfer(msg); - } - else if (message.isType("SceneTransferMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - SceneTransferMessage msg (ri); - - sendToGameServer(msg.getSourceGameServer(), msg, true); - } - else if (message.isType("GameServerReadyMessage")) - { - GameServerConnection const *g = safe_cast(&source); - UniverseManager::getInstance().onGameServerReady(*g); - } - else if (message.isType("GameServerUniverseLoadedMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const GameServerUniverseLoadedMessage msg(ri); - - // forward to the universe game server as ack that - // the game server who sent this message has received - // its UniverseCompleteMessage from the universe game server - if (msg.getSourceOfUniverseDataProcessId() != getDbProcessServerProcessId()) - sendToGameServer(msg.getSourceOfUniverseDataProcessId(), msg, true); - - CharacterCreationTracker::getInstance().retryGameServerCreates(); - } - else if (message.isType("MessageToMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - MessageToMessage msg(ri); - - WARNING_STRICT_FATAL(true,("CentralServer receieved a messageTo. These should not go to Central anymore. Sender was server %u\n", safe_cast(&source)->getProcessId())); - } - else if (message.isType("MessageToAckMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - MessageToAckMessage msg(ri); - - WARNING_STRICT_FATAL(true,("CentralServer receieved a MessageToAckMessage. These should not go to Central anymore. Sender was server %u\n",safe_cast(&source)->getProcessId())); - } - else if(message.isType("ChatServerConnectionOpened")) - { - // enumerate servers - ChatServerConnection *chatServer = const_cast(safe_cast(&source)); - IGNORE_RETURN(m_chatServerConnections.insert(chatServer)); - const int ct = static_cast(EnumerateServers::CONNECTION_SERVER); - for (ConnectionServerConnectionList::const_iterator ci = m_connectionServerConnections.begin(); ci != m_connectionServerConnections.end(); ++ci) - { - ConnectionServerConnection * c = (*ci); - - if ( (c != NULL) - && !c->getChatServiceAddress().empty() - && (c->getChatServicePort() != 0)) - { - EnumerateServers e(true, c->getChatServiceAddress(), c->getChatServicePort(), ct); - chatServer->send(e, true); - } - else - { - LOG("ChatServer", ("receiveMessage() ChatServerConnectionOpened - Invalid connection address in m_connectionServerConnections, skipping entry")); - } - } - - // Tell the single chat server the address to communicate with the customer service server - - if (!s_customerServiceServerChatServerServiceAddress.first.empty()) - { - //DEBUG_REPORT_LOG(true, ("CentralServer::receiveMessage(ChatServerConnectionOpened)\n")); - - const GenericValueTypeMessage > msg("CustomerServiceServerChatServerServiceAddress", std::make_pair(s_customerServiceServerChatServerServiceAddress.first, s_customerServiceServerChatServerServiceAddress.second)); - - chatServer->send(msg, true); - } - } - else if (message.isType("CustomerServiceServerChatServerServiceAddress")) - { - //DEBUG_REPORT_LOG(true, ("CentralServer::receiveMessage(CustomerServiceServerChatServerServiceAddress)\n")); - - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const GenericValueTypeMessage > address(ri); - - s_customerServiceServerChatServerServiceAddress.first = address.getValue().first; - s_customerServiceServerChatServerServiceAddress.second = address.getValue().second; - - // Tell the chat servers the address to communicate with the customer service server - - std::set::iterator iterChatServerConnections = m_chatServerConnections.begin(); - - for (; iterChatServerConnections != m_chatServerConnections.end(); ++iterChatServerConnections) - { - ChatServerConnection *connection = (*iterChatServerConnections); - - if (connection != NULL) - { - connection->send(address, true); - } - else - { - REPORT_LOG(true, ("Trying to send the customer service server: chat server service address to a NULL chat server\n")); - } - } - } - else if (message.isType("CustomerServiceConnectionOpened")) - { - CustomerServiceConnection *csServer = const_cast(safe_cast(&source)); - IGNORE_RETURN(m_csServerConnections.insert(csServer)); - const int ct = static_cast(EnumerateServers::CONNECTION_SERVER); - for (ConnectionServerConnectionList::const_iterator ci = m_connectionServerConnections.begin(); ci != m_connectionServerConnections.end(); ++ci) - { - ConnectionServerConnection * c = (*ci); - - if ( (c != NULL) - && !c->getCustomerServiceAddress().empty() - && (c->getCustomerServicePort() != 0)) - { - EnumerateServers e(true, c->getCustomerServiceAddress(), c->getCustomerServicePort(), ct); - csServer->send(e, true); - } - else - { - LOG("CustServ", ("receiveMessage() CustomerServiceConnectionOpened - Invalid connection address in m_connectionServerConnections, skipping entry")); - } - } - } - else if(message.isType("ChatServerConnectionClosed")) - { - ChatServerConnection *chatServer = const_cast(safe_cast(&source)); - IGNORE_RETURN(m_chatServerConnections.erase(chatServer)); - - // spawn a new chat server! - std::string options = "-s ChatServer centralServerAddress="; - if(CentralServer::getInstance().getChatService()) - { - options += CentralServer::getInstance().getChatService()->getBindAddress(); - } - else - { - options += NetworkHandler::getHostName(); - } - - options += " clusterName="; - options += ConfigCentralServer::getClusterName(); - TaskSpawnProcess pc(ConfigCentralServer::getChatServerHost(), "ChatServer", options, ConfigCentralServer::getChatServerRestartDelayTimeSeconds()); - CentralServer::getInstance().sendTaskMessage(pc); - - } - else if (message.isType("CustomerServiceConnectionClosed")) - { - CustomerServiceConnection *csServer = const_cast(safe_cast(&source)); - IGNORE_RETURN(m_csServerConnections.erase(csServer)); - - // spawn a new cs server! - std::string options = "-s CustomerServiceServer centralServerAddress="; - if(CentralServer::getInstance().getCustomerService()) - { - options += CentralServer::getInstance().getCustomerService()->getBindAddress(); - } - else - { - options += NetworkHandler::getHostName(); - } - - options += " clusterName="; - options += ConfigCentralServer::getClusterName(); - TaskSpawnProcess pc("any", "CustomerServiceServer", options); - CentralServer::getInstance().sendTaskMessage(pc); - } - else if(message.isType("ChatServerOnline")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ChatServerOnline cso (ri); - ChatServerConnection *csc = const_cast(safe_cast(&source)); - csc->setGameServicePort(cso.getPort()); - SceneGameMap::const_iterator iter; - for(iter = m_gameServers.begin(); iter != m_gameServers.end(); ++iter) - { - GameServerConnection * conn = (*iter).second; - conn->send(cso, true); - } - - } - else if (message.isType("RequestGameServerForLoginMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const RequestGameServerForLoginMessage msg(ri); - - time_t const timeNow = ::time(NULL); - PlayerSceneMapType::const_iterator i = m_playerSceneMap.find(msg.getCharacterId()); - if ((i != m_playerSceneMap.end()) && (i->second.second > timeNow)) - { - ServerConnection * c = const_cast(safe_cast(&source)); - GenericValueTypeMessage > const loginDeniedRecentCTS("LoginDeniedRecentCTS", std::make_pair(msg.getCharacterId(), msg.getStationId())); - c->send(loginDeniedRecentCTS, true); - } - else - { - std::map >::const_iterator const iterFind = s_pendingRenameCharacter.find(msg.getCharacterId()); - if ((iterFind != s_pendingRenameCharacter.end()) && (iterFind->second.first > timeNow)) - { - ServerConnection * c = const_cast(safe_cast(&source)); - GenericValueTypeMessage > const loginDeniedPendingPlayerRenameRequest("LoginDeniedPendingPlayerRenameRequest", std::make_pair(msg.getCharacterId(), msg.getStationId())); - c->send(loginDeniedPendingPlayerRenameRequest, true); - } - else - { - handleRequestGameServerForLoginMessage(msg); - } - } - } - else if (message.isType("GameServerForLoginMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GameServerForLoginMessage msg(ri); - - handleGameServerForLoginMessage(msg); - } - - - - else if (message.isType("ExchangeListCreditsMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ExchangeListCreditsMessage msg(ri); - - handleExchangeListCreditsMessage(msg); - } - - - - else if (message.isType("PlanetLoadCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - PlanetLoadCharacterMessage msg(ri); - - // let all the game servers know we are about to load a character from the DB - GenericValueTypeMessage > const aboutToLoadCharacterFromDB("AboutToLoadCharacterFromDB", std::make_pair(msg.getCharacterId(), msg.getGameServerId())); - sendToAllGameServersExceptDBProcess(aboutToLoadCharacterFromDB, true); - - sendToDBProcess(msg,true); - } - else if (message.isType("ConnSrvDropDupeConns")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - // A ConnectionServer has received and validated a new connection from the client - - // request that all other ConnectionServers drop any existing connection(s) for the account - std::string galaxyConnectionInfo = "("; - galaxyConnectionInfo += ConfigCentralServer::getClusterName(); - - if (!msg.getValue().second.empty()) - { - galaxyConnectionInfo += ", "; - galaxyConnectionInfo += msg.getValue().second; - } - - galaxyConnectionInfo += ")"; - - GenericValueTypeMessage > const dropDuplicateConnections("CntrlSrvDropDupeConns", std::make_pair(msg.getValue().first, galaxyConnectionInfo)); - sendToAllConnectionServers(dropDuplicateConnections, true, dynamic_cast(&source)); - - // request (via LoginServer) that all ConnectionServers on all other galaxies drop any existing connection(s) for the account - if (ConfigCentralServer::getDisconnectDuplicateConnectionsOnOtherGalaxies()) - IGNORE_RETURN(sendToArbitraryLoginServer(dropDuplicateConnections)); - } - else if (message.isType("CntrlSrvDropDupeConns")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - // request that all ConnectionServers drop any existing connection(s) for the account - sendToAllConnectionServers(msg, true); - } - else if (message.isType("PlayerDroppedFromGameServerCrash")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const m(ri); - - std::set::const_iterator const end = m.getValue().end(); - for (std::set::const_iterator iter = m.getValue().begin(); iter != end; ++iter) - { - IGNORE_RETURN(m_playerSceneMap.erase(*iter)); - LOG("TRACE_LOGIN", ("Forgetting sceneId (because of game server crash) for character (%s) -- will query the database on next login", iter->getValueString().c_str())); - } - } - else if (message.isType("ServerDeleteCharacterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - LoginServerConnection const *l = safe_cast(&source); - ServerDeleteCharacterMessage msg(ri); - msg.setLoginServerId(l->getProcessId()); - - if (hasDBConnection()) - { - LOG("CustomerService", ("Player:deleted character %s for stationId %u", msg.getCharacterId().getValueString().c_str(), msg.getStationId())); - sendToDBProcess(msg,true); - - // let the game servers know that the character is being deleted - GenericValueTypeMessage const msg2("DeleteCharacterNotificationMessage", msg.getCharacterId()); - IGNORE_RETURN(sendToRandomGameServer(msg2)); - } - } - else if (message.isType("UpdatePlayerCountMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - UpdatePlayerCountMessage msg(ri); - - ConnectionServerConnection * csc = const_cast(dynamic_cast(&source)); - if (csc) - { - // Update our stored values for the connection server - csc->setPlayerCount(msg.getCount()); - csc->setFreeTrialCount(msg.getFreeTrialCount()); - csc->setEmptySceneCount(msg.getEmptySceneCount()); - csc->setTutorialSceneCount(msg.getTutorialSceneCount()); - csc->setFalconSceneCount(msg.getFalconSceneCount()); - - // Update the login server with the new values - UpdateLoginConnectionServerStatus ulc(csc->getId(), csc->getClientServicePortPublic(), csc->getClientServicePortPrivate(), msg.getCount()); - sendToAllLoginServers(ulc); - - // Update the login servers with new population values - sendPopulationUpdateToLoginServer(); - } - else - { - WARNING_STRICT_FATAL(true,("Got UpdatePlayerCountMessage from something that wasn't a ConnectionServer.\n")); - } - } - else if (message.isType("ValidateAccountMessage")) - { - DEBUG_REPORT_LOG(true,("ValidateAccountMessage\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ValidateAccountMessage msg(ri); - - // Store the connection information for the account - addToAccountConnectionMap(msg.getStationId(), const_cast(dynamic_cast(&source)), msg.getSubscriptionBits()); - - // Pass the validation to a LoginServer - IGNORE_RETURN(sendToArbitraryLoginServer(msg)); - } - else if (message.isType("ValidateAccountReplyMessage")) - { - DEBUG_REPORT_LOG(true,("ValidateAccountReplyMessage\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ValidateAccountReplyMessage msg(ri); - - ConnectionServerConnection *conn=getConnectionServerForAccount(msg.getStationId()); - if (conn) - { - conn->send(msg,true); - } - } - else if (message.isType("PreloadRequestCompleteMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - PreloadRequestCompleteMessage msg(ri); - - sendToDBProcess(msg,true); - } - else if (message.isType("ReconnectToTransferServer")) - { - if(ConfigCentralServer::getTransferServerPort()) - { - if(! getInstance().m_transferServerConnection) - { - getInstance().m_transferServerConnection = new TransferServerConnection(ConfigCentralServer::getTransferServerAddress(), ConfigCentralServer::getTransferServerPort()); - s_retryTransferServerConnection = true; - } - } - } - else if (message.isType("ReconnectToStationPlayersCollector")) - { - if(ConfigCentralServer::getStationPlayersCollectorPort()) - { - if(! getInstance().m_stationPlayersCollectorConnection) - { - getInstance().m_stationPlayersCollectorConnection = new StationPlayersCollectorConnection(ConfigCentralServer::getStationPlayersCollectorAddress(), ConfigCentralServer::getStationPlayersCollectorPort()); - s_retryStationPlayersCollectorConnection = true; - } - } - } - else if (message.isType("PreloadFinishedMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - PreloadFinishedMessage msg(ri); - - const PlanetServerConnection *conn=dynamic_cast(&source); - WARNING_STRICT_FATAL(!conn,("Programmer bug: got PreloadFinishedMessaage from something that wasn't a PlanetServer.\n")); - if (conn) - { - if (msg.getFinished()) - { - IGNORE_RETURN(m_planetsWaitingForPreload.erase(conn->getSceneId())); - if (isPreloadFinished()) - { - m_timeClusterWentIntoLoadingState = 0; - - DEBUG_REPORT_LOG(true,("Preload finished on all planets.\n")); - - // record how long it took the cluster to come up - if (m_clusterStartupTime == -1) - { - m_clusterStartupTime = static_cast(time(0) - m_timeClusterStarted) / 60; - - // let all the game servers know that the cluster has completed its initial startup - GenericValueTypeMessage clusterStartComplete("ClusterStartComplete", true); - sendToAllGameServersExceptDBProcess(clusterStartComplete, true); - } - else - { - // let all the game servers know that the cluster has recovered from a crash - GenericValueTypeMessage clusterStartComplete("ClusterStartComplete", false); - sendToAllGameServersExceptDBProcess(clusterStartComplete, true); - } - - sendToAllLoginServers(msg); - sendTaskMessage(msg); - m_lastLoadingStateTime=time(0); - // connect to the character transfer server - if(ConfigCentralServer::getTransferServerPort()) - { - if(! getInstance().m_transferServerConnection) - { - getInstance().m_transferServerConnection = new TransferServerConnection(ConfigCentralServer::getTransferServerAddress(), ConfigCentralServer::getTransferServerPort()); - s_retryTransferServerConnection = true; - } - } - - // connect to the station players collector - if(ConfigCentralServer::getStationPlayersCollectorPort()) - { - if(! getInstance().m_stationPlayersCollectorConnection) - { - getInstance().m_stationPlayersCollectorConnection = new StationPlayersCollectorConnection(ConfigCentralServer::getStationPlayersCollectorAddress(), ConfigCentralServer::getStationPlayersCollectorPort()); - s_retryStationPlayersCollectorConnection = true; - } - } - } - else if (m_timeClusterWentIntoLoadingState <= 0) - { - m_timeClusterWentIntoLoadingState = time(0); - } - } - else - { - if(getInstance().m_transferServerConnection != NULL) - { - getInstance().m_transferServerConnection->disconnect(); - getInstance().m_transferServerConnection = 0; - s_retryTransferServerConnection = false; - } - - if(getInstance().m_stationPlayersCollectorConnection != NULL) - { - getInstance().m_stationPlayersCollectorConnection->disconnect(); - getInstance().m_stationPlayersCollectorConnection = 0; - s_retryStationPlayersCollectorConnection = false; - } - - - IGNORE_RETURN(m_planetsWaitingForPreload.insert(conn->getSceneId())); - - if (isPreloadFinished()) - m_timeClusterWentIntoLoadingState = 0; - else if (m_timeClusterWentIntoLoadingState <= 0) - m_timeClusterWentIntoLoadingState = time(0); - - - sendToAllLoginServers(msg); - sendTaskMessage(msg); - } - } - } - else if (message.isType("RenameCharacterMessageEx")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RenameCharacterMessageEx msg(ri); - - IGNORE_RETURN(sendToArbitraryLoginServer(RenameCharacterMessage(msg.getCharacterId(), msg.getNewName(), msg.getRequestedBy()))); - - // if the player requested the rename, also rename the chat avatar, so mail, friends list, and ignore list will migrate - if ((msg.getRenameCharacterMessageSource() == RenameCharacterMessageEx::RCMS_player_request) && !msg.getLastNameChangeOnly() && !ConfigFile::getKeyBool("CharacterRename", "disableRenameChatAvatar", false)) - { - broadcastToChatServers(msg); - } - } - else if (message.isType("PlayerRenameRequestSubmitted")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > > const msg(ri); - - GenericValueTypeMessage kick("TransferKickConnectedClients", msg.getValue().first); - CentralServer::getInstance().sendToAllLoginServers(kick); - CentralServer::getInstance().sendToAllConnectionServers(kick, true); - - // update the list of pending rename requests, to prevent a character with a pending rename request from logging in - std::map >::iterator const iterFind = s_pendingRenameCharacter.find(msg.getValue().second.first); - if (iterFind != s_pendingRenameCharacter.end()) - { - ++(iterFind->second.second); - iterFind->second.first = ::time(NULL) + 3600; // 1 hour timeout - } - else - { - s_pendingRenameCharacter.insert(std::make_pair(msg.getValue().second.first, std::make_pair((::time(NULL) + 3600), 1))); // 1 hour timeout - } - - // tell the chat server to destroy any avatar with the new name, but only if the first name changed - if (!msg.getValue().second.second.second) - { - GenericValueTypeMessage const chatDestroyAvatar("ChatDestroyAvatar", msg.getValue().second.second.first); - broadcastToChatServers(chatDestroyAvatar); - } - } - else if (message.isType("PlayerRenameRequestCompleted")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - // update the list of pending rename requests, to prevent a character with a pending rename request from logging in - std::map >::iterator const iterFind = s_pendingRenameCharacter.find(msg.getValue().second); - if (iterFind != s_pendingRenameCharacter.end()) - { - if (iterFind->second.second <= 1) - s_pendingRenameCharacter.erase(iterFind); - else - --(iterFind->second.second); - } - } - else if(message.isType("SetConnectionServerPublic")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - SetConnectionServerPublic msg(ri); - if(msg.getIsPublic()) - gs_connectionServersPublic = true; - else - gs_connectionServersPublic = false; - - sendToAllConnectionServers(msg, true); - } - else if(message.isType("ProfilerOperationMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ProfilerOperationMessage msg(ri); - sendToAllGameServers(msg, true); - sendToAllPlanetServers(msg, true); - sendToAllConnectionServers(msg, true); - } - else if (message.isType("PopulationListMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - PopulationListMessage msg(ri); - sendToAllGameServers(msg, true); - } - else if (message.isType("CentralPingMessage")) - { - GameServerConnection const *g = safe_cast(&source); - NOT_NULL(g); - LOG("CentralServerPings",("Got reply from %lu",g->getProcessId())); - IGNORE_RETURN(m_serverPings.erase(g->getProcessId())); - } - else if (message.isType("DatabaseBackloggedMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage dbbacklog(ri); - - m_databaseBacklogged = dbbacklog.getValue(); - bool const preloadFinished = isPreloadFinished(); - - if (preloadFinished) - m_timeClusterWentIntoLoadingState = 0; - else if (m_timeClusterWentIntoLoadingState <= 0) - m_timeClusterWentIntoLoadingState = time(0); - - PreloadFinishedMessage msg(preloadFinished); - sendToAllLoginServers(msg); - sendTaskMessage(msg); - } - - else if (message.isType("DatabaseSaveStart")) - { - LOG("CentralServer",("Received DatabaseSaveStart network message.")); - if( m_shutdownPhase == 4 ) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Setting indicator for receipt of DatabaseSaveStart.", m_shutdownPhase)); - m_shutdownHaveDatabaseSaveStart = true; - checkShutdownProcess(); - } - else if( m_shutdownPhase == 5 && m_shutdownHaveDatabaseSaveStart) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Setting indicator that final database save cycle is complete.", m_shutdownPhase)); - m_shutdownHaveDatabaseComplete = true; - checkShutdownProcess(); - } - } - else if (message.isType("DatabaseSaveComplete")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - LOG("CentralServer",("Received DatabaseSaveComplete network message.")); - - // tell all the Planet Servers that the save finished - sendToAllPlanetServers(msg,true); - - // don't want to indicate this yet until we are at the beginning of a full cycle - if( m_shutdownPhase == 5 && m_shutdownHaveDatabaseSaveStart) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Setting indicator that final database save cycle is complete.", m_shutdownPhase)); - m_shutdownHaveDatabaseComplete = true; - checkShutdownProcess(); - } - } - else if (message.isType("PlanetRequestSave")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GameNetworkMessage msg(ri); - - sendToDBProcess(msg,true); - } - else if (message.isType("ShutdownCluster")) - { - LOG("CentralServerShutdown",("Received ShutdownCluster network message.")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ShutdownCluster m(ri); - startShutdownProcess(m.getTimeToShutdown(), m.getMaxTime(), m.getSystemMessage()); - } - else if (message.isType("AbortShutdown")) - { - LOG("CentralServerShutdown",("Received AbortShutdown network message.")); - abortShutdownProcess(); - } - - - else if (message.isType("SetSceneForPlayer")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > ssfp(ri); - - if (ssfp.getValue().second.first.empty()) - { - static const std::string loginTrace("TRACE_LOGIN"); - - IGNORE_RETURN(m_playerSceneMap.erase(ssfp.getValue().first)); - LOG(loginTrace, ("Forgetting sceneId for character (%s) -- will query the database on next login", ssfp.getValue().first.getValueString().c_str())); - } - else - { - PlayerSceneMapType::iterator i = m_playerSceneMap.find(ssfp.getValue().first); - if (i != m_playerSceneMap.end()) - { - i->second.first = ssfp.getValue().second.first; - if (ssfp.getValue().second.second) - i->second.second = ::time(NULL) + static_cast(ConfigCentralServer::getCtsDenyLoginThresholdSeconds()); - } - else - { - m_playerSceneMap[ssfp.getValue().first]=std::make_pair(ssfp.getValue().second.first, (ssfp.getValue().second.second ? (::time(NULL) + static_cast(ConfigCentralServer::getCtsDenyLoginThresholdSeconds())) : 0)); - } - } - } - - else if (message.isType("TaskProcessDiedMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - TaskProcessDiedMessage died(ri); - LOG("TaskProcessDied", ("received TaskProcessDied for %s:%i", died.getProcessName().c_str(), died.getProcessId()));; - if(died.getProcessName().find("SwgGameServer") != std::string::npos) - { - LOG("TaskProcessDied", ("Dead process %i is a game server", died.getProcessId())); - // extract sceneId - size_t pos = died.getProcessName().find("sceneID="); - if(pos != std::string::npos) - { - pos += std::string("sceneID=").length(); - size_t end = died.getProcessName().find_first_of(' ', pos); - if(end != std::string::npos) - { - std::string scene = died.getProcessName().substr(pos, end - pos); - LOG("TaskProcessDied", ("Dead game server process %i was running sceneID %s, advising planet server", died.getProcessId(), scene.c_str())); - std::map::iterator f = m_planetServers.find(scene); - if(f != m_planetServers.end()) - { - f->second->send(died, true); - } - } - } - } - } - else if (message.isType("SystemTimeMismatchNotification")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - - m_lastTimeSystemTimeMismatchNotification = time(0); - m_lastTimeSystemTimeMismatchNotificationDescription = msg.getValue(); - } - else if (message.isType("DisconnectedTaskManagerMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - - m_disconnectedTaskManagerList = msg.getValue(); - } - else if(message.isType("TransferServerConnectionClosed")) - { - // connect to the character transfer server - if(ConfigCentralServer::getTransferServerPort()) - { - if(s_retryTransferServerConnection) - { - getInstance().m_transferServerConnection = new TransferServerConnection(ConfigCentralServer::getTransferServerAddress(), ConfigCentralServer::getTransferServerPort()); - } - } - } - else if(message.isType("StationPlayersCollectorConnectionClosed")) - { - // connect to the station players collector - if(ConfigCentralServer::getStationPlayersCollectorPort()) - { - if(s_retryStationPlayersCollectorConnection) - { - getInstance().m_stationPlayersCollectorConnection = new StationPlayersCollectorConnection(ConfigCentralServer::getStationPlayersCollectorAddress(), ConfigCentralServer::getStationPlayersCollectorPort()); - } - } - } - else if(message.isType("ClaimRewardsMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ClaimRewardsMessage msg(ri); - sendToArbitraryLoginServer(msg); - } - else if(message.isType("ClaimRewardsReplyMessage")) - { - DEBUG_REPORT_LOG(true,("Central got ClaimRewardsReplyMessage\n")); - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ClaimRewardsReplyMessage msg(ri); - sendToGameServer(msg.getGameServer(), msg, true); - } - else if (message.isType("PurgeStructuresForAccountMessage") || message.isType("WarnStructuresAboutPurgeMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - LoginServerConnection const * l = dynamic_cast(&source); - if (l) - { - m_purgeAccountToLoginServerMap[msg.getValue()]= l->getProcessId(); // remember which login server is handling this purge - sendToDBProcess(msg, true); - } - } - else if (message.isType("PurgeCompleteMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - - std::map::iterator i=m_purgeAccountToLoginServerMap.find(msg.getValue()); - if (i!=m_purgeAccountToLoginServerMap.end()) - { - sendToLoginServer(i->second,msg); - m_purgeAccountToLoginServerMap.erase(i); - } - } - else if (message.isType("RestartServerMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RestartServerMessage msg(ri); - - sendToPlanetServer(msg.getScene(), msg, true); - } - else if (message.isType("RestartServerByRoleMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > msg(ri); - - sendToPlanetServer(msg.getValue().first, msg, true); - } - else if (message.isType("ExcommunicateGameServerMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ExcommunicateGameServerMessage msg(ri); - - excommunicateServer(msg); - } - else if (message.isType("RestartPlanetMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - - GenericValueTypeMessage const shutdownMsg("ShutdownMessage", 0); - sendToPlanetServer(msg.getValue(),shutdownMsg, true); - } - else if (message.isType("UpdateClusterLockedAndSecretState")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - gs_clusterIsLocked = msg.getValue().first; - gs_clusterIsSecret = msg.getValue().second; - } - else if (message.isType("PopStatRsp")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - m_timePopulationStatisticsRefresh = ::time(NULL); - m_populationStatistics = msg.getValue(); - } - else if (message.isType("GcwScoreStatRsp")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair >, std::map > > > > const msg(ri); - - m_timeGcwScoreStatisticsRefresh = ::time(NULL); - std::string const timeGcwScoreStatisticsRefreshStr = CalendarTime::convertEpochToTimeStringLocal(m_timeGcwScoreStatisticsRefresh); - - std::map const & gcwImperialScorePercentile = msg.getValue().first; - std::map > const & gcwImperialScore = msg.getValue().second.first; - std::map > const & gcwRebelScore = msg.getValue().second.second; - std::map >::const_iterator iterFind; - std::map::const_iterator iterFindImperialScorePercentile; - std::pair > >::iterator, bool> iterInsertion; - int imperialScorePercentile; - std::string scoreText, scoreTextDesc; - - for (std::map >::const_iterator iterImp = gcwImperialScore.begin(); iterImp != gcwImperialScore.end(); ++iterImp) - { - iterFindImperialScorePercentile = gcwImperialScorePercentile.find(iterImp->first); - if (iterFindImperialScorePercentile != gcwImperialScorePercentile.end()) - imperialScorePercentile = iterFindImperialScorePercentile->second; - else - imperialScorePercentile = 0; - - iterFind = gcwRebelScore.find(iterImp->first); - if (iterFind != gcwRebelScore.end()) - scoreText = FormattedString<1024>().sprintf("Imp (%s, %s) Reb (%s, %s) - ", NetworkId(iterImp->second.first).getValueString().c_str(), NetworkId(iterImp->second.second).getValueString().c_str(), NetworkId(iterFind->second.first).getValueString().c_str(), NetworkId(iterFind->second.second).getValueString().c_str()); - else - scoreText = FormattedString<1024>().sprintf("Imp (%s, %s) Reb (0, 0) - ", NetworkId(iterImp->second.first).getValueString().c_str(), NetworkId(iterImp->second.second).getValueString().c_str()); - - scoreTextDesc = scoreText + timeGcwScoreStatisticsRefreshStr; - - iterInsertion = m_gcwScoreStatistics.insert(std::make_pair("gcwScore." + iterImp->first, std::make_pair(imperialScorePercentile, std::make_pair(scoreText, scoreTextDesc)))); - if (!iterInsertion.second) - { - if (iterInsertion.first->second.second.first != scoreText) - { - iterInsertion.first->second.first = imperialScorePercentile; - iterInsertion.first->second.second.first = scoreText; - iterInsertion.first->second.second.second = scoreTextDesc; - } - } - } - - for (std::map >::const_iterator iterReb = gcwRebelScore.begin(); iterReb != gcwRebelScore.end(); ++iterReb) - { - iterFind = gcwImperialScore.find(iterReb->first); - if (iterFind == gcwImperialScore.end()) - { - iterFindImperialScorePercentile = gcwImperialScorePercentile.find(iterReb->first); - if (iterFindImperialScorePercentile != gcwImperialScorePercentile.end()) - imperialScorePercentile = iterFindImperialScorePercentile->second; - else - imperialScorePercentile = 0; - - scoreText = FormattedString<1024>().sprintf("Imp (0, 0) Reb (%s, %s) - ", NetworkId(iterReb->second.first).getValueString().c_str(), NetworkId(iterReb->second.second).getValueString().c_str()); - scoreTextDesc = scoreText + timeGcwScoreStatisticsRefreshStr; - - iterInsertion = m_gcwScoreStatistics.insert(std::make_pair("gcwScore." + iterReb->first, std::make_pair(imperialScorePercentile, std::make_pair(scoreText, scoreTextDesc)))); - if (!iterInsertion.second) - { - if (iterInsertion.first->second.second.first != scoreText) - { - iterInsertion.first->second.first = imperialScorePercentile; - iterInsertion.first->second.second.first = scoreText; - iterInsertion.first->second.second.second = scoreTextDesc; - } - } - } - } - } - else if (message.isType("LLTStatRsp")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage >, std::map > > > const msg(ri); - - m_timeLastLoginTimeStatisticsRefresh = ::time(NULL); - m_lastLoginTimeStatistics = msg.getValue().first; - m_createTimeStatistics = msg.getValue().second; - } - else if (message.isType("LfgStatRsp")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > const msg(ri); - - m_numberOfCharacterMatchRequests += msg.getValue().first; - m_numberOfCharacterMatchResults += msg.getValue().second.first; - m_timeSpentOnCharacterMatchRequestsMs += msg.getValue().second.second; - } - else if (message.isType("OccupyUnlockedSlotRsp")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, uint32> > const occupyUnlockedSlotRsp(ri); - - // CS log the response - LoginUpgradeAccountMessage::OccupyUnlockedSlotResponse const response = static_cast(occupyUnlockedSlotRsp.getValue().first.first); - if (response == LoginUpgradeAccountMessage::OUSR_success) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request SUCCESS", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::OUSR_db_error) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - internal db error", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unlocked_slot) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - account doesn't have an unlocked slot", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unoccupied_unlocked_slot) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - account has no unoccupied unlocked slot", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::OUSR_cluster_already_has_unlocked_slot_character) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - cluster already has an unlocked slot character", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else - { - LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - unknown result code (%d)", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), occupyUnlockedSlotRsp.getValue().first.first)); - } - - GameServerConnection * gs = getGameServer(occupyUnlockedSlotRsp.getValue().second); - if (!gs) - gs = getRandomGameServer(); - - if (gs) - gs->send(occupyUnlockedSlotRsp, true); - } - else if (message.isType("VacateUnlockedSlotRsp")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > const vacateUnlockedSlotRsp(ri); - - // CS log the response - LoginUpgradeAccountMessage::VacateUnlockedSlotResponse const response = static_cast(vacateUnlockedSlotRsp.getValue().first.first); - if (response == LoginUpgradeAccountMessage::VUSR_success) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request SUCCESS", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - - // to safeguard against any sort of timing exploit to create another normal - // slot character while this one is being converted to normal, thus allowing - // the account to have more normal slot characters on this cluster than is - // allowed, make it look like a normal character has been created on this - // account on this cluster, and that mechanism will prevent such an exploit - - // let all connection servers know that a new character has been created for the station account - GenericValueTypeMessage const ncc("NewCharacterCreated", static_cast(vacateUnlockedSlotRsp.getValue().second.first)); - CentralServer::getInstance().sendToAllConnectionServers(ncc, true); - } - else if (response == LoginUpgradeAccountMessage::VUSR_db_error) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - internal db error", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::VUSR_account_has_no_unlocked_slot) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - account doesn't have an unlocked slot", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::VUSR_not_unlocked_slot_character) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - character is not an unlocked slot character", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::VUSR_no_available_normal_character_slot) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - no available normal character slot for the account on this galaxy", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); - } - else - { - LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - unknown result code (%d)", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), vacateUnlockedSlotRsp.getValue().first.first)); - } - - GameServerConnection * gs = getGameServer(vacateUnlockedSlotRsp.getValue().second.second); - if (!gs) - gs = getRandomGameServer(); - - if (gs) - gs->send(vacateUnlockedSlotRsp, true); - } - else if (message.isType("SwapUnlockedSlotRsp")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > > const swapUnlockedSlotRsp(ri); - - // CS log the response - LoginUpgradeAccountMessage::SwapUnlockedSlotResponse const response = static_cast(swapUnlockedSlotRsp.getValue().first.first); - if (response == LoginUpgradeAccountMessage::SUSR_success) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s (%s) request SUCCESS", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.second.c_str())); - } - else if (response == LoginUpgradeAccountMessage::SUSR_db_error) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - internal db error", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::SUSR_account_has_no_unlocked_slot) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - account doesn't have an unlocked slot", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::SUSR_not_unlocked_slot_character) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - source character is not an unlocked slot character", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::SUSR_invalid_target_character) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - target character is either not valid, not on the same account, or not on this galaxy", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - } - else if (response == LoginUpgradeAccountMessage::SUSR_target_character_already_unlocked_slot_character) - { - LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - target character is already an unlocked slot character", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - } - else - { - LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - unknown result code (%d)", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().first.first)); - } - - GameServerConnection * gs = getGameServer(swapUnlockedSlotRsp.getValue().second.first); - if (!gs) - gs = getRandomGameServer(); - - if (gs) - gs->send(swapUnlockedSlotRsp, true); - } - else if (message.isType("AdjustAccountFeatureIdResponse")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AdjustAccountFeatureIdResponse const msg(ri); - - GameServerConnection * gs = getGameServer(msg.getGameServer()); - if (!gs) - gs = getRandomGameServer(); - - if (gs) - gs->send(msg, true); - } - else if (message.isType("AccountFeatureIdResponse")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AccountFeatureIdResponse const msg(ri); - - GameServerConnection * gs = getGameServer(msg.getGameServer()); - if (!gs) - gs = getRandomGameServer(); - - if (gs) - gs->send(msg, true); - } - else if (message.isType("FeatureIdTransactionResponse")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - FeatureIdTransactionResponse const msg(ri); - - GameServerConnection * gs = getGameServer(msg.getGameServer()); - if (!gs) - gs = getRandomGameServer(); - - if (gs) - gs->send(msg, true); - } - else if(ClusterWideDataManagerList::handleMessage(source, message)) - { - // nothing else to do with the message since it was - // handled by the Cluster wide data manager - } -} - -//----------------------------------------------------------------------- -void CentralServer::removeConnectionServerConnection(const ConnectionServerConnection * conn) -{ - DEBUG_REPORT_LOG(true, ("Removing connection server connection\n")); - if (conn) - { - startConnectionServer(conn->getConnectionServerNumber(), - conn->getGameServiceAddress(), - conn->getClientServicePortPublic(), - conn->getClientServicePortPrivate(), true, - ConfigCentralServer::getConnectionServerRestartDelayTimeSeconds()); - - ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); - for(;i != m_connectionServerConnections.end();++i) - { - if (conn->getId() == (*i)->getId()) - { - ConnectionServerDown c((*i)->getId()); - sendToAllLoginServers(c); - IGNORE_RETURN(m_connectionServerConnections.erase(i)); - return; - } - - } - - // Clean up all the account info for the connection - removeFromAccountConnectionMap(conn->getId()); - } -} -//----------------------------------------------------------------------- -/** -* Removes all references to a game server from the server. -* -* @param gameServer the game server connection to remove -*/ -void CentralServer::removeGameServer(GameServerConnection const *gameServer) -{ - uint32 const pid = gameServer->getProcessId(); - - LOG("ServerStartup", ("Game Server %lu went down", pid)); - - //@todo this whole function needs a re-write. - NOT_NULL(gameServer); - std::map::iterator const i = m_gameServerConnections.find(pid); - if (i == m_gameServerConnections.end()) - return; - - for (std::vector::iterator ii = m_gameServerConnectionsList.begin(); ii != m_gameServerConnectionsList.end();) - { - if ((*ii) == i->second) - ii = m_gameServerConnectionsList.erase(ii); - else - ++ii; - } - - m_gameServerConnections.erase(i); - - /** @todo: this is slow, find a better way (probably by creating reverse - * lookup table(s)) - */ - if (pid == m_dbProcessServerProcessId) - { - DEBUG_REPORT_LOG(true, ("Database process died -- Central will exit and let the cluster restart\n")); - m_done = true; - return; //lint !e527 Unreachable - } - - DEBUG_WARNING(true, ("Game server %lu crashed", pid)); - - for (SceneGameMap::iterator j = m_gameServers.begin(); j != m_gameServers.end();) - { - if ((*j).second == gameServer) - m_gameServers.erase(j++); - else - ++j; - } - - UniverseManager::getInstance().onGameServerDisconnect(*gameServer); - PlanetManager::onGameServerDisconnect(gameServer); - CharacterCreationTracker::getInstance().onGameServerDisconnect(pid); - ClusterWideDataManagerList::onGameServerDisconnect(pid); - - ExcommunicateGameServerMessage const excommunicateMessage(pid, 0, ""); - sendToAllGameServersExceptDBProcess(excommunicateMessage, true); -} - -//----------------------------------------------------------------------- - -void CentralServer::done() -{ - getInstance().m_done = true; -} - -//----------------------------------------------------------------------- - -void CentralServer::run(void) -{ - SetupSharedLog::install("CentralServer"); - SetupSharedUtility::Data utilityData; - SetupSharedUtility::install (utilityData); - SetupServerUtility::install(); - - gs_connectionServersPublic = ConfigCentralServer::getStartPublic(); - // listen for game server connect requests - static CentralServer & cserver = getInstance(); - - NetworkSetupData setup; - setup.maxConnections = 100; - setup.bindInterface = ConfigCentralServer::getGameServiceBindInterface(); - setup.port = ConfigCentralServer::getGameServicePort(); - Service * gs = new Service(ConnectionAllocator(), setup); - cserver.m_gameService = gs; - - // listen for planet server connection requests - setup.bindInterface = ConfigCentralServer::getPlanetServiceBindInterface(); - setup.port = ConfigCentralServer::getPlanetServicePort(); - Service * ps = new Service(ConnectionAllocator(), setup); - cserver.m_planetService = ps; - - setup.port = ConfigCentralServer::getChatServicePort(); - setup.maxConnections = 32; - setup.bindInterface = ConfigCentralServer::getChatServiceBindInterface(); - Service * cs = new Service(ConnectionAllocator(), setup); - cserver.m_chatService = cs; - - setup.port = ConfigCentralServer::getCustomerServicePort(); - setup.bindInterface = ConfigCentralServer::getCustomerServiceBindInterface(); - Service * css = new Service(ConnectionAllocator(), setup); - cserver.m_csService = css; - - setup.port = ConfigCentralServer::getConnectionServicePort(); - setup.bindInterface = ConfigCentralServer::getConnectionServiceBindInterface(); - Service * cons = new Service(ConnectionAllocator(), setup); - NOT_NULL(cons); - cserver.m_connService = cons; - - setup.port = ConfigCentralServer::getConsoleServicePort(); - setup.bindInterface = ConfigCentralServer::getConsoleServiceBindInterface(); - cserver.m_consoleService = new Service(ConnectionAllocator(), setup); - - setup.port = ConfigCentralServer::getCommodityServerServicePort(); - setup.bindInterface = ConfigCentralServer::getCommodityServerServiceBindInterface(); - s_commodityServerService = new Service(ConnectionAllocator(), setup); - - setup.port = ConfigCentralServer::getLoginServicePort(); - if (ConfigCentralServer::getDevelopmentMode()) - cserver.connectToLoginServer(); - else - { - setup.bindInterface = ConfigCentralServer::getLoginServiceBindInterface(); - cserver.m_loginService = new Service(ConnectionAllocator(), setup); - } - - // connect to the task manager - cserver.m_taskManager = new TaskConnection("127.0.0.1", ConfigCentralServer::getTaskManagerPort()); - - unsigned long startTime = Clock::timeMs(); - unsigned long nextLoadingLogTime=0; - unsigned long nextPingTime=0; - unsigned long nextPopulationLogTime = 0; - - LOG("ServerStartup",("CentralServer starting")); -#ifndef WIN32 - if( FileExists( ".shutdown") ) - { - LOG("CentralServer", ("Removing stale .shutdown file.")); - IGNORE_RETURN(::remove( ".shutdown" )); - } - if( FileExists( ".abortshutdown" ) ) - { - LOG("CentralServer", ("Removing stale .abortshutdown file.")); - IGNORE_RETURN(::remove( ".abortshutdown" )); - } - if( FileExists( ".startanymissingplanet") ) - { - LOG("CentralServer", ("Removing stale .startanymissingplanet file.")); - IGNORE_RETURN(::remove( ".startanymissingplanet" )); - } - if( FileExists( ".startanymissinggameserver") ) - { - LOG("CentralServer", ("Removing stale .startanymissinggameserver file.")); - IGNORE_RETURN(::remove( ".startanymissinggameserver" )); - } -#endif - - while (!cserver.m_done) - { - unsigned long lastFrameTime = 0; - unsigned long frameStartTime = Clock::timeMs(); - - PROFILER_AUTO_BLOCK_DEFINE("main loop"); - - bool barrierReached = true; - - do - { - PROFILER_AUTO_BLOCK_DEFINE("BarrierWait"); - - if (!Os::update()) - cserver.m_done = true; - - { - PROFILER_AUTO_BLOCK_DEFINE("NetworkHandler::update"); - NetworkHandler::update(); - } - - { - PROFILER_AUTO_BLOCK_DEFINE("MetricsManager::update"); - unsigned long curTime = Clock::timeMs(); - MetricsManager::update(static_cast(curTime - startTime)); - startTime = curTime; - } - - if (ConfigCentralServer::getShouldSleep()) - { - PROFILER_AUTO_BLOCK_DEFINE("Os::sleep"); - Os::sleep(1); - } - - } while (!barrierReached && !cserver.m_done); - - //@todo Central needs to run a clock so we can schedule re-tries with the login server. - { - PROFILER_AUTO_BLOCK_DEFINE("NetworkHandler::dispatch"); - NetworkHandler::dispatch(); - } - - { - PROFILER_AUTO_BLOCK_DEFINE("update"); - cserver.update(); - } - - NetworkHandler::clearBytesThisFrame(); - - { - //Peridically log loading status - unsigned long curTime = Clock::timeMs(); - if (curTime > nextLoadingLogTime) - { - nextLoadingLogTime = curTime + 10000; - std::string planets; - for (std::set::const_iterator i=getInstance().m_planetsWaitingForPreload.begin(); i!=getInstance().m_planetsWaitingForPreload.end(); ++i) - LOG("Preload",("Waiting for planet %s",i->c_str())); - } - - //Perodically ping all the servers - if (ConfigCentralServer::getServerPingTimeout() != 0 && static_cast(curTime-nextPingTime) > 0) - { - nextPingTime = curTime + static_cast(ConfigCentralServer::getServerPingTimeout() * 1000); - getInstance().doServerPings(); - } - - //Periodically write out population to a log every 5 minutes - if (curTime > nextPopulationLogTime) - { - nextPopulationLogTime = curTime + 300000; - LOG("PopulationLog", ("Current Population: %d", getInstance().getPlayerCount())); - } - } - - - - - ServerClock::getInstance().incrementServerFrame(); - if(ConfigCentralServer::getShutdown()) - { - cserver.done(); - } - - unsigned long currentTime = Clock::timeMs(); - lastFrameTime = currentTime - frameStartTime; - if(lastFrameTime > 1000) - { - LOG("profile", ("Long loop (%u ms):\n%s", lastFrameTime, PROFILER_GET_LAST_FRAME_DATA())); - } - } - - LOG("ServerStartup",("CentralServer exiting")); - - SetupSharedLog::remove(); - CentralServer::remove(); -} - -// ---------------------------------------------------------------------- -/** - * Called every frame to do any required updates. - */ -void CentralServer::update() -{ - static int loopCount=0; - m_curTime = static_cast(time(0)); - - // Tell the LoginServers if necessary - if ((++loopCount > ConfigCentralServer::getUpdatePlayerCountFrequency())) - { - loopCount=0; - - // Update the population on the server - sendPopulationUpdateToLoginServer(); - } - - - - if ( ConfigCentralServer::getAuctionEnabled() ) // allow auctions? - { - if ( m_pAuctionTransferClient == NULL ) - { - const char* hostName[1] = { ConfigCentralServer::getAuctionServer() }; - const short port[1] = { (short)ConfigCentralServer::getAuctionPort() }; - - std::string s_id = ConfigCentralServer::getAuctionIDPrefix(); - s_id += ConfigCentralServer::getClusterName(); - - const char *identifier[1]; - identifier[ 0 ] = s_id.c_str(); - - m_pAuctionTransferClient = new AuctionTransferClient( hostName, port, 1, identifier, 1 ); - } - m_pAuctionTransferClient->process(); - } - else if ( m_pAuctionTransferClient ) - { - delete( m_pAuctionTransferClient ); - m_pAuctionTransferClient = 0; - } - - - - // check every 5th frame (one second roughly?) - if( loopCount%5 ) - { - checkShutdownProcess(); - } - - // update cluster wide data manager - ClusterWideDataManagerList::update(Clock::frameTime()); -} - -// ---------------------------------------------------------------------- -void CentralServer::sendPopulationUpdateToLoginServer() -{ - // Add up all the population totals (these are referenced by the metrics data) - m_totalPlayerCount = 0; - m_totalFreeTrialCount = 0; - m_totalEmptySceneCount = 0; - m_totalTutorialSceneCount = 0; - m_totalFalconSceneCount = 0; - - ConnectionServerConnectionList::const_iterator i; - for (i=m_connectionServerConnections.begin(); i!=m_connectionServerConnections.end(); ++i) - { - if (*i) - { - m_totalPlayerCount += (**i).getPlayerCount(); - m_totalFreeTrialCount += (**i).getFreeTrialCount(); - m_totalEmptySceneCount += (**i).getEmptySceneCount(); - m_totalTutorialSceneCount += (**i).getTutorialSceneCount(); - m_totalFalconSceneCount += (**i).getFalconSceneCount(); - } - } - - bool loadedRecently=false; - if (!isPreloadFinished() || (time(0)-m_lastLoadingStateTime < static_cast(ConfigCentralServer::getRecentLoadingStateSeconds()))) - loadedRecently=true; - - UpdatePlayerCountMessage upm(loadedRecently, m_totalPlayerCount, m_totalFreeTrialCount, m_totalEmptySceneCount, m_totalTutorialSceneCount, m_totalFalconSceneCount); - sendToAllLoginServers(upm); -} - -//----------------------------------------------------------------------- - -void CentralServer::sendTaskMessage(const GameNetworkMessage & source) -{ - if(m_taskManager) - m_taskManager->send(source, true); - DEBUG_REPORT_LOG(!m_taskManager, ("There is no task manager connection, but app is attempting to send to one\n")); -} - -//----------------------------------------------------------------------- - -void CentralServer::sendToGameServer(const uint32 gameServerProcessId, const GameNetworkMessage & message, const bool reliable) const -{ - GameServerConnection * g = getGameServer(gameServerProcessId); - if(g) - { - g->send(message, reliable); - } - else - { - DEBUG_WARNING(true,("Attempted to send to game server %i, without connection.\n",gameServerProcessId)); - } -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToLoginServer(uint32 loginServerId, const GameNetworkMessage &message) -{ - LoginServerConnectionMapType::iterator i=m_loginServerConnectionMap.find(loginServerId); - if (i!=m_loginServerConnectionMap.end() && i->second) - i->second->send(message,true); -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToAllGameServers(const GameNetworkMessage & message, const bool reliable) -{ - for (std::map::const_iterator i = m_gameServerConnections.begin(); i!=m_gameServerConnections.end(); ++i) - { - (*i).second->send(message, reliable); - } -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToAllGameServersExceptDBProcess(const GameNetworkMessage & message, const bool reliable) -{ - for (std::map::const_iterator i = m_gameServerConnections.begin(); i!=m_gameServerConnections.end(); ++i) - { - if ((*i).first != getDbProcessServerProcessId()) - (*i).second->send(message, reliable); - } -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToAllPlanetServers(const GameNetworkMessage & message, const bool reliable) -{ - for (std::map::const_iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) - (*i).second->send(message, reliable); -} - -// ---------------------------------------------------------------------- - -bool CentralServer::hasPlanetServer(const std::string & sceneName) const -{ - for (std::map::const_iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) - if (i->second->getSceneId() == sceneName) - return true; - return false; -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToPlanetServer(const std::string &sceneId, const GameNetworkMessage & message, const bool reliable) -{ - for (std::map::const_iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) - if (i->second->getSceneId() == sceneId) - (*i).second->send(message, reliable); -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToAllConnectionServers(const GameNetworkMessage & message, const bool reliable, Connection const * exclude /*= NULL*/) -{ - // send to all connection servers - for (ConnectionServerConnectionList::const_iterator i = m_connectionServerConnections.begin(); i != m_connectionServerConnections.end(); ++i) - { - if ((*i) && (*i != exclude)) - (*i)->send(message, reliable); - } -} - -//----------------------------------------------------------------------- - -void CentralServer::sendToDBProcess(const GameNetworkMessage & message, const bool reliable) const -{ - GameServerConnection * g = getGameServer(getDbProcessServerProcessId()); - if(g) - { - g->send(message, reliable); - } - else - { - DEBUG_FATAL(!m_done,("Attempted to send message to DBProcess without connection (there should always be a connection to DBProcess).")); - } -} - -// ---------------------------------------------------------------------- - -bool CentralServer::hasDBConnection() const -{ - const GameServerConnection * g = getGameServer(getDbProcessServerProcessId()); - return (g != NULL); -} - -//----------------------------------------------------------------------- - -void CentralServer::setTaskManager(TaskConnection * newTaskManager) -{ - if (m_taskManager && newTaskManager != m_taskManager) - { - m_taskManager->setDisconnectReason("CentralServer::setTaskManager called"); - m_taskManager->disconnect(); - } - m_taskManager = newTaskManager; -} - -// ---------------------------------------------------------------------- - -void CentralServer::removePlanetServer(const PlanetServerConnection * p) -{ - for (std::map::iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) - { - if ((*i).second == p) - { - DEBUG_REPORT_LOG(true,("Central lost connection to Planet Server %s\n",p->getSceneId().c_str())); - m_planetServers.erase(i); - - if (isPreloadFinished()) - m_timeClusterWentIntoLoadingState = 0; - else if (m_timeClusterWentIntoLoadingState <= 0) - m_timeClusterWentIntoLoadingState = time(0); - - return; - } - } -} - -// ---------------------------------------------------------------------- - -const std::string & CentralServer::getCommandLine() const -{ - return m_commandLine; -} - -//----------------------------------------------------------------------- - -void CentralServer::setCommandLine(const std::string & c) -{ - m_commandLine = c; -} - -//----------------------------------------------------------------------- - -const bool getStartLocation(const std::string & name, std::string & planetName, Vector & coordinates, NetworkId & cellId) -{ - const StartingLocationData * const sld = StartingLocationManager::findLocationByName (name); - if (sld) - { - planetName = sld->planet; - coordinates.x = sld->x; - coordinates.y = sld->y; - coordinates.z = sld->z; - cellId = NetworkId (sld->cellId); - return true; - } - - REPORT_LOG(true, ("The start location \"%s\" could not be found in StartingLocationManager", name.c_str())); - return false; -} - -//----------------------------------------------------------------------- - -void CentralServer::startPlanetServer(const std::string & host, const std::string & sceneId, const SpawnDelaySeconds spawnDelay) -{ - FATAL(sceneId.empty(), ("CentralServer::startPlanetServer: empty sceneId, host='%s'", host.c_str())); - std::map, time_t> >::const_iterator f = m_pendingPlanetServers.find(sceneId); - if(f == m_pendingPlanetServers.end()) - { - std::map::const_iterator pf = m_planetServers.find(sceneId); - if(pf == m_planetServers.end()) - { - std::string options = "-s PlanetServer centralServerAddress="; - if(m_planetService) - { - options += m_planetService->getBindAddress(); - } - else - { - options += NetworkHandler::getHostName(); - } - options += " sceneID="; - options += sceneId; - - char buffer[20]; - IGNORE_RETURN(_itoa(m_nextPlanetWatcherPort++,buffer,10)); - options += " watcherServicePort="; - options += buffer; - - static unsigned int portBase = 0; - IGNORE_RETURN(_itoa(portBase,buffer,10)); - portBase += 100; - options += " gameServerDebuggingPortBase="; - options += buffer; - - TaskSpawnProcess spawn(host.empty() ? std::string("any") : host, "PlanetServer", options, spawnDelay); - CentralServer::getInstance().sendTaskMessage(spawn); - m_pendingPlanetServers[sceneId] = std::make_pair(std::make_pair(host, options), ::time(NULL)); - IGNORE_RETURN(m_planetsWaitingForPreload.insert(sceneId)); - - bool const preloadFinished = isPreloadFinished(); - if (preloadFinished) - m_timeClusterWentIntoLoadingState = 0; - else if (m_timeClusterWentIntoLoadingState <= 0) - m_timeClusterWentIntoLoadingState = time(0); - - if(getInstance().m_transferServerConnection != NULL && !preloadFinished) - { - getInstance().m_transferServerConnection->disconnect(); - getInstance().m_transferServerConnection = 0; - s_retryTransferServerConnection = false; - } - - if(getInstance().m_stationPlayersCollectorConnection != NULL && ! isPreloadFinished()) - { - getInstance().m_stationPlayersCollectorConnection->disconnect(); - getInstance().m_stationPlayersCollectorConnection = 0; - s_retryStationPlayersCollectorConnection = false; - } - - PreloadFinishedMessage msg(preloadFinished); - sendToAllLoginServers(msg); - } - } -} - -//----------------------------------------------------------------------- -/** -* Forward the RequestGameServerForLoginMessage to the appropriate PlanetServer -*/ -void CentralServer::handleRequestGameServerForLoginMessage(const RequestGameServerForLoginMessage & msg) -{ - static const std::string loginTrace("TRACE_LOGIN"); - - std::string effectiveScene; - PlayerSceneMapType::iterator i=m_playerSceneMap.find(msg.getCharacterId()); - if (i!=m_playerSceneMap.end()) - { - effectiveScene=i->second.first; - LOG(loginTrace, ("using sceneId (%s) from memory for character (%s)", effectiveScene.c_str(), msg.getCharacterId().getValueString().c_str())); - } - else - effectiveScene=msg.getScene(); // only use the DB scene if we don't have more recent information - - // for CTS, the source character must currently be on one of the 10 original ground planets - if (msg.getForCtsSourceCharacter()) - { - static std::set s_tenOriginalGroundPlanets; - if (s_tenOriginalGroundPlanets.empty()) - { - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("tatooine")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("naboo")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("corellia")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("rori")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("talus")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("yavin4")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("endor")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("lok")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("dantooine")); - IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("dathomir")); - } - - if (s_tenOriginalGroundPlanets.count(effectiveScene) <= 0) - { - // fail CTS because source character is not on one of the 10 original ground planets - LOG("CustomerService", ("CharacterTransfer: RequestGameServerForLoginMessage failed for source character (%s) stationId (%lu) because effective scene for the character (%s) is not one of the 10 original ground planets", msg.getCharacterId().getValueString().c_str(), msg.getStationId(), effectiveScene.c_str())); - - GenericValueTypeMessage > const failureMsg("CtsSrcCharWrongPlanet", std::make_pair(msg.getCharacterId(), msg.getStationId())); - IGNORE_RETURN(ConnectionServerConnection::sendToPseudoClientConnection(msg.getStationId(), failureMsg)); - - return; - } - } - - PlanetServerConnection *conn = PlanetManager::getPlanetServerForScene(effectiveScene); - if (conn) - { - LOG(loginTrace, ("handling RequestGameServerForLoginMessage(%s)", msg.getCharacterId().getValueString().c_str())); - conn->send(msg,true); - } - else - { - bool isPlanetValid = false; - bool allowDynamicStart = ConfigFile::getKeyBool("CentralServer", "startPlanetsDynamically", false); - - std::map::const_iterator f = ms_sceneToHostMap.find(msg.getScene()); - if(f != ms_sceneToHostMap.end()) - { - isPlanetValid = true; - } - - if(isPlanetValid || allowDynamicStart) - { - LOG(loginTrace, ("deferring RequestGameServerForLoginMessage(%s)", msg.getCharacterId().getValueString().c_str())); - DEBUG_REPORT_LOG(true, ("Starting planet server for login")); - startPlanetServer(getHostForScene(msg.getScene()), msg.getScene(), 0); - m_messagesWaitingForPlanetServer.push_back(Archive::ByteStream()); - msg.pack(m_messagesWaitingForPlanetServer.back()); - } - else - { - WARNING_STRICT_FATAL(true, ("Central received a request to start a planet (name=\"%s\") that is not in the startPlanet= list in the CentralServer config file.", msg.getScene().c_str())); - } - } -} - -// ---------------------------------------------------------------------- - -void CentralServer::handleRequestSceneTransfer(const RequestSceneTransfer &msg) -{ - PlanetServerConnection *conn = PlanetManager::getPlanetServerForScene(msg.getSceneName()); - if (conn) - { - conn->send(msg,true); - } - else - { - DEBUG_REPORT_LOG(true, ("Starting planet server for login")); - startPlanetServer(getHostForScene(msg.getSceneName()), msg.getSceneName(), 0); - m_messagesWaitingForPlanetServer.push_back(Archive::ByteStream()); - msg.pack(m_messagesWaitingForPlanetServer.back()); - } -} - -// ---------------------------------------------------------------------- - -/** -* Forward the GameServerForLoginMessage to the appropriate ConnectionServer -*/ -void CentralServer::handleGameServerForLoginMessage(const GameServerForLoginMessage &msg) -{ - ConnectionServerConnection *conn = getConnectionServerForAccount(msg.getStationId()); - if (conn) - { - conn->send(msg,true); - } - else - { - if(! ConnectionServerConnection::sendToPseudoClientConnection(msg.getStationId(), msg)) - { - LOG("TRACE_LOGIN", ("Trying to log account %i in, but could not determine which connection server to use.",msg.getStationId())); - } - } -} - -// ---------------------------------------------------------------------- - -void CentralServer::handleExchangeListCreditsMessage(const ExchangeListCreditsMessage &msg) -{ - LOG("Exchange", ("Central Server got exchange list credits %d.",msg.getCredits())); - if ( m_pAuctionTransferClient == NULL ) - { - // send failure packet - } - //////////////////////m_pAuctionTransferClient->addCoinToAuction( msg ); -} - - - - - -ConnectionServerConnection * CentralServer::getAnyConnectionServer() -{ - ConnectionServerConnection * result = 0; - if(! m_connectionServerConnections.empty()) - { - result = *(m_connectionServerConnections.begin()); - if(result) - { - int leastPlayers = result->getPlayerCount(); - - std::vector::iterator i; - for(i = m_connectionServerConnections.begin(); i != m_connectionServerConnections.end(); ++i) - { - if((*i)->getPlayerCount() < leastPlayers) - result = *i; - } - } - } - return result; -} - -// ---------------------------------------------------------------------- - -ConnectionServerConnection * CentralServer::getConnectionServerForAccount(StationId suid) -{ - ConnectionServerConnection * result = NULL; - ConnectionServerSUIDMap::iterator i=m_accountConnectionMap.find(suid); - if (i!=m_accountConnectionMap.end()) - { - result = (*i).second; - } - else - { - result = ConnectionServerConnection::getConnectionForAccount(suid); - } - - return result; -} - -// ---------------------------------------------------------------------- - -void CentralServer::addToAccountConnectionMap(StationId suid, ConnectionServerConnection * cconn, uint32 subscriptionBits) -{ - m_accountConnectionMap[suid] = cconn; - - // remove corresponding "pseudo client connection" - ConnectionServerConnection::removeFromAccountConnectionMap(suid); -} - -// ---------------------------------------------------------------------- - -void CentralServer::removeFromAccountConnectionMap(StationId suid) -{ - ConnectionServerSUIDMap::iterator i=m_accountConnectionMap.find(suid); - if (i!=m_accountConnectionMap.end()) - { - // Erase the entry - m_accountConnectionMap.erase(i++); - } -} - -// ---------------------------------------------------------------------- - -void CentralServer::removeFromAccountConnectionMap(int connectionServerConnectionId) -{ - ConnectionServerSUIDMap::iterator i; - for(i = m_accountConnectionMap.begin(); i != m_accountConnectionMap.end();) - { - const ConnectionServerConnection* cconn = (*i).second; - - if(cconn && (cconn->getId() == connectionServerConnectionId)) - { - // Erase the entry - m_accountConnectionMap.erase(i++); - } - else - { - ++i; - } - } - - // We could update the LoginServer population but people - // leaving the server are not as important as people connecting - // and so we will wait for update() to handle things -} - -//-------------------------------------------------------------------------------- - -const Service * CentralServer::getChatService() const -{ - return m_chatService; -} - -//-------------------------------------------------------------------------------- - -const Service * CentralServer::getCustomerService() const -{ - return m_csService; -} - -//-------------------------------------------------------------------------------- - -const Service * CentralServer::getGameService() const -{ - return m_gameService; -} - -//-------------------------------------------------------------------------------- - -void CentralServer::startConnectionServer(int connectionServerNumber, const std::string& listenAddress, uint16 publicPort, uint16 internalPort, bool, const SpawnDelaySeconds spawnDelay) const -{ - char tmp1[32]; - char tmp2[32]; - std::string publicString = _itoa(publicPort, tmp1, 10); - std::string privateString = _itoa(internalPort, tmp2, 10); - startConnectionServer(connectionServerNumber, listenAddress, &publicString, &privateString, spawnDelay); -} - -//-------------------------------------------------------------------------------- - -void CentralServer::startConnectionServer(int connectionServerNumber, const std::string& listenAddress, const std::string * publicPort, const std::string * internalPort, const SpawnDelaySeconds spawnDelay) const -{ - UNREF(listenAddress); //once we add dual nic support, we can use this - if(!m_connService) - { - DEBUG_WARNING(true, ("Could not start connection server because there was no service for it")); - return; - } - - if (!ConfigCentralServer::getAllowZeroConnectionServerPort()) - { - if (!publicPort) - { - WARNING(true, ("Could not start connection server because there were not client ports specified")); - return; - } - if (*publicPort == "0") - { - WARNING(true, ("Could not start connection server because one or more client ports were 0.")); - return; - } - } - - // there should already be an entry in s_connectionServerHostList that - // contains the node on which to start this particular connection server - if ((connectionServerNumber <= 0) || (connectionServerNumber > static_cast(s_connectionServerHostList.size()))) - { - WARNING(true, ("Could not start connection server because connectionServerNumber=%d and s_connectionServerHostList.size()=%d", connectionServerNumber, static_cast(s_connectionServerHostList.size()))); - return; - } - - // spawn a connection server - std::string options = "-s ConnectionServer clusterName="; - options += ConfigCentralServer::getClusterName(); - - if(gs_connectionServersPublic) - options += " startPublicServer=true"; - - options += " centralServerAddress="; - options += m_connService->getBindAddress(); - - char servicePort[32]; - - options += " centralServerPort="; - options += _itoa(m_connService->getBindPort(), servicePort, 10); - - if (publicPort != 0) - { - options += " clientServicePortPublic="; - options += *publicPort; - } - if (internalPort != 0) - { - options += " clientServicePortPrivate="; - options += *internalPort; - } - - options += " connectionServerNumber="; - options += _itoa(connectionServerNumber, servicePort, 10); - - DEBUG_REPORT_LOG(true, ("Spawning Connection server with options %s\n", options.c_str())); - TaskSpawnProcess p(s_connectionServerHostList[connectionServerNumber-1], "ConnectionServer", options, spawnDelay); - CentralServer::getInstance().sendTaskMessage(p); -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToAllLoginServers(const GameNetworkMessage &message) -{ - for (LoginServerConnectionMapType::iterator i=m_loginServerConnectionMap.begin(); i!=m_loginServerConnectionMap.end(); ++i) - i->second->send(message,true); -} - -// ---------------------------------------------------------------------- - -uint32 CentralServer::sendToArbitraryLoginServer(const GameNetworkMessage &message, bool roundRobin /*= true*/) -{ - static unsigned int nextServer = 0; - - if (m_loginServerConnectionMap.empty()) - return 0; - - LoginServerConnectionMapType::const_iterator i = m_loginServerConnectionMap.begin(); - - if (!roundRobin) - { - i->second->send(message,true); - return i->second->getProcessId(); - } - - ++nextServer; - if (nextServer >= m_loginServerConnectionMap.size()) - nextServer = 0; - - std::advance(i, nextServer); - - i->second->send(message,true); - return i->second->getProcessId(); -} - -// ---------------------------------------------------------------------- - -/** - * In development mode, connect to a login server. - */ -void CentralServer::connectToLoginServer() const -{ - IGNORE_RETURN(new LoginServerConnection(ConfigCentralServer::getLoginServerAddress(), ConfigCentralServer::getLoginServerPort())); -} - -//----------------------------------------------------------------------- - -void CentralServer::remove() -{ - CentralServer & cs = getInstance(); - MetricsManager::remove(); - delete cs.m_metricsData; - cs.m_metricsData = 0; - - delete cs.m_loginServerKeys; - - cs.m_messagesWaitingForPlanetServer.clear(); - cs.m_gameServerConnections.clear(); - cs.m_gameServerConnectionsList.clear(); - cs.m_connectionServerConnections.clear(); - - delete cs.m_gameService; - delete cs.m_chatService; - delete cs.m_csService; - delete cs.m_connService; - delete cs.m_planetService; - delete cs.m_loginService; - if(cs.m_taskManager) - { - cs.m_taskManager->setDisconnectReason("CentralServer::remove"); - cs.m_taskManager->disconnect(); - } - delete cs.m_taskService; - delete cs.m_consoleService; -} - -//----------------------------------------------------------------------- - -std::vector CentralServer::getGameServers() const -{ - std::vector result; - std::map::const_iterator i; - for(i = m_gameServerConnections.begin(); i != m_gameServerConnections.end(); ++i) - { - result.push_back((*i).second); - } - return result; -} - -// ---------------------------------------------------------------------- - -void CentralServer::sendToConnectionServerForAccount(StationId account, const GameNetworkMessage & message, const bool reliable) -{ - ConnectionServerConnection *conn = getConnectionServerForAccount(account); - if (conn) - conn->send(message,reliable); -} - -// ---------------------------------------------------------------------- - -uint32 CentralServer::sendToRandomGameServer(const GameNetworkMessage &message) -{ - GameServerConnection *conn = getRandomGameServer(); - if (conn) - { - conn->send(message,true); - return conn->getProcessId(); - } - else - return 0; -} - -// ---------------------------------------------------------------------- - -void CentralServer::doServerPings() -{ - for (std::set::iterator i=m_serverPings.begin(); i!=m_serverPings.end(); ++i) - { - LOG("CentralServerPings",("Dropping server %lu because it hasn't responded to CentralPingMessage",*i)); - GameServerConnection *conn=getGameServer(*i); - if (conn) - { - // tell task manager to kill the offending process (in case it's hung) - ExcommunicateGameServerMessage msg(*i, conn->getOsProcessId(), conn->getRemoteAddress()); - // disconnect, if it's not hung, it should die - conn->setDisconnectReason("CentralServer::doServerPings, failure to respond to CentralPingMessage"); - conn->disconnect(); - sendTaskMessage(msg); - excommunicateServer(msg); - } - else - { - LOG("CentralServerPings",("Didn't have connection to %lu to drop",*i)); - ExcommunicateGameServerMessage const excommunicateMessage(*i, 0, ""); - excommunicateServer(excommunicateMessage); // haven't received a reply (see CentralPingMessage, above) - } - } - m_serverPings.clear(); - - CentralPingMessage ping; - for (std::map::iterator j=m_gameServerConnections.begin(); j!=m_gameServerConnections.end(); ++j) - { - if (j->first != getDbProcessServerProcessId()) - { - LOG("CentralServerPings",("Pinging %lu",j->first)); - IGNORE_RETURN(m_serverPings.insert(j->first)); - j->second->send(ping,true); - } - } -} - -// ---------------------------------------------------------------------- - -/** - * Declare a game server anathema. All other servers will shun this server. - */ -void CentralServer::excommunicateServer(const ExcommunicateGameServerMessage & msg) -{ - sendToAllGameServers(msg,true); - sendToAllPlanetServers(msg,true); - sendToAllConnectionServers(msg,true); -} - -//----------------------------------------------------------------------- -void CentralServer::startShutdownProcess(const uint32 timeToShutdown, const uint32 maxTime, const Unicode::String &systemMessage) -{ - // sanity checking - if ( m_shutdownPhase > 6) - { - WARNING("CentralServerShutdown", ("startShutdownProcess: invalid value in CentralServer::m_shutdownPhase. Current value is %d. Resetting.", m_shutdownPhase)); - m_shutdownPhase = 0; - } - - // server already in the process of shutting down - if ( m_shutdownPhase > 0 ) - { - LOG("CentralServerShutdown", ("startShutdownProcess: Server already in the process of shutting down. Current shutdown phase is %d.", m_shutdownPhase)); - return; - } - - if( timeToShutdown>maxTime ) - { - LOG("CentralServerShutdown", ("startShutdownProcess: time to shutdown is greater than max time.")); - return; - } - m_shutdownPhase = 1; - LOG("CentralServerShutdown",("Shutdown Phase %d: Shutdown sequence starting now.", m_shutdownPhase)); - LOG("CentralServerShutdown",("Shutdown Phase %d: time to shutdown=%dsec, max time to wait=%dsec, broadcast warning message=\"%s\".", m_shutdownPhase, timeToShutdown, maxTime, Unicode::wideToNarrow(systemMessage).c_str())); - // this is the time in the future that we need to start the shutdown process. - m_shutdownTotalTime = m_curTime + timeToShutdown; - m_shutdownMaxTime = m_curTime + maxTime; - m_shutdownSystemMessage = systemMessage; - m_shutdownHaveDatabaseSaveStart = false; - m_shutdownHaveDatabaseComplete = false; - checkShutdownProcess(); -} -//------------------------------------------------------------------------ -void CentralServer::checkShutdownProcess() -{ - static bool warn30 = false; - static bool warn10 = false; - static bool warn0 = false; - static uint32 lastWarn = m_curTime; - static uint32 nextAbortCheck = m_curTime+1; - static uint32 nextShutdownCheck = m_curTime+30; - - if( !m_shutdownPhase ) - { -#ifndef WIN32 - // check if a .shutdown file exists - if( m_curTime > nextShutdownCheck ) - { - nextShutdownCheck = m_curTime + 30; - if( FileExists(".shutdown") ) - { - StdioFile shutdownFile(".shutdown", "r"); - if(shutdownFile.isOpen()) - { - char destBuffer[64] = {"\0"}; - if(shutdownFile.read(destBuffer, sizeof(destBuffer)) > 0) - { - destBuffer[sizeof(destBuffer) - 1] = 0; - int shutdownTime = atoi(destBuffer); - if(shutdownTime > 0) - { - LOG("CentralServerShutdown", ("Detected a .shutdown file. Initiating shutdown sequence.")); - startShutdownProcess(shutdownTime, 7200, Unicode::narrowToWide("The server will be shutting down soon. Please find a safe place to logout.")); - } - } - shutdownFile.close(); - } - IGNORE_RETURN(::remove(".shutdown")); - return; - } - - if( FileExists( ".startanymissingplanet") ) - { - LOG("CentralServer", ("Detected a .startanymissingplanet file. Checking for any planets that are not started, and starting them.")); - - for (std::map::const_iterator iter = ms_sceneToHostMap.begin(); iter != ms_sceneToHostMap.end(); ++iter) - { - if (!hasPlanetServer(iter->first)) - { - std::map, time_t> >::iterator iterPendingPlanetServer = m_pendingPlanetServers.find(iter->first); - if (iterPendingPlanetServer != m_pendingPlanetServers.end()) - { - // if it's been "awhile" since we requested to restart the PlanetServer, - // then assume that something has gone wrong, and try the restart again - time_t const timeNow = ::time(NULL); - - if ((iterPendingPlanetServer->second.second + static_cast(ConfigCentralServer::getMaxTimeToWaitForPlanetServerStartSeconds())) < timeNow) - { - LOG("CentralServer", ("startanymissingplanet:Starting missing planet %s because it has been %s since we requested it to be started, which has exceeded the %s limit.", iter->first.c_str(), CalendarTime::convertSecondsToMS(static_cast(timeNow - iterPendingPlanetServer->second.second)).c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigCentralServer::getMaxTimeToWaitForPlanetServerStartSeconds())).c_str())); - iterPendingPlanetServer->second.second = timeNow; - TaskSpawnProcess spawn(iterPendingPlanetServer->second.first.first.empty() ? std::string("any") : iterPendingPlanetServer->second.first.first, "PlanetServer", iterPendingPlanetServer->second.first.second); - CentralServer::getInstance().sendTaskMessage(spawn); - } - else - { - LOG("CentralServer", ("startanymissingplanet:It's only been %s since we requested for planet %s to be started, and we must wait %s before we can start it again.", CalendarTime::convertSecondsToMS(static_cast(timeNow - iterPendingPlanetServer->second.second)).c_str(), iter->first.c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigCentralServer::getMaxTimeToWaitForPlanetServerStartSeconds())).c_str())); - } - } - else - { - LOG("CentralServer", ("startanymissingplanet:Hmmm... planet %s is missing, but also is not in the list of planets we have attempted to start, so we're ***NOT*** going to start it.", iter->first.c_str())); - } - } - } - - IGNORE_RETURN(::remove( ".startanymissingplanet" )); - return; - } - - if( FileExists( ".startanymissinggameserver") ) - { - LOG("CentralServer", ("Detected a .startanymissinggameserver file. Checking for any game servers that are not started, and starting them.")); - - const GenericValueTypeMessage startAnyMissingGameServer("SAMGS", 0); - sendToAllPlanetServers(startAnyMissingGameServer, true); - - IGNORE_RETURN(::remove( ".startanymissinggameserver" )); - return; - } - } -#endif - return; - } - - // should we abort? - if( m_curTime > nextAbortCheck ) - { -#ifndef WIN32 - nextAbortCheck = m_curTime + 1; - if( FileExists(".abortshutdown") ) - { - - IGNORE_RETURN(::remove(".abortshutdown")); - LOG("CentralServerShutdown", ("Shutdown Phase %d: Detected a .abortshutdown file. Aborting shutdown sequence.", m_shutdownPhase)); - abortShutdownProcess(); - return; - } -#endif - } - - // Phase 1 is an immediate broadcast to players for the first shutdown warning - if( m_shutdownPhase == 1 ) - { - char strTimeLeft[1024]; - uint32 timeLeft = m_shutdownTotalTime - m_curTime; - if( timeLeft < 1 ) - { - strTimeLeft[0] = '\0'; - } - else if( timeLeft < 60 ) - { - sprintf(strTimeLeft, " ( %lusec left )", timeLeft); - } - else - { - sprintf(strTimeLeft, " ( %lumin left )", timeLeft/60); - } - - LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting first shutdown message to players: \"%s %s\"", m_shutdownPhase, Unicode::wideToNarrow(m_shutdownSystemMessage).c_str(), strTimeLeft)); - ConGenericMessage const msg("game any systemMessage " + Unicode::wideToNarrow(m_shutdownSystemMessage)+strTimeLeft, 0); - IGNORE_RETURN(sendToRandomGameServer(msg)); - m_shutdownPhase = 2; - lastWarn = m_curTime; - } - // Phase 2 is broadcasting a system message every 60sec while we wait for time to expire - else if( m_shutdownPhase == 2 ) - { - if( m_curTime >= m_shutdownTotalTime) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Done broadcasting shutdown warning message to players . Advancing shutdown phase.", m_shutdownPhase)); - m_shutdownPhase = 3; - warn30 = false; - warn10 = false; - warn0 = false; - - - } - // broadcast warning message to players every 60sec. - else if( m_curTime >= lastWarn+60 ) - { - char strTimeLeft[1024]; - uint32 timeLeft = m_shutdownTotalTime - m_curTime; - if( timeLeft < 1 ) - { - strTimeLeft[0] = '\0'; - } - else if( timeLeft < 60 ) - { - sprintf(strTimeLeft, " ( %lusec left)", timeLeft); - } - else - { - sprintf(strTimeLeft, " ( %lumin left)", timeLeft/60); - } - - LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting shutdown message to players: \"%s %s\"", m_shutdownPhase, Unicode::wideToNarrow(m_shutdownSystemMessage).c_str(), strTimeLeft)); - ConGenericMessage const msg("game any systemMessage " + Unicode::wideToNarrow(m_shutdownSystemMessage)+strTimeLeft, 0); - IGNORE_RETURN(sendToRandomGameServer(msg)); - lastWarn = m_curTime; - } - } - // warn the players they are about to be disconnected - else if( m_shutdownPhase == 3 ) - { - if( m_curTime>=m_shutdownTotalTime && !warn30 ) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting 30sec disconnect warning message to players.", m_shutdownPhase)); - ConGenericMessage const msg("game any systemMessage You will be disconnected in 30sec so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0); - IGNORE_RETURN(sendToRandomGameServer(msg)); - warn30 = true; - - } - else if( m_curTime >= (m_shutdownTotalTime+20) && !warn10 ) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting 10sec disconnect warning message to players.", m_shutdownPhase)); - ConGenericMessage const msg("game any systemMessage You will be disconnected in 10sec so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0); - IGNORE_RETURN(sendToRandomGameServer(msg)); - warn10 = true; - } - else if( m_curTime >= (m_shutdownTotalTime+30) && !warn0 ) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting final disconnect warning message to players.", m_shutdownPhase)); - ConGenericMessage const msg("game any systemMessage You will now be disconnected so the server can perform a final save before shutting down.", 0); - IGNORE_RETURN(sendToRandomGameServer(msg)); - warn0 = true; - } - else if( m_curTime >= (m_shutdownTotalTime+35) ) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Setting server to private, disconnecting the players and now waiting for next database save cycle to begin.", m_shutdownPhase)); - gs_connectionServersPublic = false; - SetConnectionServerPublic const msg(false); - sendToAllConnectionServers(msg, true); - m_shutdownPhase = 4; - - // send a message to the DB telling it we're shutting down - GenericValueTypeMessage const msg2("ClusterShutdownMessage", true); - sendToDBProcess(msg2, true); - - // send a save start to the DB; must be sent after the above - // "ClusterShutdownMessage" message so the DB will know this - // is the final save before cluster shutdown - GenericValueTypeMessage const msg3("StartSaveMessage", NetworkId::cms_invalid); - sendToDBProcess(msg3, true); - } - } - else if( m_shutdownPhase == 4 ) - { - if( m_shutdownHaveDatabaseSaveStart ) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Starting final database save cycle. Advancing shutdown phase.", m_shutdownPhase)); - m_shutdownPhase = 5; - } - } - else if( m_shutdownPhase == 5 ) - { - // we are done. Shut it down. Shut it down now! - if( m_shutdownHaveDatabaseComplete) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Completed final database save cycle. Advancing shutdown phase.", m_shutdownPhase)); - m_shutdownPhase = 6; - LOG("CentralServerShutdown",("Shutdown Phase %d: Instructing TaskManager to shutdown the cluster without restarting.", m_shutdownPhase)); - ConGenericMessage const msg("stop", 0); - sendTaskMessage(msg); - } - } - // maximum amount of time to wait has expired. Shut it down now without waiting for anything else. - else if( m_curTime >= m_shutdownMaxTime ) - { - LOG("CentralServerShutdown",("Shutdown Phase %d: Maximum time has gone by. Forcing a shutdown now.", m_shutdownPhase)); - m_shutdownPhase = 6; - LOG("CentralServerShutdown",("Shutdown Phase %d: Instructing TaskManager to shutdown the cluster without restarting.", m_shutdownPhase)); - ConGenericMessage const msg("stop", 0); - sendTaskMessage(msg); - } -} - -void CentralServer::abortShutdownProcess() -{ - LOG("CentralServerShutdown", ("Shutdown Phase %d: Aborting shutdown sequence.", m_shutdownPhase)); - if( m_shutdownPhase > 0 ) - { - ConGenericMessage const msg("game any systemMessage The server shutdown has been aborted. The server is no longer shutting down.", 0); - IGNORE_RETURN(sendToRandomGameServer(msg)); - } - - // send a message to the DB telling it we're no longer shutting down - GenericValueTypeMessage const msg("ClusterShutdownMessage", false); - sendToDBProcess(msg, true); - - m_shutdownPhase = 0; - m_shutdownTotalTime = 0; - m_shutdownMaxTime = 0; - m_shutdownSystemMessage = Unicode::narrowToWide(""); - m_shutdownHaveDatabaseSaveStart = false; - m_shutdownHaveDatabaseComplete = false; -} - -//----------------------------------------------------------------------- - -void CentralServer::sendToTransferServer(const GameNetworkMessage & msg) const -{ - if(getInstance().m_transferServerConnection) - { - getInstance().m_transferServerConnection->send(msg, true); - } -} - -//----------------------------------------------------------------------- - -//----------------------------------------------------------------------- - -void CentralServer::sendToStationPlayersCollector(const GameNetworkMessage & msg) const -{ - if(getInstance().m_stationPlayersCollectorConnection) - { - getInstance().m_stationPlayersCollectorConnection->send(msg, true); - } -} - -//----------------------------------------------------------------------- - -int CentralServer::getPlanetServersCount() const -{ - return m_planetServers.size(); -} - -//----------------------------------------------------------------------- - -const Service * CentralServer::getCommoditiesService() -{ - return s_commodityServerService; -} - -//----------------------------------------------------------------------- - -int CentralServer::getClusterStartupTime() const -{ - if (m_clusterStartupTime != -1) - return m_clusterStartupTime; - else - // return how long the cluster has been taking to come up - return int((time(0) - m_timeClusterStarted) / 60); -} - -//----------------------------------------------------------------------- - -int CentralServer::getSecondsClusterHasBeenInLoadingState() const -{ - if (m_timeClusterWentIntoLoadingState > 0) - return (time(0) - m_timeClusterWentIntoLoadingState); - else - return 0; -} - -// ---------------------------------------------------------------------- - -const std::map & CentralServer::getPopulationStatistics(time_t & refreshTime) -{ - // periodically request updated statistics from the game server - time_t const timeNow = ::time(NULL); - if (m_timePopulationStatisticsNextRefresh <= timeNow) - { - GameServerConnection * universeGameServerConnection = getGameServer(UniverseManager::getInstance().getUniverseProcess()); - if (universeGameServerConnection) - { - const GenericValueTypeMessage populationStatisticsRequest("PopStatReq", 0); - universeGameServerConnection->send(populationStatisticsRequest, true); - - m_timePopulationStatisticsNextRefresh = timeNow + 60; - } - } - - refreshTime = m_timePopulationStatisticsRefresh; - return m_populationStatistics; -} - -// ---------------------------------------------------------------------- - -const std::map > > & CentralServer::getGcwScoreStatistics(time_t & refreshTime) -{ - // periodically request updated statistics from the game server - time_t const timeNow = ::time(NULL); - if (m_timeGcwScoreStatisticsNextRefresh <= timeNow) - { - GameServerConnection * universeGameServerConnection = getGameServer(UniverseManager::getInstance().getUniverseProcess()); - if (universeGameServerConnection) - { - const GenericValueTypeMessage gcwScoreStatisticsRequest("GcwScoreStatReq", 0); - universeGameServerConnection->send(gcwScoreStatisticsRequest, true); - - m_timeGcwScoreStatisticsNextRefresh = timeNow + 60; - } - } - - refreshTime = m_timeGcwScoreStatisticsRefresh; - return m_gcwScoreStatistics; -} - -// ---------------------------------------------------------------------- - -std::pair > const *, std::map > const *> CentralServer::getLastLoginTimeStatistics(time_t & refreshTime) -{ - // periodically request updated statistics from the game server - time_t const timeNow = ::time(NULL); - if (m_timeLastLoginTimeStatisticsNextRefresh <= timeNow) - { - GameServerConnection * universeGameServerConnection = getGameServer(UniverseManager::getInstance().getUniverseProcess()); - if (universeGameServerConnection) - { - const GenericValueTypeMessage lastLoginTimeStatisticsRequest("LLTStatReq", 0); - universeGameServerConnection->send(lastLoginTimeStatisticsRequest, true); - - m_timeLastLoginTimeStatisticsNextRefresh = timeNow + (15 * 60); - } - } - - refreshTime = m_timeLastLoginTimeStatisticsRefresh; - - return std::make_pair(&m_lastLoginTimeStatistics, &m_createTimeStatistics); -} - -// ---------------------------------------------------------------------- - -void CentralServer::getCharacterMatchStatistics(int & numberOfCharacterMatchRequests, int & numberOfCharacterMatchResultsPerRequest, int & timeSpentPerCharacterMatchRequestMs) -{ - // periodically request updated statistics from the game server - time_t const timeNow = ::time(NULL); - if (m_timeCharacterMatchStatisticsNextRefresh <= timeNow) - { - const GenericValueTypeMessage characterMatchStatisticsRequest("LfgStatReq", 0); - sendToAllGameServersExceptDBProcess(characterMatchStatisticsRequest, true); - - m_timeCharacterMatchStatisticsNextRefresh = timeNow + 60; - } - - // wraparound, reset statistics - if (m_numberOfCharacterMatchRequests < 0) - { - m_numberOfCharacterMatchRequests = 0; - m_numberOfCharacterMatchResults = 0; - m_timeSpentOnCharacterMatchRequestsMs = 0; - } - - numberOfCharacterMatchRequests = m_numberOfCharacterMatchRequests; - numberOfCharacterMatchResultsPerRequest = (m_numberOfCharacterMatchRequests ? static_cast(m_numberOfCharacterMatchResults / m_numberOfCharacterMatchRequests) : 0); - timeSpentPerCharacterMatchRequestMs = (m_numberOfCharacterMatchRequests ? static_cast(m_timeSpentOnCharacterMatchRequestsMs / m_numberOfCharacterMatchRequests) : 0); -} - -// ====================================================================== -//lint -e766 // todo : TRF Fix this +// CentralServer.cpp +// copyright 2000 Verant Interactive +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstCentralServer.h" +#include "CentralServer.h" + +#include "CentralCSHandler.h" +#include "CentralServerMetricsData.h" +#include "CharacterCreationTracker.h" +#include "ChatServerConnection.h" +#include "ConfigCentralServer.h" +#include "ConnectionServerConnection.h" +#include "ConsoleConnection.h" +#include "ConsoleManager.h" +#include "CustomerServiceConnection.h" +#include "fileInterface/StdioFile.h" +#include "GameServerConnection.h" +#include "LoginServerConnection.h" +#include "PlanetManager.h" +#include "PlanetServerConnection.h" +#include "TaskConnection.h" +#include "UnicodeUtils.h" +#include "UniverseManager.h" +#include "serverKeyShare/KeyShare.h" +#include "serverMetrics/MetricsManager.h" +#include "serverNetworkMessages/AccountFeatureIdResponse.h" +#include "serverNetworkMessages/AddCharacterMessage.h" +#include "serverNetworkMessages/AddObjectIdBlockMessage.h" +#include "serverNetworkMessages/AdjustAccountFeatureIdResponse.h" +#include "serverNetworkMessages/CentralConnectionServerMessages.h" +#include "serverNetworkMessages/CentralGameServerMessages.h" +#include "serverNetworkMessages/CentralPingMessage.h" +#include "serverNetworkMessages/CentralPlanetServerConnect.h" +#include "serverNetworkMessages/CentralTaskMessages.h" +#include "serverNetworkMessages/CharacterListMessage.h" +#include "serverNetworkMessages/ChatServerOnline.h" +#include "serverNetworkMessages/ChunkObjectListMessage.h" +#include "serverNetworkMessages/ClaimRewardsMessage.h" +#include "serverNetworkMessages/ClaimRewardsReplyMessage.h" +#include "serverNetworkMessages/ConnectionServerDown.h" +#include "serverNetworkMessages/CreateNewObjectMessage.h" +#include "serverNetworkMessages/EnumerateServers.h" +#include "serverNetworkMessages/ExchangeListCreditsMessage.h" +#include "serverNetworkMessages/ExcommunicateGameServerMessage.h" +#include "serverNetworkMessages/FailedToLoadObjectMessage.h" +#include "serverNetworkMessages/FeatureIdTransactionResponse.h" +#include "serverNetworkMessages/ForceUnloadObjectMessage.h" +#include "serverNetworkMessages/GameServerForLoginMessage.h" +#include "serverNetworkMessages/GameServerReadyMessage.h" +#include "serverNetworkMessages/GameServerUniverseLoadedMessage.h" +#include "serverNetworkMessages/GameTaskManagerMessages.h" +#include "serverNetworkMessages/LoadObjectMessage.h" +#include "serverNetworkMessages/LocateStructureMessage.h" +#include "serverNetworkMessages/LoginConnectionServerAddress.h" +#include "serverNetworkMessages/LoginCreateCharacterAckMessage.h" +#include "serverNetworkMessages/LoginCreateCharacterMessage.h" +#include "serverNetworkMessages/LoginKeyPush.h" +#include "serverNetworkMessages/LoginRestoreCharacterMessage.h" +#include "serverNetworkMessages/LoginUpgradeAccountMessage.h" +#include "serverNetworkMessages/MessageToAckMessage.h" +#include "serverNetworkMessages/MessageToMessage.h" +#include "serverNetworkMessages/PlanetLoadCharacterMessage.h" +#include "serverNetworkMessages/PopulationListMessage.h" +#include "serverNetworkMessages/PreloadFinishedMessage.h" +#include "serverNetworkMessages/PreloadRequestCompleteMessage.h" +#include "serverNetworkMessages/ProfilerOperationMessage.h" +#include "serverNetworkMessages/RandomName.h" +#include "serverNetworkMessages/ReleaseAuthoritativeMessage.h" +#include "serverNetworkMessages/RenameCharacterMessage.h" +#include "serverNetworkMessages/RequestChunkMessage.h" +#include "serverNetworkMessages/RequestGameServerForLoginMessage.h" +#include "serverNetworkMessages/RequestObjectIdsMessage.h" +#include "serverNetworkMessages/RequestObjectMessage.h" +#include "serverNetworkMessages/RestartServerMessage.h" +#include "serverNetworkMessages/SceneTransferMessages.h" +#include "serverNetworkMessages/ServerDeleteCharacterMessage.h" +#include "serverNetworkMessages/SetConnectionServerPublic.h" +#include "serverNetworkMessages/SetObjectPositionMessage.h" +#include "serverNetworkMessages/TaskProcessDiedMessage.h" +#include "serverNetworkMessages/TaskSpawnProcess.h" +#include "serverNetworkMessages/TransferCharacterData.h" +#include "serverNetworkMessages/TransferCharacterDataArchive.h" +#include "serverNetworkMessages/UnloadObjectMessage.h" +#include "serverNetworkMessages/UpdateLoginConnectionServerStatus.h" +#include "serverNetworkMessages/UpdatePlayerCountMessage.h" +#include "serverNetworkMessages/ValidateAccountMessage.h" +#include "serverNetworkMessages/ValidateAccountReplyMessage.h" +#include "serverNetworkMessages/ValidateCharacterForLoginMessage.h" +#include "serverNetworkMessages/ValidateCharacterForLoginReplyMessage.h" +#include "serverNetworkMessages/VerifyAndLockName.h" +#include "sharedNetworkMessages/ConsoleChannelMessages.h" +#include "serverUtility/ClusterWideDataManagerList.h" +#include "serverUtility/ServerClock.h" +#include "serverUtility/SetupServerUtility.h" +#include "sharedDebug/Profiler.h" +#include "sharedFile/Iff.h" +#include "sharedFoundation/ApplicationVersion.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/Timer.h" +#include "sharedLog/Log.h" +#include "sharedLog/SetupSharedLog.h" +#include "sharedMathArchive/VectorArchive.h" +#include "sharedNetwork/Connection.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetwork/Service.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/NameErrors.h" +#include "sharedNetworkMessages/NetworkStringIds.h" +#include "sharedUtility/SetupSharedUtility.h" +#include "sharedUtility/StartingLocationData.h" +#include "sharedUtility/StartingLocationManager.h" +#include "TransferServerConnection.h" +#include "StationPlayersCollectorConnection.h" +#include "AuctionTransferClient.h" +#include "unicodeArchive/UnicodeArchive.h" +#include + + +namespace CentralServerNamespace +{ + bool gs_connectionServersPublic=false; + bool gs_clusterIsLocked=false; + bool gs_clusterIsSecret=false; + + std::map ms_sceneToHostMap; + + // every connection server started on the cluster will + // have a entry in this vector which contains the node + // on which to start that particular connection server; + // every connection server that is started will be assigned + // a 1-based number, which corresponds to its position + // in this vector; that is, the connection server assigned + // number 1 will be at position 0 in this vector + std::vector s_connectionServerHostList; + + std::pair s_customerServiceServerChatServerServiceAddress; + std::pair s_customerServiceServerGameServerServiceAddress; + Service * s_commodityServerService = 0; + bool s_retryTransferServerConnection = false; + bool s_retryStationPlayersCollectorConnection = false; + + std::map m_purgeAccountToLoginServerMap; + std::map > s_pendingRenameCharacter; +} + +using namespace CentralServerNamespace; + +// ====================================================================== + +CentralServer::CentralObject::CentralObject() : +m_sceneId(), +m_authoritativeProcess(0), +m_proxyProcessList() +{ + +} + +//----------------------------------------------------------------------- + +CentralServer::CentralObject::CentralObject(const CentralServer::SceneId & sceneId, uint32 authProcess) : +m_sceneId(sceneId), +m_authoritativeProcess(authProcess), +m_proxyProcessList() +{ + +} + +//----------------------------------------------------------------------- + +CentralServer::CentralServer() : +Singleton(), +MessageDispatch::Receiver(), +m_connectionServerConnections(), +m_chatServerConnections(), +m_csServerConnections(), +m_gameServers(), +m_accountConnectionMap(), +m_dbProcessServerProcessId(0), +m_done(false), +m_gameService(0), +m_chatService(0), +m_connService(0), +m_csService(0), +m_planetService(0), +m_consoleService(0), +m_transferServerConnection(0), +m_stationPlayersCollectorConnection(0), +m_gameServerConnections(), +m_gameServerConnectionsList(), +m_playerSceneMap(), +m_loginServerConnectionMap(), +m_loginServerKeys(0), +m_loginService(0), +m_pAuctionTransferClient(0), +m_messagesWaitingForPlanetServer(), +m_pendingLoadingObjects(), +m_pendingNewObjects(), +m_nextFreeProcessId(0), +m_taskManager(0), +m_taskService(0), +m_commandLine(), +m_pendingTransfers(), +m_totalPlayerCount(0), +m_totalFreeTrialCount(0), +m_totalEmptySceneCount(0), +m_totalTutorialSceneCount(0), +m_totalFalconSceneCount(0), +m_metricsData(0), +m_pendingPlanetServers(), +m_planetsWaitingForPreload(), +m_planetServers(), +m_nextPlanetWatcherPort(ConfigCentralServer::getFirstPlanetWatcherPort()), +m_databaseBacklogged(false), +m_lastLoadingStateTime(0), +m_timeClusterStarted(time(0)), +m_clusterStartupTime(-1), +m_timeClusterWentIntoLoadingState(time(0)), +m_clusterId(0), +m_serverPings(), +m_shutdownTotalTime(0), +m_shutdownMaxTime(0), +m_shutdownSystemMessage(Unicode::narrowToWide("")), +m_shutdownPhase(0), +m_shutdownHaveDatabaseSaveStart(false), +m_shutdownHaveDatabaseComplete(false), +m_curTime(0), +m_lastTimeSystemTimeMismatchNotification(0), +m_lastTimeSystemTimeMismatchNotificationDescription(), +m_disconnectedTaskManagerList(), +m_populationStatistics(), +m_timePopulationStatisticsRefresh(0), +m_timePopulationStatisticsNextRefresh(0), +m_gcwScoreStatistics(), +m_timeGcwScoreStatisticsRefresh(0), +m_timeGcwScoreStatisticsNextRefresh(0), +m_lastLoginTimeStatistics(), +m_createTimeStatistics(), +m_timeLastLoginTimeStatisticsRefresh(0), +m_timeLastLoginTimeStatisticsNextRefresh(0), +m_numberOfCharacterMatchRequests(0), +m_numberOfCharacterMatchResults(0), +m_timeSpentOnCharacterMatchRequestsMs(0), +m_timeCharacterMatchStatisticsNextRefresh(0) +{ + m_curTime = static_cast(time(0)); + m_loginServerKeys = new KeyServer(20); + + connectToMessage("LoginKeyPush"); + + //Connection Messages + connectToMessage("ClientConnectionClosed"); // from connection server + connectToMessage("ConnectionOpened"); + connectToMessage("RequestClusterShutdown"); + connectToMessage("GameConnectionClosed"); + connectToMessage("CentralGameServerConnect"); + connectToMessage("CentralGameServerDbProcessServerProcessId"); + connectToMessage("LoginConnectionOpened"); + connectToMessage("LoginConnectionClosed"); + connectToMessage("ClusterId"); + connectToMessage("GameServerReadyMessage"); + connectToMessage("GameServerUniverseLoadedMessage"); + connectToMessage("ConnectionServerConnectionClosed"); + connectToMessage("ConnectionServerConnectionOpened"); + connectToMessage("TaskConnectionClosed"); + connectToMessage("TaskConnectionOpened"); + connectToMessage("RandomNameRequest"); // from connection server + connectToMessage("RandomNameResponse"); // from game server + connectToMessage("VerifyAndLockNameRequest"); // from connection server + connectToMessage("VerifyAndLockNameResponse"); // from game server + + //Object Messages + connectToMessage("RequestObjectMessage"); + connectToMessage("RequestChunkMessage"); + connectToMessage("ChunkObjectListMessage"); + connectToMessage("CreateNewObjectMessage"); + connectToMessage("SetObjectPositionMessage"); + connectToMessage("FailedToLoadObjectMessage"); + connectToMessage("ReleaseAuthoritativeMessage"); + connectToMessage("ForceUnloadObjectMessage"); + connectToMessage("RequestUnloadObjectMessage"); + connectToMessage("MessageToMessage"); + connectToMessage("MessageToAckMessage"); + connectToMessage("LocateStructureMessage"); + + //Create character messages + connectToMessage("ConnectionCreateCharacter"); + connectToMessage("DatabaseCreateCharacterSuccess"); + connectToMessage("GameCreateCharacterFailed"); + connectToMessage("RequestGameServerForLoginMessage"); + connectToMessage("GameServerForLoginMessage"); + connectToMessage("LoginCreateCharacterAckMessage"); + connectToMessage("LoginUpgradeAccountMessage"); + connectToMessage("LoginRestoreCharacterMessage"); + connectToMessage("NewCharacterCreated"); + + connectToMessage("ServerDeleteCharacterMessage"); + connectToMessage("ValidateCharacterForLoginMessage"); + connectToMessage("ValidateCharacterForLoginReplyMessage"); + connectToMessage("EnableCharacterMessage"); + connectToMessage("EnableCharacterReplyMessage"); + connectToMessage("DisableCharacterMessage"); + connectToMessage("DisableCharacterReplyMessage"); + + connectToMessage("RequestOIDsMessage"); + connectToMessage("AddOIDBlockMessage"); + connectToMessage("CharacterListMessage"); + connectToMessage("LoggedInMessage"); + connectToMessage("CentralPlanetServerConnect"); + connectToMessage("PlanetCreateProxy"); + connectToMessage("PlanetRemoveProxy"); + + connectToMessage("RequestSceneTransfer"); + connectToMessage("SceneTransferMessage"); + connectToMessage("PlanetLoadCharacterMessage"); + + connectToMessage("ConnSrvDropDupeConns"); + connectToMessage("CntrlSrvDropDupeConns"); + + connectToMessage("PlayerDroppedFromGameServerCrash"); + + // Station exchange messages + connectToMessage("ExchangeListCreditsMessage"); + + // Chat Server messages + connectToMessage("ChatServerConnectionOpened"); + connectToMessage("ChatServerConnectionClosed"); + connectToMessage("ChatServerOnline"); + + // Chat Server messages + connectToMessage("CustomerServiceConnectionOpened"); + connectToMessage("CustomerServiceConnectionClosed"); + + connectToMessage("ValidateAccountMessage"); + connectToMessage("ValidateAccountReplyMessage"); + + connectToMessage("RequestPreloadListMessage"); + connectToMessage("PreloadListMessage"); + connectToMessage("PreloadRequestCompleteMessage"); + connectToMessage("PreloadFinishedMessage"); + connectToMessage("DatabaseBackloggedMessage"); + + connectToMessage("UpdatePlayerCountMessage"); + connectToMessage("RenameCharacterMessageEx"); + connectToMessage("PlayerRenameRequestSubmitted"); + connectToMessage("PlayerRenameRequestCompleted"); + connectToMessage("PopulationListMessage"); + + connectToMessage("SetConnectionServerPublic"); + + connectToMessage("ProfilerOperationMessage"); + connectToMessage("CentralPingMessage"); + + connectToMessage("DatabaseSaveStart"); + connectToMessage("DatabaseSaveComplete"); + connectToMessage("ShutdownCluster"); + connectToMessage("AbortShutdown"); + connectToMessage("SetSceneForPlayer"); + connectToMessage("DatabaseConsoleReplyMessage"); + connectToMessage("TaskProcessDiedMessage"); + connectToMessage("SystemTimeMismatchNotification"); + connectToMessage("DisconnectedTaskManagerMessage"); + connectToMessage("TransferServerConnectionClosed"); + connectToMessage("PlanetRequestSave"); + connectToMessage("TransferReplyLoginLocationData"); + connectToMessage("CustomerServiceServerChatServerServiceAddress"); + connectToMessage("CustomerServiceServerGameServerServiceAddress"); + connectToMessage("ChatClosedConnectionWithGameServer"); + + connectToMessage("ReconnectToTransferServer"); + connectToMessage("ClaimRewardsMessage"); + connectToMessage("ClaimRewardsReplyMessage"); + connectToMessage("PurgeStructuresForAccountMessage"); + connectToMessage("WarnStructuresAboutPurgeMessage"); + connectToMessage("PurgeCompleteMessage"); + connectToMessage("RestartServerMessage"); + connectToMessage("RestartServerByRoleMessage"); + connectToMessage("ExcommunicateGameServerMessage"); + connectToMessage("RestartPlanetMessage"); + + // Cluster state + connectToMessage("UpdateClusterLockedAndSecretState"); + + // Population statistics + connectToMessage("PopStatRsp"); + connectToMessage("LLTStatRsp"); + + // GCW score statistics + connectToMessage("GcwScoreStatRsp"); + + // Character Search statistics + connectToMessage("LfgStatRsp"); + + // Account feature Id management + connectToMessage("AdjustAccountFeatureIdResponse"); + connectToMessage("AccountFeatureIdResponse"); + connectToMessage("FeatureIdTransactionResponse"); + + // Unlocked Slot management + connectToMessage("OccupyUnlockedSlotRsp"); + connectToMessage("VacateUnlockedSlotRsp"); + connectToMessage("SwapUnlockedSlotRsp"); + + // Cluster wide data manager + ClusterWideDataManagerList::install(); + ClusterWideDataManagerList::registerMessage(*this); + ClusterWideDataManagerList::setLockTimeoutValue(ConfigCentralServer::getClusterWideDataLockTimeout()); + + CentralCSHandler::install(); + + gs_connectionServersPublic = ConfigCentralServer::getStartPublic(); + + m_metricsData = new CentralServerMetricsData; + MetricsManager::install(m_metricsData, false, "CentralServer", "", 0); + ConsoleManager::install(); + CharacterCreationTracker::install(); + + IGNORE_RETURN(UniverseManager::getInstance()); //make sure it's constructed +} + +//----------------------------------------------------------------------- + +CentralServer::~CentralServer() +{ + ConsoleManager::remove(); + + CentralCSHandler::remove(); + + ms_sceneToHostMap.clear(); + + // released during CentralServer::remove() + m_gameService = 0; + m_chatService = 0; + m_connService = 0; + m_csService = 0; + m_planetService = 0; + m_consoleService = 0; + m_transferServerConnection = 0; + m_stationPlayersCollectorConnection = 0; + m_loginServerKeys = 0; //lint !e423 : leak + m_loginService = 0; + m_taskManager = 0; + m_taskService = 0; + m_metricsData = 0; //lint !e423 : leak +} + +//----------------------------------------------------------------------- +void CentralServer::addGameServer(GameServerConnection * newGameServer) +{ + uint32 pid = newGameServer->getProcessId(); + + LOG("ServerStartup", ("Adding server %lu for scene %s", pid, newGameServer->getSceneId().c_str())); + + IGNORE_RETURN(m_gameServers.insert(SceneGameMap::value_type( + newGameServer->getSceneId(), newGameServer))); + m_gameServerConnections[pid] = newGameServer; + + if (newGameServer->getSceneId() != "database") + { + m_gameServerConnectionsList.push_back(newGameServer); + + if (ConfigCentralServer::getGameServerConnectionPendingAllocatedSizeLimit() != 0) + newGameServer->setTcpClientPendingSendAllocatedSizeLimit(ConfigCentralServer::getGameServerConnectionPendingAllocatedSizeLimit()); + + PlanetManager::addGameServerForScene(newGameServer->getSceneId(), newGameServer); + + // Have the new game server connect to the db and notify it of what game servers exist + std::vector serverList; + + GameServerConnection const * const databaseProcessConnection = CentralServer::getInstance().getGameServer(CentralServer::getInstance().getDbProcessServerProcessId()); + + FATAL(!databaseProcessConnection, ("Tried to add a game server without a database process connection?")); + + for (std::map::iterator i = m_gameServerConnections.begin(); i != m_gameServerConnections.end(); ++i) + { + GameServerConnection const * const g = (*i).second; + if (g != databaseProcessConnection && g->getProcessId() != pid) + serverList.push_back(g->getProcessId()); + } + + GenericValueTypeMessage, std::pair > > > const setupMessage( + "GameServerSetupMessage", + std::make_pair( + serverList, + std::make_pair( + databaseProcessConnection->getProcessId(), + std::make_pair( + databaseProcessConnection->getGameServiceAddress(), + databaseProcessConnection->getGameServicePort())))); + + newGameServer->send(setupMessage, true); + } +} + +//----------------------------------------------------------------------- + +void CentralServer::broadcastToChatServers(const GameNetworkMessage & message) const +{ + for (std::set::const_iterator i = m_chatServerConnections.begin(); i != m_chatServerConnections.end(); ++i) + (*i)->send(message, true); +} + +//----------------------------------------------------------------------- + +void CentralServer::broadcastToCustomerServiceServers(const GameNetworkMessage & message) const +{ + for (std::set::const_iterator i = m_csServerConnections.begin(); i != m_csServerConnections.end(); ++i) + (*i)->send(message, true); +} + +//----------------------------------------------------------------------- + +void CentralServer::broadcastToGameServers(const GameNetworkMessage & message) const +{ + for (SceneGameMap::const_iterator i = m_gameServers.begin(); i != m_gameServers.end(); ++i) + (*i).second->send(message, true); +} + +//----------------------------------------------------------------------- +// /** +// * Clears the object process map for an object. +// * +// * @param objectId id of object we want to clear +// */ +// void CentralServer::clearObjectMap(const NetworkId & objectId) +// { +// IGNORE_RETURN(m_centralObjectMap.erase(objectId)); +// } + +//----------------------------------------------------------------------- + +bool CentralServer::getIsClusterPublic() const +{ + return gs_connectionServersPublic; +} + +//----------------------------------------------------------------------- + +bool CentralServer::getIsClusterLocked() const +{ + return gs_clusterIsLocked; +} + +//----------------------------------------------------------------------- + +bool CentralServer::getIsClusterSecret() const +{ + return gs_clusterIsSecret; +} + +//----------------------------------------------------------------------- + +const std::string& CentralServer::getHostForScene(const std::string& scene) const +{ + static std::string anyString = "any"; + std::map::iterator i = ms_sceneToHostMap.find(scene); + if (i != ms_sceneToHostMap.end()) + { + return i->second; + } + return anyString; +} + +// ---------------------------------------------------------------------- + +/** + * Get the list of game servers that are ready + */ +void CentralServer::getReadyGameServers(std::vector &theList) +{ + std::map::const_iterator i; + for (i = m_gameServerConnections.begin(); i!=m_gameServerConnections.end(); ++i) + { + if ((*i).second->getProcessId()!=getDbProcessServerProcessId() && i->second->getReady()) + theList.push_back(i->second->getProcessId()); + } +} + +//------------------------------------------------------------- + +GameServerConnection * CentralServer::getRandomGameServer(void) +{ + if (m_gameServerConnectionsList.empty()) + return NULL; + + // m_gameServerConnectionsList ***DOES NOT*** contain the DB server so + // we don't have to worry about checking for and excluding the DB server + size_t const listSize = m_gameServerConnectionsList.size(); + size_t const indexChosenGameServer = (::rand() % listSize); + if (m_gameServerConnectionsList[indexChosenGameServer]->getReady()) + return m_gameServerConnectionsList[indexChosenGameServer]; + + // randomly chosen game server is not ready, find next ready game server + size_t indexNextGameServer = (indexChosenGameServer + 1); + if (indexNextGameServer == listSize) + indexNextGameServer = 0; + + while (indexNextGameServer != indexChosenGameServer) + { + if (m_gameServerConnectionsList[indexNextGameServer]->getReady()) + return m_gameServerConnectionsList[indexNextGameServer]; + + ++indexNextGameServer; + if (indexNextGameServer == listSize) + indexNextGameServer = 0; + } + + return NULL; +} + +//----------------------------------------------------------------------- + +/** +* Returns a game server that is handling a scene. +* +* @param scene the scene +* +* @return a game server connection for that scene +*/ +GameServerConnection * CentralServer::getGameServer(const SceneId &scene) const +{ + // @todo: we should pick a gameserver based on load + + CentralServer::ServersList range = getGameServers(scene); + SceneGameMap::const_iterator iter = range.first; + while (iter != range.second) + { + if (iter->second->getReady()) + return iter->second; + ++iter; + } + return 0; +} + +//----------------------------------------------------------------------- + +/** +* Returns the game server for a given process id. +* +* @param processId the process id +* +* @return the game server connection +*/ +GameServerConnection * CentralServer::getGameServer(const uint32 processId) const +{ + GameServerConnection * result = 0; + std::map::const_iterator i = m_gameServerConnections.find(processId); + if(i != m_gameServerConnections.end()) + result = (*i).second; + return result; +} + +//----------------------------------------------------------------------- + +/** +* Returns a list of game servers that are handling a scene. +* +* @param scene the scene +* +* @return an iterator pair for a range of GameServerConnections +*/ +const CentralServer::ServersList CentralServer::getGameServers(const SceneId &scene) const +{ + return m_gameServers.equal_range(scene); //lint !e64 //Type mismatch +} + +//----------------------------------------------------------------------- + +void CentralServer::pushAllKeys(ConnectionServerConnection * targetConnectionServer) const +{ + DEBUG_FATAL(static_cast(m_loginServerKeys->getKeyCount()) < 0, ("Invalid number of keys (uint overflow) in CentralServer.h")); + + for(int i = static_cast(m_loginServerKeys->getKeyCount()) - 1; i >= 0 ; i --) + { + ConnectionKeyPush pk(m_loginServerKeys->getKey(static_cast(i))); + targetConnectionServer->send(pk, true); + } +} + +//----------------------------------------------------------------------- + +void CentralServer::launchStartingProcesses() const +{ + static bool startingProcessesLaunched = false; + if (startingProcessesLaunched) + return; + + // we can only launch starting processes once we have a connection to the + // TaskManager *AND* have received our cluster id from the LoginServer + if (!m_taskManager || !m_taskManager->isConnected() || (m_clusterId == 0)) + { + if (!m_taskManager) + REPORT_LOG(true, ("CentralServer not launching starting processes because m_taskManager is NULL\n")); + else if (!m_taskManager->isConnected()) + REPORT_LOG(true, ("CentralServer not launching starting processes because m_taskManager->isConnected() is false\n")); + + if (m_clusterId == 0) + REPORT_LOG(true, ("CentralServer not launching starting processes because m_clusterId is 0, meaning hasn't received the cluster Id from the LoginServer yet\n")); + + return; + } + + REPORT_LOG(true, ("CentralServer now launching starting processes because has a connection to the TaskManager *AND* has received cluster Id (%u) from the LoginServer\n", m_clusterId)); + + startingProcessesLaunched = true; + + // spawn a connection server + launchStartingConnectionServers(); + + std::string options = "-s dbProcess centralServerAddress="; + if(getGameService()) + { + options += getGameService()->getBindAddress(); + } + else + { + options += NetworkHandler::getHostName(); + } + + TaskSpawnProcess pd(ConfigCentralServer::getDbServerHost(), "SwgDatabaseServer", options); + m_taskManager->send(pd, true); + + options = "-s ChatServer centralServerAddress="; + if(getChatService()) + { + options += getChatService()->getBindAddress(); + } + else + { + options += NetworkHandler::getHostName(); + } + options += " clusterName="; + options += ConfigCentralServer::getClusterName(); + TaskSpawnProcess pc(ConfigCentralServer::getChatServerHost(), "ChatServer", options); + m_taskManager->send(pc, true); + + options = "-s CustomerServiceServer centralServerAddress="; + if(getCustomerService()) + { + options += getCustomerService()->getBindAddress(); + } + else + { + options += NetworkHandler::getHostName(); + } + + options += " clusterName="; + options += ConfigCentralServer::getClusterName(); + TaskSpawnProcess pcs("any", "CustomerServiceServer", options); + m_taskManager->send(pcs, true); +} + +//----------------------------------------------------------------------- + +void CentralServer::launchStartingConnectionServers() const +{ + // if there are several planets listed explicitly in the config file/command line, + // spawn them + + int i = 0; + + // check for nesteds + int const numberOfStartingConnectionServers = ConfigCentralServer::getNumberOfStartingConnectionServers(); + for (i = 0; i < numberOfStartingConnectionServers; ++i) + { + char const * const host = ConfigCentralServer::getStartingConnectionServer(i); + if (host) + { + char const * listenAddress = strchr(host,':'); + DEBUG_FATAL(!listenAddress, ("Could not start up connection server because string %s has no listen address", host)); + std::string hostString(host, static_cast(listenAddress - host)); + ++listenAddress; + + char const * publicPort = strchr(listenAddress,':'); + DEBUG_FATAL(!publicPort, ("Could not start up connection server because string %s has no public port", host)); + std::string listenString(listenAddress, static_cast(publicPort - listenAddress)); + ++publicPort; + + char const * privatePort = strchr(publicPort,':'); + DEBUG_FATAL(!privatePort, ("Could not start up connection server because string %s has no private port", host)); + std::string publicPortString(publicPort, static_cast(privatePort - publicPort)); + ++privatePort; + std::string privatePortString(privatePort); + + DEBUG_REPORT_LOG(true, ("Spawning Connection Server on %s listen:%s public:%s priv:%s\n", hostString.c_str(), listenString.c_str(), publicPortString.c_str(), privatePortString.c_str())); + + // must update s_connectionServerHostList before calling startConnectionServer() + s_connectionServerHostList.push_back(hostString); + startConnectionServer(s_connectionServerHostList.size(), listenString, &publicPortString, &privatePortString, 0); + } + } + + // if there were none specified, use defaults + if(i == 0) + { + // must update s_connectionServerHostList before calling startConnectionServer() + s_connectionServerHostList.push_back("node0"); + startConnectionServer(s_connectionServerHostList.size(), NetworkHandler::getHostName(), 0, 0, 0); + } + +} + +//----------------------------------------------------------------------- + +void CentralServer::launchStartingPlanetServers() +{ + // if there are several planets listed explicitly in the config file/command line, + // spawn them + int i = 0; + int const numberOfStartPlanets = ConfigCentralServer::getNumberOfStartPlanets(); + + for (i = 0; i < numberOfStartPlanets ; ++i) + { + char const * const p = ConfigCentralServer::getStartPlanet(i); + if (p) + { + FATAL(!*p, ("CentralServer::launchStartingPlanetServers: ConfigCentralServer::getStartPlanet(%d) specified a non-null but empty planet name", i)); + + std::string planetName; + std::string hostName; + char const * planet = p; + NOT_NULL(planet); + char const * host = strchr(planet,':'); + + if (host) + { + planetName = std::string(planet, static_cast(host - planet) ); + ++host; + hostName = host; + } + else + { + planetName = planet; + } + + startPlanetServer(hostName, planetName, 0); + ms_sceneToHostMap[planetName] = hostName; + } + } + + // if there were no planets specified, get the configfile default and + // start that planet + if(i == 0) + { + startPlanetServer("any", ConfigCentralServer::getStartPlanet(), 0); + } +} + +//----------------------------------------------------------------------- + +void CentralServer::launchCommoditiesServer() +{ + std::string options; + TaskSpawnProcess csp("any", "CommoditiesServer", options); + CentralServer::getInstance().sendTaskMessage(csp); +} + +//----------------------------------------------------------------------- + +void CentralServer::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) +{ + if(message.isType("LoginKeyPush")) + { + // receiving another key + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const LoginKeyPush k(ri); + m_loginServerKeys->pushKey(k.getKey()); + DEBUG_REPORT_LOG(true, ("Received session key.\n")); + ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); + for (;i != m_connectionServerConnections.end(); ++i) + { + (*i)->send(k, true); + } + } + else if (message.isType("RequestClusterShutdown")) + { + REPORT_LOG(true, ("An admin requested we shutdown the entire cluster\n")); + m_done = true; + } + else if (message.isType("ClientConnectionClosed")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + ConnectionServerSUIDMap::iterator i = m_accountConnectionMap.find(msg.getValue()); + if ((i != m_accountConnectionMap.end()) && (i->second == &source)) + { + // Erase the entry + m_accountConnectionMap.erase(i); + } + } + else if(message.isType("ConnectionOpened")) + { + if (!dynamic_cast(&source)) + { + ServerConnection *newServer = const_cast(safe_cast(&source)); + uint32 pid = newServer->getProcessId(); + + CentralGameServerSetProcessId pidMessage(pid, ServerClock::getInstance().getSubtractInterval(), ConfigCentralServer::getClusterName()); + newServer->send(pidMessage, true); + } + } + else if(message.isType("ConnectionServerConnectionClosed")) + { + DEBUG_REPORT_LOG(true,("Handling connection server crash.\n")); + ConnectionServerConnection const *c = safe_cast(&source); + removeFromAccountConnectionMap(c->getId()); + } + else if(message.isType("GameConnectionClosed")) + { + DEBUG_REPORT_LOG(true, ("Game server closed connection\n")); + GameServerConnection const *g = safe_cast(&source); + removeGameServer(g); + } + + else if (message.isType("LoginConnectionOpened")) + { + LoginServerConnection *l = const_cast(safe_cast(&source)); + m_loginServerConnectionMap[l->getProcessId()] = l; + //Send connection server data + ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); + for(; i != m_connectionServerConnections.end(); ++i) + { + const ConnectionServerConnection * const csc = *i; + if ( (csc->getClientServicePortPrivate() != 0) || (csc->getClientServicePortPublic() != 0) ) + { + const LoginConnectionServerAddress csa(csc->getId(), csc->getClientServiceAddress(), csc->getClientServicePortPrivate(), csc->getClientServicePortPublic(), csc->getPlayerCount(), csc->getPingPort ()); + l->send(csa, true); + } + } + + // send preload is finished, if it is + PreloadFinishedMessage msg(isPreloadFinished()); + l->send(msg, true); + + CharacterCreationTracker::getInstance().retryLoginServerCreates(); + } + + else if(message.isType("LoginConnectionClosed")) + { + LoginServerConnection const *l = safe_cast(&source); + LoginServerConnectionMapType::iterator i=m_loginServerConnectionMap.find(l->getProcessId()); + if (i!=m_loginServerConnectionMap.end()) + m_loginServerConnectionMap.erase(i); + + // In development mode, try to reconnect to the login server if we aren't shutting down + if (ConfigCentralServer::getDevelopmentMode() && !m_done) + connectToLoginServer(); + + CharacterCreationTracker::getInstance().onLoginServerDisconnect(l->getProcessId()); + } + + else if(message.isType("ClusterId")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + if (m_clusterId == 0) + { + FATAL(((msg.getValue() < 1) || (msg.getValue() > 255)),("Cluster Id (%lu) must be between 1 and 255 inclusive", msg.getValue())); + + m_clusterId = static_cast(msg.getValue()); + + // start launching processes + launchStartingProcesses(); + } + } + + else if(message.isType("CentralGameServerConnect")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + CentralGameServerConnect c(ri); + + GameServerConnection *g = const_cast(safe_cast(&source)); + + FATAL(ConfigCentralServer::getValidateBuildVersionNumber() && strcmp(ApplicationVersion::getInternalVersion(), c.getBuildVersionNumber().c_str()), + ("Build version number mismatch: central server (%s), remote server %s (%s)", ApplicationVersion::getInternalVersion(), g->getRemoteAddress().c_str(), c.getBuildVersionNumber().c_str()) + ); + + // a game server (or db process) has connected... + addGameServer(g); + + //Send connection server data + ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); + for(; i != m_connectionServerConnections.end(); ++i) + { + if ((*i)->getGameServicePort() != 0) + { + ConnectionServerAddress csa((*i)->getGameServiceAddress(), (*i)->getGameServicePort()); + g->send(csa, true); + } + } + + std::set::const_iterator chatIter; + for(chatIter = m_chatServerConnections.begin(); chatIter != m_chatServerConnections.end(); ++chatIter) + { + if((*chatIter)->getGameServicePort()) + { + ChatServerOnline cso((*chatIter)->getRemoteAddress(), (*chatIter)->getGameServicePort()); + g->send(cso, true); + } + } + + if (g != NULL) + { + //DEBUG_REPORT_LOG(true, ("CentralServer: Sending CustomerServiceServerGameServerServiceAddress to game server (%s:%d) pid(%i)\n", g->getRemoteAddress().c_str(), g->getRemotePort(), g->getProcessId())); + const GenericValueTypeMessage > address("CustomerServiceServerGameServerServiceAddress", std::make_pair(s_customerServiceServerGameServerServiceAddress.first, s_customerServiceServerGameServerServiceAddress.second)); + + g->send(address, true); + } + } + else if (message.isType("ChatClosedConnectionWithGameServer")) + { + GameServerConnection *g = const_cast(safe_cast(&source)); + std::set::const_iterator chatIter; + for(chatIter = m_chatServerConnections.begin(); chatIter != m_chatServerConnections.end(); ++chatIter) + { + if((*chatIter)->getGameServicePort()) + { + ChatServerOnline cso((*chatIter)->getRemoteAddress(), (*chatIter)->getGameServicePort()); + g->send(cso, true); + } + } + } + else if (message.isType("CustomerServiceServerGameServerServiceAddress")) + { + //DEBUG_REPORT_LOG(true, ("CentralServer::receiveMessage(CustomerServiceServerGameServerServiceAddress)\n")); + + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const GenericValueTypeMessage > address(ri); + s_customerServiceServerGameServerServiceAddress.first = address.getValue().first; + s_customerServiceServerGameServerServiceAddress.second = address.getValue().second; + + broadcastToGameServers(address); + } + else if(message.isType("TaskConnectionClosed")) + { + // Net::getInstance().connect(Network::Address("127.0.0.1", ConfigCentralServer::getTaskManagerPort()), TaskConnection()); + } + else if(message.isType("TaskConnectionOpened")) + { + DEBUG_REPORT_LOG(true, ("Task manager connection opened\n")); + } + + else if(message.isType("CentralGameServerDbProcessServerProcessId")) + { + DEBUG_REPORT_LOG(true, ("dbProcess connected\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + CentralGameServerDbProcessServerProcessId d(ri); + m_dbProcessServerProcessId = d.getServerProcessId(); + ServerClock::getInstance().setSubtractInterval(d.getSubtractInterval()); + + launchCommoditiesServer(); + launchStartingPlanetServers(); + } + + else if(message.isType("RequestChunkMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RequestChunkMessage t(ri); + + // Forward this message to the dbProcess + sendToGameServer(m_dbProcessServerProcessId, t, true); + } + else if(message.isType("ChunkObjectListMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ChunkObjectListMessage t(ri); + + DEBUG_FATAL(true,("Got ChunkObjectListMessage. Thought it was deprecated.\n")); + // handleChunkList(t.getProcess(), t.getIds()); + } + else if(message.isType("LocateStructureMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LocateStructureMessage t(ri); + sendToPlanetServer(t.getSceneId(), t, true); + } + else if(message.isType("RequestObjectMessage")) + { + DEBUG_FATAL(true,("Got RequestObjectMessage. Thought this went away.")); + + // Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + // RequestObjectMessage t(ri); + // // tell the authoritative object to create a proxy + // const GameServerConnection *gameServer = getGameServer(t.getProcess()); + // NOT_NULL(gameServer); + // uint32 authId = sendToAuthoritativeServer(t.getId(), + // LoadObjectMessage(t.getId(), t.getProcess(), gameServer->getGameServiceAddress(), gameServer->getGameServicePort(), false), + // true); + // // if we sent the message to the database process, mark it as being + // // authoritative for this object + // if (authId == m_dbProcessServerProcessId) + // { + // addObjectToMap(t.getId(), authId, gameServer->getSceneId(), true); + // m_pendingLoadingObjects[t.getId()] = t.getProcess(); + // } + } + else if(message.isType("CreateNewObjectMessage")) + { + DEBUG_FATAL(true,("Ain't this supposed to be deprecated or something?")); + } + else if(message.isType("SetObjectPositionMessage")) + { + //@todo remove this message from the library + DEBUG_FATAL(true,("Got SetObjectPositionMessage. Thought this went away")); + } + else if(message.isType("FailedToLoadObjectMessage")) + { + //@todo remove this message from the library + DEBUG_FATAL(true,("Received Failed To Load Object Message. Thought it was depricated\n")); + } + else if(message.isType("ReleaseAuthoritativeMessage")) + { + //@todo remove this message from the library + DEBUG_FATAL(true, ("Received ReleaseAuthoritative for. Thought it was deprecated.")); + } + else if(message.isType("ForceUnloadObjectMessage")) + { + //N.B. This message can come from a game server or from the planet server. + DEBUG_WARNING(true, ("Received ForceUnloadObject. Need to implement this\n")); + + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ForceUnloadObjectMessage t(ri); + + //@todo: figure out some way to handle this (such as forwarding to PlanetServers), or remove every case where it's sent + // forceUnload(t.getId(),t.getPermaDelete()); + } + //Character Creation Messages + else if(message.isType("ConnectionCreateCharacter")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ConnectionCreateCharacter c(ri); + + LOG("TraceCharacterCreation", ("%d received ConnectionCreateCharacter", c.getStationId())); + CharacterCreationTracker::getInstance().handleCreateNewCharacter(c); + } + else if(message.isType("GameCreateCharacterFailed")) + { + DEBUG_REPORT_LOG(true, ("Game server advises central that character creation failed\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GameCreateCharacterFailed f(ri); + CharacterCreationTracker::getInstance().handleGameCreateCharacterFailed(f.getStationId(), f.getName(), f.getErrorMessage(), f.getOptionalDetailedErrorMessage()); + } + else if(message.isType("DatabaseCreateCharacterSuccess")) + { + DEBUG_REPORT_LOG(true, ("Database Process advises central that character creation succeeded\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + DatabaseCreateCharacterSuccess s(ri); + CharacterCreationTracker::getInstance().handleDatabaseCreateCharacterSuccess(s.getStationId(), s.getCharacterName(), s.getObjectId(), s.getTemplateId(), s.getJedi()); + } + else if(message.isType("LoginCreateCharacterAckMessage")) + { + DEBUG_REPORT_LOG(true, ("Login Server advises central that character creation succeeded\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginCreateCharacterAckMessage s(ri); + CharacterCreationTracker::getInstance().handleLoginCreateCharacterAck(s.getStationId()); + } + else if(message.isType("LoginRestoreCharacterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginRestoreCharacterMessage msg(ri); + + IGNORE_RETURN(sendToArbitraryLoginServer(msg)); + } + else if(message.isType("NewCharacterCreated")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const ncc(ri); + + CentralServer::getInstance().sendToAllConnectionServers(ncc, true); + } + else if(message.isType("DatabaseConsoleReplyMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > msg(ri); + + IGNORE_RETURN(sendToRandomGameServer(msg)); + } + else if(message.isType("LoginRestoreCharacterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginRestoreCharacterMessage msg(ri); + + IGNORE_RETURN(sendToArbitraryLoginServer(msg)); + } + else if(message.isType("DatabaseConsoleReplyMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > msg(ri); + + IGNORE_RETURN(sendToRandomGameServer(msg)); + } + else if(message.isType("LoginUpgradeAccountMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginUpgradeAccountMessage msg(ri); + + if (msg.getIsAck()) + { + MessageToMessage const reply( + MessageToPayload(msg.getReplyToObject(), NetworkId::cms_invalid, msg.getReplyMessage(), msg.getPackedMessageData(), 0, false, MessageToPayload::DT_c,NetworkId::cms_invalid,std::string(), 0), + 0); + sendToAllGameServers (reply,true); + } + else + { + IGNORE_RETURN(sendToArbitraryLoginServer(msg)); + } + } + else if (message.isType("RandomNameRequest")) + { + GameServerConnection * gameServer = getRandomGameServer(); + if(gameServer) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RandomNameRequest crnr(ri); + gameServer->send(crnr, true); + } + } + else if (message.isType("RandomNameResponse")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RandomNameResponse crnr(ri); + ConnectionServerConnection * conn = getConnectionServerForAccount(crnr.getStationId()); + if (conn) + { + conn->send(crnr, true); + } + else + { + DEBUG_REPORT_LOG(true,("Could not send name to client because unable to determine which connection server to use.\n")); + } + } + else if (message.isType("VerifyAndLockNameRequest")) + { + GameServerConnection * gameServer = getRandomGameServer(); + if(gameServer) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + VerifyAndLockNameRequest valnr(ri); + gameServer->send(valnr, true); + } + } + else if (message.isType("VerifyAndLockNameResponse")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + VerifyAndLockNameResponse valnr(ri); + ConnectionServerConnection * conn = getConnectionServerForAccount(valnr.getStationId()); + if (conn) + { + conn->send(valnr, true); + } + else + { + DEBUG_REPORT_LOG(true,("Could not send name lock response to client because unable to determine which connection server to use.\n")); + } + } + else if (message.isType("RequestOIDsMessage")) + { + DEBUG_REPORT_LOG(true,("Got RequestOIDsMessage.\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RequestOIDsMessage m(ri); + + if (m.getLogRequest()) + LOG("ObjectIdManager", ("Requesting %lu more object ids for pid %lu", m.getHowMany(), m.getServerId())); + + sendToGameServer(m_dbProcessServerProcessId, m, true); + } + else if (message.isType("AddOIDBlockMessage")) + { + DEBUG_REPORT_LOG(true,("Got AddOIDBlockMessage.\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AddOIDBlockMessage m(ri); + + if (m.getLogRequest()) + LOG("ObjectIdManager", ("Returning object ids (%s - %s) for pid %lu", m.getStart().getValueString().c_str(), m.getEnd().getValueString().c_str(), m.getServerId())); + + sendToGameServer(m.getServerId(), m, true); + } + else if (message.isType("LoggedInMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoggedInMessage m (ri); + DEBUG_REPORT_LOG(true, ("Pending character %lu is logging in or dropping\n", m.getAccountNumber())); + + // Once they're logged in, Central doesn't need to know about them anymore: + removeFromAccountConnectionMap(m.getAccountNumber()); + } + + else if (message.isType("CharacterListMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + CharacterListMessage m(ri); + + // Find the client connection and send the character to it. + DEBUG_REPORT_LOG(true,("Got CharacterListMessage for %lu.\n",m.getAccountNumber())); + ConnectionServerConnection *conn = getConnectionServerForAccount(m.getAccountNumber()); + + if (conn) + { + conn->send(m, true); + } + else + { + DEBUG_REPORT_LOG(true,("Warning: received CharacterListMessage for client that is not connected.")); + } + } + else if (message.isType("ValidateCharacterForLoginMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ValidateCharacterForLoginMessage m(ri); + + // ask DBProcess to check whether the character is valid + //pendingCharactersLogin[m.getSuid()] = safe_cast(&source); + if (hasDBConnection()) + sendToDBProcess(m, true); + } + else if (message.isType("ValidateCharacterForLoginReplyMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ValidateCharacterForLoginReplyMessage msg(ri); + + ConnectionServerConnection *conn = getConnectionServerForAccount(msg.getSuid()); + if(conn) + conn->send(msg,true); + else + DEBUG_REPORT_LOG(true,("Trying to handle ValidateCharacterForLoginReplyMessage for account %lu, but could not determine which connection server to use.\n",msg.getSuid())); + } + else if (message.isType("EnableCharacterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::string> > msg(ri); + + LOG("CustomerService", ("EnableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); + // forward this request to LoginServer + IGNORE_RETURN(sendToArbitraryLoginServer(msg)); + } + else if (message.isType("EnableCharacterReplyMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > msg(ri); + GenericValueTypeMessage > reply("DatabaseConsoleReplyMessage", std::make_pair(msg.getValue().first, msg.getValue().second)); + getRandomGameServer()->send(reply, true); + } + else if (message.isType("DisableCharacterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::string> > msg(ri); + + LOG("CustomerService", ("DisableCharacter %d, %s request from %s\n", msg.getValue().first.first, msg.getValue().first.second.getValueString().c_str(), msg.getValue().second.c_str())); + // forward this request to LoginServer + IGNORE_RETURN(sendToArbitraryLoginServer(msg)); + } + else if (message.isType("DisableCharacterReplyMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > msg(ri); + GenericValueTypeMessage > reply("DatabaseConsoleReplyMessage", std::make_pair(msg.getValue().first, msg.getValue().second)); + getRandomGameServer()->send(reply, true); + } + else if(message.isType("TransferReplyLoginLocationData")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage reply(ri); + // If this request has a CS Tool Id associated with it, it is an admin request for the CSTool, + // and so we should send it directly to the connection server, and not depend on a + // transfer server existing. + + if(reply.getValue().getCSToolId() > 0) + { + GenericValueTypeMessage loginMessage("TransferLoginCharacterToSourceServer", reply.getValue()); + ConnectionServerConnection * conn = getAnyConnectionServer(); + if(conn) + { + conn->send(loginMessage, true); + } + return; + } + + LOG("CustomerService", ("CharacterTransfer: Received TransferReplyLoginLocationData from database for character %s\n", reply.getValue().getSourceCharacterName().c_str())); + + if(reply.getValue().getTransferRequestSource() == TransferRequestMoveValidation::TRS_transfer_server) + { + CentralServer::getInstance().sendToTransferServer(reply); + } + else + { + // send character to ConnectionServer for login to a game server + ConnectionServerConnection * connectionServer = CentralServer::getInstance().getAnyConnectionServer(); + if(connectionServer) + { + const GenericValueTypeMessage login("TransferLoginCharacterToSourceServer", reply.getValue()); + connectionServer->send(login, true); + + LOG("CustomerService", ("CharacterTransfer: Sending TransferLoginCharacterToSourceServer to ConnectionServer : %s", login.getValue().toString().c_str())); + } + } + } + else if (message.isType("CentralPlanetServerConnect")) + { + PlanetServerConnection *g = const_cast(safe_cast(&source)); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + CentralPlanetServerConnect msg(ri); + g->setGameServerConnectionData(msg.getConnectionAddress(), msg.getGameServerPort()); + PlanetManager::addServer(msg.getSceneId(), g); + + std::map, time_t> >::iterator f = m_pendingPlanetServers.find(msg.getSceneId()); + if(f != m_pendingPlanetServers.end()) + m_pendingPlanetServers.erase(f); + + IGNORE_RETURN(m_planetServers.insert(std::make_pair(msg.getSceneId(), g))); + + if (isPreloadFinished()) + m_timeClusterWentIntoLoadingState = 0; + else if (m_timeClusterWentIntoLoadingState <= 0) + m_timeClusterWentIntoLoadingState = time(0); + + // handle planet transfers and logins for planet server that aren't up yet + std::vector::iterator t; + for(t = m_messagesWaitingForPlanetServer.begin(); t != m_messagesWaitingForPlanetServer.end();) + { + Archive::ReadIterator tri = t->begin(); + const GameNetworkMessage gnm(tri); + tri = t->begin(); + if(gnm.isType("RequestGameServerForLoginMessage")) + { + const RequestGameServerForLoginMessage loginMessage(tri); + if (loginMessage.getScene() == msg.getSceneId()) + { + t = m_messagesWaitingForPlanetServer.erase(t); + handleRequestGameServerForLoginMessage(loginMessage); + } + } + else if(gnm.isType("RequestSceneTransfer")) + { + const RequestSceneTransfer sceneMessage(tri); + if (sceneMessage.getSceneName() == msg.getSceneId()) + { + t = m_messagesWaitingForPlanetServer.erase(t); + handleRequestSceneTransfer(sceneMessage); + } + } + else + { + t = m_messagesWaitingForPlanetServer.erase(t); + WARNING_STRICT_FATAL(true, ("Unknown message type waiting for planet server")); + } + } + } + else if (message.isType("RequestSceneTransfer")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const RequestSceneTransfer msg (ri); + + handleRequestSceneTransfer(msg); + } + else if (message.isType("SceneTransferMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + SceneTransferMessage msg (ri); + + sendToGameServer(msg.getSourceGameServer(), msg, true); + } + else if (message.isType("GameServerReadyMessage")) + { + GameServerConnection const *g = safe_cast(&source); + UniverseManager::getInstance().onGameServerReady(*g); + } + else if (message.isType("GameServerUniverseLoadedMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const GameServerUniverseLoadedMessage msg(ri); + + // forward to the universe game server as ack that + // the game server who sent this message has received + // its UniverseCompleteMessage from the universe game server + if (msg.getSourceOfUniverseDataProcessId() != getDbProcessServerProcessId()) + sendToGameServer(msg.getSourceOfUniverseDataProcessId(), msg, true); + + CharacterCreationTracker::getInstance().retryGameServerCreates(); + } + else if (message.isType("MessageToMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + MessageToMessage msg(ri); + + WARNING_STRICT_FATAL(true,("CentralServer receieved a messageTo. These should not go to Central anymore. Sender was server %u\n", safe_cast(&source)->getProcessId())); + } + else if (message.isType("MessageToAckMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + MessageToAckMessage msg(ri); + + WARNING_STRICT_FATAL(true,("CentralServer receieved a MessageToAckMessage. These should not go to Central anymore. Sender was server %u\n",safe_cast(&source)->getProcessId())); + } + else if(message.isType("ChatServerConnectionOpened")) + { + // enumerate servers + ChatServerConnection *chatServer = const_cast(safe_cast(&source)); + IGNORE_RETURN(m_chatServerConnections.insert(chatServer)); + const int ct = static_cast(EnumerateServers::CONNECTION_SERVER); + for (ConnectionServerConnectionList::const_iterator ci = m_connectionServerConnections.begin(); ci != m_connectionServerConnections.end(); ++ci) + { + ConnectionServerConnection * c = (*ci); + + if ( (c != NULL) + && !c->getChatServiceAddress().empty() + && (c->getChatServicePort() != 0)) + { + EnumerateServers e(true, c->getChatServiceAddress(), c->getChatServicePort(), ct); + chatServer->send(e, true); + } + else + { + LOG("ChatServer", ("receiveMessage() ChatServerConnectionOpened - Invalid connection address in m_connectionServerConnections, skipping entry")); + } + } + + // Tell the single chat server the address to communicate with the customer service server + + if (!s_customerServiceServerChatServerServiceAddress.first.empty()) + { + //DEBUG_REPORT_LOG(true, ("CentralServer::receiveMessage(ChatServerConnectionOpened)\n")); + + const GenericValueTypeMessage > msg("CustomerServiceServerChatServerServiceAddress", std::make_pair(s_customerServiceServerChatServerServiceAddress.first, s_customerServiceServerChatServerServiceAddress.second)); + + chatServer->send(msg, true); + } + } + else if (message.isType("CustomerServiceServerChatServerServiceAddress")) + { + //DEBUG_REPORT_LOG(true, ("CentralServer::receiveMessage(CustomerServiceServerChatServerServiceAddress)\n")); + + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const GenericValueTypeMessage > address(ri); + + s_customerServiceServerChatServerServiceAddress.first = address.getValue().first; + s_customerServiceServerChatServerServiceAddress.second = address.getValue().second; + + // Tell the chat servers the address to communicate with the customer service server + + std::set::iterator iterChatServerConnections = m_chatServerConnections.begin(); + + for (; iterChatServerConnections != m_chatServerConnections.end(); ++iterChatServerConnections) + { + ChatServerConnection *connection = (*iterChatServerConnections); + + if (connection != NULL) + { + connection->send(address, true); + } + else + { + REPORT_LOG(true, ("Trying to send the customer service server: chat server service address to a NULL chat server\n")); + } + } + } + else if (message.isType("CustomerServiceConnectionOpened")) + { + CustomerServiceConnection *csServer = const_cast(safe_cast(&source)); + IGNORE_RETURN(m_csServerConnections.insert(csServer)); + const int ct = static_cast(EnumerateServers::CONNECTION_SERVER); + for (ConnectionServerConnectionList::const_iterator ci = m_connectionServerConnections.begin(); ci != m_connectionServerConnections.end(); ++ci) + { + ConnectionServerConnection * c = (*ci); + + if ( (c != NULL) + && !c->getCustomerServiceAddress().empty() + && (c->getCustomerServicePort() != 0)) + { + EnumerateServers e(true, c->getCustomerServiceAddress(), c->getCustomerServicePort(), ct); + csServer->send(e, true); + } + else + { + LOG("CustServ", ("receiveMessage() CustomerServiceConnectionOpened - Invalid connection address in m_connectionServerConnections, skipping entry")); + } + } + } + else if(message.isType("ChatServerConnectionClosed")) + { + ChatServerConnection *chatServer = const_cast(safe_cast(&source)); + IGNORE_RETURN(m_chatServerConnections.erase(chatServer)); + + // spawn a new chat server! + std::string options = "-s ChatServer centralServerAddress="; + if(CentralServer::getInstance().getChatService()) + { + options += CentralServer::getInstance().getChatService()->getBindAddress(); + } + else + { + options += NetworkHandler::getHostName(); + } + + options += " clusterName="; + options += ConfigCentralServer::getClusterName(); + TaskSpawnProcess pc(ConfigCentralServer::getChatServerHost(), "ChatServer", options, ConfigCentralServer::getChatServerRestartDelayTimeSeconds()); + CentralServer::getInstance().sendTaskMessage(pc); + + } + else if (message.isType("CustomerServiceConnectionClosed")) + { + CustomerServiceConnection *csServer = const_cast(safe_cast(&source)); + IGNORE_RETURN(m_csServerConnections.erase(csServer)); + + // spawn a new cs server! + std::string options = "-s CustomerServiceServer centralServerAddress="; + if(CentralServer::getInstance().getCustomerService()) + { + options += CentralServer::getInstance().getCustomerService()->getBindAddress(); + } + else + { + options += NetworkHandler::getHostName(); + } + + options += " clusterName="; + options += ConfigCentralServer::getClusterName(); + TaskSpawnProcess pc("any", "CustomerServiceServer", options); + CentralServer::getInstance().sendTaskMessage(pc); + } + else if(message.isType("ChatServerOnline")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ChatServerOnline cso (ri); + ChatServerConnection *csc = const_cast(safe_cast(&source)); + csc->setGameServicePort(cso.getPort()); + SceneGameMap::const_iterator iter; + for(iter = m_gameServers.begin(); iter != m_gameServers.end(); ++iter) + { + GameServerConnection * conn = (*iter).second; + conn->send(cso, true); + } + + } + else if (message.isType("RequestGameServerForLoginMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const RequestGameServerForLoginMessage msg(ri); + + time_t const timeNow = ::time(NULL); + PlayerSceneMapType::const_iterator i = m_playerSceneMap.find(msg.getCharacterId()); + if ((i != m_playerSceneMap.end()) && (i->second.second > timeNow)) + { + ServerConnection * c = const_cast(safe_cast(&source)); + GenericValueTypeMessage > const loginDeniedRecentCTS("LoginDeniedRecentCTS", std::make_pair(msg.getCharacterId(), msg.getStationId())); + c->send(loginDeniedRecentCTS, true); + } + else + { + std::map >::const_iterator const iterFind = s_pendingRenameCharacter.find(msg.getCharacterId()); + if ((iterFind != s_pendingRenameCharacter.end()) && (iterFind->second.first > timeNow)) + { + ServerConnection * c = const_cast(safe_cast(&source)); + GenericValueTypeMessage > const loginDeniedPendingPlayerRenameRequest("LoginDeniedPendingPlayerRenameRequest", std::make_pair(msg.getCharacterId(), msg.getStationId())); + c->send(loginDeniedPendingPlayerRenameRequest, true); + } + else + { + handleRequestGameServerForLoginMessage(msg); + } + } + } + else if (message.isType("GameServerForLoginMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GameServerForLoginMessage msg(ri); + + handleGameServerForLoginMessage(msg); + } + + + + else if (message.isType("ExchangeListCreditsMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ExchangeListCreditsMessage msg(ri); + + handleExchangeListCreditsMessage(msg); + } + + + + else if (message.isType("PlanetLoadCharacterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + PlanetLoadCharacterMessage msg(ri); + + // let all the game servers know we are about to load a character from the DB + GenericValueTypeMessage > const aboutToLoadCharacterFromDB("AboutToLoadCharacterFromDB", std::make_pair(msg.getCharacterId(), msg.getGameServerId())); + sendToAllGameServersExceptDBProcess(aboutToLoadCharacterFromDB, true); + + sendToDBProcess(msg,true); + } + else if (message.isType("ConnSrvDropDupeConns")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + // A ConnectionServer has received and validated a new connection from the client + + // request that all other ConnectionServers drop any existing connection(s) for the account + std::string galaxyConnectionInfo = "("; + galaxyConnectionInfo += ConfigCentralServer::getClusterName(); + + if (!msg.getValue().second.empty()) + { + galaxyConnectionInfo += ", "; + galaxyConnectionInfo += msg.getValue().second; + } + + galaxyConnectionInfo += ")"; + + GenericValueTypeMessage > const dropDuplicateConnections("CntrlSrvDropDupeConns", std::make_pair(msg.getValue().first, galaxyConnectionInfo)); + sendToAllConnectionServers(dropDuplicateConnections, true, dynamic_cast(&source)); + + // request (via LoginServer) that all ConnectionServers on all other galaxies drop any existing connection(s) for the account + if (ConfigCentralServer::getDisconnectDuplicateConnectionsOnOtherGalaxies()) + IGNORE_RETURN(sendToArbitraryLoginServer(dropDuplicateConnections)); + } + else if (message.isType("CntrlSrvDropDupeConns")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + // request that all ConnectionServers drop any existing connection(s) for the account + sendToAllConnectionServers(msg, true); + } + else if (message.isType("PlayerDroppedFromGameServerCrash")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const m(ri); + + std::set::const_iterator const end = m.getValue().end(); + for (std::set::const_iterator iter = m.getValue().begin(); iter != end; ++iter) + { + IGNORE_RETURN(m_playerSceneMap.erase(*iter)); + LOG("TRACE_LOGIN", ("Forgetting sceneId (because of game server crash) for character (%s) -- will query the database on next login", iter->getValueString().c_str())); + } + } + else if (message.isType("ServerDeleteCharacterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + LoginServerConnection const *l = safe_cast(&source); + ServerDeleteCharacterMessage msg(ri); + msg.setLoginServerId(l->getProcessId()); + + if (hasDBConnection()) + { + LOG("CustomerService", ("Player:deleted character %s for stationId %u", msg.getCharacterId().getValueString().c_str(), msg.getStationId())); + sendToDBProcess(msg,true); + + // let the game servers know that the character is being deleted + GenericValueTypeMessage const msg2("DeleteCharacterNotificationMessage", msg.getCharacterId()); + IGNORE_RETURN(sendToRandomGameServer(msg2)); + } + } + else if (message.isType("UpdatePlayerCountMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + UpdatePlayerCountMessage msg(ri); + + ConnectionServerConnection * csc = const_cast(dynamic_cast(&source)); + if (csc) + { + // Update our stored values for the connection server + csc->setPlayerCount(msg.getCount()); + csc->setFreeTrialCount(msg.getFreeTrialCount()); + csc->setEmptySceneCount(msg.getEmptySceneCount()); + csc->setTutorialSceneCount(msg.getTutorialSceneCount()); + csc->setFalconSceneCount(msg.getFalconSceneCount()); + + // Update the login server with the new values + UpdateLoginConnectionServerStatus ulc(csc->getId(), csc->getClientServicePortPublic(), csc->getClientServicePortPrivate(), msg.getCount()); + sendToAllLoginServers(ulc); + + // Update the login servers with new population values + sendPopulationUpdateToLoginServer(); + } + else + { + WARNING_STRICT_FATAL(true,("Got UpdatePlayerCountMessage from something that wasn't a ConnectionServer.\n")); + } + } + else if (message.isType("ValidateAccountMessage")) + { + DEBUG_REPORT_LOG(true,("ValidateAccountMessage\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ValidateAccountMessage msg(ri); + + // Store the connection information for the account + addToAccountConnectionMap(msg.getStationId(), const_cast(dynamic_cast(&source)), msg.getSubscriptionBits()); + + // Pass the validation to a LoginServer + IGNORE_RETURN(sendToArbitraryLoginServer(msg)); + } + else if (message.isType("ValidateAccountReplyMessage")) + { + DEBUG_REPORT_LOG(true,("ValidateAccountReplyMessage\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ValidateAccountReplyMessage msg(ri); + + ConnectionServerConnection *conn=getConnectionServerForAccount(msg.getStationId()); + if (conn) + { + conn->send(msg,true); + } + } + else if (message.isType("PreloadRequestCompleteMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + PreloadRequestCompleteMessage msg(ri); + + sendToDBProcess(msg,true); + } + else if (message.isType("ReconnectToTransferServer")) + { + if(ConfigCentralServer::getTransferServerPort()) + { + if(! getInstance().m_transferServerConnection) + { + getInstance().m_transferServerConnection = new TransferServerConnection(ConfigCentralServer::getTransferServerAddress(), ConfigCentralServer::getTransferServerPort()); + s_retryTransferServerConnection = true; + } + } + } + else if (message.isType("ReconnectToStationPlayersCollector")) + { + if(ConfigCentralServer::getStationPlayersCollectorPort()) + { + if(! getInstance().m_stationPlayersCollectorConnection) + { + getInstance().m_stationPlayersCollectorConnection = new StationPlayersCollectorConnection(ConfigCentralServer::getStationPlayersCollectorAddress(), ConfigCentralServer::getStationPlayersCollectorPort()); + s_retryStationPlayersCollectorConnection = true; + } + } + } + else if (message.isType("PreloadFinishedMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + PreloadFinishedMessage msg(ri); + + const PlanetServerConnection *conn=dynamic_cast(&source); + WARNING_STRICT_FATAL(!conn,("Programmer bug: got PreloadFinishedMessaage from something that wasn't a PlanetServer.\n")); + if (conn) + { + if (msg.getFinished()) + { + IGNORE_RETURN(m_planetsWaitingForPreload.erase(conn->getSceneId())); + if (isPreloadFinished()) + { + m_timeClusterWentIntoLoadingState = 0; + + DEBUG_REPORT_LOG(true,("Preload finished on all planets.\n")); + + // record how long it took the cluster to come up + if (m_clusterStartupTime == -1) + { + m_clusterStartupTime = static_cast(time(0) - m_timeClusterStarted) / 60; + + // let all the game servers know that the cluster has completed its initial startup + GenericValueTypeMessage clusterStartComplete("ClusterStartComplete", true); + sendToAllGameServersExceptDBProcess(clusterStartComplete, true); + } + else + { + // let all the game servers know that the cluster has recovered from a crash + GenericValueTypeMessage clusterStartComplete("ClusterStartComplete", false); + sendToAllGameServersExceptDBProcess(clusterStartComplete, true); + } + + sendToAllLoginServers(msg); + sendTaskMessage(msg); + m_lastLoadingStateTime=time(0); + // connect to the character transfer server + if(ConfigCentralServer::getTransferServerPort()) + { + if(! getInstance().m_transferServerConnection) + { + getInstance().m_transferServerConnection = new TransferServerConnection(ConfigCentralServer::getTransferServerAddress(), ConfigCentralServer::getTransferServerPort()); + s_retryTransferServerConnection = true; + } + } + + // connect to the station players collector + if(ConfigCentralServer::getStationPlayersCollectorPort()) + { + if(! getInstance().m_stationPlayersCollectorConnection) + { + getInstance().m_stationPlayersCollectorConnection = new StationPlayersCollectorConnection(ConfigCentralServer::getStationPlayersCollectorAddress(), ConfigCentralServer::getStationPlayersCollectorPort()); + s_retryStationPlayersCollectorConnection = true; + } + } + } + else if (m_timeClusterWentIntoLoadingState <= 0) + { + m_timeClusterWentIntoLoadingState = time(0); + } + } + else + { + if(getInstance().m_transferServerConnection != NULL) + { + getInstance().m_transferServerConnection->disconnect(); + getInstance().m_transferServerConnection = 0; + s_retryTransferServerConnection = false; + } + + if(getInstance().m_stationPlayersCollectorConnection != NULL) + { + getInstance().m_stationPlayersCollectorConnection->disconnect(); + getInstance().m_stationPlayersCollectorConnection = 0; + s_retryStationPlayersCollectorConnection = false; + } + + + IGNORE_RETURN(m_planetsWaitingForPreload.insert(conn->getSceneId())); + + if (isPreloadFinished()) + m_timeClusterWentIntoLoadingState = 0; + else if (m_timeClusterWentIntoLoadingState <= 0) + m_timeClusterWentIntoLoadingState = time(0); + + + sendToAllLoginServers(msg); + sendTaskMessage(msg); + } + } + } + else if (message.isType("RenameCharacterMessageEx")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RenameCharacterMessageEx msg(ri); + + IGNORE_RETURN(sendToArbitraryLoginServer(RenameCharacterMessage(msg.getCharacterId(), msg.getNewName(), msg.getRequestedBy()))); + + // if the player requested the rename, also rename the chat avatar, so mail, friends list, and ignore list will migrate + if ((msg.getRenameCharacterMessageSource() == RenameCharacterMessageEx::RCMS_player_request) && !msg.getLastNameChangeOnly() && !ConfigFile::getKeyBool("CharacterRename", "disableRenameChatAvatar", false)) + { + broadcastToChatServers(msg); + } + } + else if (message.isType("PlayerRenameRequestSubmitted")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > > const msg(ri); + + GenericValueTypeMessage kick("TransferKickConnectedClients", msg.getValue().first); + CentralServer::getInstance().sendToAllLoginServers(kick); + CentralServer::getInstance().sendToAllConnectionServers(kick, true); + + // update the list of pending rename requests, to prevent a character with a pending rename request from logging in + std::map >::iterator const iterFind = s_pendingRenameCharacter.find(msg.getValue().second.first); + if (iterFind != s_pendingRenameCharacter.end()) + { + ++(iterFind->second.second); + iterFind->second.first = ::time(NULL) + 3600; // 1 hour timeout + } + else + { + s_pendingRenameCharacter.insert(std::make_pair(msg.getValue().second.first, std::make_pair((::time(NULL) + 3600), 1))); // 1 hour timeout + } + + // tell the chat server to destroy any avatar with the new name, but only if the first name changed + if (!msg.getValue().second.second.second) + { + GenericValueTypeMessage const chatDestroyAvatar("ChatDestroyAvatar", msg.getValue().second.second.first); + broadcastToChatServers(chatDestroyAvatar); + } + } + else if (message.isType("PlayerRenameRequestCompleted")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + // update the list of pending rename requests, to prevent a character with a pending rename request from logging in + std::map >::iterator const iterFind = s_pendingRenameCharacter.find(msg.getValue().second); + if (iterFind != s_pendingRenameCharacter.end()) + { + if (iterFind->second.second <= 1) + s_pendingRenameCharacter.erase(iterFind); + else + --(iterFind->second.second); + } + } + else if(message.isType("SetConnectionServerPublic")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + SetConnectionServerPublic msg(ri); + if(msg.getIsPublic()) + gs_connectionServersPublic = true; + else + gs_connectionServersPublic = false; + + sendToAllConnectionServers(msg, true); + } + else if(message.isType("ProfilerOperationMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ProfilerOperationMessage msg(ri); + sendToAllGameServers(msg, true); + sendToAllPlanetServers(msg, true); + sendToAllConnectionServers(msg, true); + } + else if (message.isType("PopulationListMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + PopulationListMessage msg(ri); + sendToAllGameServers(msg, true); + } + else if (message.isType("CentralPingMessage")) + { + GameServerConnection const *g = safe_cast(&source); + NOT_NULL(g); + LOG("CentralServerPings",("Got reply from %lu",g->getProcessId())); + IGNORE_RETURN(m_serverPings.erase(g->getProcessId())); + } + else if (message.isType("DatabaseBackloggedMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage dbbacklog(ri); + + m_databaseBacklogged = dbbacklog.getValue(); + bool const preloadFinished = isPreloadFinished(); + + if (preloadFinished) + m_timeClusterWentIntoLoadingState = 0; + else if (m_timeClusterWentIntoLoadingState <= 0) + m_timeClusterWentIntoLoadingState = time(0); + + PreloadFinishedMessage msg(preloadFinished); + sendToAllLoginServers(msg); + sendTaskMessage(msg); + } + + else if (message.isType("DatabaseSaveStart")) + { + LOG("CentralServer",("Received DatabaseSaveStart network message.")); + if( m_shutdownPhase == 4 ) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Setting indicator for receipt of DatabaseSaveStart.", m_shutdownPhase)); + m_shutdownHaveDatabaseSaveStart = true; + checkShutdownProcess(); + } + else if( m_shutdownPhase == 5 && m_shutdownHaveDatabaseSaveStart) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Setting indicator that final database save cycle is complete.", m_shutdownPhase)); + m_shutdownHaveDatabaseComplete = true; + checkShutdownProcess(); + } + } + else if (message.isType("DatabaseSaveComplete")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + LOG("CentralServer",("Received DatabaseSaveComplete network message.")); + + // tell all the Planet Servers that the save finished + sendToAllPlanetServers(msg,true); + + // don't want to indicate this yet until we are at the beginning of a full cycle + if( m_shutdownPhase == 5 && m_shutdownHaveDatabaseSaveStart) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Setting indicator that final database save cycle is complete.", m_shutdownPhase)); + m_shutdownHaveDatabaseComplete = true; + checkShutdownProcess(); + } + } + else if (message.isType("PlanetRequestSave")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GameNetworkMessage msg(ri); + + sendToDBProcess(msg,true); + } + else if (message.isType("ShutdownCluster")) + { + LOG("CentralServerShutdown",("Received ShutdownCluster network message.")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ShutdownCluster m(ri); + startShutdownProcess(m.getTimeToShutdown(), m.getMaxTime(), m.getSystemMessage()); + } + else if (message.isType("AbortShutdown")) + { + LOG("CentralServerShutdown",("Received AbortShutdown network message.")); + abortShutdownProcess(); + } + + + else if (message.isType("SetSceneForPlayer")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > ssfp(ri); + + if (ssfp.getValue().second.first.empty()) + { + static const std::string loginTrace("TRACE_LOGIN"); + + IGNORE_RETURN(m_playerSceneMap.erase(ssfp.getValue().first)); + LOG(loginTrace, ("Forgetting sceneId for character (%s) -- will query the database on next login", ssfp.getValue().first.getValueString().c_str())); + } + else + { + PlayerSceneMapType::iterator i = m_playerSceneMap.find(ssfp.getValue().first); + if (i != m_playerSceneMap.end()) + { + i->second.first = ssfp.getValue().second.first; + if (ssfp.getValue().second.second) + i->second.second = ::time(NULL) + static_cast(ConfigCentralServer::getCtsDenyLoginThresholdSeconds()); + } + else + { + m_playerSceneMap[ssfp.getValue().first]=std::make_pair(ssfp.getValue().second.first, (ssfp.getValue().second.second ? (::time(NULL) + static_cast(ConfigCentralServer::getCtsDenyLoginThresholdSeconds())) : 0)); + } + } + } + + else if (message.isType("TaskProcessDiedMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + TaskProcessDiedMessage died(ri); + LOG("TaskProcessDied", ("received TaskProcessDied for %s:%i", died.getProcessName().c_str(), died.getProcessId()));; + if(died.getProcessName().find("SwgGameServer") != std::string::npos) + { + LOG("TaskProcessDied", ("Dead process %i is a game server", died.getProcessId())); + // extract sceneId + size_t pos = died.getProcessName().find("sceneID="); + if(pos != std::string::npos) + { + pos += std::string("sceneID=").length(); + size_t end = died.getProcessName().find_first_of(' ', pos); + if(end != std::string::npos) + { + std::string scene = died.getProcessName().substr(pos, end - pos); + LOG("TaskProcessDied", ("Dead game server process %i was running sceneID %s, advising planet server", died.getProcessId(), scene.c_str())); + std::map::iterator f = m_planetServers.find(scene); + if(f != m_planetServers.end()) + { + f->second->send(died, true); + } + } + } + } + } + else if (message.isType("SystemTimeMismatchNotification")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + + m_lastTimeSystemTimeMismatchNotification = time(0); + m_lastTimeSystemTimeMismatchNotificationDescription = msg.getValue(); + } + else if (message.isType("DisconnectedTaskManagerMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + + m_disconnectedTaskManagerList = msg.getValue(); + } + else if(message.isType("TransferServerConnectionClosed")) + { + // connect to the character transfer server + if(ConfigCentralServer::getTransferServerPort()) + { + if(s_retryTransferServerConnection) + { + getInstance().m_transferServerConnection = new TransferServerConnection(ConfigCentralServer::getTransferServerAddress(), ConfigCentralServer::getTransferServerPort()); + } + } + } + else if(message.isType("StationPlayersCollectorConnectionClosed")) + { + // connect to the station players collector + if(ConfigCentralServer::getStationPlayersCollectorPort()) + { + if(s_retryStationPlayersCollectorConnection) + { + getInstance().m_stationPlayersCollectorConnection = new StationPlayersCollectorConnection(ConfigCentralServer::getStationPlayersCollectorAddress(), ConfigCentralServer::getStationPlayersCollectorPort()); + } + } + } + else if(message.isType("ClaimRewardsMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ClaimRewardsMessage msg(ri); + sendToArbitraryLoginServer(msg); + } + else if(message.isType("ClaimRewardsReplyMessage")) + { + DEBUG_REPORT_LOG(true,("Central got ClaimRewardsReplyMessage\n")); + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ClaimRewardsReplyMessage msg(ri); + sendToGameServer(msg.getGameServer(), msg, true); + } + else if (message.isType("PurgeStructuresForAccountMessage") || message.isType("WarnStructuresAboutPurgeMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + LoginServerConnection const * l = dynamic_cast(&source); + if (l) + { + m_purgeAccountToLoginServerMap[msg.getValue()]= l->getProcessId(); // remember which login server is handling this purge + sendToDBProcess(msg, true); + } + } + else if (message.isType("PurgeCompleteMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + + std::map::iterator i=m_purgeAccountToLoginServerMap.find(msg.getValue()); + if (i!=m_purgeAccountToLoginServerMap.end()) + { + sendToLoginServer(i->second,msg); + m_purgeAccountToLoginServerMap.erase(i); + } + } + else if (message.isType("RestartServerMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RestartServerMessage msg(ri); + + sendToPlanetServer(msg.getScene(), msg, true); + } + else if (message.isType("RestartServerByRoleMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > msg(ri); + + sendToPlanetServer(msg.getValue().first, msg, true); + } + else if (message.isType("ExcommunicateGameServerMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ExcommunicateGameServerMessage msg(ri); + + excommunicateServer(msg); + } + else if (message.isType("RestartPlanetMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + + GenericValueTypeMessage const shutdownMsg("ShutdownMessage", 0); + sendToPlanetServer(msg.getValue(),shutdownMsg, true); + } + else if (message.isType("UpdateClusterLockedAndSecretState")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + gs_clusterIsLocked = msg.getValue().first; + gs_clusterIsSecret = msg.getValue().second; + } + else if (message.isType("PopStatRsp")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + m_timePopulationStatisticsRefresh = ::time(NULL); + m_populationStatistics = msg.getValue(); + } + else if (message.isType("GcwScoreStatRsp")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair >, std::map > > > > const msg(ri); + + m_timeGcwScoreStatisticsRefresh = ::time(NULL); + std::string const timeGcwScoreStatisticsRefreshStr = CalendarTime::convertEpochToTimeStringLocal(m_timeGcwScoreStatisticsRefresh); + + std::map const & gcwImperialScorePercentile = msg.getValue().first; + std::map > const & gcwImperialScore = msg.getValue().second.first; + std::map > const & gcwRebelScore = msg.getValue().second.second; + std::map >::const_iterator iterFind; + std::map::const_iterator iterFindImperialScorePercentile; + std::pair > >::iterator, bool> iterInsertion; + int imperialScorePercentile; + std::string scoreText, scoreTextDesc; + + for (std::map >::const_iterator iterImp = gcwImperialScore.begin(); iterImp != gcwImperialScore.end(); ++iterImp) + { + iterFindImperialScorePercentile = gcwImperialScorePercentile.find(iterImp->first); + if (iterFindImperialScorePercentile != gcwImperialScorePercentile.end()) + imperialScorePercentile = iterFindImperialScorePercentile->second; + else + imperialScorePercentile = 0; + + iterFind = gcwRebelScore.find(iterImp->first); + if (iterFind != gcwRebelScore.end()) + scoreText = FormattedString<1024>().sprintf("Imp (%s, %s) Reb (%s, %s) - ", NetworkId(iterImp->second.first).getValueString().c_str(), NetworkId(iterImp->second.second).getValueString().c_str(), NetworkId(iterFind->second.first).getValueString().c_str(), NetworkId(iterFind->second.second).getValueString().c_str()); + else + scoreText = FormattedString<1024>().sprintf("Imp (%s, %s) Reb (0, 0) - ", NetworkId(iterImp->second.first).getValueString().c_str(), NetworkId(iterImp->second.second).getValueString().c_str()); + + scoreTextDesc = scoreText + timeGcwScoreStatisticsRefreshStr; + + iterInsertion = m_gcwScoreStatistics.insert(std::make_pair("gcwScore." + iterImp->first, std::make_pair(imperialScorePercentile, std::make_pair(scoreText, scoreTextDesc)))); + if (!iterInsertion.second) + { + if (iterInsertion.first->second.second.first != scoreText) + { + iterInsertion.first->second.first = imperialScorePercentile; + iterInsertion.first->second.second.first = scoreText; + iterInsertion.first->second.second.second = scoreTextDesc; + } + } + } + + for (std::map >::const_iterator iterReb = gcwRebelScore.begin(); iterReb != gcwRebelScore.end(); ++iterReb) + { + iterFind = gcwImperialScore.find(iterReb->first); + if (iterFind == gcwImperialScore.end()) + { + iterFindImperialScorePercentile = gcwImperialScorePercentile.find(iterReb->first); + if (iterFindImperialScorePercentile != gcwImperialScorePercentile.end()) + imperialScorePercentile = iterFindImperialScorePercentile->second; + else + imperialScorePercentile = 0; + + scoreText = FormattedString<1024>().sprintf("Imp (0, 0) Reb (%s, %s) - ", NetworkId(iterReb->second.first).getValueString().c_str(), NetworkId(iterReb->second.second).getValueString().c_str()); + scoreTextDesc = scoreText + timeGcwScoreStatisticsRefreshStr; + + iterInsertion = m_gcwScoreStatistics.insert(std::make_pair("gcwScore." + iterReb->first, std::make_pair(imperialScorePercentile, std::make_pair(scoreText, scoreTextDesc)))); + if (!iterInsertion.second) + { + if (iterInsertion.first->second.second.first != scoreText) + { + iterInsertion.first->second.first = imperialScorePercentile; + iterInsertion.first->second.second.first = scoreText; + iterInsertion.first->second.second.second = scoreTextDesc; + } + } + } + } + } + else if (message.isType("LLTStatRsp")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage >, std::map > > > const msg(ri); + + m_timeLastLoginTimeStatisticsRefresh = ::time(NULL); + m_lastLoginTimeStatistics = msg.getValue().first; + m_createTimeStatistics = msg.getValue().second; + } + else if (message.isType("LfgStatRsp")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > const msg(ri); + + m_numberOfCharacterMatchRequests += msg.getValue().first; + m_numberOfCharacterMatchResults += msg.getValue().second.first; + m_timeSpentOnCharacterMatchRequestsMs += msg.getValue().second.second; + } + else if (message.isType("OccupyUnlockedSlotRsp")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, uint32> > const occupyUnlockedSlotRsp(ri); + + // CS log the response + LoginUpgradeAccountMessage::OccupyUnlockedSlotResponse const response = static_cast(occupyUnlockedSlotRsp.getValue().first.first); + if (response == LoginUpgradeAccountMessage::OUSR_success) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request SUCCESS", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::OUSR_db_error) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - internal db error", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unlocked_slot) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - account doesn't have an unlocked slot", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unoccupied_unlocked_slot) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - account has no unoccupied unlocked slot", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::OUSR_cluster_already_has_unlocked_slot_character) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - cluster already has an unlocked slot character", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else + { + LOG("CustomerService",("JediUnlockedSlot:Player %s OccupyUnlockedSlot request FAILED - unknown result code (%d)", occupyUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), occupyUnlockedSlotRsp.getValue().first.first)); + } + + GameServerConnection * gs = getGameServer(occupyUnlockedSlotRsp.getValue().second); + if (!gs) + gs = getRandomGameServer(); + + if (gs) + gs->send(occupyUnlockedSlotRsp, true); + } + else if (message.isType("VacateUnlockedSlotRsp")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > const vacateUnlockedSlotRsp(ri); + + // CS log the response + LoginUpgradeAccountMessage::VacateUnlockedSlotResponse const response = static_cast(vacateUnlockedSlotRsp.getValue().first.first); + if (response == LoginUpgradeAccountMessage::VUSR_success) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request SUCCESS", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + + // to safeguard against any sort of timing exploit to create another normal + // slot character while this one is being converted to normal, thus allowing + // the account to have more normal slot characters on this cluster than is + // allowed, make it look like a normal character has been created on this + // account on this cluster, and that mechanism will prevent such an exploit + + // let all connection servers know that a new character has been created for the station account + GenericValueTypeMessage const ncc("NewCharacterCreated", static_cast(vacateUnlockedSlotRsp.getValue().second.first)); + CentralServer::getInstance().sendToAllConnectionServers(ncc, true); + } + else if (response == LoginUpgradeAccountMessage::VUSR_db_error) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - internal db error", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::VUSR_account_has_no_unlocked_slot) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - account doesn't have an unlocked slot", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::VUSR_not_unlocked_slot_character) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - character is not an unlocked slot character", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::VUSR_no_available_normal_character_slot) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - no available normal character slot for the account on this galaxy", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str())); + } + else + { + LOG("CustomerService",("JediUnlockedSlot:Player %s VacateUnlockedSlot request FAILED - unknown result code (%d)", vacateUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), vacateUnlockedSlotRsp.getValue().first.first)); + } + + GameServerConnection * gs = getGameServer(vacateUnlockedSlotRsp.getValue().second.second); + if (!gs) + gs = getRandomGameServer(); + + if (gs) + gs->send(vacateUnlockedSlotRsp, true); + } + else if (message.isType("SwapUnlockedSlotRsp")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > > const swapUnlockedSlotRsp(ri); + + // CS log the response + LoginUpgradeAccountMessage::SwapUnlockedSlotResponse const response = static_cast(swapUnlockedSlotRsp.getValue().first.first); + if (response == LoginUpgradeAccountMessage::SUSR_success) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s (%s) request SUCCESS", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.second.c_str())); + } + else if (response == LoginUpgradeAccountMessage::SUSR_db_error) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - internal db error", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::SUSR_account_has_no_unlocked_slot) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - account doesn't have an unlocked slot", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::SUSR_not_unlocked_slot_character) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - source character is not an unlocked slot character", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::SUSR_invalid_target_character) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - target character is either not valid, not on the same account, or not on this galaxy", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + } + else if (response == LoginUpgradeAccountMessage::SUSR_target_character_already_unlocked_slot_character) + { + LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - target character is already an unlocked slot character", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + } + else + { + LOG("CustomerService",("JediUnlockedSlot:Player %s SwapUnlockedSlot with %s request FAILED - unknown result code (%d)", swapUnlockedSlotRsp.getValue().first.second.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().first.first)); + } + + GameServerConnection * gs = getGameServer(swapUnlockedSlotRsp.getValue().second.first); + if (!gs) + gs = getRandomGameServer(); + + if (gs) + gs->send(swapUnlockedSlotRsp, true); + } + else if (message.isType("AdjustAccountFeatureIdResponse")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AdjustAccountFeatureIdResponse const msg(ri); + + GameServerConnection * gs = getGameServer(msg.getGameServer()); + if (!gs) + gs = getRandomGameServer(); + + if (gs) + gs->send(msg, true); + } + else if (message.isType("AccountFeatureIdResponse")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AccountFeatureIdResponse const msg(ri); + + GameServerConnection * gs = getGameServer(msg.getGameServer()); + if (!gs) + gs = getRandomGameServer(); + + if (gs) + gs->send(msg, true); + } + else if (message.isType("FeatureIdTransactionResponse")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + FeatureIdTransactionResponse const msg(ri); + + GameServerConnection * gs = getGameServer(msg.getGameServer()); + if (!gs) + gs = getRandomGameServer(); + + if (gs) + gs->send(msg, true); + } + else if(ClusterWideDataManagerList::handleMessage(source, message)) + { + // nothing else to do with the message since it was + // handled by the Cluster wide data manager + } +} + +//----------------------------------------------------------------------- +void CentralServer::removeConnectionServerConnection(const ConnectionServerConnection * conn) +{ + DEBUG_REPORT_LOG(true, ("Removing connection server connection\n")); + if (conn) + { + startConnectionServer(conn->getConnectionServerNumber(), + conn->getGameServiceAddress(), + conn->getClientServicePortPublic(), + conn->getClientServicePortPrivate(), true, + ConfigCentralServer::getConnectionServerRestartDelayTimeSeconds()); + + ConnectionServerConnectionList::iterator i = m_connectionServerConnections.begin(); + for(;i != m_connectionServerConnections.end();++i) + { + if (conn->getId() == (*i)->getId()) + { + ConnectionServerDown c((*i)->getId()); + sendToAllLoginServers(c); + IGNORE_RETURN(m_connectionServerConnections.erase(i)); + return; + } + + } + + // Clean up all the account info for the connection + removeFromAccountConnectionMap(conn->getId()); + } +} +//----------------------------------------------------------------------- +/** +* Removes all references to a game server from the server. +* +* @param gameServer the game server connection to remove +*/ +void CentralServer::removeGameServer(GameServerConnection const *gameServer) +{ + uint32 const pid = gameServer->getProcessId(); + + LOG("ServerStartup", ("Game Server %lu went down", pid)); + + //@todo this whole function needs a re-write. + NOT_NULL(gameServer); + std::map::iterator const i = m_gameServerConnections.find(pid); + if (i == m_gameServerConnections.end()) + return; + + for (std::vector::iterator ii = m_gameServerConnectionsList.begin(); ii != m_gameServerConnectionsList.end();) + { + if ((*ii) == i->second) + ii = m_gameServerConnectionsList.erase(ii); + else + ++ii; + } + + m_gameServerConnections.erase(i); + + /** @todo: this is slow, find a better way (probably by creating reverse + * lookup table(s)) + */ + if (pid == m_dbProcessServerProcessId) + { + DEBUG_REPORT_LOG(true, ("Database process died -- Central will exit and let the cluster restart\n")); + m_done = true; + return; //lint !e527 Unreachable + } + + DEBUG_WARNING(true, ("Game server %lu crashed", pid)); + + for (SceneGameMap::iterator j = m_gameServers.begin(); j != m_gameServers.end();) + { + if ((*j).second == gameServer) + m_gameServers.erase(j++); + else + ++j; + } + + UniverseManager::getInstance().onGameServerDisconnect(*gameServer); + PlanetManager::onGameServerDisconnect(gameServer); + CharacterCreationTracker::getInstance().onGameServerDisconnect(pid); + ClusterWideDataManagerList::onGameServerDisconnect(pid); + + ExcommunicateGameServerMessage const excommunicateMessage(pid, 0, ""); + sendToAllGameServersExceptDBProcess(excommunicateMessage, true); +} + +//----------------------------------------------------------------------- + +void CentralServer::done() +{ + getInstance().m_done = true; +} + +//----------------------------------------------------------------------- + +void CentralServer::run(void) +{ + SetupSharedLog::install("CentralServer"); + SetupSharedUtility::Data utilityData; + SetupSharedUtility::install (utilityData); + SetupServerUtility::install(); + + gs_connectionServersPublic = ConfigCentralServer::getStartPublic(); + // listen for game server connect requests + static CentralServer & cserver = getInstance(); + + NetworkSetupData setup; + setup.maxConnections = 100; + setup.bindInterface = ConfigCentralServer::getGameServiceBindInterface(); + setup.port = ConfigCentralServer::getGameServicePort(); + Service * gs = new Service(ConnectionAllocator(), setup); + cserver.m_gameService = gs; + + // listen for planet server connection requests + setup.bindInterface = ConfigCentralServer::getPlanetServiceBindInterface(); + setup.port = ConfigCentralServer::getPlanetServicePort(); + Service * ps = new Service(ConnectionAllocator(), setup); + cserver.m_planetService = ps; + + setup.port = ConfigCentralServer::getChatServicePort(); + setup.maxConnections = 32; + setup.bindInterface = ConfigCentralServer::getChatServiceBindInterface(); + Service * cs = new Service(ConnectionAllocator(), setup); + cserver.m_chatService = cs; + + setup.port = ConfigCentralServer::getCustomerServicePort(); + setup.bindInterface = ConfigCentralServer::getCustomerServiceBindInterface(); + Service * css = new Service(ConnectionAllocator(), setup); + cserver.m_csService = css; + + setup.port = ConfigCentralServer::getConnectionServicePort(); + setup.bindInterface = ConfigCentralServer::getConnectionServiceBindInterface(); + Service * cons = new Service(ConnectionAllocator(), setup); + NOT_NULL(cons); + cserver.m_connService = cons; + + setup.port = ConfigCentralServer::getConsoleServicePort(); + setup.bindInterface = ConfigCentralServer::getConsoleServiceBindInterface(); + cserver.m_consoleService = new Service(ConnectionAllocator(), setup); + + setup.port = ConfigCentralServer::getCommodityServerServicePort(); + setup.bindInterface = ConfigCentralServer::getCommodityServerServiceBindInterface(); + s_commodityServerService = new Service(ConnectionAllocator(), setup); + + setup.port = ConfigCentralServer::getLoginServicePort(); + if (ConfigCentralServer::getDevelopmentMode()) + cserver.connectToLoginServer(); + else + { + setup.bindInterface = ConfigCentralServer::getLoginServiceBindInterface(); + cserver.m_loginService = new Service(ConnectionAllocator(), setup); + } + + // connect to the task manager + cserver.m_taskManager = new TaskConnection("127.0.0.1", ConfigCentralServer::getTaskManagerPort()); + + unsigned long startTime = Clock::timeMs(); + unsigned long nextLoadingLogTime=0; + unsigned long nextPingTime=0; + unsigned long nextPopulationLogTime = 0; + + LOG("ServerStartup",("CentralServer starting")); +#ifndef WIN32 + if( FileExists( ".shutdown") ) + { + LOG("CentralServer", ("Removing stale .shutdown file.")); + IGNORE_RETURN(::remove( ".shutdown" )); + } + if( FileExists( ".abortshutdown" ) ) + { + LOG("CentralServer", ("Removing stale .abortshutdown file.")); + IGNORE_RETURN(::remove( ".abortshutdown" )); + } + if( FileExists( ".startanymissingplanet") ) + { + LOG("CentralServer", ("Removing stale .startanymissingplanet file.")); + IGNORE_RETURN(::remove( ".startanymissingplanet" )); + } + if( FileExists( ".startanymissinggameserver") ) + { + LOG("CentralServer", ("Removing stale .startanymissinggameserver file.")); + IGNORE_RETURN(::remove( ".startanymissinggameserver" )); + } +#endif + + while (!cserver.m_done) + { + unsigned long lastFrameTime = 0; + unsigned long frameStartTime = Clock::timeMs(); + + PROFILER_AUTO_BLOCK_DEFINE("main loop"); + + bool barrierReached = true; + + do + { + PROFILER_AUTO_BLOCK_DEFINE("BarrierWait"); + + if (!Os::update()) + cserver.m_done = true; + + { + PROFILER_AUTO_BLOCK_DEFINE("NetworkHandler::update"); + NetworkHandler::update(); + } + + { + PROFILER_AUTO_BLOCK_DEFINE("MetricsManager::update"); + unsigned long curTime = Clock::timeMs(); + MetricsManager::update(static_cast(curTime - startTime)); + startTime = curTime; + } + + if (ConfigCentralServer::getShouldSleep()) + { + PROFILER_AUTO_BLOCK_DEFINE("Os::sleep"); + Os::sleep(1); + } + + } while (!barrierReached && !cserver.m_done); + + //@todo Central needs to run a clock so we can schedule re-tries with the login server. + { + PROFILER_AUTO_BLOCK_DEFINE("NetworkHandler::dispatch"); + NetworkHandler::dispatch(); + } + + { + PROFILER_AUTO_BLOCK_DEFINE("update"); + cserver.update(); + } + + NetworkHandler::clearBytesThisFrame(); + + { + //Peridically log loading status + unsigned long curTime = Clock::timeMs(); + if (curTime > nextLoadingLogTime) + { + nextLoadingLogTime = curTime + 10000; + std::string planets; + for (std::set::const_iterator i=getInstance().m_planetsWaitingForPreload.begin(); i!=getInstance().m_planetsWaitingForPreload.end(); ++i) + LOG("Preload",("Waiting for planet %s",i->c_str())); + } + + //Perodically ping all the servers + if (ConfigCentralServer::getServerPingTimeout() != 0 && static_cast(curTime-nextPingTime) > 0) + { + nextPingTime = curTime + static_cast(ConfigCentralServer::getServerPingTimeout() * 1000); + getInstance().doServerPings(); + } + + //Periodically write out population to a log every 5 minutes + if (curTime > nextPopulationLogTime) + { + nextPopulationLogTime = curTime + 300000; + LOG("PopulationLog", ("Current Population: %d", getInstance().getPlayerCount())); + } + } + + + + + ServerClock::getInstance().incrementServerFrame(); + if(ConfigCentralServer::getShutdown()) + { + cserver.done(); + } + + unsigned long currentTime = Clock::timeMs(); + lastFrameTime = currentTime - frameStartTime; + if(lastFrameTime > 1000) + { + LOG("profile", ("Long loop (%u ms):\n%s", lastFrameTime, PROFILER_GET_LAST_FRAME_DATA())); + } + } + + LOG("ServerStartup",("CentralServer exiting")); + + SetupSharedLog::remove(); + CentralServer::remove(); +} + +// ---------------------------------------------------------------------- +/** + * Called every frame to do any required updates. + */ +void CentralServer::update() +{ + static int loopCount=0; + m_curTime = static_cast(time(0)); + + // Tell the LoginServers if necessary + if ((++loopCount > ConfigCentralServer::getUpdatePlayerCountFrequency())) + { + loopCount=0; + + // Update the population on the server + sendPopulationUpdateToLoginServer(); + } + + + + if ( ConfigCentralServer::getAuctionEnabled() ) // allow auctions? + { + if ( m_pAuctionTransferClient == NULL ) + { + const char* hostName[1] = { ConfigCentralServer::getAuctionServer() }; + const short port[1] = { (short)ConfigCentralServer::getAuctionPort() }; + + std::string s_id = ConfigCentralServer::getAuctionIDPrefix(); + s_id += ConfigCentralServer::getClusterName(); + + const char *identifier[1]; + identifier[ 0 ] = s_id.c_str(); + + m_pAuctionTransferClient = new AuctionTransferClient( hostName, port, 1, identifier, 1 ); + } + m_pAuctionTransferClient->process(); + } + else if ( m_pAuctionTransferClient ) + { + delete( m_pAuctionTransferClient ); + m_pAuctionTransferClient = 0; + } + + + + // check every 5th frame (one second roughly?) + if( loopCount%5 ) + { + checkShutdownProcess(); + } + + // update cluster wide data manager + ClusterWideDataManagerList::update(Clock::frameTime()); +} + +// ---------------------------------------------------------------------- +void CentralServer::sendPopulationUpdateToLoginServer() +{ + // Add up all the population totals (these are referenced by the metrics data) + m_totalPlayerCount = 0; + m_totalFreeTrialCount = 0; + m_totalEmptySceneCount = 0; + m_totalTutorialSceneCount = 0; + m_totalFalconSceneCount = 0; + + ConnectionServerConnectionList::const_iterator i; + for (i=m_connectionServerConnections.begin(); i!=m_connectionServerConnections.end(); ++i) + { + if (*i) + { + m_totalPlayerCount += (**i).getPlayerCount(); + m_totalFreeTrialCount += (**i).getFreeTrialCount(); + m_totalEmptySceneCount += (**i).getEmptySceneCount(); + m_totalTutorialSceneCount += (**i).getTutorialSceneCount(); + m_totalFalconSceneCount += (**i).getFalconSceneCount(); + } + } + + bool loadedRecently=false; + if (!isPreloadFinished() || (time(0)-m_lastLoadingStateTime < static_cast(ConfigCentralServer::getRecentLoadingStateSeconds()))) + loadedRecently=true; + + UpdatePlayerCountMessage upm(loadedRecently, m_totalPlayerCount, m_totalFreeTrialCount, m_totalEmptySceneCount, m_totalTutorialSceneCount, m_totalFalconSceneCount); + sendToAllLoginServers(upm); +} + +//----------------------------------------------------------------------- + +void CentralServer::sendTaskMessage(const GameNetworkMessage & source) +{ + if(m_taskManager) + m_taskManager->send(source, true); + DEBUG_REPORT_LOG(!m_taskManager, ("There is no task manager connection, but app is attempting to send to one\n")); +} + +//----------------------------------------------------------------------- + +void CentralServer::sendToGameServer(const uint32 gameServerProcessId, const GameNetworkMessage & message, const bool reliable) const +{ + GameServerConnection * g = getGameServer(gameServerProcessId); + if(g) + { + g->send(message, reliable); + } + else + { + DEBUG_WARNING(true,("Attempted to send to game server %i, without connection.\n",gameServerProcessId)); + } +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToLoginServer(uint32 loginServerId, const GameNetworkMessage &message) +{ + LoginServerConnectionMapType::iterator i=m_loginServerConnectionMap.find(loginServerId); + if (i!=m_loginServerConnectionMap.end() && i->second) + i->second->send(message,true); +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToAllGameServers(const GameNetworkMessage & message, const bool reliable) +{ + for (std::map::const_iterator i = m_gameServerConnections.begin(); i!=m_gameServerConnections.end(); ++i) + { + (*i).second->send(message, reliable); + } +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToAllGameServersExceptDBProcess(const GameNetworkMessage & message, const bool reliable) +{ + for (std::map::const_iterator i = m_gameServerConnections.begin(); i!=m_gameServerConnections.end(); ++i) + { + if ((*i).first != getDbProcessServerProcessId()) + (*i).second->send(message, reliable); + } +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToAllPlanetServers(const GameNetworkMessage & message, const bool reliable) +{ + for (std::map::const_iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) + (*i).second->send(message, reliable); +} + +// ---------------------------------------------------------------------- + +bool CentralServer::hasPlanetServer(const std::string & sceneName) const +{ + for (std::map::const_iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) + if (i->second->getSceneId() == sceneName) + return true; + return false; +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToPlanetServer(const std::string &sceneId, const GameNetworkMessage & message, const bool reliable) +{ + for (std::map::const_iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) + if (i->second->getSceneId() == sceneId) + (*i).second->send(message, reliable); +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToAllConnectionServers(const GameNetworkMessage & message, const bool reliable, Connection const * exclude /*= NULL*/) +{ + // send to all connection servers + for (ConnectionServerConnectionList::const_iterator i = m_connectionServerConnections.begin(); i != m_connectionServerConnections.end(); ++i) + { + if ((*i) && (*i != exclude)) + (*i)->send(message, reliable); + } +} + +//----------------------------------------------------------------------- + +void CentralServer::sendToDBProcess(const GameNetworkMessage & message, const bool reliable) const +{ + GameServerConnection * g = getGameServer(getDbProcessServerProcessId()); + if(g) + { + g->send(message, reliable); + } + else + { + DEBUG_FATAL(!m_done,("Attempted to send message to DBProcess without connection (there should always be a connection to DBProcess).")); + } +} + +// ---------------------------------------------------------------------- + +bool CentralServer::hasDBConnection() const +{ + const GameServerConnection * g = getGameServer(getDbProcessServerProcessId()); + return (g != NULL); +} + +//----------------------------------------------------------------------- + +void CentralServer::setTaskManager(TaskConnection * newTaskManager) +{ + if (m_taskManager && newTaskManager != m_taskManager) + { + m_taskManager->setDisconnectReason("CentralServer::setTaskManager called"); + m_taskManager->disconnect(); + } + m_taskManager = newTaskManager; +} + +// ---------------------------------------------------------------------- + +void CentralServer::removePlanetServer(const PlanetServerConnection * p) +{ + for (std::map::iterator i = m_planetServers.begin(); i != m_planetServers.end(); ++i) + { + if ((*i).second == p) + { + DEBUG_REPORT_LOG(true,("Central lost connection to Planet Server %s\n",p->getSceneId().c_str())); + m_planetServers.erase(i); + + if (isPreloadFinished()) + m_timeClusterWentIntoLoadingState = 0; + else if (m_timeClusterWentIntoLoadingState <= 0) + m_timeClusterWentIntoLoadingState = time(0); + + return; + } + } +} + +// ---------------------------------------------------------------------- + +const std::string & CentralServer::getCommandLine() const +{ + return m_commandLine; +} + +//----------------------------------------------------------------------- + +void CentralServer::setCommandLine(const std::string & c) +{ + m_commandLine = c; +} + +//----------------------------------------------------------------------- + +const bool getStartLocation(const std::string & name, std::string & planetName, Vector & coordinates, NetworkId & cellId) +{ + const StartingLocationData * const sld = StartingLocationManager::findLocationByName (name); + if (sld) + { + planetName = sld->planet; + coordinates.x = sld->x; + coordinates.y = sld->y; + coordinates.z = sld->z; + cellId = NetworkId (sld->cellId); + return true; + } + + REPORT_LOG(true, ("The start location \"%s\" could not be found in StartingLocationManager", name.c_str())); + return false; +} + +//----------------------------------------------------------------------- + +void CentralServer::startPlanetServer(const std::string & host, const std::string & sceneId, const SpawnDelaySeconds spawnDelay) +{ + FATAL(sceneId.empty(), ("CentralServer::startPlanetServer: empty sceneId, host='%s'", host.c_str())); + std::map, time_t> >::const_iterator f = m_pendingPlanetServers.find(sceneId); + if(f == m_pendingPlanetServers.end()) + { + std::map::const_iterator pf = m_planetServers.find(sceneId); + if(pf == m_planetServers.end()) + { + std::string options = "-s PlanetServer centralServerAddress="; + if(m_planetService) + { + options += m_planetService->getBindAddress(); + } + else + { + options += NetworkHandler::getHostName(); + } + options += " sceneID="; + options += sceneId; + + char buffer[20]; + IGNORE_RETURN(_itoa(m_nextPlanetWatcherPort++,buffer,10)); + options += " watcherServicePort="; + options += buffer; + + static unsigned int portBase = 0; + IGNORE_RETURN(_itoa(portBase,buffer,10)); + portBase += 100; + options += " gameServerDebuggingPortBase="; + options += buffer; + + TaskSpawnProcess spawn(host.empty() ? std::string("any") : host, "PlanetServer", options, spawnDelay); + CentralServer::getInstance().sendTaskMessage(spawn); + m_pendingPlanetServers[sceneId] = std::make_pair(std::make_pair(host, options), ::time(NULL)); + IGNORE_RETURN(m_planetsWaitingForPreload.insert(sceneId)); + + bool const preloadFinished = isPreloadFinished(); + if (preloadFinished) + m_timeClusterWentIntoLoadingState = 0; + else if (m_timeClusterWentIntoLoadingState <= 0) + m_timeClusterWentIntoLoadingState = time(0); + + if(getInstance().m_transferServerConnection != NULL && !preloadFinished) + { + getInstance().m_transferServerConnection->disconnect(); + getInstance().m_transferServerConnection = 0; + s_retryTransferServerConnection = false; + } + + if(getInstance().m_stationPlayersCollectorConnection != NULL && ! isPreloadFinished()) + { + getInstance().m_stationPlayersCollectorConnection->disconnect(); + getInstance().m_stationPlayersCollectorConnection = 0; + s_retryStationPlayersCollectorConnection = false; + } + + PreloadFinishedMessage msg(preloadFinished); + sendToAllLoginServers(msg); + } + } +} + +//----------------------------------------------------------------------- +/** +* Forward the RequestGameServerForLoginMessage to the appropriate PlanetServer +*/ +void CentralServer::handleRequestGameServerForLoginMessage(const RequestGameServerForLoginMessage & msg) +{ + static const std::string loginTrace("TRACE_LOGIN"); + + std::string effectiveScene; + PlayerSceneMapType::iterator i=m_playerSceneMap.find(msg.getCharacterId()); + if (i!=m_playerSceneMap.end()) + { + effectiveScene=i->second.first; + LOG(loginTrace, ("using sceneId (%s) from memory for character (%s)", effectiveScene.c_str(), msg.getCharacterId().getValueString().c_str())); + } + else + effectiveScene=msg.getScene(); // only use the DB scene if we don't have more recent information + + // for CTS, the source character must currently be on one of the 10 original ground planets + if (msg.getForCtsSourceCharacter()) + { + static std::set s_tenOriginalGroundPlanets; + if (s_tenOriginalGroundPlanets.empty()) + { + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("tatooine")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("naboo")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("corellia")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("rori")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("talus")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("yavin4")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("endor")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("lok")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("dantooine")); + IGNORE_RETURN(s_tenOriginalGroundPlanets.insert("dathomir")); + } + + if (s_tenOriginalGroundPlanets.count(effectiveScene) <= 0) + { + // fail CTS because source character is not on one of the 10 original ground planets + LOG("CustomerService", ("CharacterTransfer: RequestGameServerForLoginMessage failed for source character (%s) stationId (%lu) because effective scene for the character (%s) is not one of the 10 original ground planets", msg.getCharacterId().getValueString().c_str(), msg.getStationId(), effectiveScene.c_str())); + + GenericValueTypeMessage > const failureMsg("CtsSrcCharWrongPlanet", std::make_pair(msg.getCharacterId(), msg.getStationId())); + IGNORE_RETURN(ConnectionServerConnection::sendToPseudoClientConnection(msg.getStationId(), failureMsg)); + + return; + } + } + + PlanetServerConnection *conn = PlanetManager::getPlanetServerForScene(effectiveScene); + if (conn) + { + LOG(loginTrace, ("handling RequestGameServerForLoginMessage(%s)", msg.getCharacterId().getValueString().c_str())); + conn->send(msg,true); + } + else + { + bool isPlanetValid = false; + bool allowDynamicStart = ConfigFile::getKeyBool("CentralServer", "startPlanetsDynamically", false); + + std::map::const_iterator f = ms_sceneToHostMap.find(msg.getScene()); + if(f != ms_sceneToHostMap.end()) + { + isPlanetValid = true; + } + + if(isPlanetValid || allowDynamicStart) + { + LOG(loginTrace, ("deferring RequestGameServerForLoginMessage(%s)", msg.getCharacterId().getValueString().c_str())); + DEBUG_REPORT_LOG(true, ("Starting planet server for login")); + startPlanetServer(getHostForScene(msg.getScene()), msg.getScene(), 0); + m_messagesWaitingForPlanetServer.push_back(Archive::ByteStream()); + msg.pack(m_messagesWaitingForPlanetServer.back()); + } + else + { + WARNING_STRICT_FATAL(true, ("Central received a request to start a planet (name=\"%s\") that is not in the startPlanet= list in the CentralServer config file.", msg.getScene().c_str())); + } + } +} + +// ---------------------------------------------------------------------- + +void CentralServer::handleRequestSceneTransfer(const RequestSceneTransfer &msg) +{ + PlanetServerConnection *conn = PlanetManager::getPlanetServerForScene(msg.getSceneName()); + if (conn) + { + conn->send(msg,true); + } + else + { + DEBUG_REPORT_LOG(true, ("Starting planet server for login")); + startPlanetServer(getHostForScene(msg.getSceneName()), msg.getSceneName(), 0); + m_messagesWaitingForPlanetServer.push_back(Archive::ByteStream()); + msg.pack(m_messagesWaitingForPlanetServer.back()); + } +} + +// ---------------------------------------------------------------------- + +/** +* Forward the GameServerForLoginMessage to the appropriate ConnectionServer +*/ +void CentralServer::handleGameServerForLoginMessage(const GameServerForLoginMessage &msg) +{ + ConnectionServerConnection *conn = getConnectionServerForAccount(msg.getStationId()); + if (conn) + { + conn->send(msg,true); + } + else + { + if(! ConnectionServerConnection::sendToPseudoClientConnection(msg.getStationId(), msg)) + { + LOG("TRACE_LOGIN", ("Trying to log account %i in, but could not determine which connection server to use.",msg.getStationId())); + } + } +} + +// ---------------------------------------------------------------------- + +void CentralServer::handleExchangeListCreditsMessage(const ExchangeListCreditsMessage &msg) +{ + LOG("Exchange", ("Central Server got exchange list credits %d.",msg.getCredits())); + if ( m_pAuctionTransferClient == NULL ) + { + // send failure packet + } + //////////////////////m_pAuctionTransferClient->addCoinToAuction( msg ); +} + + + + + +ConnectionServerConnection * CentralServer::getAnyConnectionServer() +{ + ConnectionServerConnection * result = 0; + if(! m_connectionServerConnections.empty()) + { + result = *(m_connectionServerConnections.begin()); + if(result) + { + int leastPlayers = result->getPlayerCount(); + + std::vector::iterator i; + for(i = m_connectionServerConnections.begin(); i != m_connectionServerConnections.end(); ++i) + { + if((*i)->getPlayerCount() < leastPlayers) + result = *i; + } + } + } + return result; +} + +// ---------------------------------------------------------------------- + +ConnectionServerConnection * CentralServer::getConnectionServerForAccount(StationId suid) +{ + ConnectionServerConnection * result = NULL; + ConnectionServerSUIDMap::iterator i=m_accountConnectionMap.find(suid); + if (i!=m_accountConnectionMap.end()) + { + result = (*i).second; + } + else + { + result = ConnectionServerConnection::getConnectionForAccount(suid); + } + + return result; +} + +// ---------------------------------------------------------------------- + +void CentralServer::addToAccountConnectionMap(StationId suid, ConnectionServerConnection * cconn, uint32 subscriptionBits) +{ + m_accountConnectionMap[suid] = cconn; + + // remove corresponding "pseudo client connection" + ConnectionServerConnection::removeFromAccountConnectionMap(suid); +} + +// ---------------------------------------------------------------------- + +void CentralServer::removeFromAccountConnectionMap(StationId suid) +{ + ConnectionServerSUIDMap::iterator i=m_accountConnectionMap.find(suid); + if (i!=m_accountConnectionMap.end()) + { + // Erase the entry + m_accountConnectionMap.erase(i++); + } +} + +// ---------------------------------------------------------------------- + +void CentralServer::removeFromAccountConnectionMap(int connectionServerConnectionId) +{ + ConnectionServerSUIDMap::iterator i; + for(i = m_accountConnectionMap.begin(); i != m_accountConnectionMap.end();) + { + const ConnectionServerConnection* cconn = (*i).second; + + if(cconn && (cconn->getId() == connectionServerConnectionId)) + { + // Erase the entry + m_accountConnectionMap.erase(i++); + } + else + { + ++i; + } + } + + // We could update the LoginServer population but people + // leaving the server are not as important as people connecting + // and so we will wait for update() to handle things +} + +//-------------------------------------------------------------------------------- + +const Service * CentralServer::getChatService() const +{ + return m_chatService; +} + +//-------------------------------------------------------------------------------- + +const Service * CentralServer::getCustomerService() const +{ + return m_csService; +} + +//-------------------------------------------------------------------------------- + +const Service * CentralServer::getGameService() const +{ + return m_gameService; +} + +//-------------------------------------------------------------------------------- + +void CentralServer::startConnectionServer(int connectionServerNumber, const std::string& listenAddress, uint16 publicPort, uint16 internalPort, bool, const SpawnDelaySeconds spawnDelay) const +{ + char tmp1[32]; + char tmp2[32]; + std::string publicString = _itoa(publicPort, tmp1, 10); + std::string privateString = _itoa(internalPort, tmp2, 10); + startConnectionServer(connectionServerNumber, listenAddress, &publicString, &privateString, spawnDelay); +} + +//-------------------------------------------------------------------------------- + +void CentralServer::startConnectionServer(int connectionServerNumber, const std::string& listenAddress, const std::string * publicPort, const std::string * internalPort, const SpawnDelaySeconds spawnDelay) const +{ + UNREF(listenAddress); //once we add dual nic support, we can use this + if(!m_connService) + { + DEBUG_WARNING(true, ("Could not start connection server because there was no service for it")); + return; + } + + if (!ConfigCentralServer::getAllowZeroConnectionServerPort()) + { + if (!publicPort) + { + WARNING(true, ("Could not start connection server because there were not client ports specified")); + return; + } + if (*publicPort == "0") + { + WARNING(true, ("Could not start connection server because one or more client ports were 0.")); + return; + } + } + + // there should already be an entry in s_connectionServerHostList that + // contains the node on which to start this particular connection server + if ((connectionServerNumber <= 0) || (connectionServerNumber > static_cast(s_connectionServerHostList.size()))) + { + WARNING(true, ("Could not start connection server because connectionServerNumber=%d and s_connectionServerHostList.size()=%d", connectionServerNumber, static_cast(s_connectionServerHostList.size()))); + return; + } + + // spawn a connection server + std::string options = "-s ConnectionServer clusterName="; + options += ConfigCentralServer::getClusterName(); + + if(gs_connectionServersPublic) + options += " startPublicServer=true"; + + options += " centralServerAddress="; + options += m_connService->getBindAddress(); + + char servicePort[32]; + + options += " centralServerPort="; + options += _itoa(m_connService->getBindPort(), servicePort, 10); + + if (publicPort != 0) + { + options += " clientServicePortPublic="; + options += *publicPort; + } + if (internalPort != 0) + { + options += " clientServicePortPrivate="; + options += *internalPort; + } + + options += " connectionServerNumber="; + options += _itoa(connectionServerNumber, servicePort, 10); + + DEBUG_REPORT_LOG(true, ("Spawning Connection server with options %s\n", options.c_str())); + TaskSpawnProcess p(s_connectionServerHostList[connectionServerNumber-1], "ConnectionServer", options, spawnDelay); + CentralServer::getInstance().sendTaskMessage(p); +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToAllLoginServers(const GameNetworkMessage &message) +{ + for (LoginServerConnectionMapType::iterator i=m_loginServerConnectionMap.begin(); i!=m_loginServerConnectionMap.end(); ++i) + i->second->send(message,true); +} + +// ---------------------------------------------------------------------- + +uint32 CentralServer::sendToArbitraryLoginServer(const GameNetworkMessage &message, bool roundRobin /*= true*/) +{ + static unsigned int nextServer = 0; + + if (m_loginServerConnectionMap.empty()) + return 0; + + LoginServerConnectionMapType::const_iterator i = m_loginServerConnectionMap.begin(); + + if (!roundRobin) + { + i->second->send(message,true); + return i->second->getProcessId(); + } + + ++nextServer; + if (nextServer >= m_loginServerConnectionMap.size()) + nextServer = 0; + + std::advance(i, nextServer); + + i->second->send(message,true); + return i->second->getProcessId(); +} + +// ---------------------------------------------------------------------- + +/** + * In development mode, connect to a login server. + */ +void CentralServer::connectToLoginServer() const +{ + IGNORE_RETURN(new LoginServerConnection(ConfigCentralServer::getLoginServerAddress(), ConfigCentralServer::getLoginServerPort())); +} + +//----------------------------------------------------------------------- + +void CentralServer::remove() +{ + CentralServer & cs = getInstance(); + MetricsManager::remove(); + delete cs.m_metricsData; + cs.m_metricsData = 0; + + delete cs.m_loginServerKeys; + + cs.m_messagesWaitingForPlanetServer.clear(); + cs.m_gameServerConnections.clear(); + cs.m_gameServerConnectionsList.clear(); + cs.m_connectionServerConnections.clear(); + + delete cs.m_gameService; + delete cs.m_chatService; + delete cs.m_csService; + delete cs.m_connService; + delete cs.m_planetService; + delete cs.m_loginService; + if(cs.m_taskManager) + { + cs.m_taskManager->setDisconnectReason("CentralServer::remove"); + cs.m_taskManager->disconnect(); + } + delete cs.m_taskService; + delete cs.m_consoleService; +} + +//----------------------------------------------------------------------- + +std::vector CentralServer::getGameServers() const +{ + std::vector result; + std::map::const_iterator i; + for(i = m_gameServerConnections.begin(); i != m_gameServerConnections.end(); ++i) + { + result.push_back((*i).second); + } + return result; +} + +// ---------------------------------------------------------------------- + +void CentralServer::sendToConnectionServerForAccount(StationId account, const GameNetworkMessage & message, const bool reliable) +{ + ConnectionServerConnection *conn = getConnectionServerForAccount(account); + if (conn) + conn->send(message,reliable); +} + +// ---------------------------------------------------------------------- + +uint32 CentralServer::sendToRandomGameServer(const GameNetworkMessage &message) +{ + GameServerConnection *conn = getRandomGameServer(); + if (conn) + { + conn->send(message,true); + return conn->getProcessId(); + } + else + return 0; +} + +// ---------------------------------------------------------------------- + +void CentralServer::doServerPings() +{ + for (std::set::iterator i=m_serverPings.begin(); i!=m_serverPings.end(); ++i) + { + LOG("CentralServerPings",("Dropping server %lu because it hasn't responded to CentralPingMessage",*i)); + GameServerConnection *conn=getGameServer(*i); + if (conn) + { + // tell task manager to kill the offending process (in case it's hung) + ExcommunicateGameServerMessage msg(*i, conn->getOsProcessId(), conn->getRemoteAddress()); + // disconnect, if it's not hung, it should die + conn->setDisconnectReason("CentralServer::doServerPings, failure to respond to CentralPingMessage"); + conn->disconnect(); + sendTaskMessage(msg); + excommunicateServer(msg); + } + else + { + LOG("CentralServerPings",("Didn't have connection to %lu to drop",*i)); + ExcommunicateGameServerMessage const excommunicateMessage(*i, 0, ""); + excommunicateServer(excommunicateMessage); // haven't received a reply (see CentralPingMessage, above) + } + } + m_serverPings.clear(); + + CentralPingMessage ping; + for (std::map::iterator j=m_gameServerConnections.begin(); j!=m_gameServerConnections.end(); ++j) + { + if (j->first != getDbProcessServerProcessId()) + { + LOG("CentralServerPings",("Pinging %lu",j->first)); + IGNORE_RETURN(m_serverPings.insert(j->first)); + j->second->send(ping,true); + } + } +} + +// ---------------------------------------------------------------------- + +/** + * Declare a game server anathema. All other servers will shun this server. + */ +void CentralServer::excommunicateServer(const ExcommunicateGameServerMessage & msg) +{ + sendToAllGameServers(msg,true); + sendToAllPlanetServers(msg,true); + sendToAllConnectionServers(msg,true); +} + +//----------------------------------------------------------------------- +void CentralServer::startShutdownProcess(const uint32 timeToShutdown, const uint32 maxTime, const Unicode::String &systemMessage) +{ + // sanity checking + if ( m_shutdownPhase > 6) + { + WARNING("CentralServerShutdown", ("startShutdownProcess: invalid value in CentralServer::m_shutdownPhase. Current value is %d. Resetting.", m_shutdownPhase)); + m_shutdownPhase = 0; + } + + // server already in the process of shutting down + if ( m_shutdownPhase > 0 ) + { + LOG("CentralServerShutdown", ("startShutdownProcess: Server already in the process of shutting down. Current shutdown phase is %d.", m_shutdownPhase)); + return; + } + + if( timeToShutdown>maxTime ) + { + LOG("CentralServerShutdown", ("startShutdownProcess: time to shutdown is greater than max time.")); + return; + } + m_shutdownPhase = 1; + LOG("CentralServerShutdown",("Shutdown Phase %d: Shutdown sequence starting now.", m_shutdownPhase)); + LOG("CentralServerShutdown",("Shutdown Phase %d: time to shutdown=%dsec, max time to wait=%dsec, broadcast warning message=\"%s\".", m_shutdownPhase, timeToShutdown, maxTime, Unicode::wideToNarrow(systemMessage).c_str())); + // this is the time in the future that we need to start the shutdown process. + m_shutdownTotalTime = m_curTime + timeToShutdown; + m_shutdownMaxTime = m_curTime + maxTime; + m_shutdownSystemMessage = systemMessage; + m_shutdownHaveDatabaseSaveStart = false; + m_shutdownHaveDatabaseComplete = false; + checkShutdownProcess(); +} +//------------------------------------------------------------------------ +void CentralServer::checkShutdownProcess() +{ + static bool warn30 = false; + static bool warn10 = false; + static bool warn0 = false; + static uint32 lastWarn = m_curTime; + static uint32 nextAbortCheck = m_curTime+1; + static uint32 nextShutdownCheck = m_curTime+30; + + if( !m_shutdownPhase ) + { +#ifndef WIN32 + // check if a .shutdown file exists + if( m_curTime > nextShutdownCheck ) + { + nextShutdownCheck = m_curTime + 30; + if( FileExists(".shutdown") ) + { + StdioFile shutdownFile(".shutdown", "r"); + if(shutdownFile.isOpen()) + { + char destBuffer[64] = {"\0"}; + if(shutdownFile.read(destBuffer, sizeof(destBuffer)) > 0) + { + destBuffer[sizeof(destBuffer) - 1] = 0; + int shutdownTime = atoi(destBuffer); + if(shutdownTime > 0) + { + LOG("CentralServerShutdown", ("Detected a .shutdown file. Initiating shutdown sequence.")); + startShutdownProcess(shutdownTime, 7200, Unicode::narrowToWide("The server will be shutting down soon. Please find a safe place to logout.")); + } + } + shutdownFile.close(); + } + IGNORE_RETURN(::remove(".shutdown")); + return; + } + + if( FileExists( ".startanymissingplanet") ) + { + LOG("CentralServer", ("Detected a .startanymissingplanet file. Checking for any planets that are not started, and starting them.")); + + for (std::map::const_iterator iter = ms_sceneToHostMap.begin(); iter != ms_sceneToHostMap.end(); ++iter) + { + if (!hasPlanetServer(iter->first)) + { + std::map, time_t> >::iterator iterPendingPlanetServer = m_pendingPlanetServers.find(iter->first); + if (iterPendingPlanetServer != m_pendingPlanetServers.end()) + { + // if it's been "awhile" since we requested to restart the PlanetServer, + // then assume that something has gone wrong, and try the restart again + time_t const timeNow = ::time(NULL); + + if ((iterPendingPlanetServer->second.second + static_cast(ConfigCentralServer::getMaxTimeToWaitForPlanetServerStartSeconds())) < timeNow) + { + LOG("CentralServer", ("startanymissingplanet:Starting missing planet %s because it has been %s since we requested it to be started, which has exceeded the %s limit.", iter->first.c_str(), CalendarTime::convertSecondsToMS(static_cast(timeNow - iterPendingPlanetServer->second.second)).c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigCentralServer::getMaxTimeToWaitForPlanetServerStartSeconds())).c_str())); + iterPendingPlanetServer->second.second = timeNow; + TaskSpawnProcess spawn(iterPendingPlanetServer->second.first.first.empty() ? std::string("any") : iterPendingPlanetServer->second.first.first, "PlanetServer", iterPendingPlanetServer->second.first.second); + CentralServer::getInstance().sendTaskMessage(spawn); + } + else + { + LOG("CentralServer", ("startanymissingplanet:It's only been %s since we requested for planet %s to be started, and we must wait %s before we can start it again.", CalendarTime::convertSecondsToMS(static_cast(timeNow - iterPendingPlanetServer->second.second)).c_str(), iter->first.c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigCentralServer::getMaxTimeToWaitForPlanetServerStartSeconds())).c_str())); + } + } + else + { + LOG("CentralServer", ("startanymissingplanet:Hmmm... planet %s is missing, but also is not in the list of planets we have attempted to start, so we're ***NOT*** going to start it.", iter->first.c_str())); + } + } + } + + IGNORE_RETURN(::remove( ".startanymissingplanet" )); + return; + } + + if( FileExists( ".startanymissinggameserver") ) + { + LOG("CentralServer", ("Detected a .startanymissinggameserver file. Checking for any game servers that are not started, and starting them.")); + + const GenericValueTypeMessage startAnyMissingGameServer("SAMGS", 0); + sendToAllPlanetServers(startAnyMissingGameServer, true); + + IGNORE_RETURN(::remove( ".startanymissinggameserver" )); + return; + } + } +#endif + return; + } + + // should we abort? + if( m_curTime > nextAbortCheck ) + { +#ifndef WIN32 + nextAbortCheck = m_curTime + 1; + if( FileExists(".abortshutdown") ) + { + + IGNORE_RETURN(::remove(".abortshutdown")); + LOG("CentralServerShutdown", ("Shutdown Phase %d: Detected a .abortshutdown file. Aborting shutdown sequence.", m_shutdownPhase)); + abortShutdownProcess(); + return; + } +#endif + } + + // Phase 1 is an immediate broadcast to players for the first shutdown warning + if( m_shutdownPhase == 1 ) + { + char strTimeLeft[1024]; + uint32 timeLeft = m_shutdownTotalTime - m_curTime; + if( timeLeft < 1 ) + { + strTimeLeft[0] = '\0'; + } + else if( timeLeft < 60 ) + { + sprintf(strTimeLeft, " ( %lusec left )", timeLeft); + } + else + { + sprintf(strTimeLeft, " ( %lumin left )", timeLeft/60); + } + + LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting first shutdown message to players: \"%s %s\"", m_shutdownPhase, Unicode::wideToNarrow(m_shutdownSystemMessage).c_str(), strTimeLeft)); + ConGenericMessage const msg("game any systemMessage " + Unicode::wideToNarrow(m_shutdownSystemMessage)+strTimeLeft, 0); + IGNORE_RETURN(sendToRandomGameServer(msg)); + m_shutdownPhase = 2; + lastWarn = m_curTime; + } + // Phase 2 is broadcasting a system message every 60sec while we wait for time to expire + else if( m_shutdownPhase == 2 ) + { + if( m_curTime >= m_shutdownTotalTime) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Done broadcasting shutdown warning message to players . Advancing shutdown phase.", m_shutdownPhase)); + m_shutdownPhase = 3; + warn30 = false; + warn10 = false; + warn0 = false; + + + } + // broadcast warning message to players every 60sec. + else if( m_curTime >= lastWarn+60 ) + { + char strTimeLeft[1024]; + uint32 timeLeft = m_shutdownTotalTime - m_curTime; + if( timeLeft < 1 ) + { + strTimeLeft[0] = '\0'; + } + else if( timeLeft < 60 ) + { + sprintf(strTimeLeft, " ( %lusec left)", timeLeft); + } + else + { + sprintf(strTimeLeft, " ( %lumin left)", timeLeft/60); + } + + LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting shutdown message to players: \"%s %s\"", m_shutdownPhase, Unicode::wideToNarrow(m_shutdownSystemMessage).c_str(), strTimeLeft)); + ConGenericMessage const msg("game any systemMessage " + Unicode::wideToNarrow(m_shutdownSystemMessage)+strTimeLeft, 0); + IGNORE_RETURN(sendToRandomGameServer(msg)); + lastWarn = m_curTime; + } + } + // warn the players they are about to be disconnected + else if( m_shutdownPhase == 3 ) + { + if( m_curTime>=m_shutdownTotalTime && !warn30 ) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting 30sec disconnect warning message to players.", m_shutdownPhase)); + ConGenericMessage const msg("game any systemMessage You will be disconnected in 30sec so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0); + IGNORE_RETURN(sendToRandomGameServer(msg)); + warn30 = true; + + } + else if( m_curTime >= (m_shutdownTotalTime+20) && !warn10 ) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting 10sec disconnect warning message to players.", m_shutdownPhase)); + ConGenericMessage const msg("game any systemMessage You will be disconnected in 10sec so the server can perform a final save before shutting down. Please find a safe place to logout now.", 0); + IGNORE_RETURN(sendToRandomGameServer(msg)); + warn10 = true; + } + else if( m_curTime >= (m_shutdownTotalTime+30) && !warn0 ) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Broadcasting final disconnect warning message to players.", m_shutdownPhase)); + ConGenericMessage const msg("game any systemMessage You will now be disconnected so the server can perform a final save before shutting down.", 0); + IGNORE_RETURN(sendToRandomGameServer(msg)); + warn0 = true; + } + else if( m_curTime >= (m_shutdownTotalTime+35) ) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Setting server to private, disconnecting the players and now waiting for next database save cycle to begin.", m_shutdownPhase)); + gs_connectionServersPublic = false; + SetConnectionServerPublic const msg(false); + sendToAllConnectionServers(msg, true); + m_shutdownPhase = 4; + + // send a message to the DB telling it we're shutting down + GenericValueTypeMessage const msg2("ClusterShutdownMessage", true); + sendToDBProcess(msg2, true); + + // send a save start to the DB; must be sent after the above + // "ClusterShutdownMessage" message so the DB will know this + // is the final save before cluster shutdown + GenericValueTypeMessage const msg3("StartSaveMessage", NetworkId::cms_invalid); + sendToDBProcess(msg3, true); + } + } + else if( m_shutdownPhase == 4 ) + { + if( m_shutdownHaveDatabaseSaveStart ) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Starting final database save cycle. Advancing shutdown phase.", m_shutdownPhase)); + m_shutdownPhase = 5; + } + } + else if( m_shutdownPhase == 5 ) + { + // we are done. Shut it down. Shut it down now! + if( m_shutdownHaveDatabaseComplete) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Completed final database save cycle. Advancing shutdown phase.", m_shutdownPhase)); + m_shutdownPhase = 6; + LOG("CentralServerShutdown",("Shutdown Phase %d: Instructing TaskManager to shutdown the cluster without restarting.", m_shutdownPhase)); + ConGenericMessage const msg("stop", 0); + sendTaskMessage(msg); + } + } + // maximum amount of time to wait has expired. Shut it down now without waiting for anything else. + else if( m_curTime >= m_shutdownMaxTime ) + { + LOG("CentralServerShutdown",("Shutdown Phase %d: Maximum time has gone by. Forcing a shutdown now.", m_shutdownPhase)); + m_shutdownPhase = 6; + LOG("CentralServerShutdown",("Shutdown Phase %d: Instructing TaskManager to shutdown the cluster without restarting.", m_shutdownPhase)); + ConGenericMessage const msg("stop", 0); + sendTaskMessage(msg); + } +} + +void CentralServer::abortShutdownProcess() +{ + LOG("CentralServerShutdown", ("Shutdown Phase %d: Aborting shutdown sequence.", m_shutdownPhase)); + if( m_shutdownPhase > 0 ) + { + ConGenericMessage const msg("game any systemMessage The server shutdown has been aborted. The server is no longer shutting down.", 0); + IGNORE_RETURN(sendToRandomGameServer(msg)); + } + + // send a message to the DB telling it we're no longer shutting down + GenericValueTypeMessage const msg("ClusterShutdownMessage", false); + sendToDBProcess(msg, true); + + m_shutdownPhase = 0; + m_shutdownTotalTime = 0; + m_shutdownMaxTime = 0; + m_shutdownSystemMessage = Unicode::narrowToWide(""); + m_shutdownHaveDatabaseSaveStart = false; + m_shutdownHaveDatabaseComplete = false; +} + +//----------------------------------------------------------------------- + +void CentralServer::sendToTransferServer(const GameNetworkMessage & msg) const +{ + if(getInstance().m_transferServerConnection) + { + getInstance().m_transferServerConnection->send(msg, true); + } +} + +//----------------------------------------------------------------------- + +//----------------------------------------------------------------------- + +void CentralServer::sendToStationPlayersCollector(const GameNetworkMessage & msg) const +{ + if(getInstance().m_stationPlayersCollectorConnection) + { + getInstance().m_stationPlayersCollectorConnection->send(msg, true); + } +} + +//----------------------------------------------------------------------- + +int CentralServer::getPlanetServersCount() const +{ + return m_planetServers.size(); +} + +//----------------------------------------------------------------------- + +const Service * CentralServer::getCommoditiesService() +{ + return s_commodityServerService; +} + +//----------------------------------------------------------------------- + +int CentralServer::getClusterStartupTime() const +{ + if (m_clusterStartupTime != -1) + return m_clusterStartupTime; + else + // return how long the cluster has been taking to come up + return int((time(0) - m_timeClusterStarted) / 60); +} + +//----------------------------------------------------------------------- + +int CentralServer::getSecondsClusterHasBeenInLoadingState() const +{ + if (m_timeClusterWentIntoLoadingState > 0) + return (time(0) - m_timeClusterWentIntoLoadingState); + else + return 0; +} + +// ---------------------------------------------------------------------- + +const std::map & CentralServer::getPopulationStatistics(time_t & refreshTime) +{ + // periodically request updated statistics from the game server + time_t const timeNow = ::time(NULL); + if (m_timePopulationStatisticsNextRefresh <= timeNow) + { + GameServerConnection * universeGameServerConnection = getGameServer(UniverseManager::getInstance().getUniverseProcess()); + if (universeGameServerConnection) + { + const GenericValueTypeMessage populationStatisticsRequest("PopStatReq", 0); + universeGameServerConnection->send(populationStatisticsRequest, true); + + m_timePopulationStatisticsNextRefresh = timeNow + 60; + } + } + + refreshTime = m_timePopulationStatisticsRefresh; + return m_populationStatistics; +} + +// ---------------------------------------------------------------------- + +const std::map > > & CentralServer::getGcwScoreStatistics(time_t & refreshTime) +{ + // periodically request updated statistics from the game server + time_t const timeNow = ::time(NULL); + if (m_timeGcwScoreStatisticsNextRefresh <= timeNow) + { + GameServerConnection * universeGameServerConnection = getGameServer(UniverseManager::getInstance().getUniverseProcess()); + if (universeGameServerConnection) + { + const GenericValueTypeMessage gcwScoreStatisticsRequest("GcwScoreStatReq", 0); + universeGameServerConnection->send(gcwScoreStatisticsRequest, true); + + m_timeGcwScoreStatisticsNextRefresh = timeNow + 60; + } + } + + refreshTime = m_timeGcwScoreStatisticsRefresh; + return m_gcwScoreStatistics; +} + +// ---------------------------------------------------------------------- + +std::pair > const *, std::map > const *> CentralServer::getLastLoginTimeStatistics(time_t & refreshTime) +{ + // periodically request updated statistics from the game server + time_t const timeNow = ::time(NULL); + if (m_timeLastLoginTimeStatisticsNextRefresh <= timeNow) + { + GameServerConnection * universeGameServerConnection = getGameServer(UniverseManager::getInstance().getUniverseProcess()); + if (universeGameServerConnection) + { + const GenericValueTypeMessage lastLoginTimeStatisticsRequest("LLTStatReq", 0); + universeGameServerConnection->send(lastLoginTimeStatisticsRequest, true); + + m_timeLastLoginTimeStatisticsNextRefresh = timeNow + (15 * 60); + } + } + + refreshTime = m_timeLastLoginTimeStatisticsRefresh; + + return std::make_pair(&m_lastLoginTimeStatistics, &m_createTimeStatistics); +} + +// ---------------------------------------------------------------------- + +void CentralServer::getCharacterMatchStatistics(int & numberOfCharacterMatchRequests, int & numberOfCharacterMatchResultsPerRequest, int & timeSpentPerCharacterMatchRequestMs) +{ + // periodically request updated statistics from the game server + time_t const timeNow = ::time(NULL); + if (m_timeCharacterMatchStatisticsNextRefresh <= timeNow) + { + const GenericValueTypeMessage characterMatchStatisticsRequest("LfgStatReq", 0); + sendToAllGameServersExceptDBProcess(characterMatchStatisticsRequest, true); + + m_timeCharacterMatchStatisticsNextRefresh = timeNow + 60; + } + + // wraparound, reset statistics + if (m_numberOfCharacterMatchRequests < 0) + { + m_numberOfCharacterMatchRequests = 0; + m_numberOfCharacterMatchResults = 0; + m_timeSpentOnCharacterMatchRequestsMs = 0; + } + + numberOfCharacterMatchRequests = m_numberOfCharacterMatchRequests; + numberOfCharacterMatchResultsPerRequest = (m_numberOfCharacterMatchRequests ? static_cast(m_numberOfCharacterMatchResults / m_numberOfCharacterMatchRequests) : 0); + timeSpentPerCharacterMatchRequestMs = (m_numberOfCharacterMatchRequests ? static_cast(m_timeSpentOnCharacterMatchRequestsMs / m_numberOfCharacterMatchRequests) : 0); +} + +// ====================================================================== +//lint -e766 // todo : TRF Fix this diff --git a/src/engine/server/application/CentralServer/src/shared/ConfigCentralServer.cpp b/src/engine/server/application/CentralServer/src/shared/ConfigCentralServer.cpp index 0d26f54bc..a13bd448f 100644 --- a/src/engine/server/application/CentralServer/src/shared/ConfigCentralServer.cpp +++ b/src/engine/server/application/CentralServer/src/shared/ConfigCentralServer.cpp @@ -1,165 +1,165 @@ -// ConfigCentralServer.cpp -// copyright 2000 Verant Interactive -// Author: Justin Randall - - -//----------------------------------------------------------------------- - -#include "FirstCentralServer.h" -#include "serverUtility/ConfigServerUtility.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedNetwork/SetupSharedNetwork.h" -#include "ConfigCentralServer.h" - -//----------------------------------------------------------------------- - -ConfigCentralServer::Data * ConfigCentralServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("CentralServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("CentralServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("CentralServer", #a, b)) - -//----------------------------------------------------------------------- - -namespace ConfigCentralServerNamespace -{ - typedef std::vector StringPtrArray; - StringPtrArray ms_startPlanets; // ConfigFile owns the pointer - StringPtrArray ms_startConnectionServer; -} - -using namespace ConfigCentralServerNamespace; - -// ====================================================================== - -int ConfigCentralServer::getNumberOfStartPlanets() -{ - return static_cast(ms_startPlanets.size()); -} - -// ---------------------------------------------------------------------- - -char const * ConfigCentralServer::getStartPlanet(int index) -{ - VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfStartPlanets()); - return ms_startPlanets[static_cast(index)]; -} - -// ---------------------------------------------------------------------- - -int ConfigCentralServer::getNumberOfStartingConnectionServers() -{ - return static_cast(ms_startConnectionServer.size()); -} - -// ---------------------------------------------------------------------- - -char const * ConfigCentralServer::getStartingConnectionServer(int index) -{ - VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfStartingConnectionServers()); - return ms_startConnectionServer[static_cast(index)]; -} - -// ---------------------------------------------------------------------- - -void ConfigCentralServer::install(void) -{ - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - SetupSharedNetwork::install(networkSetupData); - - ConfigServerUtility::install(); - - data = new ConfigCentralServer::Data; - - KEY_INT (chatServicePort, 61232); - KEY_INT (connectionServicePort, 0); - KEY_INT (customerServicePort, 61242); - KEY_INT (gameServicePort, 44451); - KEY_STRING (loginServerAddress, "127.0.0.1"); - KEY_INT (loginServerPort, 44452); - KEY_STRING (clusterName, "devcluster"); - KEY_STRING (startPlanet, "tatooine"); - KEY_INT (taskManagerPort, 60001); - KEY_INT (planetServicePort, 44455); - KEY_INT (planetServerRestartDelayTimeSeconds, 60); - KEY_INT (connectionServerRestartDelayTimeSeconds, 60); - KEY_INT (chatServerRestartDelayTimeSeconds, 60); - KEY_INT (updatePlayerCountFrequency, 10); - KEY_BOOL (newbieTutorialEnabled, false); - KEY_STRING (chatServiceBindInterface, ""); - KEY_STRING (connectionServiceBindInterface, ""); - KEY_STRING (customerServiceBindInterface, ""); - KEY_STRING (gameServiceBindInterface, ""); - KEY_STRING (loginServiceBindInterface, ""); - KEY_STRING (planetServiceBindInterface, ""); - KEY_INT (firstPlanetWatcherPort, 60002); - KEY_INT (loginServicePort, 44452); - KEY_BOOL (developmentMode, true); - KEY_BOOL (shouldSleep, true); - KEY_BOOL (startPublic, true); - KEY_INT (consoleServicePort, 61000); - KEY_STRING (consoleServiceBindInterface, ""); - KEY_INT (characterCreationTimeout,5*60); // seconds - KEY_STRING (chatServerHost, "local"); - KEY_STRING (dbServerHost, "local"); - KEY_INT (serverPingTimeout,0); // seconds - KEY_INT (recentLoadingStateSeconds,60*60); - KEY_INT (characterCreationRateLimitSeconds, 0); - KEY_INT (characterCtsCreationRateLimitSeconds, 0); - KEY_STRING (transferServerAddress, "127.0.0.1"); - KEY_INT (transferServerPort, 0); // TransferServer listens on 50005, default to "off" - KEY_STRING (stationPlayersCollectorAddress, "127.0.0.1"); - KEY_INT (stationPlayersCollectorPort, 0); // StationPlayersCollector listens on 50010, default to "off" - KEY_BOOL (allowZeroConnectionServerPort, true); - KEY_INT (clusterWideDataLockTimeout, 300); // seconds - KEY_STRING (commodityServerServiceBindInterface, ""); - KEY_INT (commodityServerServicePort, 44456); - KEY_BOOL (shutdown, false); - KEY_BOOL (validateBuildVersionNumber, false); - KEY_INT (gameServerConnectionPendingAllocatedSizeLimit, 0); - KEY_INT (systemTimeMismatchAlertIntervalSeconds, 1*60*60); // seconds - KEY_INT (ctsDenyLoginThresholdSeconds, 2*60*60); // seconds - KEY_BOOL (auctionEnabled, true); - KEY_STRING (auctionServer, "localhost"); - KEY_INT (auctionPort, 5901 ); - KEY_STRING (auctionIDPrefix, "SWG+"); - KEY_BOOL (disconnectDuplicateConnectionsOnOtherGalaxies, false); - KEY_BOOL (requestDbSaveOnPlanetServerCrash, true); - KEY_INT (maxTimeToWaitForPlanetServerStartSeconds, 5*60); // seconds - - int index = 0; - char const * result = 0; - do - { - result = ConfigFile::getKeyString("CentralServer", "startPlanet", index++, 0); - if (result != 0) - { - ms_startPlanets.push_back(result); - } - } - while (result); - - index = 0; - result = 0; - do - { - result = ConfigFile::getKeyString("CentralServer", "startConnectionServer", index++, 0); - if (result != 0) - { - ms_startConnectionServer.push_back(result); - } - } - while (result); -} - -//----------------------------------------------------------------------- - -void ConfigCentralServer::remove(void) -{ - delete data; - data = 0; - ConfigServerUtility::remove(); -} - -//----------------------------------------------------------------------- +// ConfigCentralServer.cpp +// copyright 2000 Verant Interactive +// Author: Justin Randall + + +//----------------------------------------------------------------------- + +#include "FirstCentralServer.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigCentralServer.h" + +//----------------------------------------------------------------------- + +ConfigCentralServer::Data * ConfigCentralServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("CentralServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("CentralServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("CentralServer", #a, b)) + +//----------------------------------------------------------------------- + +namespace ConfigCentralServerNamespace +{ + typedef std::vector StringPtrArray; + StringPtrArray ms_startPlanets; // ConfigFile owns the pointer + StringPtrArray ms_startConnectionServer; +} + +using namespace ConfigCentralServerNamespace; + +// ====================================================================== + +int ConfigCentralServer::getNumberOfStartPlanets() +{ + return static_cast(ms_startPlanets.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigCentralServer::getStartPlanet(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfStartPlanets()); + return ms_startPlanets[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +int ConfigCentralServer::getNumberOfStartingConnectionServers() +{ + return static_cast(ms_startConnectionServer.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigCentralServer::getStartingConnectionServer(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfStartingConnectionServers()); + return ms_startConnectionServer[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +void ConfigCentralServer::install(void) +{ + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + ConfigServerUtility::install(); + + data = new ConfigCentralServer::Data; + + KEY_INT (chatServicePort, 61232); + KEY_INT (connectionServicePort, 0); + KEY_INT (customerServicePort, 61242); + KEY_INT (gameServicePort, 44451); + KEY_STRING (loginServerAddress, "127.0.0.1"); + KEY_INT (loginServerPort, 44452); + KEY_STRING (clusterName, "devcluster"); + KEY_STRING (startPlanet, "tatooine"); + KEY_INT (taskManagerPort, 60001); + KEY_INT (planetServicePort, 44455); + KEY_INT (planetServerRestartDelayTimeSeconds, 60); + KEY_INT (connectionServerRestartDelayTimeSeconds, 60); + KEY_INT (chatServerRestartDelayTimeSeconds, 60); + KEY_INT (updatePlayerCountFrequency, 10); + KEY_BOOL (newbieTutorialEnabled, false); + KEY_STRING (chatServiceBindInterface, ""); + KEY_STRING (connectionServiceBindInterface, ""); + KEY_STRING (customerServiceBindInterface, ""); + KEY_STRING (gameServiceBindInterface, ""); + KEY_STRING (loginServiceBindInterface, ""); + KEY_STRING (planetServiceBindInterface, ""); + KEY_INT (firstPlanetWatcherPort, 60002); + KEY_INT (loginServicePort, 44452); + KEY_BOOL (developmentMode, true); + KEY_BOOL (shouldSleep, true); + KEY_BOOL (startPublic, true); + KEY_INT (consoleServicePort, 61000); + KEY_STRING (consoleServiceBindInterface, ""); + KEY_INT (characterCreationTimeout,5*60); // seconds + KEY_STRING (chatServerHost, "local"); + KEY_STRING (dbServerHost, "local"); + KEY_INT (serverPingTimeout,0); // seconds + KEY_INT (recentLoadingStateSeconds,60*60); + KEY_INT (characterCreationRateLimitSeconds, 0); + KEY_INT (characterCtsCreationRateLimitSeconds, 0); + KEY_STRING (transferServerAddress, "127.0.0.1"); + KEY_INT (transferServerPort, 0); // TransferServer listens on 50005, default to "off" + KEY_STRING (stationPlayersCollectorAddress, "127.0.0.1"); + KEY_INT (stationPlayersCollectorPort, 0); // StationPlayersCollector listens on 50010, default to "off" + KEY_BOOL (allowZeroConnectionServerPort, true); + KEY_INT (clusterWideDataLockTimeout, 300); // seconds + KEY_STRING (commodityServerServiceBindInterface, ""); + KEY_INT (commodityServerServicePort, 44456); + KEY_BOOL (shutdown, false); + KEY_BOOL (validateBuildVersionNumber, false); + KEY_INT (gameServerConnectionPendingAllocatedSizeLimit, 0); + KEY_INT (systemTimeMismatchAlertIntervalSeconds, 1*60*60); // seconds + KEY_INT (ctsDenyLoginThresholdSeconds, 2*60*60); // seconds + KEY_BOOL (auctionEnabled, true); + KEY_STRING (auctionServer, "localhost"); + KEY_INT (auctionPort, 5901 ); + KEY_STRING (auctionIDPrefix, "SWG+"); + KEY_BOOL (disconnectDuplicateConnectionsOnOtherGalaxies, false); + KEY_BOOL (requestDbSaveOnPlanetServerCrash, true); + KEY_INT (maxTimeToWaitForPlanetServerStartSeconds, 5*60); // seconds + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("CentralServer", "startPlanet", index++, 0); + if (result != 0) + { + ms_startPlanets.push_back(result); + } + } + while (result); + + index = 0; + result = 0; + do + { + result = ConfigFile::getKeyString("CentralServer", "startConnectionServer", index++, 0); + if (result != 0) + { + ms_startConnectionServer.push_back(result); + } + } + while (result); +} + +//----------------------------------------------------------------------- + +void ConfigCentralServer::remove(void) +{ + delete data; + data = 0; + ConfigServerUtility::remove(); +} + +//----------------------------------------------------------------------- diff --git a/src/engine/server/application/ChatServer/src/shared/ChatInterface.cpp b/src/engine/server/application/ChatServer/src/shared/ChatInterface.cpp index a25d2c542..9f71e8c3d 100644 --- a/src/engine/server/application/ChatServer/src/shared/ChatInterface.cpp +++ b/src/engine/server/application/ChatServer/src/shared/ChatInterface.cpp @@ -1851,7 +1851,7 @@ void ChatInterface::OnReceiveForcedLogout(const ChatAvatar *oldAvatar) ChatServer::fileLog(false, "ChatInterface", "OnReceiveForcedLogout() oldAvatar(%s)", ChatServer::getFullChatAvatarName(oldAvatar).c_str()); PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceiveForcedLogout"); - if ((oldAvatar == NULL)) + if (oldAvatar == NULL) { DEBUG_WARNING(true, ("We received an OnReceiveForcedLogout with a success result code but NULL data. This is an error that the API should never give.")); return; @@ -2877,7 +2877,7 @@ void ChatInterface::OnReceivePersistentMessage(const ChatAvatar *destAvatar, con ChatServer::fileLog(false, "ChatInterface", "OnReceivePersistentMessage() destAvatar(%s)", ChatServer::getFullChatAvatarName(destAvatar).c_str()); PROFILER_AUTO_BLOCK_DEFINE("ChatInterface - OnReceivePersistentMessage"); - if ((destAvatar == NULL)) + if (destAvatar == NULL) { DEBUG_WARNING(true, ("We received an OnREceivePersistentMessage with a success result code but NULL data. This is an error that the API should never give.")); return; diff --git a/src/engine/server/application/ChatServer/src/shared/ConfigChatServer.cpp b/src/engine/server/application/ChatServer/src/shared/ConfigChatServer.cpp index b89226bdc..1dda67f17 100644 --- a/src/engine/server/application/ChatServer/src/shared/ConfigChatServer.cpp +++ b/src/engine/server/application/ChatServer/src/shared/ConfigChatServer.cpp @@ -1,148 +1,148 @@ -// ConfigChatServer.cpp -// copyright 2000 Verant Interactive -// Author: Justin Randall - - -//----------------------------------------------------------------------- - -#include "FirstChatServer.h" -#include "serverUtility/ConfigServerUtility.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedNetwork/SetupSharedNetwork.h" -#include "ConfigChatServer.h" - -//----------------------------------------------------------------------- - -ConfigChatServer::Data * ConfigChatServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("ChatServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("ChatServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("ChatServer", #a, b)) - -//Commented out so lint doesn't whine that we're not using them -//#define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("ChatServer", #a, b)) - -// ====================================================================== - -namespace ConfigChatServerNamespace -{ - typedef std::vector StringPtrArray; - StringPtrArray ms_createRoom; // ConfigFile owns the pointer - StringPtrArray ms_voiceGateways; -} - -using namespace ConfigChatServerNamespace; - -// ====================================================================== - -int ConfigChatServer::getNumberOfCreateRooms() -{ - return static_cast(ms_createRoom.size()); -} - -// ---------------------------------------------------------------------- - -char const * ConfigChatServer::getCreateRoom(int index) -{ - VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCreateRooms()); - return ms_createRoom[static_cast(index)]; -} - -// ---------------------------------------------------------------------- - -int ConfigChatServer::getNumberOfVoiceChatGateways() -{ - return static_cast(ms_voiceGateways.size()); -} - -// ---------------------------------------------------------------------- - -char const * ConfigChatServer::getVoiceChatGateway(int index) -{ - VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVoiceChatGateways()); - return ms_voiceGateways[static_cast(index)]; -} - -void ConfigChatServer::install(void) -{ - ConfigServerUtility::install(); - - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - SetupSharedNetwork::install(networkSetupData); - - data = new ConfigChatServer::Data; - - KEY_STRING (backupGatewayServerIP, "localhost"); - KEY_INT (backupGatewayServerPort, 15150); - KEY_STRING (clusterName, "devcluster"); - KEY_STRING (centralServerAddress, "localhost"); - KEY_INT (centralServerPort, 61232); - KEY_STRING (gameCode, "SWG"); - KEY_STRING (gatewayServerIP, "localhost"); - KEY_INT (gatewayServerPort, 5001); - KEY_INT (roomInactivityTimeout, 60 * 60 * 24 * 3); - KEY_INT (roomUnpopulatedTimeout, 60 * 5); - KEY_STRING (gameServiceBindInterface, ""); - KEY_STRING (planetServiceBindInterface, ""); - KEY_INT (loginFlowControlRate, 50); - KEY_INT (maxRoomQueriesPerFrame, 5); - KEY_BOOL (loggingEnabled, false); - KEY_STRING (registrarHost, "localhost"); - KEY_INT (registrarPort, 5000); - KEY_INT (intervalToSendHeadersToClientSeconds, 1); - KEY_INT (maxHeadersToSendToClientPerInterval, 100); - KEY_INT (chatStatisticsReportIntervalSeconds, 60); - KEY_INT (chatSpamLimiterNumCharacters, 400); - KEY_BOOL (chatSpamLimiterEnabledForFreeTrial, true); - KEY_INT (chatSpamNotifyPlayerWhenLimitedIntervalSeconds, 30); // <= 0 to disable - KEY_BOOL (voiceChatLoggingEnabled, false); - KEY_INT (voiceChatRoomListRefresh, 600000); - - int index = 0; - char const * result = 0; - do - { - result = ConfigFile::getKeyString("ChatServer", "createRoom", index++, 0); - if (result != 0) - { - ms_createRoom.push_back(result); - } - } - while (result); - - index = 0; - result = 0; - do - { - result = ConfigFile::getKeyString("ChatServer", "voiceChatGateway", index++, 0); - if(result != 0) - { - ms_voiceGateways.push_back(result); - } - } while(result); - - if(ms_voiceGateways.empty()) - { - static char const * const defaultGateway = "localhost:9102"; - ms_voiceGateways.push_back(defaultGateway); - } -} - -//----------------------------------------------------------------------- - -void ConfigChatServer::remove(void) -{ - delete data; - data = 0; - ConfigServerUtility::remove(); -} - -//----------------------------------------------------------------------- - -bool ConfigChatServer::isLoggingEnabled() -{ - return data->loggingEnabled; -} - -//----------------------------------------------------------------------- +// ConfigChatServer.cpp +// copyright 2000 Verant Interactive +// Author: Justin Randall + + +//----------------------------------------------------------------------- + +#include "FirstChatServer.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigChatServer.h" + +//----------------------------------------------------------------------- + +ConfigChatServer::Data * ConfigChatServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("ChatServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("ChatServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("ChatServer", #a, b)) + +//Commented out so lint doesn't whine that we're not using them +//#define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("ChatServer", #a, b)) + +// ====================================================================== + +namespace ConfigChatServerNamespace +{ + typedef std::vector StringPtrArray; + StringPtrArray ms_createRoom; // ConfigFile owns the pointer + StringPtrArray ms_voiceGateways; +} + +using namespace ConfigChatServerNamespace; + +// ====================================================================== + +int ConfigChatServer::getNumberOfCreateRooms() +{ + return static_cast(ms_createRoom.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigChatServer::getCreateRoom(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCreateRooms()); + return ms_createRoom[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +int ConfigChatServer::getNumberOfVoiceChatGateways() +{ + return static_cast(ms_voiceGateways.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigChatServer::getVoiceChatGateway(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfVoiceChatGateways()); + return ms_voiceGateways[static_cast(index)]; +} + +void ConfigChatServer::install(void) +{ + ConfigServerUtility::install(); + + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + data = new ConfigChatServer::Data; + + KEY_STRING (backupGatewayServerIP, "localhost"); + KEY_INT (backupGatewayServerPort, 15150); + KEY_STRING (clusterName, "devcluster"); + KEY_STRING (centralServerAddress, "localhost"); + KEY_INT (centralServerPort, 61232); + KEY_STRING (gameCode, "SWG"); + KEY_STRING (gatewayServerIP, "localhost"); + KEY_INT (gatewayServerPort, 5001); + KEY_INT (roomInactivityTimeout, 60 * 60 * 24 * 3); + KEY_INT (roomUnpopulatedTimeout, 60 * 5); + KEY_STRING (gameServiceBindInterface, ""); + KEY_STRING (planetServiceBindInterface, ""); + KEY_INT (loginFlowControlRate, 50); + KEY_INT (maxRoomQueriesPerFrame, 5); + KEY_BOOL (loggingEnabled, false); + KEY_STRING (registrarHost, "localhost"); + KEY_INT (registrarPort, 5000); + KEY_INT (intervalToSendHeadersToClientSeconds, 1); + KEY_INT (maxHeadersToSendToClientPerInterval, 100); + KEY_INT (chatStatisticsReportIntervalSeconds, 60); + KEY_INT (chatSpamLimiterNumCharacters, 400); + KEY_BOOL (chatSpamLimiterEnabledForFreeTrial, true); + KEY_INT (chatSpamNotifyPlayerWhenLimitedIntervalSeconds, 30); // <= 0 to disable + KEY_BOOL (voiceChatLoggingEnabled, false); + KEY_INT (voiceChatRoomListRefresh, 600000); + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("ChatServer", "createRoom", index++, 0); + if (result != 0) + { + ms_createRoom.push_back(result); + } + } + while (result); + + index = 0; + result = 0; + do + { + result = ConfigFile::getKeyString("ChatServer", "voiceChatGateway", index++, 0); + if(result != 0) + { + ms_voiceGateways.push_back(result); + } + } while(result); + + if(ms_voiceGateways.empty()) + { + static char const * const defaultGateway = "localhost:9102"; + ms_voiceGateways.push_back(defaultGateway); + } +} + +//----------------------------------------------------------------------- + +void ConfigChatServer::remove(void) +{ + delete data; + data = 0; + ConfigServerUtility::remove(); +} + +//----------------------------------------------------------------------- + +bool ConfigChatServer::isLoggingEnabled() +{ + return data->loggingEnabled; +} + +//----------------------------------------------------------------------- diff --git a/src/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.cpp b/src/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.cpp index 6dbad80b1..2ce8ddbd7 100644 --- a/src/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.cpp +++ b/src/engine/server/application/ChatServer/src/shared/ConnectionServerConnection.cpp @@ -421,7 +421,7 @@ void ConnectionServerConnection::onReceive(const Archive::ByteStream & message) NetworkId targetId = message.getKickeeId(); std::string const & targetName = message.getKickeeName(); if(targetId.isValid() || - !targetName.empty() && (ChatServer::getVoiceChatLoginInfoFromName(targetName, targetId))) + (!targetName.empty() && (ChatServer::getVoiceChatLoginInfoFromName(targetName, targetId)))) { ChatServer::requestKickPlayerFromChannel(message.getRequester(), targetId, message.getChannelName()); } diff --git a/src/engine/server/application/CommoditiesServer/src/shared/Auction.cpp b/src/engine/server/application/CommoditiesServer/src/shared/Auction.cpp index 612a37159..0d1edd7fc 100644 --- a/src/engine/server/application/CommoditiesServer/src/shared/Auction.cpp +++ b/src/engine/server/application/CommoditiesServer/src/shared/Auction.cpp @@ -1,1457 +1,1457 @@ -// ====================================================================== -// -// Auction.cpp -// copyright (c) 2004 Sony Online Entertainment -// -// (refactor of original code only to the degree to make it work with new) -// (server & database framework ... i.e. none of the logic has changed) -// -// Original Author: Matt Severenson -// Refactored by : Doug Mellencamp -// -// ====================================================================== - -#include "FirstCommodityServer.h" -#include "Auction.h" -#include "AuctionMarket.h" -#include "CommodityServer.h" -#include "ConfigCommodityServer.h" -#include "StringId.h" -#include "UnicodeUtils.h" -#include "sharedFoundation/Crc.h" -#include "sharedFoundation/CrcLowerString.h" -#include "sharedGame/CommoditiesAdvancedSearchAttribute.h" -#include "sharedGame/GameObjectTypes.h" -#include "sharedGame/SharedObjectTemplate.h" -#include "sharedLog/Log.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" - -#include - -// src/engine/client/library/clientGame/src/shared/core/AuctionManagerClient.cpp (s_maxBid) -// src/engine/server/application/CommoditiesServer/src/shared/Auction.cpp (MAX_BID) -// src/engine/server/library/serverGame/src/shared/commoditiesMarket/CommoditiesMarket.cpp (MAX_BID) -#define MAX_BID 10000000 -#define MAX_VENDOR_PRICE 833333333 - -namespace AuctionNamespace -{ - typedef bool (*SearchConditionComparisonFn) (AuctionQueryHeadersMessage::SearchCondition const & /*searchCondition*/, - std::map const * /*searchableAttributeInt*/, - std::map const * /*searchableAttributeFloat*/, - std::map const * /*searchableAttributeString*/, - bool & /*applicableSearchCondition*/); - - SearchConditionComparisonFn s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_LAST)]; - - // ---------------------------------------------------------------------- - - bool searchConditionComparisonFnInt(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, - std::map const * searchableAttributeInt, - std::map const * searchableAttributeFloat, - std::map const * searchableAttributeString, - bool & applicableSearchCondition) - { -#ifdef _DEBUG - DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_int), ("searchConditionComparisonFnInt() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_int", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); - DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnInt\n")); -#endif - UNREF(searchableAttributeFloat); - UNREF(searchableAttributeString); - - // if the filter condition requires the attribute, - // it will always be an applicable filter condition; - // otherwise, it will only be applicable if the item - // has the attribute - applicableSearchCondition = searchCondition.requiredAttribute; - - if (searchableAttributeInt) - { - std::map::const_iterator iterAttr = searchableAttributeInt->find(searchCondition.attributeNameCrc); - if (iterAttr != searchableAttributeInt->end()) - { - applicableSearchCondition = true; - return ((iterAttr->second >= searchCondition.intMin) && (iterAttr->second <= searchCondition.intMax)); - } - } - - return false; - } - - // ---------------------------------------------------------------------- - - bool searchConditionComparisonFnFloat(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, - std::map const * searchableAttributeInt, - std::map const * searchableAttributeFloat, - std::map const * searchableAttributeString, - bool & applicableSearchCondition) - { -#ifdef _DEBUG - DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_float), ("searchConditionComparisonFnFloat() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_float", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); - DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnFloat\n")); -#endif - UNREF(searchableAttributeInt); - UNREF(searchableAttributeString); - - // if the filter condition requires the attribute, - // it will always be an applicable filter condition; - // otherwise, it will only be applicable if the item - // has the attribute - applicableSearchCondition = searchCondition.requiredAttribute; - - if (searchableAttributeFloat) - { - std::map::const_iterator iterAttr = searchableAttributeFloat->find(searchCondition.attributeNameCrc); - if (iterAttr != searchableAttributeFloat->end()) - { - applicableSearchCondition = true; - return ((iterAttr->second >= searchCondition.floatMin) && (iterAttr->second <= searchCondition.floatMax)); - } - } - - return false; - } - - // ---------------------------------------------------------------------- - - bool searchConditionComparisonFnStringEqual(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, - std::map const * searchableAttributeInt, - std::map const * searchableAttributeFloat, - std::map const * searchableAttributeString, - bool & applicableSearchCondition) - { -#ifdef _DEBUG - DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_equal), ("searchConditionComparisonFnStringEqual() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_equal", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); - DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringEqual\n")); -#endif - UNREF(searchableAttributeInt); - UNREF(searchableAttributeFloat); - - // if the filter condition requires the attribute, - // it will always be an applicable filter condition; - // otherwise, it will only be applicable if the item - // has the attribute - applicableSearchCondition = searchCondition.requiredAttribute; - - if (searchableAttributeString) - { - std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); - if (iterAttr != searchableAttributeString->end()) - { - applicableSearchCondition = true; - return (0 == strcmp(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) - } - } - - return false; - } - - // ---------------------------------------------------------------------- - - bool searchConditionComparisonFnStringNotEqual(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, - std::map const * searchableAttributeInt, - std::map const * searchableAttributeFloat, - std::map const * searchableAttributeString, - bool & applicableSearchCondition) - { -#ifdef _DEBUG - DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_not_equal), ("searchConditionComparisonFnStringNotEqual() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_not_equal", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); - DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringNotEqual\n")); -#endif - UNREF(searchableAttributeInt); - UNREF(searchableAttributeFloat); - - // if the filter condition requires the attribute, - // it will always be an applicable filter condition; - // otherwise, it will only be applicable if the item - // has the attribute - applicableSearchCondition = searchCondition.requiredAttribute; - - if (searchableAttributeString) - { - std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); - if (iterAttr != searchableAttributeString->end()) - { - applicableSearchCondition = true; - return (0 != strcmp(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) - } - } - - return false; - } - - // ---------------------------------------------------------------------- - - bool searchConditionComparisonFnStringContain(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, - std::map const * searchableAttributeInt, - std::map const * searchableAttributeFloat, - std::map const * searchableAttributeString, - bool & applicableSearchCondition) - { -#ifdef _DEBUG - DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_contain), ("searchConditionComparisonFnStringContain() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_contain", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); - DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringContain\n")); -#endif - UNREF(searchableAttributeInt); - UNREF(searchableAttributeFloat); - - // if the filter condition requires the attribute, - // it will always be an applicable filter condition; - // otherwise, it will only be applicable if the item - // has the attribute - applicableSearchCondition = searchCondition.requiredAttribute; - - if (searchableAttributeString) - { - std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); - if (iterAttr != searchableAttributeString->end()) - { - applicableSearchCondition = true; - return (NULL != strstr(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) - } - } - - return false; - } - - // ---------------------------------------------------------------------- - - bool searchConditionComparisonFnStringNotContain(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, - std::map const * searchableAttributeInt, - std::map const * searchableAttributeFloat, - std::map const * searchableAttributeString, - bool & applicableSearchCondition) - { -#ifdef _DEBUG - DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_not_contain), ("searchConditionComparisonFnStringNotContain() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_not_contain", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); - DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringNotContain\n")); -#endif - UNREF(searchableAttributeInt); - UNREF(searchableAttributeFloat); - - // if the filter condition requires the attribute, - // it will always be an applicable filter condition; - // otherwise, it will only be applicable if the item - // has the attribute - applicableSearchCondition = searchCondition.requiredAttribute; - - if (searchableAttributeString) - { - std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); - if (iterAttr != searchableAttributeString->end()) - { - applicableSearchCondition = true; - return (NULL == strstr(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) - } - } - - return false; - } - - // ---------------------------------------------------------------------- - - // - std::pair s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; - std::pair s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; - - // search return value - bool s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; - bool s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; -}; - -using namespace AuctionNamespace; - -// ====================================================================== - -Auction::Auction( - const NetworkId & creatorId, - int minBid, - int auctionTimer, - const NetworkId & itemId, - int itemNameLength, - const Unicode::String & itemName, - int itemType, - int itemTemplateId, - int itemTimer, - int itemSize, - const AuctionLocation & location, - int flags, - int buyNowPrice, - int userDescriptionLength, - const Unicode::String & userDescription, - int oobLength, - const Unicode::String & oobData, - std::vector > const & attributes -) : -m_creatorId(creatorId), -m_minBid(minBid), -m_auctionTimer(auctionTimer), -m_buyNowPrice(buyNowPrice), -m_userDescriptionLength(userDescriptionLength), -m_userDescription(userDescription), -m_oobLength(oobLength), -m_oobData(oobData), -m_attributes(), -m_searchableAttributeInt(NULL), -m_searchableAttributeFloat(NULL), -m_searchableAttributeString(NULL), -m_highBid(NULL), -m_item(new AuctionItem(itemId, itemType, itemTemplateId, itemTimer, itemNameLength, itemName, creatorId, itemSize)), -m_sold(false), -m_active(true), -m_bids(), -m_location(const_cast(location)), -m_flags(flags), -m_trackId(-1) -{ - assert(m_auctionTimer != 0); - - // it it's a instant sale resource container, add "credits per unit" attribute - if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && (m_buyNowPrice > 0)) - { - for (std::vector >::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) - { - if (iter->first == "credits_per_unit") - { - // ignore any existing credits per unit attribute; we'll recalculate it and add the updated attribute - continue; - } - - m_attributes.push_back(*iter); - - if (iter->first == "resource_contents") - { - int count = ::atoi(Unicode::wideToNarrow(iter->second).c_str()); - if (count > 0) - { - char buffer[128]; - int const len = snprintf(buffer, sizeof(buffer)-1, "%.6f", (static_cast(m_buyNowPrice) / static_cast(count))); - buffer[sizeof(buffer)-1] = '\0'; - - // trim trailing 0s after the decimal point - char * pChar = buffer + len - 1; - while (pChar >= buffer) - { - if (*pChar == '.') - { - *pChar = '\0'; - break; - } - else if (*pChar != '0') - { - ++pChar; - *pChar = '\0'; - break; - } - - --pChar; - } - - m_attributes.push_back(std::make_pair("credits_per_unit", Unicode::narrowToWide(buffer))); - } - } - } - } - else - { - m_attributes = attributes; - } - - SetItemResourceContainerClassCrc(); - BuildSearchableAttributeList(); -} - -// ---------------------------------------------------------------------- - -Auction::Auction( - const NetworkId & creatorId, - int minBid, - int auctionTimer, - const NetworkId & itemId, - int itemNameLength, - const Unicode::String & itemName, - int itemType, - int itemTemplateId, - int itemTimer, - int itemSize, - const AuctionLocation & location, - int flags, - int buyNowPrice, - int userDescriptionLength, - const Unicode::String & userDescription, - int oobLength, - const Unicode::String & oobData, - std::vector > const & attributes, - bool isActive, - bool isSold -) : -m_creatorId(creatorId), -m_minBid(minBid), -m_auctionTimer(auctionTimer), -m_buyNowPrice(buyNowPrice), -m_userDescriptionLength(userDescriptionLength), -m_userDescription(userDescription), -m_oobLength(oobLength), -m_oobData(oobData), -m_attributes(), -m_searchableAttributeInt(NULL), -m_searchableAttributeFloat(NULL), -m_searchableAttributeString(NULL), -m_highBid(NULL), -m_item(new AuctionItem(itemId, itemType, itemTemplateId, itemTimer, itemNameLength, itemName, creatorId, itemSize)), -m_sold(isSold), -m_active(isActive), -m_bids(), -m_location(const_cast(location)), -m_flags(flags), -m_trackId(-1) -{ - assert(m_auctionTimer != 0); - - // it it's a instant sale resource container, add "credits per unit" attribute - if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && (m_buyNowPrice > 0)) - { - for (std::vector >::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) - { - if (iter->first == "credits_per_unit") - { - // ignore any existing credits per unit attribute; we'll recalculate it and add the updated attribute - continue; - } - - m_attributes.push_back(*iter); - - if (iter->first == "resource_contents") - { - int count = ::atoi(Unicode::wideToNarrow(iter->second).c_str()); - if (count > 0) - { - char buffer[128]; - int const len = snprintf(buffer, sizeof(buffer)-1, "%.6f", (static_cast(m_buyNowPrice) / static_cast(count))); - buffer[sizeof(buffer)-1] = '\0'; - - // trim trailing 0s after the decimal point - char * pChar = buffer + len - 1; - while (pChar >= buffer) - { - if (*pChar == '.') - { - *pChar = '\0'; - break; - } - else if (*pChar != '0') - { - ++pChar; - *pChar = '\0'; - break; - } - - --pChar; - } - - m_attributes.push_back(std::make_pair("credits_per_unit", Unicode::narrowToWide(buffer))); - } - } - } - } - else - { - m_attributes = attributes; - } - - SetItemResourceContainerClassCrc(); - BuildSearchableAttributeList(); -} - -// ---------------------------------------------------------------------- - -Auction::~Auction() -{ - std::vector::iterator i = m_bids.begin(); - for (; i != m_bids.end(); ++i) - { - AuctionBid *bid = (*i); - delete bid; - } - delete m_item; - - delete m_searchableAttributeInt; - delete m_searchableAttributeFloat; - delete m_searchableAttributeString; -} - -// ---------------------------------------------------------------------- - -void Auction::Initialization() -{ -#ifdef _DEBUG - for (int i = 0; i < static_cast(AuctionQueryHeadersMessage::SCC_LAST); ++i) - { - s_searchConditionComparisonFn[i] = NULL; - } -#endif - - s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_int)] = searchConditionComparisonFnInt; - s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_float)] = searchConditionComparisonFnFloat; - s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_equal)] = searchConditionComparisonFnStringEqual; - s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_not_equal)] = searchConditionComparisonFnStringNotEqual; - s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_contain)] = searchConditionComparisonFnStringContain; - s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_not_contain)] = searchConditionComparisonFnStringNotContain; - -#ifdef _DEBUG - for (int j = 0; j < static_cast(AuctionQueryHeadersMessage::SCC_LAST); ++j) - { - DEBUG_FATAL((s_searchConditionComparisonFn[j] == NULL), ("s_searchConditionComparisonFn array is NULL at index (%d)", j)); - } -#endif - - // - static std::pair const continueToCheckNextMatch(std::make_pair(false, false)); - static std::pair const stopAndReturnTrue(std::make_pair(true, true)); - static std::pair const stopAndReturnFalse(std::make_pair(true, false)); - - // "will only match if all applicable attribute filter conditions match" - // ASMAA_match_all -> true after all match - // -> false after first mismatch - s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = continueToCheckNextMatch; // after any match, continue to check next match - s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = stopAndReturnFalse; // after any not match, stop and return false - s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = true; // after all match, return true - s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = false; // after all not match, return false - - // "will only match if any applicable attribute filter condition matches" - // ASMAA_match_any -> false after all mismatch - // -> true after first match - s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = stopAndReturnTrue; // after any match, stop and return true - s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = continueToCheckNextMatch; // after any not match, continue to check next match - s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = true; // after all match, return true - s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = false; // after all not match, return false - - // "will only match if no applicable attribute filter condition matches" - // (i.e. match none) - // ASMAA_not_match_all is basically "not ASMAA_match_any" - // ASMAA_not_match_all -> true after all mismatch - // -> false after first match - s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = stopAndReturnFalse; // after any match, stop and return false - s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = continueToCheckNextMatch; // after any not match, continue to check next match - s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = false; // after all match, return false - s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = true; // after all not match, return true - - // "will only match if any applicable attribute filter condition does not match" - // ASMAA_not_match_any is basically "not ASMAA_match_all" - // ASMAA_not_match_any -> false after all match - // -> true after first mismatch - s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = continueToCheckNextMatch; // after any match, continue to check next match - s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = stopAndReturnTrue; // after any not match, stop and return true - s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = false; // after all match, return false - s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = true; // after all not match, return true -} - -// ---------------------------------------------------------------------- - -void Auction::GetAttributes(std::string & output) const -{ - output.clear(); - - output = Unicode::wideToNarrow(m_item->GetName()); - output += " ("; - output += m_item->GetItemId().getValueString(); - output += ") (GOT_"; - output += GameObjectTypes::getCanonicalName(m_item->GetCategory()); - output += ")\r\n\r\n"; - - char buffer[2048]; - for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) - { - snprintf(buffer, sizeof(buffer)-1, "(%s) (%s)", iter->first.c_str(), Unicode::wideToNarrow(iter->second).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - - output += buffer; - output += "\r\n"; - } - - if (m_searchableAttributeInt) - { - output += "\r\nInteger indexed search attribute:\r\n"; - - for (std::map::const_iterator iter = m_searchableAttributeInt->begin(); iter != m_searchableAttributeInt->end(); ++iter) - { - std::string attributeName; - for (std::vector >::const_iterator iterAttribute = m_attributes.begin(); iterAttribute != m_attributes.end(); ++iterAttribute) - { - if (Crc::calculate(iterAttribute->first.c_str()) == iter->first) - { - attributeName = iterAttribute->first; - break; - } - } - - snprintf(buffer, sizeof(buffer)-1, "(%s, %lu) (%d)", attributeName.c_str(), iter->first, iter->second); - buffer[sizeof(buffer)-1] = '\0'; - - output += buffer; - output += "\r\n"; - } - } - - if (m_searchableAttributeFloat) - { - output += "\r\nFloat indexed search attribute:\r\n"; - - for (std::map::const_iterator iter = m_searchableAttributeFloat->begin(); iter != m_searchableAttributeFloat->end(); ++iter) - { - std::string attributeName; - for (std::vector >::const_iterator iterAttribute = m_attributes.begin(); iterAttribute != m_attributes.end(); ++iterAttribute) - { - if (Crc::calculate(iterAttribute->first.c_str()) == iter->first) - { - attributeName = iterAttribute->first; - break; - } - } - - snprintf(buffer, sizeof(buffer)-1, "(%s, %lu) (%.10g)", attributeName.c_str(), iter->first, iter->second); - buffer[sizeof(buffer)-1] = '\0'; - - output += buffer; - output += "\r\n"; - } - } - - if (m_searchableAttributeString) - { - output += "\r\nString indexed search attribute:\r\n"; - - for (std::map::const_iterator iter = m_searchableAttributeString->begin(); iter != m_searchableAttributeString->end(); ++iter) - { - std::string attributeName; - for (std::vector >::const_iterator iterAttribute = m_attributes.begin(); iterAttribute != m_attributes.end(); ++iterAttribute) - { - if (Crc::calculate(iterAttribute->first.c_str()) == iter->first) - { - attributeName = iterAttribute->first; - break; - } - } - - snprintf(buffer, sizeof(buffer)-1, "(%s, %lu) (%s)", attributeName.c_str(), iter->first, iter->second.c_str()); - buffer[sizeof(buffer)-1] = '\0'; - - output += buffer; - output += "\r\n"; - } - } -} - -// ---------------------------------------------------------------------- - -int Auction::GetHighBidAmount() const -{ - if (m_highBid) - return m_highBid->GetBid(); - else - return 0; -} - -// ---------------------------------------------------------------------- - -const AuctionBid *Auction::GetPreviousBid() const -{ - if (m_bids.size() <= 1) - { - return NULL; - } - else - { - return m_bids[m_bids.size() - 2]; - } -} - -// ---------------------------------------------------------------------- - -/** - * This isn't at all obvious, so here is a description. This function returns - * bid that will actually take place when a given bid is attempted. This bid - * can be less than the existing bid, so the bid will fail, but we still need - * to adjust the existing high bid to outbid the current one. - */ -int Auction::GetActualBid(AuctionBid *bid) -{ - assert(bid != NULL); - int bidNeeded = std::max(m_minBid, bid->GetBid()); - if (m_highBid != NULL) - { - bidNeeded = m_highBid->GetBid(); - if (*bid > *m_highBid) - { - bidNeeded = std::max(bid->GetBid(), m_highBid->GetMaxProxyBid() + 1); - } - else if (*bid == *m_highBid) - { - bidNeeded = m_highBid->GetMaxProxyBid(); - } - else if (*bid < *m_highBid) - { - bidNeeded = std::max(m_highBid->GetBid(), bid->GetMaxProxyBid() + 1); - } - } - return bidNeeded; -} - -// ---------------------------------------------------------------------- - -void Auction::AddLoadedBid( - const NetworkId & bidderId, - int bid, - int maxProxyBid -) -{ - AuctionBid *auctionBid = new AuctionBid(bidderId, bid, maxProxyBid); - std::vector::iterator i = m_bids.begin(); - bool inserted = false; - for (; i != m_bids.end(); ++i) - { - if ((*i)->GetMaxProxyBid() > auctionBid->GetMaxProxyBid()) - { - m_bids.insert(i, auctionBid); - inserted = true; - break; - } - } - - if (!inserted) - { - m_bids.push_back(auctionBid); - } - m_highBid = m_bids.back(); -} - -// ---------------------------------------------------------------------- - -AuctionResultCode Auction::AddBid( - const NetworkId & bidderId, - int bid, - int maxProxyBid -) -{ - AuctionResultCode success = ARC_Success; - int maxBid = std::max(bid, maxProxyBid); - - if (!m_active || m_sold) - { - return ARC_AuctionExpired; - DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Auction Expired - Auction is sold and inactive.\n")); - } - - if (maxBid > MAX_BID && !m_location.IsVendorMarket()) - { - return ARC_BidTooHigh; - DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Bid too high.\n")); - } - - /*!!!TODO, put me back in after testingif (bidderId == m_creatorId) - { - return ARC_OwnerBidOnOwnItem; - }*/ - if (maxProxyBid < m_minBid) - { - return ARC_BidTooLow; - DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Bid too low.\n")); - } - if (IsImmediate() && (GetFlags() & AUCTION_ALWAYS_PRESENT)) - { - return ARC_SuccessPermanentAuction; - } - - AuctionBid *auctionBid = new AuctionBid(bidderId, bid, maxProxyBid); - int newBidForHighBidder = GetActualBid(auctionBid); - if (m_highBid != NULL) - { - if (*auctionBid <= *m_highBid) - { - delete auctionBid; - success = ARC_BidOutbid; - DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Bid outbid.\n")); - } - } - - if (success == ARC_Success) - { - m_highBid = auctionBid; - m_bids.push_back(auctionBid); - } - m_highBid->SetBid(newBidForHighBidder); - - if (IsImmediate()) - { - m_sold = true; - DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Immediate Auction - marked as sold.\n")); - - // put auction into the completed auctions list so - // that the auction can be processed to completion - // during the next frame - AuctionMarket::getInstance().AddAuctionToCompletedAuctionsList(*this); - } - return success; -} - -// ---------------------------------------------------------------------- - -const AuctionBid *Auction::GetPlayerBid(const NetworkId & playerId) const -{ - // new bids are pushed on the back of the vector - // so, we search using a reverse iterator - std::vector::const_reverse_iterator iter = m_bids.rbegin(); - while (iter != m_bids.rend()) - { - if ((*iter) && ((*iter)->GetBidderId() == playerId)) - { - return (*iter); - } - ++iter; - } - return NULL; -} - -// ---------------------------------------------------------------------- - -bool Auction::Update(int gameTime) -{ - if (GetFlags() & AUCTION_ALWAYS_PRESENT) - { - return true; - } - if (m_active && m_sold) - { - //immediate sale - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Update] : Expiring immediate sale - Auction is active and sold.\n")); - - if ((m_trackId != -1) && (CommodityServer::getInstance().getGameServer(m_trackId) != NULL)) - { - Expire(true, false, m_trackId); - m_trackId = -1; - } - else - { - Expire(true, false); - } - } - else if (m_active && (gameTime >= m_auctionTimer)) - { - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Update] : Auction expiring based on timer.\n")); - - if ((m_trackId != -1) && (CommodityServer::getInstance().getGameServer(m_trackId) != NULL)) - { - Expire(m_highBid != NULL, true, m_trackId); - m_trackId = -1; - } - else - { - Expire(m_highBid != NULL, true); - } - } - - return !m_item->IsExpired(gameTime); -} - -// ---------------------------------------------------------------------- - -void Auction::Expire(bool sold, bool expiredBasedOnTimer, int track_id) -{ - AuctionMarket::getInstance().RemoveFromAuctionTimerPriorityQueue(m_auctionTimer, m_item->GetItemId()); - - m_auctionTimer = 0; - m_active = false; - if (sold && m_highBid != NULL) - { - m_sold = true; - } - else - { - m_sold = false; - } - - bool immediate = IsImmediate(); - - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sold flag is %d.\n", m_sold)); - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Active flag is %d.\n", m_active)); - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Immediate flag is %d.\n", immediate)); - - if (m_sold) - { - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Old Owner is %s.\n", m_item->GetOwnerId().getValueString().c_str())); - m_item->SetOwnerId(m_highBid->GetBidderId()); - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : New Owner is %s.\n", m_item->GetOwnerId().getValueString().c_str())); - - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sending OnAuctionExpired for sold auction .\n")); - - AuctionMarket::getInstance().OnAuctionExpired( - GetCreatorId(), m_sold, m_flags, - m_highBid->GetBidderId(), m_highBid->GetBid(), m_item->GetItemId(), - m_highBid->GetMaxProxyBid(), - m_location.GetLocationString(), immediate, - m_item->GetNameLength(), m_item->GetName(), - m_item->GetOwnerId(), track_id, true); - } - else - { - if (m_highBid) - { - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sending OnAuctionExpired for non-sold auction and high bid obj .\n")); - AuctionMarket::getInstance().OnAuctionExpired( - GetCreatorId(), m_sold, m_flags, - m_highBid->GetBidderId(), m_highBid->GetBid(), m_item->GetItemId(), - m_highBid->GetMaxProxyBid(), - m_location.GetLocationString(), immediate, - m_item->GetNameLength(), m_item->GetName(), - m_item->GetOwnerId(), track_id, true); - } - else - { - // for items on a vendor placed by the vendor owner, we - // use the following rule to determine if a mail message - // should be sent to the vendor owner when the item - // auction expire and goes back into the vendor stockroom; - // the goal here is to avoid sending too many mail message - // to a vendor owner when a bunch of auctions expire around - // the same time - // - // 1) if the auction did not expire because of the auction - // timer, don't send mail. This means if the vendor owner - // withdraws the sale of an item, no mail is sent. - // 2) if the auction expired because of the auction timer, - // send mail only for the first item, and don't send - // another mail until the next auction expires after - // the vendor is next accessed or the cluster is restarted. - bool sendSellerMail = true; - if (m_location.IsVendorMarket() && m_location.IsOwner(GetCreatorId())) - { - if (!expiredBasedOnTimer) - sendSellerMail = false; - else if (m_location.GetVendorFirstTimerExpiredAuctionDate() > 0) - sendSellerMail = false; - else - m_location.SetVendorFirstTimerExpiredAuctionDate(time(0)); - } - - DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sending OnAuctionExpired for non-sold auction and null high bid obj .\n")); - AuctionMarket::getInstance().OnAuctionExpired( - GetCreatorId(), m_sold, m_flags, - NetworkId::cms_invalid, 0, m_item->GetItemId(), 0, - m_location.GetLocationString(), immediate, - m_item->GetNameLength(), m_item->GetName(), - m_item->GetOwnerId(), track_id, sendSellerMail); - } - if (m_location.IsVendorMarket() && - m_location.IsOwner(GetCreatorId())) - { - //vendor owner canceled his own auction. Sorry this is such a hack - m_location.CancelVendorSale(this); - } - } - - if (m_location.IsVendorMarket()) - { - //If its a vendor, remove and then re-add the item to ensure it is in the right list - m_location.RemoveAuction(this); - m_location.AddAuction(this); - } -} - -// ---------------------------------------------------------------------- - -int Auction::GetBuyNowPriceWithSalesTax() const -{ - if( GetBuyNowPrice() > 0 ) - { - int salesTax = GetLocation().GetSalesTax(); - return (int)(GetBuyNowPrice() + (GetBuyNowPrice() * (salesTax/10000.0f))); - } - else - { - return 0; - } -} - -// ---------------------------------------------------------------------- - -void Auction::AddAttributes(const std::string & attributeName, const Unicode::String & attributeValue) -{ - // it it's a instant sale resource container, add "credits per unit" attribute - // once we receive the item count attribute for the resource container, and also - // ignore any existing "credits per unit" attribute to avoid duplicate attribute - if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory())) - { - if (m_buyNowPrice > 0) - { - if (attributeName == "credits_per_unit") - { - // ignore any existing credits per unit attribute; we'll recalculate it and add the updated attribute - return; - } - - m_attributes.push_back(std::make_pair(attributeName, attributeValue)); - - if (attributeName == "resource_contents") - { - int count = ::atoi(Unicode::wideToNarrow(attributeValue).c_str()); - if (count > 0) - { - char buffer[128]; - int const len = snprintf(buffer, sizeof(buffer)-1, "%.6f", (static_cast(m_buyNowPrice) / static_cast(count))); - buffer[sizeof(buffer)-1] = '\0'; - - // trim trailing 0s after the decimal point - char * pChar = buffer + len - 1; - while (pChar >= buffer) - { - if (*pChar == '.') - { - *pChar = '\0'; - break; - } - else if (*pChar != '0') - { - ++pChar; - *pChar = '\0'; - break; - } - - --pChar; - } - - m_attributes.push_back(std::make_pair("credits_per_unit", Unicode::narrowToWide(buffer))); - } - - return; - } - } - else - { - m_attributes.push_back(std::make_pair(attributeName, attributeValue)); - } - - SetItemResourceContainerClassCrc(attributeName, attributeValue); - } - else - { - m_attributes.push_back(std::make_pair(attributeName, attributeValue)); - } -} - -// ---------------------------------------------------------------------- - -void Auction::SetItemResourceContainerClassCrc() -{ - if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && ((m_item->GetResourceContainerClassCrc() == 0) || (m_item->GetResourceNameCrc() == 0))) - { - for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) - { - if ((iter->first == "resource_class") || (iter->first == "resource_name")) - { - SetItemResourceContainerClassCrc(iter->first, iter->second); - - if ((m_item->GetResourceContainerClassCrc() != 0) && (m_item->GetResourceNameCrc() != 0)) - break; - } - } - } -} - -// ---------------------------------------------------------------------- - -void Auction::SetItemResourceContainerClassCrc(const std::string & attributeName, const Unicode::String & attributeValue) -{ - if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && ((m_item->GetResourceContainerClassCrc() == 0) || (m_item->GetResourceNameCrc() == 0))) - { - if ((attributeName == "resource_class") || (attributeName == "resource_name")) - { - if ((attributeName == "resource_class") && (m_item->GetResourceContainerClassCrc() == 0)) - { - std::string className = Unicode::wideToNarrow(attributeValue); - if (0 == className.find("@resource/resource_names:")) - { - className = className.substr(sizeof("@resource/resource_names:") - 1); - if (!className.empty()) - { - m_item->SetResourceContainerClassCrc(static_cast(Crc::calculate(className.c_str()))); - } - } - } - else if ((attributeName == "resource_name") && (m_item->GetResourceNameCrc() == 0)) - { - std::string name = Unicode::wideToNarrow(attributeValue); - if (!name.empty()) - { - m_item->SetResourceName(name); - m_item->SetResourceNameCrc(static_cast(Crc::calculate(name.c_str()))); - } - } - - if ((m_item->GetResourceContainerClassCrc() != 0) && (m_item->GetResourceNameCrc() != 0)) - { - AuctionMarket::getInstance().AddResourceType(m_item->GetResourceContainerClassCrc(), m_item->GetResourceName()); - } - } - } -} - -// ---------------------------------------------------------------------- - -void Auction::BuildSearchableAttributeList() -{ - std::map const & sa = CommoditiesAdvancedSearchAttribute::getSearchAttributeForGameObjectType(m_item->GetCategory()); - if (sa.empty()) - return; - - std::map const & saAlias = CommoditiesAdvancedSearchAttribute::getSearchAttributeNameAliasesForGameObjectType(m_item->GetCategory()); - - // for factory crates, also include the attributes of the item inside the crate - std::map const * saItemInsideFactoryCrate = NULL; - std::map const * saAliasItemInsideFactoryCrate = NULL; - int gotItemInsideFactoryCrate = 0; - - if (m_item->GetCategory() == SharedObjectTemplate::GOT_misc_factory_crate) - { - // determine the type of item inside the crate by looking at the value of the object_type attribute - for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) - { - if (iter->first == "object_type") - { - std::string const objectType(Unicode::wideToNarrow(iter->second)); - if (0 == objectType.find("@got_n:")) - { - gotItemInsideFactoryCrate = GameObjectTypes::getGameObjectType(objectType.substr(7)); - if (gotItemInsideFactoryCrate == SharedObjectTemplate::GOT_misc_factory_crate) - { - // factory crate inside factory crate??? - gotItemInsideFactoryCrate = 0; - } - - if (gotItemInsideFactoryCrate > 0) - { - saItemInsideFactoryCrate = &(CommoditiesAdvancedSearchAttribute::getSearchAttributeForGameObjectType(gotItemInsideFactoryCrate)); - saAliasItemInsideFactoryCrate = &(CommoditiesAdvancedSearchAttribute::getSearchAttributeNameAliasesForGameObjectType(gotItemInsideFactoryCrate)); - - if (saItemInsideFactoryCrate->empty()) - saItemInsideFactoryCrate = NULL; - - if (saAliasItemInsideFactoryCrate->empty()) - saAliasItemInsideFactoryCrate = NULL; - } - } - - break; - } - } - } - - std::string attributeName; - for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) - { - // strip out the embedded trailing '\0' on those funky attribute - // name that have the trailing '\0' embedded in the string - // - // also, remove any leading/trailing white space - attributeName = Unicode::getTrim(iter->first.c_str()); - - // handle attribute name alias - if (!saAlias.empty()) - { - std::map::const_iterator const iterFindAlias = saAlias.find(attributeName); - if (iterFindAlias != saAlias.end()) - { - attributeName = iterFindAlias->second; - } - } - - std::map::const_iterator iterFind = sa.find(attributeName); - if ((iterFind == sa.end()) && (m_item->GetCategory() == SharedObjectTemplate::GOT_misc_factory_crate) && saItemInsideFactoryCrate) - { - // strip out the embedded trailing '\0' on those funky attribute - // name that have the trailing '\0' embedded in the string - // - // also, remove any leading/trailing white space - attributeName = Unicode::getTrim(iter->first.c_str()); - - // handle attribute name alias - if (saAliasItemInsideFactoryCrate && !saAliasItemInsideFactoryCrate->empty()) - { - std::map::const_iterator const iterFindAlias = saAliasItemInsideFactoryCrate->find(attributeName); - if (iterFindAlias != saAliasItemInsideFactoryCrate->end()) - { - attributeName = iterFindAlias->second; - } - } - - iterFind = saItemInsideFactoryCrate->find(attributeName); - if (iterFind == saItemInsideFactoryCrate->end()) - { - iterFind = sa.end(); - } - } - - if (iterFind != sa.end()) - { - if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_int) - { - if (!m_searchableAttributeInt) - m_searchableAttributeInt = new std::map; - - if (attributeName == "cat_wpn_other.wpn_range") - { - // special parsing for cat_wpn_other.wpn_range attribute which is - // of the "range" form 22-49m and we want to use the second value - std::string const narrowStr(Unicode::wideToNarrow(iter->second)); - - char const * const pChar = strchr(narrowStr.c_str(), '-'); - if (pChar) - { - (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(pChar + 1); - } - else - { - (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(narrowStr.c_str()); - } - } - else if (attributeName == "storage_module_rating") - { - // Storage Module Rating - 10 - std::string const narrowStr(Unicode::wideToNarrow(iter->second)); - - char const * const pChar = strchr(narrowStr.c_str(), '-'); - if (pChar) - { - (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(pChar + 1); - } - else - { - (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(narrowStr.c_str()); - } - } - else - { - (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(Unicode::wideToNarrow(iter->second).c_str()); - } - } - else if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_float) - { - if (!m_searchableAttributeFloat) - m_searchableAttributeFloat = new std::map; - - (*m_searchableAttributeFloat)[iterFind->second->attributeNameCrc] = ::atof(Unicode::wideToNarrow(iter->second).c_str()); - } - else if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_string) - { - if (!m_searchableAttributeString) - m_searchableAttributeString = new std::map; - - // strip out the embedded trailing '\0' on those funky attribute - // values that have the trailing '\0' embedded in the string - // - // also, remove any leading/trailing white space - std::string const attributeValue(Unicode::getTrim(Unicode::wideToNarrow(iter->second).c_str())); - - // for resource container's "Resource Class" attribute, convert - // the string id to a display string so it can be searched on - if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && (attributeName == "resource_class")) - { - (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::getTrim(Unicode::toLower(Unicode::wideToNarrow(StringId::decodeString(Unicode::narrowToWide(attributeValue))))); - } - // for fish type, convert the string id to a display string so it can be searched on - else if ((m_item->GetCategory() == SharedObjectTemplate::GOT_misc) && (attributeName == "type")) - { - (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::getTrim(Unicode::toLower(Unicode::wideToNarrow(StringId::decodeString(Unicode::narrowToWide(attributeValue))))); - } - else - { - (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::toLower(attributeValue); - } - } - else if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_enum) - { - if (!m_searchableAttributeString) - m_searchableAttributeString = new std::map; - - // strip out the embedded trailing '\0' on those funky attribute - // values that have the trailing '\0' embedded in the string - std::string attributeValue(Unicode::wideToNarrow(iter->second).c_str()); - - // handle enum value alias - std::map::const_iterator const iterFindAlias = iterFind->second->enumValueAliasList.find(attributeValue); - if (iterFindAlias != iterFind->second->enumValueAliasList.end()) - { - attributeValue = iterFindAlias->second; - } - - // remove any leading/trailing white space - attributeValue = Unicode::getTrim(attributeValue); - - (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::toLower(attributeValue); - - if (iterFind->second->defaultSearchValueList.count(attributeValue) <= 0) - { - std::string bufferStr; - char buffer[16]; - for (size_t i = 0, size = attributeValue.size(); i < size; ++i) - { - snprintf(buffer, sizeof(buffer)-1, "%d ", attributeValue[i]); - buffer[sizeof(buffer)-1] = '\0'; - - bufferStr += buffer; - } - - LOG("CustomerService", ("CommoditiesAttributeSearch:Item %s (%s) in category %d (%s) has value (%s) (%s) (%d) for attribute (%s) that is not in the attribute enum list", - m_item->GetItemId().getValueString().c_str(), - Unicode::wideToNarrow(m_item->GetName()).c_str(), - m_item->GetCategory(), - GameObjectTypes::getCanonicalName(m_item->GetCategory()).c_str(), - attributeValue.c_str(), - bufferStr.c_str(), - attributeValue.size(), - iterFind->second->attributeName.c_str())); - } - } - } - } - - // for ship component and ship flight computer (or factory crate containing them), need to add "certifications required" search attribute - bool const itemIsShipComponentOrShipFlightComputer = ((GameObjectTypes::getMaskedType(m_item->GetCategory()) == SharedObjectTemplate::GOT_ship_component) || (m_item->GetCategory() == SharedObjectTemplate::GOT_deed_droid)); - bool const factoryCrateItemIsShipComponentOrShipFlightComputer = ((m_item->GetCategory() == SharedObjectTemplate::GOT_misc_factory_crate) && (gotItemInsideFactoryCrate > 0) && ((GameObjectTypes::getMaskedType(gotItemInsideFactoryCrate) == SharedObjectTemplate::GOT_ship_component) || (gotItemInsideFactoryCrate == SharedObjectTemplate::GOT_deed_droid))); - if (itemIsShipComponentOrShipFlightComputer || factoryCrateItemIsShipComponentOrShipFlightComputer) - { - static std::map requiredCerts; - - // load the required certs table - static bool requiredCertsLoaded = false; - if (!requiredCertsLoaded) - { - requiredCertsLoaded = true; - - DataTable * table = DataTableManager::getTable("datatables/commodity/ship_certification_attribute.iff", true); - if (table) - { - int const columnItem = table->findColumnNumber("Item"); - int const columnCert = table->findColumnNumber("Certifications Required"); - - if ((columnItem >= 0) && (columnCert >= 0) && (columnItem != columnCert)) - { - std::string item, cert; - int const numRows = table->getNumRows(); - for (int i = 0; i < numRows; ++i) - { - item = Unicode::getTrim(table->getStringValue(columnItem, i)); - cert = Unicode::getTrim(table->getStringValue(columnCert, i)); - - if (!item.empty() && !cert.empty()) - { - requiredCerts[static_cast(CrcLowerString::calculateCrc(item.c_str()))] = cert; - } - } - } - - DataTableManager::close("datatables/commodity/ship_certification_attribute.iff"); - } - } - - std::map::const_iterator const iterFind = requiredCerts.find(m_item->GetItemTemplateId()); - if (iterFind != requiredCerts.end()) - { - if (!m_searchableAttributeString) - m_searchableAttributeString = new std::map; - - static uint32 const shipCertAttributeCrc = Crc::calculate("ship_equipment_certification_search_attribute"); - static uint32 const astromechCertAttributeCrc = Crc::calculate("astromech_certification_search_attribute"); - - if (itemIsShipComponentOrShipFlightComputer) - { - (*m_searchableAttributeString)[((m_item->GetCategory() == SharedObjectTemplate::GOT_deed_droid) ? astromechCertAttributeCrc : shipCertAttributeCrc)] = iterFind->second; - } - else - { - (*m_searchableAttributeString)[((gotItemInsideFactoryCrate == SharedObjectTemplate::GOT_deed_droid) ? astromechCertAttributeCrc : shipCertAttributeCrc)] = iterFind->second; - } - } - } -} - -// ---------------------------------------------------------------------- - -bool Auction::IsAdvancedFilterMatch(std::list const & advancedSearch, int matchAllAny) const -{ - if (advancedSearch.empty()) - return true; - - // the following is the logic what will be used to determine match/no match - - // "will only match if all applicable attribute filter conditions match" - // ASMAA_match_all -> true after all match - // -> false after first mismatch - - // "will only match if any applicable attribute filter condition does not match" - // ASMAA_not_match_any is basically "not ASMAA_match_all" - // ASMAA_not_match_any -> false after all match - // -> true after first mismatch - - // "will only match if any applicable attribute filter condition matches" - // ASMAA_match_any -> false after all mismatch - // -> true after first match - - // "will only match if no applicable attribute filter condition matches" - // (i.e. match none) - // ASMAA_not_match_all is basically "not ASMAA_match_any" - // ASMAA_not_match_all -> true after all mismatch - // -> false after first match - - int filterCountMatch = 0; - int filterCountNotMatch = 0; - bool applicableFilter = 0; - bool matchFilter; - for (std::list::const_iterator iter = advancedSearch.begin(); iter != advancedSearch.end(); ++iter) - { - matchFilter = (*(s_searchConditionComparisonFn[static_cast(iter->comparison)]))(*iter, m_searchableAttributeInt, m_searchableAttributeFloat, m_searchableAttributeString, applicableFilter); - - if (!applicableFilter) - { - continue; - } - else if (matchFilter) // match filter - { - if (s_searchConditionMatchAllAnyActionAnyMatch[matchAllAny].first) - return s_searchConditionMatchAllAnyActionAnyMatch[matchAllAny].second; - - ++filterCountMatch; - } - else // does not match filter - { - if (s_searchConditionMatchAllAnyActionAnyNotMatch[matchAllAny].first) - return s_searchConditionMatchAllAnyActionAnyNotMatch[matchAllAny].second; - - ++filterCountNotMatch; - } - } - - // if we get this far, then either all applicable filters - // match or all applicable filters do not match, or there - // were no applicable filters - // - // it's impossible to have gotten this far and have some - // applicable filters match and some not match, because - // that situation should have caused an immediate return - // as soon as it was encountered - if (filterCountMatch > 0) - { - // all applicable filters match - return s_searchConditionMatchAllAnyActionAllMatch[matchAllAny]; - } - else if (filterCountNotMatch > 0) - { - // all applicable filters do not match - return s_searchConditionMatchAllAnyActionAllNotMatch[matchAllAny]; - } - - // no filter was applicable, so treat as if no filter was specified - return true; -} - -// ====================================================================== +// ====================================================================== +// +// Auction.cpp +// copyright (c) 2004 Sony Online Entertainment +// +// (refactor of original code only to the degree to make it work with new) +// (server & database framework ... i.e. none of the logic has changed) +// +// Original Author: Matt Severenson +// Refactored by : Doug Mellencamp +// +// ====================================================================== + +#include "FirstCommodityServer.h" +#include "Auction.h" +#include "AuctionMarket.h" +#include "CommodityServer.h" +#include "ConfigCommodityServer.h" +#include "StringId.h" +#include "UnicodeUtils.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedGame/CommoditiesAdvancedSearchAttribute.h" +#include "sharedGame/GameObjectTypes.h" +#include "sharedGame/SharedObjectTemplate.h" +#include "sharedLog/Log.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" + +#include + +// src/engine/client/library/clientGame/src/shared/core/AuctionManagerClient.cpp (s_maxBid) +// src/engine/server/application/CommoditiesServer/src/shared/Auction.cpp (MAX_BID) +// src/engine/server/library/serverGame/src/shared/commoditiesMarket/CommoditiesMarket.cpp (MAX_BID) +#define MAX_BID 10000000 +#define MAX_VENDOR_PRICE 833333333 + +namespace AuctionNamespace +{ + typedef bool (*SearchConditionComparisonFn) (AuctionQueryHeadersMessage::SearchCondition const & /*searchCondition*/, + std::map const * /*searchableAttributeInt*/, + std::map const * /*searchableAttributeFloat*/, + std::map const * /*searchableAttributeString*/, + bool & /*applicableSearchCondition*/); + + SearchConditionComparisonFn s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_LAST)]; + + // ---------------------------------------------------------------------- + + bool searchConditionComparisonFnInt(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, + std::map const * searchableAttributeInt, + std::map const * searchableAttributeFloat, + std::map const * searchableAttributeString, + bool & applicableSearchCondition) + { +#ifdef _DEBUG + DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_int), ("searchConditionComparisonFnInt() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_int", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); + DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnInt\n")); +#endif + UNREF(searchableAttributeFloat); + UNREF(searchableAttributeString); + + // if the filter condition requires the attribute, + // it will always be an applicable filter condition; + // otherwise, it will only be applicable if the item + // has the attribute + applicableSearchCondition = searchCondition.requiredAttribute; + + if (searchableAttributeInt) + { + std::map::const_iterator iterAttr = searchableAttributeInt->find(searchCondition.attributeNameCrc); + if (iterAttr != searchableAttributeInt->end()) + { + applicableSearchCondition = true; + return ((iterAttr->second >= searchCondition.intMin) && (iterAttr->second <= searchCondition.intMax)); + } + } + + return false; + } + + // ---------------------------------------------------------------------- + + bool searchConditionComparisonFnFloat(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, + std::map const * searchableAttributeInt, + std::map const * searchableAttributeFloat, + std::map const * searchableAttributeString, + bool & applicableSearchCondition) + { +#ifdef _DEBUG + DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_float), ("searchConditionComparisonFnFloat() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_float", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); + DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnFloat\n")); +#endif + UNREF(searchableAttributeInt); + UNREF(searchableAttributeString); + + // if the filter condition requires the attribute, + // it will always be an applicable filter condition; + // otherwise, it will only be applicable if the item + // has the attribute + applicableSearchCondition = searchCondition.requiredAttribute; + + if (searchableAttributeFloat) + { + std::map::const_iterator iterAttr = searchableAttributeFloat->find(searchCondition.attributeNameCrc); + if (iterAttr != searchableAttributeFloat->end()) + { + applicableSearchCondition = true; + return ((iterAttr->second >= searchCondition.floatMin) && (iterAttr->second <= searchCondition.floatMax)); + } + } + + return false; + } + + // ---------------------------------------------------------------------- + + bool searchConditionComparisonFnStringEqual(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, + std::map const * searchableAttributeInt, + std::map const * searchableAttributeFloat, + std::map const * searchableAttributeString, + bool & applicableSearchCondition) + { +#ifdef _DEBUG + DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_equal), ("searchConditionComparisonFnStringEqual() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_equal", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); + DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringEqual\n")); +#endif + UNREF(searchableAttributeInt); + UNREF(searchableAttributeFloat); + + // if the filter condition requires the attribute, + // it will always be an applicable filter condition; + // otherwise, it will only be applicable if the item + // has the attribute + applicableSearchCondition = searchCondition.requiredAttribute; + + if (searchableAttributeString) + { + std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); + if (iterAttr != searchableAttributeString->end()) + { + applicableSearchCondition = true; + return (0 == strcmp(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) + } + } + + return false; + } + + // ---------------------------------------------------------------------- + + bool searchConditionComparisonFnStringNotEqual(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, + std::map const * searchableAttributeInt, + std::map const * searchableAttributeFloat, + std::map const * searchableAttributeString, + bool & applicableSearchCondition) + { +#ifdef _DEBUG + DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_not_equal), ("searchConditionComparisonFnStringNotEqual() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_not_equal", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); + DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringNotEqual\n")); +#endif + UNREF(searchableAttributeInt); + UNREF(searchableAttributeFloat); + + // if the filter condition requires the attribute, + // it will always be an applicable filter condition; + // otherwise, it will only be applicable if the item + // has the attribute + applicableSearchCondition = searchCondition.requiredAttribute; + + if (searchableAttributeString) + { + std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); + if (iterAttr != searchableAttributeString->end()) + { + applicableSearchCondition = true; + return (0 != strcmp(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) + } + } + + return false; + } + + // ---------------------------------------------------------------------- + + bool searchConditionComparisonFnStringContain(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, + std::map const * searchableAttributeInt, + std::map const * searchableAttributeFloat, + std::map const * searchableAttributeString, + bool & applicableSearchCondition) + { +#ifdef _DEBUG + DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_contain), ("searchConditionComparisonFnStringContain() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_contain", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); + DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringContain\n")); +#endif + UNREF(searchableAttributeInt); + UNREF(searchableAttributeFloat); + + // if the filter condition requires the attribute, + // it will always be an applicable filter condition; + // otherwise, it will only be applicable if the item + // has the attribute + applicableSearchCondition = searchCondition.requiredAttribute; + + if (searchableAttributeString) + { + std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); + if (iterAttr != searchableAttributeString->end()) + { + applicableSearchCondition = true; + return (NULL != strstr(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) + } + } + + return false; + } + + // ---------------------------------------------------------------------- + + bool searchConditionComparisonFnStringNotContain(AuctionQueryHeadersMessage::SearchCondition const & searchCondition, + std::map const * searchableAttributeInt, + std::map const * searchableAttributeFloat, + std::map const * searchableAttributeString, + bool & applicableSearchCondition) + { +#ifdef _DEBUG + DEBUG_FATAL((searchCondition.comparison != AuctionQueryHeadersMessage::SCC_string_not_contain), ("searchConditionComparisonFnStringNotContain() called for attributeNameCrc=(%lu), comparison=(%d) that is not AuctionQueryHeadersMessage::SCC_string_not_contain", searchCondition.attributeNameCrc, static_cast(searchCondition.comparison))); + DEBUG_REPORT_LOG(ConfigCommodityServer::getShowAllDebugInfo(), ("[Commodities Server QueryAuctionHeadersMessage] searchConditionComparisonFnStringNotContain\n")); +#endif + UNREF(searchableAttributeInt); + UNREF(searchableAttributeFloat); + + // if the filter condition requires the attribute, + // it will always be an applicable filter condition; + // otherwise, it will only be applicable if the item + // has the attribute + applicableSearchCondition = searchCondition.requiredAttribute; + + if (searchableAttributeString) + { + std::map::const_iterator iterAttr = searchableAttributeString->find(searchCondition.attributeNameCrc); + if (iterAttr != searchableAttributeString->end()) + { + applicableSearchCondition = true; + return (NULL == strstr(iterAttr->second.c_str(), searchCondition.stringValue.c_str())); // lowercase is assumed (and required) + } + } + + return false; + } + + // ---------------------------------------------------------------------- + + // + std::pair s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; + std::pair s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; + + // search return value + bool s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; + bool s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_LAST)]; +}; + +using namespace AuctionNamespace; + +// ====================================================================== + +Auction::Auction( + const NetworkId & creatorId, + int minBid, + int auctionTimer, + const NetworkId & itemId, + int itemNameLength, + const Unicode::String & itemName, + int itemType, + int itemTemplateId, + int itemTimer, + int itemSize, + const AuctionLocation & location, + int flags, + int buyNowPrice, + int userDescriptionLength, + const Unicode::String & userDescription, + int oobLength, + const Unicode::String & oobData, + std::vector > const & attributes +) : +m_creatorId(creatorId), +m_minBid(minBid), +m_auctionTimer(auctionTimer), +m_buyNowPrice(buyNowPrice), +m_userDescriptionLength(userDescriptionLength), +m_userDescription(userDescription), +m_oobLength(oobLength), +m_oobData(oobData), +m_attributes(), +m_searchableAttributeInt(NULL), +m_searchableAttributeFloat(NULL), +m_searchableAttributeString(NULL), +m_highBid(NULL), +m_item(new AuctionItem(itemId, itemType, itemTemplateId, itemTimer, itemNameLength, itemName, creatorId, itemSize)), +m_sold(false), +m_active(true), +m_bids(), +m_location(const_cast(location)), +m_flags(flags), +m_trackId(-1) +{ + assert(m_auctionTimer != 0); + + // it it's a instant sale resource container, add "credits per unit" attribute + if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && (m_buyNowPrice > 0)) + { + for (std::vector >::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) + { + if (iter->first == "credits_per_unit") + { + // ignore any existing credits per unit attribute; we'll recalculate it and add the updated attribute + continue; + } + + m_attributes.push_back(*iter); + + if (iter->first == "resource_contents") + { + int count = ::atoi(Unicode::wideToNarrow(iter->second).c_str()); + if (count > 0) + { + char buffer[128]; + int const len = snprintf(buffer, sizeof(buffer)-1, "%.6f", (static_cast(m_buyNowPrice) / static_cast(count))); + buffer[sizeof(buffer)-1] = '\0'; + + // trim trailing 0s after the decimal point + char * pChar = buffer + len - 1; + while (pChar >= buffer) + { + if (*pChar == '.') + { + *pChar = '\0'; + break; + } + else if (*pChar != '0') + { + ++pChar; + *pChar = '\0'; + break; + } + + --pChar; + } + + m_attributes.push_back(std::make_pair("credits_per_unit", Unicode::narrowToWide(buffer))); + } + } + } + } + else + { + m_attributes = attributes; + } + + SetItemResourceContainerClassCrc(); + BuildSearchableAttributeList(); +} + +// ---------------------------------------------------------------------- + +Auction::Auction( + const NetworkId & creatorId, + int minBid, + int auctionTimer, + const NetworkId & itemId, + int itemNameLength, + const Unicode::String & itemName, + int itemType, + int itemTemplateId, + int itemTimer, + int itemSize, + const AuctionLocation & location, + int flags, + int buyNowPrice, + int userDescriptionLength, + const Unicode::String & userDescription, + int oobLength, + const Unicode::String & oobData, + std::vector > const & attributes, + bool isActive, + bool isSold +) : +m_creatorId(creatorId), +m_minBid(minBid), +m_auctionTimer(auctionTimer), +m_buyNowPrice(buyNowPrice), +m_userDescriptionLength(userDescriptionLength), +m_userDescription(userDescription), +m_oobLength(oobLength), +m_oobData(oobData), +m_attributes(), +m_searchableAttributeInt(NULL), +m_searchableAttributeFloat(NULL), +m_searchableAttributeString(NULL), +m_highBid(NULL), +m_item(new AuctionItem(itemId, itemType, itemTemplateId, itemTimer, itemNameLength, itemName, creatorId, itemSize)), +m_sold(isSold), +m_active(isActive), +m_bids(), +m_location(const_cast(location)), +m_flags(flags), +m_trackId(-1) +{ + assert(m_auctionTimer != 0); + + // it it's a instant sale resource container, add "credits per unit" attribute + if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && (m_buyNowPrice > 0)) + { + for (std::vector >::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) + { + if (iter->first == "credits_per_unit") + { + // ignore any existing credits per unit attribute; we'll recalculate it and add the updated attribute + continue; + } + + m_attributes.push_back(*iter); + + if (iter->first == "resource_contents") + { + int count = ::atoi(Unicode::wideToNarrow(iter->second).c_str()); + if (count > 0) + { + char buffer[128]; + int const len = snprintf(buffer, sizeof(buffer)-1, "%.6f", (static_cast(m_buyNowPrice) / static_cast(count))); + buffer[sizeof(buffer)-1] = '\0'; + + // trim trailing 0s after the decimal point + char * pChar = buffer + len - 1; + while (pChar >= buffer) + { + if (*pChar == '.') + { + *pChar = '\0'; + break; + } + else if (*pChar != '0') + { + ++pChar; + *pChar = '\0'; + break; + } + + --pChar; + } + + m_attributes.push_back(std::make_pair("credits_per_unit", Unicode::narrowToWide(buffer))); + } + } + } + } + else + { + m_attributes = attributes; + } + + SetItemResourceContainerClassCrc(); + BuildSearchableAttributeList(); +} + +// ---------------------------------------------------------------------- + +Auction::~Auction() +{ + std::vector::iterator i = m_bids.begin(); + for (; i != m_bids.end(); ++i) + { + AuctionBid *bid = (*i); + delete bid; + } + delete m_item; + + delete m_searchableAttributeInt; + delete m_searchableAttributeFloat; + delete m_searchableAttributeString; +} + +// ---------------------------------------------------------------------- + +void Auction::Initialization() +{ +#ifdef _DEBUG + for (int i = 0; i < static_cast(AuctionQueryHeadersMessage::SCC_LAST); ++i) + { + s_searchConditionComparisonFn[i] = NULL; + } +#endif + + s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_int)] = searchConditionComparisonFnInt; + s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_float)] = searchConditionComparisonFnFloat; + s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_equal)] = searchConditionComparisonFnStringEqual; + s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_not_equal)] = searchConditionComparisonFnStringNotEqual; + s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_contain)] = searchConditionComparisonFnStringContain; + s_searchConditionComparisonFn[static_cast(AuctionQueryHeadersMessage::SCC_string_not_contain)] = searchConditionComparisonFnStringNotContain; + +#ifdef _DEBUG + for (int j = 0; j < static_cast(AuctionQueryHeadersMessage::SCC_LAST); ++j) + { + DEBUG_FATAL((s_searchConditionComparisonFn[j] == NULL), ("s_searchConditionComparisonFn array is NULL at index (%d)", j)); + } +#endif + + // + static std::pair const continueToCheckNextMatch(std::make_pair(false, false)); + static std::pair const stopAndReturnTrue(std::make_pair(true, true)); + static std::pair const stopAndReturnFalse(std::make_pair(true, false)); + + // "will only match if all applicable attribute filter conditions match" + // ASMAA_match_all -> true after all match + // -> false after first mismatch + s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = continueToCheckNextMatch; // after any match, continue to check next match + s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = stopAndReturnFalse; // after any not match, stop and return false + s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = true; // after all match, return true + s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_all)] = false; // after all not match, return false + + // "will only match if any applicable attribute filter condition matches" + // ASMAA_match_any -> false after all mismatch + // -> true after first match + s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = stopAndReturnTrue; // after any match, stop and return true + s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = continueToCheckNextMatch; // after any not match, continue to check next match + s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = true; // after all match, return true + s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_match_any)] = false; // after all not match, return false + + // "will only match if no applicable attribute filter condition matches" + // (i.e. match none) + // ASMAA_not_match_all is basically "not ASMAA_match_any" + // ASMAA_not_match_all -> true after all mismatch + // -> false after first match + s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = stopAndReturnFalse; // after any match, stop and return false + s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = continueToCheckNextMatch; // after any not match, continue to check next match + s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = false; // after all match, return false + s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_all)] = true; // after all not match, return true + + // "will only match if any applicable attribute filter condition does not match" + // ASMAA_not_match_any is basically "not ASMAA_match_all" + // ASMAA_not_match_any -> false after all match + // -> true after first mismatch + s_searchConditionMatchAllAnyActionAnyMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = continueToCheckNextMatch; // after any match, continue to check next match + s_searchConditionMatchAllAnyActionAnyNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = stopAndReturnTrue; // after any not match, stop and return true + s_searchConditionMatchAllAnyActionAllMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = false; // after all match, return false + s_searchConditionMatchAllAnyActionAllNotMatch[static_cast(AuctionQueryHeadersMessage::ASMAA_not_match_any)] = true; // after all not match, return true +} + +// ---------------------------------------------------------------------- + +void Auction::GetAttributes(std::string & output) const +{ + output.clear(); + + output = Unicode::wideToNarrow(m_item->GetName()); + output += " ("; + output += m_item->GetItemId().getValueString(); + output += ") (GOT_"; + output += GameObjectTypes::getCanonicalName(m_item->GetCategory()); + output += ")\r\n\r\n"; + + char buffer[2048]; + for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) + { + snprintf(buffer, sizeof(buffer)-1, "(%s) (%s)", iter->first.c_str(), Unicode::wideToNarrow(iter->second).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + output += buffer; + output += "\r\n"; + } + + if (m_searchableAttributeInt) + { + output += "\r\nInteger indexed search attribute:\r\n"; + + for (std::map::const_iterator iter = m_searchableAttributeInt->begin(); iter != m_searchableAttributeInt->end(); ++iter) + { + std::string attributeName; + for (std::vector >::const_iterator iterAttribute = m_attributes.begin(); iterAttribute != m_attributes.end(); ++iterAttribute) + { + if (Crc::calculate(iterAttribute->first.c_str()) == iter->first) + { + attributeName = iterAttribute->first; + break; + } + } + + snprintf(buffer, sizeof(buffer)-1, "(%s, %lu) (%d)", attributeName.c_str(), iter->first, iter->second); + buffer[sizeof(buffer)-1] = '\0'; + + output += buffer; + output += "\r\n"; + } + } + + if (m_searchableAttributeFloat) + { + output += "\r\nFloat indexed search attribute:\r\n"; + + for (std::map::const_iterator iter = m_searchableAttributeFloat->begin(); iter != m_searchableAttributeFloat->end(); ++iter) + { + std::string attributeName; + for (std::vector >::const_iterator iterAttribute = m_attributes.begin(); iterAttribute != m_attributes.end(); ++iterAttribute) + { + if (Crc::calculate(iterAttribute->first.c_str()) == iter->first) + { + attributeName = iterAttribute->first; + break; + } + } + + snprintf(buffer, sizeof(buffer)-1, "(%s, %lu) (%.10g)", attributeName.c_str(), iter->first, iter->second); + buffer[sizeof(buffer)-1] = '\0'; + + output += buffer; + output += "\r\n"; + } + } + + if (m_searchableAttributeString) + { + output += "\r\nString indexed search attribute:\r\n"; + + for (std::map::const_iterator iter = m_searchableAttributeString->begin(); iter != m_searchableAttributeString->end(); ++iter) + { + std::string attributeName; + for (std::vector >::const_iterator iterAttribute = m_attributes.begin(); iterAttribute != m_attributes.end(); ++iterAttribute) + { + if (Crc::calculate(iterAttribute->first.c_str()) == iter->first) + { + attributeName = iterAttribute->first; + break; + } + } + + snprintf(buffer, sizeof(buffer)-1, "(%s, %lu) (%s)", attributeName.c_str(), iter->first, iter->second.c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + output += buffer; + output += "\r\n"; + } + } +} + +// ---------------------------------------------------------------------- + +int Auction::GetHighBidAmount() const +{ + if (m_highBid) + return m_highBid->GetBid(); + else + return 0; +} + +// ---------------------------------------------------------------------- + +const AuctionBid *Auction::GetPreviousBid() const +{ + if (m_bids.size() <= 1) + { + return NULL; + } + else + { + return m_bids[m_bids.size() - 2]; + } +} + +// ---------------------------------------------------------------------- + +/** + * This isn't at all obvious, so here is a description. This function returns + * bid that will actually take place when a given bid is attempted. This bid + * can be less than the existing bid, so the bid will fail, but we still need + * to adjust the existing high bid to outbid the current one. + */ +int Auction::GetActualBid(AuctionBid *bid) +{ + assert(bid != NULL); + int bidNeeded = std::max(m_minBid, bid->GetBid()); + if (m_highBid != NULL) + { + bidNeeded = m_highBid->GetBid(); + if (*bid > *m_highBid) + { + bidNeeded = std::max(bid->GetBid(), m_highBid->GetMaxProxyBid() + 1); + } + else if (*bid == *m_highBid) + { + bidNeeded = m_highBid->GetMaxProxyBid(); + } + else if (*bid < *m_highBid) + { + bidNeeded = std::max(m_highBid->GetBid(), bid->GetMaxProxyBid() + 1); + } + } + return bidNeeded; +} + +// ---------------------------------------------------------------------- + +void Auction::AddLoadedBid( + const NetworkId & bidderId, + int bid, + int maxProxyBid +) +{ + AuctionBid *auctionBid = new AuctionBid(bidderId, bid, maxProxyBid); + std::vector::iterator i = m_bids.begin(); + bool inserted = false; + for (; i != m_bids.end(); ++i) + { + if ((*i)->GetMaxProxyBid() > auctionBid->GetMaxProxyBid()) + { + m_bids.insert(i, auctionBid); + inserted = true; + break; + } + } + + if (!inserted) + { + m_bids.push_back(auctionBid); + } + m_highBid = m_bids.back(); +} + +// ---------------------------------------------------------------------- + +AuctionResultCode Auction::AddBid( + const NetworkId & bidderId, + int bid, + int maxProxyBid +) +{ + AuctionResultCode success = ARC_Success; + int maxBid = std::max(bid, maxProxyBid); + + if (!m_active || m_sold) + { + return ARC_AuctionExpired; + DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Auction Expired - Auction is sold and inactive.\n")); + } + + if (maxBid > MAX_BID && !m_location.IsVendorMarket()) + { + return ARC_BidTooHigh; + DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Bid too high.\n")); + } + + /*!!!TODO, put me back in after testingif (bidderId == m_creatorId) + { + return ARC_OwnerBidOnOwnItem; + }*/ + if (maxProxyBid < m_minBid) + { + return ARC_BidTooLow; + DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Bid too low.\n")); + } + if (IsImmediate() && (GetFlags() & AUCTION_ALWAYS_PRESENT)) + { + return ARC_SuccessPermanentAuction; + } + + AuctionBid *auctionBid = new AuctionBid(bidderId, bid, maxProxyBid); + int newBidForHighBidder = GetActualBid(auctionBid); + if (m_highBid != NULL) + { + if (*auctionBid <= *m_highBid) + { + delete auctionBid; + success = ARC_BidOutbid; + DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Bid outbid.\n")); + } + } + + if (success == ARC_Success) + { + m_highBid = auctionBid; + m_bids.push_back(auctionBid); + } + m_highBid->SetBid(newBidForHighBidder); + + if (IsImmediate()) + { + m_sold = true; + DEBUG_REPORT_LOG(true, ("[Commodities Server AddBid] : Immediate Auction - marked as sold.\n")); + + // put auction into the completed auctions list so + // that the auction can be processed to completion + // during the next frame + AuctionMarket::getInstance().AddAuctionToCompletedAuctionsList(*this); + } + return success; +} + +// ---------------------------------------------------------------------- + +const AuctionBid *Auction::GetPlayerBid(const NetworkId & playerId) const +{ + // new bids are pushed on the back of the vector + // so, we search using a reverse iterator + std::vector::const_reverse_iterator iter = m_bids.rbegin(); + while (iter != m_bids.rend()) + { + if ((*iter) && ((*iter)->GetBidderId() == playerId)) + { + return (*iter); + } + ++iter; + } + return NULL; +} + +// ---------------------------------------------------------------------- + +bool Auction::Update(int gameTime) +{ + if (GetFlags() & AUCTION_ALWAYS_PRESENT) + { + return true; + } + if (m_active && m_sold) + { + //immediate sale + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Update] : Expiring immediate sale - Auction is active and sold.\n")); + + if ((m_trackId != -1) && (CommodityServer::getInstance().getGameServer(m_trackId) != NULL)) + { + Expire(true, false, m_trackId); + m_trackId = -1; + } + else + { + Expire(true, false); + } + } + else if (m_active && (gameTime >= m_auctionTimer)) + { + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Update] : Auction expiring based on timer.\n")); + + if ((m_trackId != -1) && (CommodityServer::getInstance().getGameServer(m_trackId) != NULL)) + { + Expire(m_highBid != NULL, true, m_trackId); + m_trackId = -1; + } + else + { + Expire(m_highBid != NULL, true); + } + } + + return !m_item->IsExpired(gameTime); +} + +// ---------------------------------------------------------------------- + +void Auction::Expire(bool sold, bool expiredBasedOnTimer, int track_id) +{ + AuctionMarket::getInstance().RemoveFromAuctionTimerPriorityQueue(m_auctionTimer, m_item->GetItemId()); + + m_auctionTimer = 0; + m_active = false; + if (sold && m_highBid != NULL) + { + m_sold = true; + } + else + { + m_sold = false; + } + + bool immediate = IsImmediate(); + + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sold flag is %d.\n", m_sold)); + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Active flag is %d.\n", m_active)); + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Immediate flag is %d.\n", immediate)); + + if (m_sold) + { + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Old Owner is %s.\n", m_item->GetOwnerId().getValueString().c_str())); + m_item->SetOwnerId(m_highBid->GetBidderId()); + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : New Owner is %s.\n", m_item->GetOwnerId().getValueString().c_str())); + + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sending OnAuctionExpired for sold auction .\n")); + + AuctionMarket::getInstance().OnAuctionExpired( + GetCreatorId(), m_sold, m_flags, + m_highBid->GetBidderId(), m_highBid->GetBid(), m_item->GetItemId(), + m_highBid->GetMaxProxyBid(), + m_location.GetLocationString(), immediate, + m_item->GetNameLength(), m_item->GetName(), + m_item->GetOwnerId(), track_id, true); + } + else + { + if (m_highBid) + { + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sending OnAuctionExpired for non-sold auction and high bid obj .\n")); + AuctionMarket::getInstance().OnAuctionExpired( + GetCreatorId(), m_sold, m_flags, + m_highBid->GetBidderId(), m_highBid->GetBid(), m_item->GetItemId(), + m_highBid->GetMaxProxyBid(), + m_location.GetLocationString(), immediate, + m_item->GetNameLength(), m_item->GetName(), + m_item->GetOwnerId(), track_id, true); + } + else + { + // for items on a vendor placed by the vendor owner, we + // use the following rule to determine if a mail message + // should be sent to the vendor owner when the item + // auction expire and goes back into the vendor stockroom; + // the goal here is to avoid sending too many mail message + // to a vendor owner when a bunch of auctions expire around + // the same time + // + // 1) if the auction did not expire because of the auction + // timer, don't send mail. This means if the vendor owner + // withdraws the sale of an item, no mail is sent. + // 2) if the auction expired because of the auction timer, + // send mail only for the first item, and don't send + // another mail until the next auction expires after + // the vendor is next accessed or the cluster is restarted. + bool sendSellerMail = true; + if (m_location.IsVendorMarket() && m_location.IsOwner(GetCreatorId())) + { + if (!expiredBasedOnTimer) + sendSellerMail = false; + else if (m_location.GetVendorFirstTimerExpiredAuctionDate() > 0) + sendSellerMail = false; + else + m_location.SetVendorFirstTimerExpiredAuctionDate(time(0)); + } + + DEBUG_REPORT_LOG(true, ("[Commodities Server Auction::Expire] : Sending OnAuctionExpired for non-sold auction and null high bid obj .\n")); + AuctionMarket::getInstance().OnAuctionExpired( + GetCreatorId(), m_sold, m_flags, + NetworkId::cms_invalid, 0, m_item->GetItemId(), 0, + m_location.GetLocationString(), immediate, + m_item->GetNameLength(), m_item->GetName(), + m_item->GetOwnerId(), track_id, sendSellerMail); + } + if (m_location.IsVendorMarket() && + m_location.IsOwner(GetCreatorId())) + { + //vendor owner canceled his own auction. Sorry this is such a hack + m_location.CancelVendorSale(this); + } + } + + if (m_location.IsVendorMarket()) + { + //If its a vendor, remove and then re-add the item to ensure it is in the right list + m_location.RemoveAuction(this); + m_location.AddAuction(this); + } +} + +// ---------------------------------------------------------------------- + +int Auction::GetBuyNowPriceWithSalesTax() const +{ + if( GetBuyNowPrice() > 0 ) + { + int salesTax = GetLocation().GetSalesTax(); + return (int)(GetBuyNowPrice() + (GetBuyNowPrice() * (salesTax/10000.0f))); + } + else + { + return 0; + } +} + +// ---------------------------------------------------------------------- + +void Auction::AddAttributes(const std::string & attributeName, const Unicode::String & attributeValue) +{ + // it it's a instant sale resource container, add "credits per unit" attribute + // once we receive the item count attribute for the resource container, and also + // ignore any existing "credits per unit" attribute to avoid duplicate attribute + if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory())) + { + if (m_buyNowPrice > 0) + { + if (attributeName == "credits_per_unit") + { + // ignore any existing credits per unit attribute; we'll recalculate it and add the updated attribute + return; + } + + m_attributes.push_back(std::make_pair(attributeName, attributeValue)); + + if (attributeName == "resource_contents") + { + int count = ::atoi(Unicode::wideToNarrow(attributeValue).c_str()); + if (count > 0) + { + char buffer[128]; + int const len = snprintf(buffer, sizeof(buffer)-1, "%.6f", (static_cast(m_buyNowPrice) / static_cast(count))); + buffer[sizeof(buffer)-1] = '\0'; + + // trim trailing 0s after the decimal point + char * pChar = buffer + len - 1; + while (pChar >= buffer) + { + if (*pChar == '.') + { + *pChar = '\0'; + break; + } + else if (*pChar != '0') + { + ++pChar; + *pChar = '\0'; + break; + } + + --pChar; + } + + m_attributes.push_back(std::make_pair("credits_per_unit", Unicode::narrowToWide(buffer))); + } + + return; + } + } + else + { + m_attributes.push_back(std::make_pair(attributeName, attributeValue)); + } + + SetItemResourceContainerClassCrc(attributeName, attributeValue); + } + else + { + m_attributes.push_back(std::make_pair(attributeName, attributeValue)); + } +} + +// ---------------------------------------------------------------------- + +void Auction::SetItemResourceContainerClassCrc() +{ + if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && ((m_item->GetResourceContainerClassCrc() == 0) || (m_item->GetResourceNameCrc() == 0))) + { + for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) + { + if ((iter->first == "resource_class") || (iter->first == "resource_name")) + { + SetItemResourceContainerClassCrc(iter->first, iter->second); + + if ((m_item->GetResourceContainerClassCrc() != 0) && (m_item->GetResourceNameCrc() != 0)) + break; + } + } + } +} + +// ---------------------------------------------------------------------- + +void Auction::SetItemResourceContainerClassCrc(const std::string & attributeName, const Unicode::String & attributeValue) +{ + if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && ((m_item->GetResourceContainerClassCrc() == 0) || (m_item->GetResourceNameCrc() == 0))) + { + if ((attributeName == "resource_class") || (attributeName == "resource_name")) + { + if ((attributeName == "resource_class") && (m_item->GetResourceContainerClassCrc() == 0)) + { + std::string className = Unicode::wideToNarrow(attributeValue); + if (0 == className.find("@resource/resource_names:")) + { + className = className.substr(sizeof("@resource/resource_names:") - 1); + if (!className.empty()) + { + m_item->SetResourceContainerClassCrc(static_cast(Crc::calculate(className.c_str()))); + } + } + } + else if ((attributeName == "resource_name") && (m_item->GetResourceNameCrc() == 0)) + { + std::string name = Unicode::wideToNarrow(attributeValue); + if (!name.empty()) + { + m_item->SetResourceName(name); + m_item->SetResourceNameCrc(static_cast(Crc::calculate(name.c_str()))); + } + } + + if ((m_item->GetResourceContainerClassCrc() != 0) && (m_item->GetResourceNameCrc() != 0)) + { + AuctionMarket::getInstance().AddResourceType(m_item->GetResourceContainerClassCrc(), m_item->GetResourceName()); + } + } + } +} + +// ---------------------------------------------------------------------- + +void Auction::BuildSearchableAttributeList() +{ + std::map const & sa = CommoditiesAdvancedSearchAttribute::getSearchAttributeForGameObjectType(m_item->GetCategory()); + if (sa.empty()) + return; + + std::map const & saAlias = CommoditiesAdvancedSearchAttribute::getSearchAttributeNameAliasesForGameObjectType(m_item->GetCategory()); + + // for factory crates, also include the attributes of the item inside the crate + std::map const * saItemInsideFactoryCrate = NULL; + std::map const * saAliasItemInsideFactoryCrate = NULL; + int gotItemInsideFactoryCrate = 0; + + if (m_item->GetCategory() == SharedObjectTemplate::GOT_misc_factory_crate) + { + // determine the type of item inside the crate by looking at the value of the object_type attribute + for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) + { + if (iter->first == "object_type") + { + std::string const objectType(Unicode::wideToNarrow(iter->second)); + if (0 == objectType.find("@got_n:")) + { + gotItemInsideFactoryCrate = GameObjectTypes::getGameObjectType(objectType.substr(7)); + if (gotItemInsideFactoryCrate == SharedObjectTemplate::GOT_misc_factory_crate) + { + // factory crate inside factory crate??? + gotItemInsideFactoryCrate = 0; + } + + if (gotItemInsideFactoryCrate > 0) + { + saItemInsideFactoryCrate = &(CommoditiesAdvancedSearchAttribute::getSearchAttributeForGameObjectType(gotItemInsideFactoryCrate)); + saAliasItemInsideFactoryCrate = &(CommoditiesAdvancedSearchAttribute::getSearchAttributeNameAliasesForGameObjectType(gotItemInsideFactoryCrate)); + + if (saItemInsideFactoryCrate->empty()) + saItemInsideFactoryCrate = NULL; + + if (saAliasItemInsideFactoryCrate->empty()) + saAliasItemInsideFactoryCrate = NULL; + } + } + + break; + } + } + } + + std::string attributeName; + for (std::vector >::const_iterator iter = m_attributes.begin(); iter != m_attributes.end(); ++iter) + { + // strip out the embedded trailing '\0' on those funky attribute + // name that have the trailing '\0' embedded in the string + // + // also, remove any leading/trailing white space + attributeName = Unicode::getTrim(iter->first.c_str()); + + // handle attribute name alias + if (!saAlias.empty()) + { + std::map::const_iterator const iterFindAlias = saAlias.find(attributeName); + if (iterFindAlias != saAlias.end()) + { + attributeName = iterFindAlias->second; + } + } + + std::map::const_iterator iterFind = sa.find(attributeName); + if ((iterFind == sa.end()) && (m_item->GetCategory() == SharedObjectTemplate::GOT_misc_factory_crate) && saItemInsideFactoryCrate) + { + // strip out the embedded trailing '\0' on those funky attribute + // name that have the trailing '\0' embedded in the string + // + // also, remove any leading/trailing white space + attributeName = Unicode::getTrim(iter->first.c_str()); + + // handle attribute name alias + if (saAliasItemInsideFactoryCrate && !saAliasItemInsideFactoryCrate->empty()) + { + std::map::const_iterator const iterFindAlias = saAliasItemInsideFactoryCrate->find(attributeName); + if (iterFindAlias != saAliasItemInsideFactoryCrate->end()) + { + attributeName = iterFindAlias->second; + } + } + + iterFind = saItemInsideFactoryCrate->find(attributeName); + if (iterFind == saItemInsideFactoryCrate->end()) + { + iterFind = sa.end(); + } + } + + if (iterFind != sa.end()) + { + if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_int) + { + if (!m_searchableAttributeInt) + m_searchableAttributeInt = new std::map; + + if (attributeName == "cat_wpn_other.wpn_range") + { + // special parsing for cat_wpn_other.wpn_range attribute which is + // of the "range" form 22-49m and we want to use the second value + std::string const narrowStr(Unicode::wideToNarrow(iter->second)); + + char const * const pChar = strchr(narrowStr.c_str(), '-'); + if (pChar) + { + (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(pChar + 1); + } + else + { + (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(narrowStr.c_str()); + } + } + else if (attributeName == "storage_module_rating") + { + // Storage Module Rating - 10 + std::string const narrowStr(Unicode::wideToNarrow(iter->second)); + + char const * const pChar = strchr(narrowStr.c_str(), '-'); + if (pChar) + { + (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(pChar + 1); + } + else + { + (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(narrowStr.c_str()); + } + } + else + { + (*m_searchableAttributeInt)[iterFind->second->attributeNameCrc] = ::atoi(Unicode::wideToNarrow(iter->second).c_str()); + } + } + else if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_float) + { + if (!m_searchableAttributeFloat) + m_searchableAttributeFloat = new std::map; + + (*m_searchableAttributeFloat)[iterFind->second->attributeNameCrc] = ::atof(Unicode::wideToNarrow(iter->second).c_str()); + } + else if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_string) + { + if (!m_searchableAttributeString) + m_searchableAttributeString = new std::map; + + // strip out the embedded trailing '\0' on those funky attribute + // values that have the trailing '\0' embedded in the string + // + // also, remove any leading/trailing white space + std::string const attributeValue(Unicode::getTrim(Unicode::wideToNarrow(iter->second).c_str())); + + // for resource container's "Resource Class" attribute, convert + // the string id to a display string so it can be searched on + if (AuctionItem::IsCategoryResourceContainer(m_item->GetCategory()) && (attributeName == "resource_class")) + { + (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::getTrim(Unicode::toLower(Unicode::wideToNarrow(StringId::decodeString(Unicode::narrowToWide(attributeValue))))); + } + // for fish type, convert the string id to a display string so it can be searched on + else if ((m_item->GetCategory() == SharedObjectTemplate::GOT_misc) && (attributeName == "type")) + { + (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::getTrim(Unicode::toLower(Unicode::wideToNarrow(StringId::decodeString(Unicode::narrowToWide(attributeValue))))); + } + else + { + (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::toLower(attributeValue); + } + } + else if (iterFind->second->attributeDataType == CommoditiesAdvancedSearchAttribute::SADT_enum) + { + if (!m_searchableAttributeString) + m_searchableAttributeString = new std::map; + + // strip out the embedded trailing '\0' on those funky attribute + // values that have the trailing '\0' embedded in the string + std::string attributeValue(Unicode::wideToNarrow(iter->second).c_str()); + + // handle enum value alias + std::map::const_iterator const iterFindAlias = iterFind->second->enumValueAliasList.find(attributeValue); + if (iterFindAlias != iterFind->second->enumValueAliasList.end()) + { + attributeValue = iterFindAlias->second; + } + + // remove any leading/trailing white space + attributeValue = Unicode::getTrim(attributeValue); + + (*m_searchableAttributeString)[iterFind->second->attributeNameCrc] = Unicode::toLower(attributeValue); + + if (iterFind->second->defaultSearchValueList.count(attributeValue) <= 0) + { + std::string bufferStr; + char buffer[16]; + for (size_t i = 0, size = attributeValue.size(); i < size; ++i) + { + snprintf(buffer, sizeof(buffer)-1, "%d ", attributeValue[i]); + buffer[sizeof(buffer)-1] = '\0'; + + bufferStr += buffer; + } + + LOG("CustomerService", ("CommoditiesAttributeSearch:Item %s (%s) in category %d (%s) has value (%s) (%s) (%d) for attribute (%s) that is not in the attribute enum list", + m_item->GetItemId().getValueString().c_str(), + Unicode::wideToNarrow(m_item->GetName()).c_str(), + m_item->GetCategory(), + GameObjectTypes::getCanonicalName(m_item->GetCategory()).c_str(), + attributeValue.c_str(), + bufferStr.c_str(), + attributeValue.size(), + iterFind->second->attributeName.c_str())); + } + } + } + } + + // for ship component and ship flight computer (or factory crate containing them), need to add "certifications required" search attribute + bool const itemIsShipComponentOrShipFlightComputer = ((GameObjectTypes::getMaskedType(m_item->GetCategory()) == SharedObjectTemplate::GOT_ship_component) || (m_item->GetCategory() == SharedObjectTemplate::GOT_deed_droid)); + bool const factoryCrateItemIsShipComponentOrShipFlightComputer = ((m_item->GetCategory() == SharedObjectTemplate::GOT_misc_factory_crate) && (gotItemInsideFactoryCrate > 0) && ((GameObjectTypes::getMaskedType(gotItemInsideFactoryCrate) == SharedObjectTemplate::GOT_ship_component) || (gotItemInsideFactoryCrate == SharedObjectTemplate::GOT_deed_droid))); + if (itemIsShipComponentOrShipFlightComputer || factoryCrateItemIsShipComponentOrShipFlightComputer) + { + static std::map requiredCerts; + + // load the required certs table + static bool requiredCertsLoaded = false; + if (!requiredCertsLoaded) + { + requiredCertsLoaded = true; + + DataTable * table = DataTableManager::getTable("datatables/commodity/ship_certification_attribute.iff", true); + if (table) + { + int const columnItem = table->findColumnNumber("Item"); + int const columnCert = table->findColumnNumber("Certifications Required"); + + if ((columnItem >= 0) && (columnCert >= 0) && (columnItem != columnCert)) + { + std::string item, cert; + int const numRows = table->getNumRows(); + for (int i = 0; i < numRows; ++i) + { + item = Unicode::getTrim(table->getStringValue(columnItem, i)); + cert = Unicode::getTrim(table->getStringValue(columnCert, i)); + + if (!item.empty() && !cert.empty()) + { + requiredCerts[static_cast(CrcLowerString::calculateCrc(item.c_str()))] = cert; + } + } + } + + DataTableManager::close("datatables/commodity/ship_certification_attribute.iff"); + } + } + + std::map::const_iterator const iterFind = requiredCerts.find(m_item->GetItemTemplateId()); + if (iterFind != requiredCerts.end()) + { + if (!m_searchableAttributeString) + m_searchableAttributeString = new std::map; + + static uint32 const shipCertAttributeCrc = Crc::calculate("ship_equipment_certification_search_attribute"); + static uint32 const astromechCertAttributeCrc = Crc::calculate("astromech_certification_search_attribute"); + + if (itemIsShipComponentOrShipFlightComputer) + { + (*m_searchableAttributeString)[((m_item->GetCategory() == SharedObjectTemplate::GOT_deed_droid) ? astromechCertAttributeCrc : shipCertAttributeCrc)] = iterFind->second; + } + else + { + (*m_searchableAttributeString)[((gotItemInsideFactoryCrate == SharedObjectTemplate::GOT_deed_droid) ? astromechCertAttributeCrc : shipCertAttributeCrc)] = iterFind->second; + } + } + } +} + +// ---------------------------------------------------------------------- + +bool Auction::IsAdvancedFilterMatch(std::list const & advancedSearch, int matchAllAny) const +{ + if (advancedSearch.empty()) + return true; + + // the following is the logic what will be used to determine match/no match + + // "will only match if all applicable attribute filter conditions match" + // ASMAA_match_all -> true after all match + // -> false after first mismatch + + // "will only match if any applicable attribute filter condition does not match" + // ASMAA_not_match_any is basically "not ASMAA_match_all" + // ASMAA_not_match_any -> false after all match + // -> true after first mismatch + + // "will only match if any applicable attribute filter condition matches" + // ASMAA_match_any -> false after all mismatch + // -> true after first match + + // "will only match if no applicable attribute filter condition matches" + // (i.e. match none) + // ASMAA_not_match_all is basically "not ASMAA_match_any" + // ASMAA_not_match_all -> true after all mismatch + // -> false after first match + + int filterCountMatch = 0; + int filterCountNotMatch = 0; + bool applicableFilter = 0; + bool matchFilter; + for (std::list::const_iterator iter = advancedSearch.begin(); iter != advancedSearch.end(); ++iter) + { + matchFilter = (*(s_searchConditionComparisonFn[static_cast(iter->comparison)]))(*iter, m_searchableAttributeInt, m_searchableAttributeFloat, m_searchableAttributeString, applicableFilter); + + if (!applicableFilter) + { + continue; + } + else if (matchFilter) // match filter + { + if (s_searchConditionMatchAllAnyActionAnyMatch[matchAllAny].first) + return s_searchConditionMatchAllAnyActionAnyMatch[matchAllAny].second; + + ++filterCountMatch; + } + else // does not match filter + { + if (s_searchConditionMatchAllAnyActionAnyNotMatch[matchAllAny].first) + return s_searchConditionMatchAllAnyActionAnyNotMatch[matchAllAny].second; + + ++filterCountNotMatch; + } + } + + // if we get this far, then either all applicable filters + // match or all applicable filters do not match, or there + // were no applicable filters + // + // it's impossible to have gotten this far and have some + // applicable filters match and some not match, because + // that situation should have caused an immediate return + // as soon as it was encountered + if (filterCountMatch > 0) + { + // all applicable filters match + return s_searchConditionMatchAllAnyActionAllMatch[matchAllAny]; + } + else if (filterCountNotMatch > 0) + { + // all applicable filters do not match + return s_searchConditionMatchAllAnyActionAllNotMatch[matchAllAny]; + } + + // no filter was applicable, so treat as if no filter was specified + return true; +} + +// ====================================================================== diff --git a/src/engine/server/application/CommoditiesServer/src/shared/ConfigCommodityServer.cpp b/src/engine/server/application/CommoditiesServer/src/shared/ConfigCommodityServer.cpp index f7406959e..8e73017bc 100644 --- a/src/engine/server/application/CommoditiesServer/src/shared/ConfigCommodityServer.cpp +++ b/src/engine/server/application/CommoditiesServer/src/shared/ConfigCommodityServer.cpp @@ -1,72 +1,72 @@ -// ====================================================================== -// -// ConfigCommodityServer.cpp -// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. -// Author: Doug Mellencamp -// -// ====================================================================== - -//----------------------------------------------------------------------- - -#include "FirstCommodityServer.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedNetwork/SetupSharedNetwork.h" -#include "ConfigCommodityServer.h" - -//----------------------------------------------------------------------- - -ConfigCommodityServer::Data * ConfigCommodityServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("CommodityServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("CommodityServer", #a, b)) -#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("CommodityServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("CommodityServer", #a, b)) - -//----------------------------------------------------------------------- - -void ConfigCommodityServer::install(void) -{ - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - - data = new ConfigCommodityServer::Data; - - KEY_INT (cmServerServiceBindPort, 4069); - KEY_STRING (cmServerServiceBindInterface, "localhost"); - KEY_INT (databaseServerPort, 44457); //TODO: confirm port - KEY_STRING (databaseServerAddress, "localhost"); - KEY_STRING (dsn,"swodb"); - KEY_STRING (databaseUID,"dmellencamp"); - KEY_STRING (databasePWD, "compts6m"); - KEY_STRING (databaseSchema, "dmellencamp"); - KEY_INT (secondsBetweenDBReconnect, 45); - KEY_STRING (databaseProtocol, "OCI"); - KEY_BOOL (enableQueryProfile,false); - KEY_BOOL (verboseQueryMode,false); - KEY_BOOL (developmentMode, true); - KEY_INT (databaseThreads, 1); - KEY_INT (databaseCharacterNameSizeLimit, 64); - KEY_INT (databaseItemNameSizeLimit, 256); - KEY_INT (databaseUserDescriptionSizeLimit, 1024); - KEY_INT (databaseOOBDataSizeLimit, 4000); - KEY_BOOL (snapshotDBWrite, true); - KEY_BOOL (showAllDebugInfo, true); - KEY_INT (centralServerPort, 44456); - KEY_STRING (centralServerAddress, "localhost"); - KEY_INT (sleepTimePerFrameMs, 1); - KEY_INT (minutesActiveToUnaccessed, 7 * 24 * 60); - KEY_INT (minutesEmptyToEndangered, 7 * 24 * 60); - KEY_INT (minutesUnaccessedToEndangered, 7 * 24 * 60); - KEY_INT (minutesEndangeredToRemoved, 7 * 24 * 60); - KEY_INT (minutesVendorAuctionTimer, 30 * 24 * 60); - KEY_INT (minutesVendorItemTimer, 30 * 24 * 60); - KEY_INT (maxAuctionsPerPage, 100); -} - -//----------------------------------------------------------------------- - -void ConfigCommodityServer::remove(void) -{ - delete data; - data = 0; -} +// ====================================================================== +// +// ConfigCommodityServer.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Doug Mellencamp +// +// ====================================================================== + +//----------------------------------------------------------------------- + +#include "FirstCommodityServer.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigCommodityServer.h" + +//----------------------------------------------------------------------- + +ConfigCommodityServer::Data * ConfigCommodityServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("CommodityServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("CommodityServer", #a, b)) +#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("CommodityServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("CommodityServer", #a, b)) + +//----------------------------------------------------------------------- + +void ConfigCommodityServer::install(void) +{ + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + + data = new ConfigCommodityServer::Data; + + KEY_INT (cmServerServiceBindPort, 4069); + KEY_STRING (cmServerServiceBindInterface, "localhost"); + KEY_INT (databaseServerPort, 44457); //TODO: confirm port + KEY_STRING (databaseServerAddress, "localhost"); + KEY_STRING (dsn,"swodb"); + KEY_STRING (databaseUID,"dmellencamp"); + KEY_STRING (databasePWD, "compts6m"); + KEY_STRING (databaseSchema, "dmellencamp"); + KEY_INT (secondsBetweenDBReconnect, 45); + KEY_STRING (databaseProtocol, "OCI"); + KEY_BOOL (enableQueryProfile,false); + KEY_BOOL (verboseQueryMode,false); + KEY_BOOL (developmentMode, true); + KEY_INT (databaseThreads, 1); + KEY_INT (databaseCharacterNameSizeLimit, 64); + KEY_INT (databaseItemNameSizeLimit, 256); + KEY_INT (databaseUserDescriptionSizeLimit, 1024); + KEY_INT (databaseOOBDataSizeLimit, 4000); + KEY_BOOL (snapshotDBWrite, true); + KEY_BOOL (showAllDebugInfo, true); + KEY_INT (centralServerPort, 44456); + KEY_STRING (centralServerAddress, "localhost"); + KEY_INT (sleepTimePerFrameMs, 1); + KEY_INT (minutesActiveToUnaccessed, 7 * 24 * 60); + KEY_INT (minutesEmptyToEndangered, 7 * 24 * 60); + KEY_INT (minutesUnaccessedToEndangered, 7 * 24 * 60); + KEY_INT (minutesEndangeredToRemoved, 7 * 24 * 60); + KEY_INT (minutesVendorAuctionTimer, 30 * 24 * 60); + KEY_INT (minutesVendorItemTimer, 30 * 24 * 60); + KEY_INT (maxAuctionsPerPage, 100); +} + +//----------------------------------------------------------------------- + +void ConfigCommodityServer::remove(void) +{ + delete data; + data = 0; +} diff --git a/src/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp b/src/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp index 4876d52e1..3ed0d56b1 100644 --- a/src/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp +++ b/src/engine/server/application/ConnectionServer/src/shared/ClientConnection.cpp @@ -1,1690 +1,1690 @@ -// ClientConnection.cpp -// copyright 2001 Verant Interactive - -//----------------------------------------------------------------------- - -#include "FirstConnectionServer.h" -#include "ClientConnection.h" - -#include "Archive/ByteStream.h" -#include "ChatServerConnection.h" -#include "CustomerServiceConnection.h" -#include "ConfigConnectionServer.h" -#include "ConnectionServer.h" -#include "GameConnection.h" -#include "SessionApiClient.h" -#include "UnicodeUtils.h" -#include "serverKeyShare/KeyShare.h" -#include "serverNetworkMessages/CentralConnectionServerMessages.h" -#include "serverNetworkMessages/ChatDisconnectAvatar.h" -#include "serverNetworkMessages/GameConnectionServerMessages.h" -#include "serverNetworkMessages/RandomName.h" -#include "serverNetworkMessages/RequestGameServerForLoginMessage.h" -#include "serverNetworkMessages/ValidateAccountMessage.h" -#include "serverNetworkMessages/ValidateCharacterForLoginMessage.h" -#include "serverNetworkMessages/VerifyAndLockName.h" -#include "serverUtility/AdminAccountManager.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/Clock.h" -#include "sharedFoundation/Crc.h" -#include "sharedGame/PlatformFeatureBits.h" -#include "sharedLog/Log.h" -#include "sharedNetwork/Connection.h" -#include "sharedNetworkMessages/ClientCentralMessages.h" -#include "sharedNetworkMessages/ClientPermissionsMessage.h" -#include "sharedNetworkMessages/AppendCommentMessage.h" -#include "sharedNetworkMessages/CancelTicketMessage.h" -#include "sharedNetworkMessages/ChatEnterRoom.h" -#include "sharedNetworkMessages/ChatEnterRoomById.h" -#include "sharedNetworkMessages/ChatEnum.h" -#include "sharedNetworkMessages/ChatOnEnteredRoom.h" -#include "sharedNetworkMessages/ChatPersistentMessageToServer.h" -#include "sharedNetworkMessages/ChatQueryRoom.h" -#include "sharedNetworkMessages/ConnectPlayerMessage.h" -#include "sharedNetworkMessages/CreateTicketMessage.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/GetTicketsMessage.h" -#include "sharedNetworkMessages/NewTicketActivityMessage.h" -#include "sharedNetworkMessages/ErrorMessage.h" -#include "sharedNetworkMessages/HeartBeat.h" -#include "Session/LoginAPI/Client.h" -#include "UdpLibrary.h" - -#include - -//----------------------------------------------------------------------- - -namespace ClientConnectionNamespace -{ - unsigned long gs_receiveDelayMaxMs = 16384; -} - -using namespace ClientConnectionNamespace; - - - - -//----------------------------------------------------------------------- - - -std::map< std::string, uint32 > ClientConnection::sm_outgoingBytesMap_Working; // working stats that will rotate after 1 minute -std::map< std::string, uint32 > ClientConnection::sm_outgoingBytesMap_Stats; // computed stats from the last minute -uint32 ClientConnection::sm_outgoingBytesMap_Worktime = 0 ; // time we started filling in the working map - - - -//----------------------------------------------------------------------- - -ClientConnection::ClientConnection(UdpConnectionMT * u, TcpClient * t) : -ServerConnection(u, t), -m_accountName(""), -m_canCreateRegularCharacter(false), -m_canCreateJediCharacter(false), -m_hasRequestedCharacterCreate(false), -m_hasCreatedCharacter(false), -m_pendingCharacterCreate(NULL), -m_canSkipTutorial(false), -m_characterId(NetworkId::cms_invalid), -m_characterName(), -m_startPlayTime(0), -m_lastActiveTime(0), -m_activePlayTimeDuration(0), -m_client(0), -m_containerId(NetworkId::cms_invalid), -m_featureBitsGame(0), -m_featureBitsSubscription(0), -m_hasBeenSentToGameServer(false), -m_hasBeenValidated(false), -m_hasSelectedCharacter(false), -m_isSecure(false), -m_isAdminAccount(false), -m_hasCSLoggedAccountFeatureIds(false), -m_suid(0), -m_requestedSuid(0), -m_usingAdminLogin(false), -m_targetCoordinates(), -m_targetScene(""), -m_validatingCharacter(false), -m_receiveHistoryBytes(0), -m_receiveHistoryPackets(0), -m_receiveHistoryMs(0), -m_receiveLastTimeMs(0), -m_sendLastTimeMs(0), -m_sessionId(""), -m_sessionValidated(false), -m_connectionServerLag(0), -m_gameServerLag(0), -m_countSpamLimitResetTime(0), -m_entitlementTotalTime(0), -m_entitlementEntitledTime(0), -m_entitlementTotalTimeSinceLastLogin(0), -m_entitlementEntitledTimeSinceLastLogin(0), -m_buddyPoints(0), -m_sendToStarport(false), -m_pendingChatEnterRoomRequests(), -m_pendingChatQueryRoomRequests() -{ - static const std::string loginTrace("TRACE_LOGIN"); - LOG(loginTrace, ("new ClientConnection")); - - setNoDataTimeout(600000); -} - -//----------------------------------------------------------------------- - -ClientConnection::~ClientConnection() -{ - bool hasBeenKicked = false; - - if (ConnectionServer::getClientConnection(m_suid) == this) - { - ConnectionServer::removeConnectedCharacter(m_suid); - } - if (m_client) - { - hasBeenKicked = m_client->hasBeenKicked(); - delete m_client; - m_client = NULL; - } - - // tell Session to stop recording play time for the character - if (m_hasBeenValidated && m_sessionValidated && ConnectionServer::getSessionApiClient() && (m_lastActiveTime > 0) && ConfigConnectionServer::getSessionRecordPlayTime()) - { - LOG("CustomerService", ("Login:%s calling SessionStopPlay() for %s/%s/%s (%s). Active play time: %s", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str(), this->getCurrentActivePlayTimeDuration().c_str())); - - // log total active play time for the session to the balance log - LOG("GameBalance", ("balancelog:%s calling SessionStopPlay() for %s/%s/%s (%s). Active play time: %s", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str(), this->getActivePlayTimeDuration().c_str())); - - ConnectionServer::getSessionApiClient()->stopPlay(*this); - } - - if (ConnectionServer::getSessionApiClient()) - { - ConnectionServer::getSessionApiClient()->dropClient(this, hasBeenKicked); - } - - std::map::const_iterator iter; - for (iter = m_pendingChatEnterRoomRequests.begin(); iter != m_pendingChatEnterRoomRequests.end(); ++iter) - { - delete iter->second; - } - m_pendingChatEnterRoomRequests.clear(); - - for (iter = m_pendingChatQueryRoomRequests.begin(); iter != m_pendingChatQueryRoomRequests.end(); ++iter) - { - delete iter->second; - } - m_pendingChatQueryRoomRequests.clear(); - - delete m_pendingCharacterCreate; - m_pendingCharacterCreate = NULL; -} - - -//----------------------------------------------------------------------- - -const NetworkId & ClientConnection::getCharacterId() const -{ - return m_characterId; -} - -//----------------------------------------------------------------------- - -const std::string & ClientConnection::getCharacterName() const -{ - return m_characterName; -} - -//----------------------------------------------------------------------- - -std::string ClientConnection::getPlayTimeDuration() const -{ - int playTimeDuration = 0; - - if (m_startPlayTime > 0) - playTimeDuration = static_cast(::time(NULL) - m_startPlayTime); - - return CalendarTime::convertSecondsToHMS(static_cast(playTimeDuration)); -} - -//----------------------------------------------------------------------- - -std::string ClientConnection::getActivePlayTimeDuration() const -{ - int activePlayTimeDuration = static_cast(m_activePlayTimeDuration); - - if (m_lastActiveTime > 0) - activePlayTimeDuration += static_cast(::time(NULL) - m_lastActiveTime); - - return CalendarTime::convertSecondsToHMS(static_cast(activePlayTimeDuration)); -} - -//----------------------------------------------------------------------- - -std::string ClientConnection::getCurrentActivePlayTimeDuration() const -{ - int activePlayTimeDuration = 0; - - if (m_lastActiveTime > 0) - activePlayTimeDuration = static_cast(::time(NULL) - m_lastActiveTime); - - return CalendarTime::convertSecondsToHMS(static_cast(activePlayTimeDuration)); -} - -//----------------------------------------------------------------------- - -void ClientConnection::sendPlayTimeInfoToGameServer() const -{ - if (m_client && m_client->getGameConnection()) - { - // update the game server with play time info - GenericValueTypeMessage > > const msgPlayTimeInfo( - "UpdateSessionPlayTimeInfo", - std::make_pair(static_cast(m_startPlayTime), - std::make_pair(static_cast(m_lastActiveTime), m_activePlayTimeDuration) - ) - ); - - std::vector v; - v.push_back(m_client->getNetworkId()); - GameClientMessage const gcm(v, true, msgPlayTimeInfo); - m_client->getGameConnection()->send(gcm, true); - } -} - -// ---------------------------------------------------------------------- - -void ClientConnection::handleSelectCharacterMessage(const SelectCharacter& msg) -{ - //Only accept this message from clients who have been validated and - //haven't already selected. - if (m_hasSelectedCharacter || m_validatingCharacter || !m_hasBeenValidated || !m_sessionValidated) - { - if(m_hasSelectedCharacter) - { - LOG("TraceCharacterSelection", ("%d cannot select a character because the client has already selected a character", getSUID())); - } - if(m_validatingCharacter) - { - LOG("TraceCharacterSelection", ("%d cannot select a character because the client has not yet received validation", getSUID())); - } - if(!m_hasBeenValidated) - { - LOG("TraceCharacterSelection", ("%d cannot select a character because the client has not been validated", getSUID())); - } - if (!m_sessionValidated) - { - LOG("TraceCharacterSelection", ("%d cannot select a character because the client has not been session validated", getSUID())); - } - - return; - } - - m_validatingCharacter = true; - - // The client is picking a character from the list the Login Server gave him. - // But we don't trust him not to cheat, so we double-check that he really - // owns the character he selected. - - ValidateCharacterForLoginMessage vclm(getSUID(), msg.getId()); - ConnectionServer::sendToCentralProcess(vclm); - LOG("TraceCharacterSelection", ("%d selected %s for login. Sending a validation request to CentralServer to verify this client can use this character", getSUID(), msg.getId().getValueString().c_str())); - -} - -// ---------------------------------------------------------------------- - -/** - * We got a message telling us what game server to use for the player (who - * is in the process of logging in). - * Connect the player with the game server. - */ -void ClientConnection::handleGameServerForLoginMessage(uint32 serverId) -{ - DEBUG_WARNING(serverId==0,("Got handleGameServerForLoginMessage with serverId=0.\n")); - IGNORE_RETURN( sendToGameServer(serverId) ); -} - -//---------------------------------------------------------------------- - -/** - * Examine the ID the client sends us. If it looks OK, send it to Central - * to be validated. Central will reply with a list of permissions. - * @see onIdValidated - */ -void ClientConnection::handleClientIdMessage(const ClientIdMsg& msg) -{ - //Only check clients that have not been validated. - if (m_hasBeenValidated) - return; - - DEBUG_FATAL(m_hasSelectedCharacter, ("Trying to validate a client who already has a character selected.\n")); - bool result = false; - char sessionId[apiSessionIdWidth]; - - m_gameBitsToClear = msg.getGameBitsToClear(); - - if(msg.getTokenSize() > 0) - { - Archive::ByteStream t(msg.getToken(), msg.getTokenSize()); - Archive::ReadIterator ri(t); - KeyShare::Token token(ri); - - if (!ConfigConnectionServer::getValidateStationKey()) - { - // get SUID from token - result = ConnectionServer::decryptToken(token, m_suid, m_isSecure, m_accountName); - } - else - { - result = ConnectionServer::decryptToken(token, sessionId, m_requestedSuid); - } - - static const std::string loginTrace("TRACE_LOGIN"); - LOG(loginTrace, ("ClientConnection SUID = %d", m_suid)); - - } - if (result) - { - //check for duplicate login - ClientConnection * oldConnection = ConnectionServer::getClientConnection(m_suid); - if (oldConnection) - { - //There is already someone connected to this cluster with this suid. - LOG("Network", ("SUID %d already logged in, disconnecting client.\n", m_suid)); - - ConnectionServer::dropClient(oldConnection, "Already Connected"); - - disconnect(); - return; - } - - // verify version - if (ConfigConnectionServer::getValidateClientVersion() && msg.getVersion() != GameNetworkMessage::NetworkVersionId) - { - std::string strSessionId(sessionId, apiSessionIdWidth); - strSessionId += '\0'; - - const int bufferSize = 255 + apiSessionIdWidth; - char * buffer = new char[bufferSize]; - snprintf(buffer, bufferSize-1, "network version mismatch: got (ip=[%s], sessionId=[%s], version=[%s]), required (version=[%s])", getRemoteAddress().c_str(), strSessionId.c_str(), msg.getVersion().c_str(), GameNetworkMessage::NetworkVersionId.c_str()); - buffer[bufferSize-1] = '\0'; - - ConnectionServer::dropClient(this, std::string(buffer)); - disconnect(); - - delete[] buffer; - - return; - } - - if (ConfigConnectionServer::getValidateStationKey()) - { - SessionApiClient * session = ConnectionServer::getSessionApiClient(); - NOT_NULL(session); - if(session) - { - session->validateClient(this, sessionId); - } - else - { - ConnectionServer::dropClient(this, "SessionApiClient is not available!"); - disconnect(); - } - } - else - { - m_suid = atoi(m_accountName.c_str()); - if (m_suid == 0) - { - std::hash h; - m_suid = h(m_accountName.c_str()); - } - onValidateClient(m_suid, m_accountName, m_isSecure, NULL, ConfigConnectionServer::getDefaultGameFeatures(), ConfigConnectionServer::getDefaultSubscriptionFeatures(), 0, 0, 0, 0, ConfigConnectionServer::getFakeBuddyPoints()); - } - } - else - { - // They sent us a token that was no good -- either a hack attempt, or - // possibly it was just too old. - LOG("ClientDisconnect", ("SUID %d passed a bad token to the connections erver. Disconnecting.", m_suid)); - disconnect(); - } -} - -//----------------------------------------------------------------------- - -void ClientConnection::onIdValidated(bool canLogin, bool canCreateRegularCharacter, bool canCreateJediCharacter, bool canSkipTutorial, std::vector > const & consumedRewardEvents, std::vector > const & claimedRewardItems) -{ - //@todo start session with station. - //@todo add more permissions to this message as needed. - - // resume character creation - if (m_pendingCharacterCreate) - { - if (!m_pendingCharacterCreate->getUseNewbieTutorial() && !canSkipTutorial) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to skip the tutorial", getSUID())); - // This is probably a hack attempt, because the Client was already told they couldn't skip the tutorial - LOG("ClientDisconnect", ("Disconnecting %u because they tried to skip the tutorial without permission.\n",getSUID())); - disconnect(); - } - else if (m_pendingCharacterCreate->getJedi() && !canCreateJediCharacter) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The request character type was Jedi, but this client cannot create a Jedi character", getSUID())); - // This is probably a hack attempt, because the Client was already told they couldn't create a character - LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a Jedi character without permission.\n",getSUID())); - disconnect(); - } - else if (!m_pendingCharacterCreate->getJedi() && !canCreateRegularCharacter) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to create any characters", getSUID())); - // This is probably a hack attempt, because the Client was already told they couldn't create a character - LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a regular character without permission.\n",getSUID())); - disconnect(); - } - else - { - ConnectionServer::sendToCentralProcess(*m_pendingCharacterCreate); - LOG("TraceCharacterCreation", ("%d character creation request sent to CentralServer", getSUID())); - - m_hasRequestedCharacterCreate = true; - } - - delete m_pendingCharacterCreate; - m_pendingCharacterCreate = NULL; - - return; - } - - // Save lists of claimed rewards, which won't be used again until later in the login sequence - m_consumedRewardEvents = consumedRewardEvents; - m_claimedRewardItems = claimedRewardItems; - - - int level=0; - if (AdminAccountManager::isAdminAccount(Unicode::toLower(getAccountName()),level) && (level !=0)) // Note: not checking IP, so that owners of god accounts can create characters to play from home without having to erase the characters they use for work - { - canLogin = true; - canCreateRegularCharacter = true; - canSkipTutorial = true; - m_isAdminAccount = true; - } - - ClientPermissionsMessage c(canLogin, canCreateRegularCharacter, canCreateJediCharacter, canSkipTutorial); - send(c, true); - - DEBUG_REPORT_LOG(true,("Permissions for %lu:\n",getSUID())); - DEBUG_REPORT_LOG(canLogin,("\tcanLogin\n")); - DEBUG_REPORT_LOG(canCreateRegularCharacter,("\tcanCreateRegularCharacter\n")); - DEBUG_REPORT_LOG(canCreateJediCharacter,("\tcanCreateJediCharacter\n")); - DEBUG_REPORT_LOG(canSkipTutorial,("\tcanSkipTutorial\n")); - DEBUG_REPORT_LOG(!(canLogin || canCreateRegularCharacter || canCreateJediCharacter || canSkipTutorial),("\tnone\n")); - - if (canLogin) - { - m_hasBeenValidated = true; - m_canCreateRegularCharacter = canCreateRegularCharacter; - m_canCreateJediCharacter = canCreateJediCharacter; - m_canSkipTutorial = canSkipTutorial; - } - else - { - LOG("TRACE_LOGIN", ("%d does not have permissions to log in", getSUID())); - LOG("ClientDisconnect", ("Client (SUID %u) does not have permissions to log in. Disconnecting.", getSUID())); - disconnect(); - } -} - -//----------------------------------------------------------------------- - -void ClientConnection::onConnectionClosed() -{ - ServerConnection::onConnectionClosed(); - static MessageConnectionCallback m("ClientConnectionClosed"); - emitMessage(m); - - LOG("TRACE_LOGIN", ("%d closed connection", getSUID())); - if (m_client) - { - if (!m_client->hasBeenKicked()) - { - LOG("CustomerService", ("Login:%s Dropped Reason: Client Dropped Connection. Character: %s (%s). Play time: %s. Active play time: %s", describeAccount(this).c_str(), getCharacterName().c_str(), getCharacterId().getValueString().c_str(), getPlayTimeDuration().c_str(), getActivePlayTimeDuration().c_str())); - } - ChatServerConnection * chatConnection = m_client->getChatConnection(); - if(chatConnection) - { - ChatDisconnectAvatar m(m_characterId); - chatConnection->send(m, true); - } - // We cannot do this here, as this connection will be deleted on - // return from this function already. - //m_client->kick(); - } -} - -//----------------------------------------------------------------------- - -void ClientConnection::onConnectionOpened() -{ - ServerConnection::onConnectionOpened(); - static MessageConnectionCallback m("ClientConnectionOpened"); - emitMessage(m); - setOverflowLimit(ConfigConnectionServer::getClientOverflowLimit()); -} - -//----------------------------------------------------------------------- - -void ClientConnection::onConnectionOverflowing (const unsigned int bytesPending) -{ - char errbuf[1024]; - snprintf(errbuf, sizeof(errbuf), "Connection overflow from server to client, %d bytes. Disconnected.", bytesPending); - std::string name("Connection overflow server->client"); - std::string desc(errbuf); - LOG("Network", ("Disconnect: Client connection overflowing. %d bytes pending", bytesPending)); - - std::vector >::const_iterator i; - for(i = m_pendingPackets.begin(); i != m_pendingPackets.end(); ++i) - { - LOG("Network", ("Overflow packets this frame: [%s] %d bytes", i->first.c_str(), i->second)); - } - -// ErrorMessage err(name, desc, false); -// send(err, true); - WARNING(true, (errbuf)); - LOG("ClientDisconnect", ("About to drop client (character) %s because the connection is overflowing\n", m_characterName.c_str())); - - snprintf(errbuf, sizeof(errbuf)-1, "Connection Overflow (bytes pending=%u)", bytesPending); - errbuf[sizeof(errbuf)-1] = '\0'; - ConnectionServer::dropClient(this, std::string(errbuf)); -} - -//----------------------------------------------------------------------- - -bool ClientConnection::checkSpamLimit(unsigned int messageSize) -{ - if (!ConfigConnectionServer::getSpamLimitEnabled()) - return true; - - unsigned long curTimeMs = Clock::timeMs(); - if (m_receiveLastTimeMs) - { - ++m_receiveHistoryPackets; - m_receiveHistoryBytes += messageSize; - m_receiveHistoryMs += curTimeMs-m_receiveLastTimeMs; - - // rescale the history information if we've exceeded the reset time; this - // must be done before the spam check below or else we may run into overflow - // issues because m_receiveHistoryMs could be pretty large if we haven't - // received anything from the client for a while - while (m_receiveHistoryMs > ConfigConnectionServer::getSpamLimitResetTimeMs()) - { - ++m_countSpamLimitResetTime; - - unsigned int resetScale = ConfigConnectionServer::getSpamLimitResetScaleFactor(); - m_receiveHistoryMs /= resetScale; - m_receiveHistoryBytes /= resetScale; - m_receiveHistoryPackets /= resetScale; - } - - // check for exceeding limits, but wait for at least - // one reset cycle so that there has been enough - // elapsed time, so we won't get a false positive - if (m_countSpamLimitResetTime) - { - if (m_receiveHistoryBytes >= m_receiveHistoryMs*ConfigConnectionServer::getSpamLimitBytesPerSec()/1000) - { - LOG("Network", ("Client %s disconnected for exceeding bytes/sec limit (bytes=%u, time=%lums)\n", getCharacterId().getValueString().c_str(), m_receiveHistoryBytes, m_receiveHistoryMs)); - return false; - } - if (m_receiveHistoryPackets >= m_receiveHistoryMs*ConfigConnectionServer::getSpamLimitPacketsPerSec()/1000) - { - LOG("Network", ("Client %s disconnected for exceeding packets/sec limit (packets=%u, time=%lums)\n", getCharacterId().getValueString().c_str(), m_receiveHistoryPackets, m_receiveHistoryMs)); - return false; - } - } - } - m_receiveLastTimeMs = curTimeMs; - return true; -} - -//----------------------------------------------------------------------- - -void ClientConnection::onReceive(const Archive::ByteStream & message) -{ - try - { - if (!checkSpamLimit(message.getSize())) - { - ConnectionServer::dropClient(this, "Spam Detected"); - return; - } - - unsigned long curTimeMs = Clock::timeMs(); - if (m_sendLastTimeMs + std::min(gs_receiveDelayMaxMs, static_cast(Clock::frameTime()*1000.0f)) < curTimeMs) - { - static HeartBeat h; - send(h, false); - } - - Archive::ReadIterator ri = message.begin(); - GameNetworkMessage m(ri); - ri = message.begin(); - - //Clients with a selected character get routed to a game server. - //@todo check for filtering out bad messages. - if (m_hasSelectedCharacter) - { - // if it is a chat message, send it directly to the chat server - if( - m.isType("ChatAddFriend") || - m.isType("ChatAddModeratorToRoom") || - m.isType("ChatBanAvatarFromRoom") || - m.isType("ChatCreateRoom") || - m.isType("ChatDeletePersistentMessage") || - m.isType("ChatDeleteAllPersistentMessages") || - m.isType("ChatDestroyRoom") || - m.isType("ChatInstantMessageToCharacter") || - m.isType("ChatInviteAvatarToRoom") || - m.isType("ChatKickAvatarFromRoom") || - m.isType("ChatRemoveAvatarFromRoom") || - m.isType("ChatRemoveFriend") || - m.isType("ChatRemoveModeratorFromRoom") || - m.isType("ChatRequestPersistentMessage") || - m.isType("ChatRequestRoomList") || - m.isType("ChatSendToRoom") || - m.isType("ChatUninviteFromRoom") || - m.isType("ChatUnbanAvatarFromRoom") || - m.isType("VerifyPlayerNameMessage") || - m.isType("VoiceChatRequestPersonalChannel") || - m.isType("VoiceChatInvite") || - m.isType("VoiceChatKick") || - m.isType("VoiceChatRequestChannelInfo") - ) - { - DEBUG_REPORT_LOG(true, ("ConnServ: ClientConnection::onReceive()\n")); - - NOT_NULL(m_client); - if(m_client) - { - static std::vector v; - v.clear(); - v.push_back(m_client->getNetworkId()); - GameClientMessage gcm(v, true, ri); - if(m_client->getChatConnection()) - { - m_client->getChatConnection()->send(gcm , true); - } - else - { - // defer chat messages until a server is back online - Archive::ByteStream bs; - m.pack(bs); - m_client->deferChatMessage(bs); - } - } - else - { - ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); - disconnect(); - } - } - // ChatEnterRoom and ChatEnterRoomById needs to go to the game server to determine - // if the character is not allowed to enter the room because of game rule restrictions; - // only if that test pass do we forward the message on to the chat server to request - // to enter the room - else if (m.isType("ChatEnterRoom") || - m.isType("ChatEnterRoomById") - ) - { - NOT_NULL(m_client); - - unsigned int sequence; - std::string roomName; - - Archive::ReadIterator cri = message.begin(); - if (m.isType("ChatEnterRoom")) - { - ChatEnterRoom const cer(cri); - sequence = cer.getSequence(); - roomName = cer.getRoomName(); - } - else - { - ChatEnterRoomById const cerbi(cri); - sequence = cerbi.getSequence(); - roomName = cerbi.getRoomName(); - } - - if(m_client && m_client->getGameConnection()) - { - if (m_pendingChatEnterRoomRequests.count(sequence) == 0) - { - GenericValueTypeMessage, unsigned int> > const cervr( - "ChatEnterRoomValidationRequest", - std::make_pair( - std::make_pair(m_client->getNetworkId(), roomName), - sequence)); - - m_client->getGameConnection()->send(cervr, true); - - // queue up request until game server responds - static std::vector v; - v.clear(); - v.push_back(m_client->getNetworkId()); - m_pendingChatEnterRoomRequests[sequence] = new GameClientMessage(v, true, ri); - } - } - else - { - // send back response to client saying game server not available - - // the client only cares about sequence and result when it's a failure - ChatOnEnteredRoom fail(sequence, SWG_CHAT_ERR_NO_GAME_SERVER, 0, ChatAvatarId()); - send(fail, true); - } - } - // ChatQueryRoom needs to go to the game server to determine if the character is - // not allowed to query the room because of game rule restrictions; only if that - // test pass do we forward the message on to the chat server for completion - else if (m.isType("ChatQueryRoom")) - { - NOT_NULL(m_client); - - Archive::ReadIterator cri = message.begin(); - ChatQueryRoom cqr(cri); - - if(m_client && m_client->getGameConnection()) - { - if (m_pendingChatQueryRoomRequests.count(cqr.getSequence()) == 0) - { - GenericValueTypeMessage, unsigned int> > const cqrvr( - "ChatQueryRoomValidationRequest", - std::make_pair( - std::make_pair(m_client->getNetworkId(), cqr.getRoomName()), - cqr.getSequence())); - - m_client->getGameConnection()->send(cqrvr, true); - - // queue up request until game server responds - static std::vector v; - v.clear(); - v.push_back(m_client->getNetworkId()); - m_pendingChatQueryRoomRequests[cqr.getSequence()] = new GameClientMessage(v, true, ri); - } - } - } - // ChatInviteGroupToRoom needs to go to the game server to get group information - else if (m.isType("ChatInviteGroupToRoom")) - { - NOT_NULL(m_client); - if(m_client) - { - if (m_client->getGameConnection()) - { - static std::vector v; - v.clear(); - v.push_back(m_client->getNetworkId()); - GameClientMessage gcm(v, true, ri); - m_client->getGameConnection()->send(gcm, true); - } - else - { - // defer chat messages until a server is back online - Archive::ByteStream bs; - m.pack(bs); - m_client->deferChatMessage(bs); - } - } - else - { - ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); - disconnect(); - } - } - // ChatPersistentMessageToServer may need to be passed off to the game server for guild or citizens messages - else if (m.isType("ChatPersistentMessageToServer")) - { - NOT_NULL(m_client); - if(m_client) - { - static std::vector v; - v.clear(); - v.push_back(m_client->getNetworkId()); - - Archive::ReadIterator cri = message.begin(); - ChatPersistentMessageToServer chat(cri); - std::string const &toName = chat.getToCharacterName().name; - if (!_stricmp(toName.c_str(), "guild") || !_strnicmp(toName.c_str(), "guild ", 6) || !_stricmp(toName.c_str(), "citizens")) - { - if (m_client->getGameConnection()) - { - GameClientMessage gcm(v, true, ri); - m_client->getGameConnection()->send(gcm, true); - } - } - else - { - if (m_client->getChatConnection()) - { - GameClientMessage gcm(v, true, ri); - m_client->getChatConnection()->send(gcm, true); - } - else - { - // defer chat messages until a server is back online - Archive::ByteStream bs; - m.pack(bs); - m_client->deferChatMessage(bs); - } - } - } - else - { - ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); - disconnect(); - } - } - // if it is a cs message, send it directly to the cs server - else if ( - m.isType("ConnectPlayerMessage") || - m.isType("DisconnectPlayerMessage") || - m.isType("CreateTicketMessage") || - m.isType("AppendCommentMessage") || - m.isType("CancelTicketMessage") || - m.isType("GetTicketsMessage") || - m.isType("GetCommentsMessage") || - m.isType("SearchKnowledgeBaseMessage") || - m.isType("GetArticleMessage") || - m.isType("RequestCategoriesMessage") || - m.isType("NewTicketActivityMessage") - ) - { - NOT_NULL(m_client); - if(m_client) - { - CustomerServiceConnection *customerServiceConnection = m_client->getCustomerServiceConnection(); - - //DEBUG_REPORT_LOG(true, ("CONSRV::CS - suid: %i\n", getSUID())); - - if (customerServiceConnection != NULL) - { - static std::vector v; - v.clear(); - v.push_back(m_client->getNetworkId()); - if (m.isType("ConnectPlayerMessage")) - { - ConnectPlayerMessage message(ri); - message.setStationId(getSUID()); - - GameClientMessage gcm(v, true, message); - customerServiceConnection->send(gcm , true); - } - else if (m.isType("CreateTicketMessage")) - { - CreateTicketMessage message(ri); - message.setStationId(getSUID()); - - GameClientMessage gcm(v, true, message); - customerServiceConnection->send(gcm , true); - } - else if (m.isType("AppendCommentMessage")) - { - AppendCommentMessage message(ri); - message.setStationId(getSUID()); - - GameClientMessage gcm(v, true, message); - customerServiceConnection->send(gcm , true); - } - else if (m.isType("CancelTicketMessage")) - { - CancelTicketMessage message(ri); - message.setStationId(getSUID()); - - GameClientMessage gcm(v, true, message); - customerServiceConnection->send(gcm , true); - } - else if (m.isType("GetTicketsMessage")) - { - GetTicketsMessage message(ri); - message.setStationId(getSUID()); - - GameClientMessage gcm(v, true, message); - customerServiceConnection->send(gcm , true); - } - else if (m.isType("NewTicketActivityMessage")) - { - NewTicketActivityMessage message(ri); - message.setStationId(getSUID()); - - GameClientMessage gcm(v, true, message); - customerServiceConnection->send(gcm , true); - } - else - { - GameClientMessage gcm(v, true, ri); - customerServiceConnection->send(gcm , true); - } - //else - //{ - // /*// defer chat messages until a server is back online - // Archive::ByteStream bs; - // m.pack(bs); - // m_client->deferChatMessage(bs); - // */ - //} - } - } - else - { - ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); - disconnect(); - } - } - else if (m.isType("28afefcc187a11dc888b001")) // obfuscation for ClientInactivityMessage message - { - GenericValueTypeMessage msg(ri); - - if (m_hasBeenValidated && m_sessionValidated) - { - // client went inactive - if (msg.getValue()) - { - if (m_lastActiveTime > 0) - { - // record the amount of active time - m_activePlayTimeDuration += static_cast(::time(NULL) - m_lastActiveTime); - - // tell Session to stop recording play time for the character - if (ConnectionServer::getSessionApiClient() && ConfigConnectionServer::getSessionRecordPlayTime()) - { - LOG("CustomerService", ("Login:%s calling SessionStopPlay() for %s/%s/%s (%s). Active play time: %s", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str(), this->getCurrentActivePlayTimeDuration().c_str())); - ConnectionServer::getSessionApiClient()->stopPlay(*this); - } - - // client is no longer active; this needs to be set after the LOG() statement - // above because getCurrentActivePlayTimeDuration() uses m_lastActiveTime - m_lastActiveTime = 0; - - // update the play time info on the game server - sendPlayTimeInfoToGameServer(); - - // drop inactive character - if (ConfigConnectionServer::getDisconnectOnInactive()) - { - LOG("ClientDisconnect", ("Disconnecting %u because the player was inactive for too long.",getSUID())); - ConnectionServer::dropClient(this, "Client inactivity"); - disconnect(); - } - else if (ConfigConnectionServer::getDisconnectFreeTrialOnInactive() && ((m_featureBitsSubscription & ClientSubscriptionFeature::Base) == 0)) - { - LOG("ClientDisconnect", ("Disconnecting (free trial) %u because the player was inactive for too long.",getSUID())); - ConnectionServer::dropClient(this, "Client inactivity (free trial)"); - disconnect(); - } - } - } - // client went active - else - { - if (m_lastActiveTime == 0) - { - // record the time client went active - m_lastActiveTime = ::time(NULL); - - // tell Session to start recording play time for the character - if (ConnectionServer::getSessionApiClient() && ConfigConnectionServer::getSessionRecordPlayTime()) - { - LOG("CustomerService", ("Login:%s calling SessionStartPlay() for %s/%s/%s (%s)", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str())); - ConnectionServer::getSessionApiClient()->startPlay(*this); - } - - // update the play time info on the game server - sendPlayTimeInfoToGameServer(); - } - } - } - } - else - { - //Forward on to Game Server - DEBUG_REPORT_LOG((!m_client || !m_client->getGameConnection()), ("Warn, received game message with no game connection. This may happen for a short time after a GameServer crashes. If it continues to happen, it indicates a bug.\n")); - - if (m_client && m_client->getGameConnection()) - { - static std::vector v; - v.clear(); - v.push_back(m_client->getNetworkId()); - GameClientMessage gcm(v, true, ri); - m_client->getGameConnection()->send(gcm, true); - } - } - } - - else if(m.isType("ClientIdMsg")) - { - DEBUG_REPORT_LOG(true,("Recieved ClientIdMsg\n")); - ClientIdMsg k(ri); - - handleClientIdMessage(k); - } - else if(m.isType("SelectCharacter")) - { - SelectCharacter s(ri); - DEBUG_REPORT_LOG(true,("Recvd SelectCharacter message for %s.\n", s.getId().getValueString().c_str())); - - handleSelectCharacterMessage(s); - } - else if(m.isType("ClientCreateCharacter")) - { - if (m_hasBeenValidated && !m_hasSelectedCharacter) //lint !e774 no this doesn't always eval to true - { - ClientCreateCharacter clientCreate(ri); - DEBUG_REPORT_LOG(true,("Got ClientCreateCharacter message for %lu with name %s\n", m_suid, Unicode::wideToNarrow(clientCreate.getCharacterName()).c_str())); - LOG("TraceCharacterCreation", ("%d sent ClientCreateCharacter(charaterName=%s, templateName=%s, scaleFactor=%f, startingLocation=%s, hairTemplateName=%s, profession=%s, jedi=%d, useNewbieTutorial=%d, skillTemplate=%s, workingSkill=%s)", - getSUID(), - Unicode::wideToNarrow(clientCreate.getCharacterName()).c_str(), - clientCreate.getTemplateName().c_str(), - clientCreate.getScaleFactor(), - clientCreate.getStartingLocation().c_str(), - clientCreate.getHairTemplateName().c_str(), - clientCreate.getProfession().c_str(), - static_cast(clientCreate.getJedi()), - static_cast(clientCreate.getUseNewbieTutorial()), - clientCreate.getSkillTemplate().c_str(), - clientCreate.getWorkingSkill().c_str())); - - if (!clientCreate.getUseNewbieTutorial() && !m_canSkipTutorial) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to skip the tutorial", getSUID())); - // This is probably a hack attempt, because the Client was already told they couldn't skip the tutorial - LOG("ClientDisconnect", ("Disconnecting %u because they tried to skip the tutorial without permission.\n",getSUID())); - disconnect(); - } - else if (clientCreate.getJedi() && !m_canCreateJediCharacter) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The request character type was Jedi, but this client cannot create a Jedi character", getSUID())); - // This is probably a hack attempt, because the Client was already told they couldn't create a character - LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a Jedi character without permission.\n",getSUID())); - disconnect(); - } - else if (!clientCreate.getJedi() && !m_canCreateRegularCharacter) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to create any characters", getSUID())); - // This is probably a hack attempt, because the Client was already told they couldn't create a character - LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a regular character without permission.\n",getSUID())); - disconnect(); - } - else if (m_hasRequestedCharacterCreate) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The client has already requested character creation on this connection", getSUID())); - LOG("ClientDisconnect", ("Disconnecting %u because the client has already requested character creation on this connection.\n",getSUID())); - disconnect(); - } - else if (m_hasCreatedCharacter) - { - LOG("TraceCharacterCreation", ("%d failed character creation. A character has been created on this or another galaxy for this account while this connection was up", getSUID())); - LOG("ClientDisconnect", ("Disconnecting %u because a character has been created on this or another galaxy for this account while this connection was up.\n",getSUID())); - disconnect(); - } - else if (clientCreate.getCharacterName().length()==0) - { - LOG("TraceCharacterCreation", ("%d failed character creation. The character's name is empty", getSUID())); - LOG("ClientDisconnect",("Disconnecting %u because they tried to create a character with no name.\n",getSUID())); - disconnect(); - } - else - { - Unicode::String biography(clientCreate.getBiography()); - if (biography.length() > 1024) - { - IGNORE_RETURN( biography.erase(1024) ); - DEBUG_REPORT_LOG(true,("Biography shortened to 1024 characters.\n")); - } - - if (m_isAdminAccount) - { - ConnectionCreateCharacter connectionCreate( - m_suid, - clientCreate.getCharacterName(), - clientCreate.getTemplateName(), - clientCreate.getScaleFactor(), - clientCreate.getStartingLocation(), - clientCreate.getAppearanceData(), - clientCreate.getHairTemplateName(), - clientCreate.getHairAppearanceData(), - clientCreate.getProfession(), - clientCreate.getJedi(), - biography, - clientCreate.getUseNewbieTutorial(), - clientCreate.getSkillTemplate(), - clientCreate.getWorkingSkill(), - m_isAdminAccount, - false, - m_featureBitsGame); - - ConnectionServer::sendToCentralProcess(connectionCreate); - LOG("TraceCharacterCreation", ("%d character creation request sent to CentralServer", getSUID())); - } - else - { - // for regular players, do one final check with the LoginServer - // to make sure the character can be created (i.e. that character - // limits have not been exceeded) - delete m_pendingCharacterCreate; - m_pendingCharacterCreate = new ConnectionCreateCharacter( - m_suid, - clientCreate.getCharacterName(), - clientCreate.getTemplateName(), - clientCreate.getScaleFactor(), - clientCreate.getStartingLocation(), - clientCreate.getAppearanceData(), - clientCreate.getHairTemplateName(), - clientCreate.getHairAppearanceData(), - clientCreate.getProfession(), - clientCreate.getJedi(), - biography, - clientCreate.getUseNewbieTutorial(), - clientCreate.getSkillTemplate(), - clientCreate.getWorkingSkill(), - m_isAdminAccount, - false, - m_featureBitsGame); - - LOG("TraceCharacterCreation", ("%d character creation request awaiting final verification from LoginServer", getSUID())); - - ValidateAccountMessage vcm(m_suid, 0, m_featureBitsSubscription); - ConnectionServer::sendToCentralProcess(vcm); - } - - m_hasRequestedCharacterCreate = true; - } - } - } - else if(m.isType("ClientRandomNameRequest")) - { - ClientRandomNameRequest clientRandomName(ri); - - RandomNameRequest randomNameRequest(m_suid, clientRandomName.getCreatureTemplate()); - ConnectionServer::sendToCentralProcess(randomNameRequest); - LOG("TraceCharacterCreation", ("%d requested a random name. Request sent to CentralServer", getSUID())); - } - else if(m.isType("ClientVerifyAndLockNameRequest")) - { - ClientVerifyAndLockNameRequest clientVerifyAndLockNameRequest(ri); - - VerifyAndLockNameRequest verifyAndLockNameRequest(m_suid, NetworkId::cms_invalid, clientVerifyAndLockNameRequest.getTemplateName(), clientVerifyAndLockNameRequest.getCharacterName(), m_featureBitsGame); - ConnectionServer::sendToCentralProcess(verifyAndLockNameRequest); - LOG("TraceCharacterCreation", ("%d requested a verify and lock of name: %s. Request sent to CentralServer", getSUID(), Unicode::wideToNarrow(verifyAndLockNameRequest.getCharacterName()).c_str())); - } - else if(m.isType("LagRequest")) - { - /* - handleLagRequest(); - */ - } - } - catch(const Archive::ReadException & readException) - { - WARNING(true, ("Archive read error (%s) from client. Disconnecting client", readException.what())); - LOG("ClientDisconnect", ("Archive read error (%s) from client. Disconnecting client", readException.what())); - disconnect(); - } -} - -//----------------------------------------------------------------------- - -void ClientConnection::handleLagRequest() -{ - // client is requesting a lag ping (reliable trace) - GameNetworkMessage response("ConnectionServerLagResponse"); - send(response, true); - - if(m_hasSelectedCharacter && m_client && m_client->getGameConnection()) - { - // send to game server - GameNetworkMessage request("LagRequest"); - std::vector v; - v.push_back(m_characterId); - GameClientMessage gcm(v, true, request); - m_client->getGameConnection()->send(gcm, true); - } - else - { - // send game response immediately - GameNetworkMessage gameResponse("GameServerLagResponse"); - send(gameResponse, true); - } - -} - -//----------------------------------------------------------------------- - -/** character has selected a character and calls this function -* to associate the connection with the new client they created with that -* character. We no longer need the character map. -*/ -void ClientConnection::setClient(Client* newClient) -{ - //This fatal is here to try to catch the reconnect bug. - WARNING_STRICT_FATAL(m_client, ("Attempting to set the client on a connection that already has one. Client %s\n", getCharacterName().c_str())); - // jrandall - I've removed the fatal because it is blocking some people from getting some work - // done. I'm on a high priority fix at the moment. If this warning starts appearing, - // set a break point or something. - //DEBUG_FATAL(client, ("Attempting to set the client on a connection that already has one.\n")); - m_client = newClient; - - // todo put this in: characterMap.clear(); -} - -//----------------------------------------------------------------------- - -void ClientConnection::send(const GameNetworkMessage & message, const bool reliable) -{ - m_sendLastTimeMs = Clock::timeMs(); - - - if ( sm_outgoingBytesMap_Worktime == 0 ) - sm_outgoingBytesMap_Worktime = m_sendLastTimeMs; - else if ( (m_sendLastTimeMs - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds - { - sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; - std::map< std::string, uint32 >::iterator iter; - for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) - { - iter->second = 0; - } - sm_outgoingBytesMap_Worktime = m_sendLastTimeMs; - } - sm_outgoingBytesMap_Working[ message.getCmdName() ] += message.getByteStream().getSize(); - - - ServerConnection::send(message, reliable); -} - -//----------------------------------------------------------------------- - -std::map< std::string, uint32 >& ClientConnection::getPacketBytesPerMinStats() -{ - uint32 now = Clock::timeMs(); - if ( sm_outgoingBytesMap_Worktime == 0 ) - sm_outgoingBytesMap_Worktime = now; - else if ( (now - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds - { - sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; - std::map< std::string, uint32 >::iterator iter; - for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) - { - iter->second = 0; - } - sm_outgoingBytesMap_Worktime = now; - } - - return sm_outgoingBytesMap_Stats; -} - -//----------------------------------------------------------------------- - -void ClientConnection::handleChatEnterRoomValidationResponse(unsigned int sequence, unsigned int result) -{ - std::map::iterator iterFind = m_pendingChatEnterRoomRequests.find(sequence); - if (iterFind != m_pendingChatEnterRoomRequests.end()) - { - if (result == CHATRESULT_SUCCESS) - { - if (m_client && m_client->getChatConnection()) - { - // game server says it's ok to enter the chat room, - // so forward the request on to the chat server - m_client->getChatConnection()->send(*(iterFind->second), true); - } - else - { - // send back response to client saying chat server not available - - // the client only cares about sequence and result when it's a failure - ChatOnEnteredRoom fail(sequence, SWG_CHAT_ERR_CHAT_SERVER_UNAVAILABLE, 0, ChatAvatarId()); - send(fail, true); - } - } - else - { - // send back response to client saying game server denied enter room request - - // the client only cares about sequence and result when it's a failure - ChatOnEnteredRoom fail(sequence, result, 0, ChatAvatarId()); - send(fail, true); - } - - delete iterFind->second; - m_pendingChatEnterRoomRequests.erase(iterFind); - } -} - -//----------------------------------------------------------------------- - -void ClientConnection::handleChatQueryRoomValidationResponse(unsigned int sequence, bool success) -{ - std::map::iterator iterFind = m_pendingChatQueryRoomRequests.find(sequence); - if (iterFind != m_pendingChatQueryRoomRequests.end()) - { - if (success) - { - if (m_client && m_client->getChatConnection()) - { - // game server says it's ok to query the chat room, - // so forward the request on to the chat server - m_client->getChatConnection()->send(*(iterFind->second), true); - } - } - - delete iterFind->second; - m_pendingChatQueryRoomRequests.erase(iterFind); - } -} - -//----------------------------------------------------------------------- - -void ClientConnection::sendByteStream(const Archive::ByteStream& bs, bool reliable) -{ - Connection::send(bs, reliable); -} - -//----------------------------------------------------------------------- - -/** - * Send the client to an arbitratry game server based on the current scene - */ -const bool ClientConnection::sendToGameServer() -{ - GameConnection * c = const_cast(ConnectionServer::getGameConnection(m_targetScene)); - return sendToGameServer(c); -} - -// ---------------------------------------------------------------------- - -/** - * Send the client to a particular game server, sepcified by process id. - */ - -const bool ClientConnection::sendToGameServer(uint32 gameServerId) -{ - GameConnection * c = const_cast(ConnectionServer::getGameConnection(gameServerId)); - return sendToGameServer(c); -} - -// ---------------------------------------------------------------------- - -bool ClientConnection::sendToGameServer(GameConnection *c) -{ - bool result = false; - - if(c && m_hasSelectedCharacter && m_hasBeenValidated) - { - //create a new client - ConnectionServer::addNewClient(this, - m_characterId, - c, - m_targetScene, - m_sendToStarport); - - LoggedInMessage m(m_suid); - ConnectionServer::sendToCentralProcess(m); - result = true; - m_hasBeenSentToGameServer = true; - } - return result; -} - -//----------------------------------------------------------------------- - -/** - * Called when DBProcess responds to our ValidateCharacterForLoginMessage. - * Now we know whether the character is valid and where in the world it - * is located. - */ -void ClientConnection::onCharacterValidated(bool isValid, const NetworkId &character, const std::string &characterName, const NetworkId &container, const std::string &scene, const Vector &coordinates) -{ - if (!m_validatingCharacter) - { - LOG("TraceCharacterSelection", ("%d received a validation response, but is not in the process of validation", getSUID())); - DEBUG_REPORT_LOG(true,("Got unexpected onCharacterValidated() for account %lu.\n",getSUID())); - return; - } - m_validatingCharacter=false; - - if (isValid) - { - - LOG("TraceCharacterSelection", ("%d received a validation response. The character (%s: %s) at (%s,%f,%f,%f,%s) selected is valid", getSUID(), character.getValueString().c_str(), characterName.c_str(), scene.c_str(), coordinates.x, coordinates.y, coordinates.z, container.getValueString().c_str())); - LOG("CustomerService", ("Login:%s received a validation response. The character (%s: %s) at (%s,%f,%f,%f,%s) selected is valid", describeAccount(this).c_str(), character.getValueString().c_str(), characterName.c_str(), scene.c_str(), coordinates.x, coordinates.y, coordinates.z, container.getValueString().c_str())); - m_targetScene = scene; - m_targetCoordinates = coordinates; - m_characterId = character; - m_containerId = container; - m_characterName = characterName; - - m_hasSelectedCharacter = true; - - - - // If they don't have access to mustafar but are on the planet, move them to a safe spot - uint32 features = getGameFeatures(); - if ( (strncmp(scene.c_str(), "mustafar", strlen("mustafar")) == 0 ) && - ( (features & ClientGameFeature::TrialsOfObiwanRetail) == 0 ) ) - { - // mos eisley starport - m_sendToStarport = true; - m_targetScene = "tatooine"; - m_targetCoordinates.x = 3528; - m_targetCoordinates.y = 4; - m_targetCoordinates.z = -4804; - - // Make sure Central knows the right sceneId for the player - GenericValueTypeMessage > > const msg( - "SetSceneForPlayer", - std::make_pair( - m_characterId, - std::make_pair("tatooine", false))); - ConnectionServer::sendToCentralProcess(msg); - - - LOG("TraceCharacterSelection", ("Character didn't have Mustafar feature bit, moving to Tattoine.")); - } - - - // ask CentralServer to suggest a game server for this character - // (Central will forward the request to a Planet Server) - - RequestGameServerForLoginMessage requestmsg(getSUID(), m_characterId, m_containerId, m_targetScene, m_targetCoordinates, false); - if(ConnectionServer::getCentralConnection()) - ConnectionServer::getCentralConnection()->send(requestmsg, true); - else - { - LOG("ClientDisconnect",("Can't handle login of character %s because there is no connection to Central.\n",m_characterId.getValueString().c_str())); - ErrorMessage err("Validation Failed", "The connection to the central server is down. Please try again later."); - send(err, true); - - disconnect(); - } - } - else - { - LOG("TraceCharacterSelection", ("%d validation failed, disconnecting client", getSUID())); - ErrorMessage err("Validation Failed", "Your character was denied login by the database."); - send(err, true); - - LOG("ClientDisconnect", ("Denying login for account %u.\n",getSUID())); - disconnect(); - } -} - -//------------------------------------------------------------------------------------------ - -void ClientConnection::onValidateClient (uint32 suid, const std::string & username, bool secure, const char* id, const uint32 gameFeatures, const uint32 subscriptionFeatures, unsigned int entitlementTotalTime, unsigned int entitlementEntitledTime, unsigned int entitlementTotalTimeSinceLastLogin, unsigned int entitlementEntitledTimeSinceLastLogin, int buddyPoints) -{ - UNREF(id); - m_sessionValidated = true; - m_suid = suid; - m_accountName = username; - m_featureBitsGame = gameFeatures; - m_featureBitsSubscription = subscriptionFeatures; - m_isSecure = secure; - m_entitlementTotalTime = entitlementTotalTime; - m_entitlementEntitledTime = entitlementEntitledTime; - m_entitlementTotalTimeSinceLastLogin = entitlementTotalTimeSinceLastLogin; - m_entitlementEntitledTimeSinceLastLogin = entitlementEntitledTimeSinceLastLogin; - m_buddyPoints = buddyPoints; - - if (id) - m_sessionId = id; - - if (m_requestedSuid != 0 && suid != m_requestedSuid) - { - //verify internal, secure, is on the god list - bool loginOK=false; - if(!secure) - LOG("CustomerService",("AdminLogin: User %s (account %li) attempted to log into account %li, but was not using a SecureID token", username.c_str(),suid, m_requestedSuid)); - else - { - if (!AdminAccountManager::isInternalIp(getRemoteAddress())) - LOG("CustomerService",("AdminLogin: User %s (account %li) attempted to log into account %li, but was not logging in from an internal IP", username.c_str(),suid, m_requestedSuid)); - else - { - int adminLevel=0; - if (!AdminAccountManager::isAdminAccount(Unicode::toLower(username), adminLevel) || adminLevel < 10) - LOG("CustomerService",("AdminLogin: User %s (account %li) attempted to log into account %li, but did not have sufficient permissions", username.c_str(),suid, m_requestedSuid)); - else - { - LOG("CustomerService",("AdminLogin: User %s (account %li) logged into account %li", username.c_str(),m_suid,m_requestedSuid)); - DEBUG_REPORT_LOG(true,("AdminLogin: User %s (account %li) logged into account %li\n", username.c_str(),m_suid,m_requestedSuid)); - m_suid = m_requestedSuid; - m_usingAdminLogin = true; - loginOK=true; - } - } - } - if (!loginOK) - { - disconnect(); - return; - } - } - - m_featureBitsGame &= ~ConfigConnectionServer::getDisabledFeatureBits(); - - //Configoption to enable JTL features for beta players so that our code can pretend everything uses the JTL Retail bit - if (ConfigConnectionServer::getSetJtlRetailIfBetaIsSet()) - { - if (ClientGameFeature::SpaceExpansionBeta & m_featureBitsGame) - { - m_featureBitsGame |= ClientGameFeature::SpaceExpansionRetail; - } - } - - //Configoption to enable Obiwan features for beta players so that our code can pretend everything uses the Obiwan Retail bit - if (ConfigConnectionServer::getSetTrialsOfObiwanRetailIfBetaIsSet()) - { - if (ClientGameFeature::TrialsOfObiwanBeta & m_featureBitsGame) - { - //-- add retail bit only if player does not have the preorder bit - if ((m_featureBitsGame & ClientGameFeature::TrialsOfObiwanPreorder) == 0) - m_featureBitsGame |= ClientGameFeature::TrialsOfObiwanRetail; - } - else - { - // Clear bits from players who might have them for real, but aren't in the beta - m_featureBitsGame &= ~ClientGameFeature::TrialsOfObiwanRetail; - m_featureBitsGame &= ~ClientGameFeature::TrialsOfObiwanPreorder; - } - } - - //-- Obiwan Preorders get the Retail bit as well... All rewards etc... - if (ClientGameFeature::TrialsOfObiwanPreorder & m_featureBitsGame) - { - m_featureBitsGame |= ClientGameFeature::TrialsOfObiwanRetail; - } - - // Restrictions for "new free trial" account - if ( ((m_featureBitsSubscription & ClientSubscriptionFeature::FreeTrial2) != 0) - && ((m_featureBitsSubscription & ClientSubscriptionFeature::Base) == 0)) - { - // "new free trial" account don't have access to RoW until they convert - m_featureBitsGame &= ~ClientGameFeature::Episode3ExpansionRetail; - m_featureBitsGame &= ~ClientGameFeature::Episode3PreorderDownload; - - // ClientGameFeature::FreeTrial2 indicates this is a converted "new free trial" - // account, and since this account hasn't converted yet, we remove this bit - m_featureBitsGame &= ~ClientGameFeature::FreeTrial2; - } - - // Clear feature bits that only apply if the account is paying (i.e. the sub base bit is set) - if ((m_featureBitsSubscription & ClientSubscriptionFeature::Base) == 0) - { - m_featureBitsGame &= ~ClientGameFeature::HousePackupReward; - m_featureBitsGame &= ~ClientGameFeature::BuddyProgramReward; - } - - //hack to prevent non-jtl users from using jtl assets. In this hack, clients who didn't patch through jtl patcher will send us information requesting we clear their jtl bit since they are supposed to go through the jtl patcher. We can remove this hack once the launch pad takes care of this for us. - m_featureBitsGame &= ~m_gameBitsToClear; - //end hack - - ValidateAccountMessage vcm(m_suid, 0, m_featureBitsSubscription); - ConnectionServer::sendToCentralProcess(vcm); - ConnectionServer::addConnectedClient(m_suid, this); - - uint32 const requiredSubscriptionBits = ConfigConnectionServer::getRequiredSubscriptionBits(); - if (requiredSubscriptionBits != 0) - { - if ((subscriptionFeatures & requiredSubscriptionBits) != requiredSubscriptionBits) - { - LOG("ClientDisconnect", ("Suid %d (%s) by session denial reason 'Invalid Subscription Bits'.", suid, username.c_str())); - LOG("CustomerService", ("Login: %s by session denial reason 'Invalid Subscription Bits'.", describeAccount(this).c_str())); - disconnect(); - return; - } - } - - uint32 const requiredGameBits = ConfigConnectionServer::getRequiredGameBits(); - if (requiredGameBits != 0) - { - if ((gameFeatures & requiredGameBits) != requiredGameBits) - { - LOG("ClientDisconnect", ("Suid %d (%s) by session denial reason 'Invalid Game Bits'.", suid, username.c_str())); - LOG("CustomerService", ("Login: %s by session denial reason 'Invalid Game Bits'.", describeAccount(this).c_str())); - disconnect(); - return; - } - } - - // tell client the server-side game and subscription feature bits and which ConnectionServer we are and the current server Epoch time - GenericValueTypeMessage, std::pair > > const msgFeatureBits("AccountFeatureBits", std::make_pair(std::make_pair(gameFeatures, subscriptionFeatures), std::make_pair(ConfigConnectionServer::getConnectionServerNumber(), static_cast(::time(NULL))))); - send(msgFeatureBits, true); - - std::string const gameFeaturesDescription = ClientGameFeature::getDescription(gameFeatures); - std::string const subscriptionFeaturesDescription = ClientSubscriptionFeature::getDescription(subscriptionFeatures); - - LOG("CustomerService", ("Login:%s at IP: %s:%hu has connected with game code 0x%x (%s) and sub code 0x%x (%s) (entitlement total: %u/%u, since last login: %u/%u)", describeAccount(this).c_str(), getRemoteAddress().c_str(), getRemotePort(), gameFeatures, gameFeaturesDescription.c_str(), subscriptionFeatures, subscriptionFeaturesDescription.c_str(), m_entitlementEntitledTime, m_entitlementTotalTime, m_entitlementEntitledTimeSinceLastLogin, m_entitlementTotalTimeSinceLastLogin)); - - // ask CentralServer to tell all other ConnectionServers on this galaxy to drop duplicate connections for this account - // and ask CentralServer (via LoginServer) to tell all ConnectionServers on other galaxies to drop duplicate connections for this account - if (!m_usingAdminLogin && !m_isSecure) - { - GenericValueTypeMessage > const dropDuplicateConnections("ConnSrvDropDupeConns", std::make_pair(m_suid, m_sessionId)); - ConnectionServer::sendToCentralProcess(dropDuplicateConnections); - } -} - -//----------------------------------------------------------------------- - -std::string ClientConnection::describeAccount(const ClientConnection * c) -{ - std::string result = ""; - if(c) - { - char idbuf[512] = {"\0"}; - const std::string & sessionId = c->getSessionId(); - if (sessionId.empty()) - { - snprintf(idbuf, sizeof(idbuf), " (%lu)", c->m_suid); - } - else - { - snprintf(idbuf, sizeof(idbuf), " (%lu, %s)", c->m_suid, sessionId.c_str()); - } - - result = c->m_accountName; - result += idbuf; - } - return result; -} - -// ---------------------------------------------------------------------- - -std::vector > const & ClientConnection::getConsumedRewardEvents() const -{ - return m_consumedRewardEvents; -} - -// ---------------------------------------------------------------------- - -std::vector > const & ClientConnection::getClaimedRewardItems() const -{ - return m_claimedRewardItems; -} - -// ---------------------------------------------------------------------- - -bool ClientConnection::isUsingAdminLogin() const -{ - return m_usingAdminLogin; -} - -// ---------------------------------------------------------------------- - -int ClientConnection::getBuddyPoints() const -{ - return m_buddyPoints; -} - -// ====================================================================== +// ClientConnection.cpp +// copyright 2001 Verant Interactive + +//----------------------------------------------------------------------- + +#include "FirstConnectionServer.h" +#include "ClientConnection.h" + +#include "Archive/ByteStream.h" +#include "ChatServerConnection.h" +#include "CustomerServiceConnection.h" +#include "ConfigConnectionServer.h" +#include "ConnectionServer.h" +#include "GameConnection.h" +#include "SessionApiClient.h" +#include "UnicodeUtils.h" +#include "serverKeyShare/KeyShare.h" +#include "serverNetworkMessages/CentralConnectionServerMessages.h" +#include "serverNetworkMessages/ChatDisconnectAvatar.h" +#include "serverNetworkMessages/GameConnectionServerMessages.h" +#include "serverNetworkMessages/RandomName.h" +#include "serverNetworkMessages/RequestGameServerForLoginMessage.h" +#include "serverNetworkMessages/ValidateAccountMessage.h" +#include "serverNetworkMessages/ValidateCharacterForLoginMessage.h" +#include "serverNetworkMessages/VerifyAndLockName.h" +#include "serverUtility/AdminAccountManager.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/Crc.h" +#include "sharedGame/PlatformFeatureBits.h" +#include "sharedLog/Log.h" +#include "sharedNetwork/Connection.h" +#include "sharedNetworkMessages/ClientCentralMessages.h" +#include "sharedNetworkMessages/ClientPermissionsMessage.h" +#include "sharedNetworkMessages/AppendCommentMessage.h" +#include "sharedNetworkMessages/CancelTicketMessage.h" +#include "sharedNetworkMessages/ChatEnterRoom.h" +#include "sharedNetworkMessages/ChatEnterRoomById.h" +#include "sharedNetworkMessages/ChatEnum.h" +#include "sharedNetworkMessages/ChatOnEnteredRoom.h" +#include "sharedNetworkMessages/ChatPersistentMessageToServer.h" +#include "sharedNetworkMessages/ChatQueryRoom.h" +#include "sharedNetworkMessages/ConnectPlayerMessage.h" +#include "sharedNetworkMessages/CreateTicketMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/GetTicketsMessage.h" +#include "sharedNetworkMessages/NewTicketActivityMessage.h" +#include "sharedNetworkMessages/ErrorMessage.h" +#include "sharedNetworkMessages/HeartBeat.h" +#include "Session/LoginAPI/Client.h" +#include "UdpLibrary.h" + +#include + +//----------------------------------------------------------------------- + +namespace ClientConnectionNamespace +{ + unsigned long gs_receiveDelayMaxMs = 16384; +} + +using namespace ClientConnectionNamespace; + + + + +//----------------------------------------------------------------------- + + +std::map< std::string, uint32 > ClientConnection::sm_outgoingBytesMap_Working; // working stats that will rotate after 1 minute +std::map< std::string, uint32 > ClientConnection::sm_outgoingBytesMap_Stats; // computed stats from the last minute +uint32 ClientConnection::sm_outgoingBytesMap_Worktime = 0 ; // time we started filling in the working map + + + +//----------------------------------------------------------------------- + +ClientConnection::ClientConnection(UdpConnectionMT * u, TcpClient * t) : +ServerConnection(u, t), +m_accountName(""), +m_canCreateRegularCharacter(false), +m_canCreateJediCharacter(false), +m_hasRequestedCharacterCreate(false), +m_hasCreatedCharacter(false), +m_pendingCharacterCreate(NULL), +m_canSkipTutorial(false), +m_characterId(NetworkId::cms_invalid), +m_characterName(), +m_startPlayTime(0), +m_lastActiveTime(0), +m_activePlayTimeDuration(0), +m_client(0), +m_containerId(NetworkId::cms_invalid), +m_featureBitsGame(0), +m_featureBitsSubscription(0), +m_hasBeenSentToGameServer(false), +m_hasBeenValidated(false), +m_hasSelectedCharacter(false), +m_isSecure(false), +m_isAdminAccount(false), +m_hasCSLoggedAccountFeatureIds(false), +m_suid(0), +m_requestedSuid(0), +m_usingAdminLogin(false), +m_targetCoordinates(), +m_targetScene(""), +m_validatingCharacter(false), +m_receiveHistoryBytes(0), +m_receiveHistoryPackets(0), +m_receiveHistoryMs(0), +m_receiveLastTimeMs(0), +m_sendLastTimeMs(0), +m_sessionId(""), +m_sessionValidated(false), +m_connectionServerLag(0), +m_gameServerLag(0), +m_countSpamLimitResetTime(0), +m_entitlementTotalTime(0), +m_entitlementEntitledTime(0), +m_entitlementTotalTimeSinceLastLogin(0), +m_entitlementEntitledTimeSinceLastLogin(0), +m_buddyPoints(0), +m_sendToStarport(false), +m_pendingChatEnterRoomRequests(), +m_pendingChatQueryRoomRequests() +{ + static const std::string loginTrace("TRACE_LOGIN"); + LOG(loginTrace, ("new ClientConnection")); + + setNoDataTimeout(600000); +} + +//----------------------------------------------------------------------- + +ClientConnection::~ClientConnection() +{ + bool hasBeenKicked = false; + + if (ConnectionServer::getClientConnection(m_suid) == this) + { + ConnectionServer::removeConnectedCharacter(m_suid); + } + if (m_client) + { + hasBeenKicked = m_client->hasBeenKicked(); + delete m_client; + m_client = NULL; + } + + // tell Session to stop recording play time for the character + if (m_hasBeenValidated && m_sessionValidated && ConnectionServer::getSessionApiClient() && (m_lastActiveTime > 0) && ConfigConnectionServer::getSessionRecordPlayTime()) + { + LOG("CustomerService", ("Login:%s calling SessionStopPlay() for %s/%s/%s (%s). Active play time: %s", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str(), this->getCurrentActivePlayTimeDuration().c_str())); + + // log total active play time for the session to the balance log + LOG("GameBalance", ("balancelog:%s calling SessionStopPlay() for %s/%s/%s (%s). Active play time: %s", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str(), this->getActivePlayTimeDuration().c_str())); + + ConnectionServer::getSessionApiClient()->stopPlay(*this); + } + + if (ConnectionServer::getSessionApiClient()) + { + ConnectionServer::getSessionApiClient()->dropClient(this, hasBeenKicked); + } + + std::map::const_iterator iter; + for (iter = m_pendingChatEnterRoomRequests.begin(); iter != m_pendingChatEnterRoomRequests.end(); ++iter) + { + delete iter->second; + } + m_pendingChatEnterRoomRequests.clear(); + + for (iter = m_pendingChatQueryRoomRequests.begin(); iter != m_pendingChatQueryRoomRequests.end(); ++iter) + { + delete iter->second; + } + m_pendingChatQueryRoomRequests.clear(); + + delete m_pendingCharacterCreate; + m_pendingCharacterCreate = NULL; +} + + +//----------------------------------------------------------------------- + +const NetworkId & ClientConnection::getCharacterId() const +{ + return m_characterId; +} + +//----------------------------------------------------------------------- + +const std::string & ClientConnection::getCharacterName() const +{ + return m_characterName; +} + +//----------------------------------------------------------------------- + +std::string ClientConnection::getPlayTimeDuration() const +{ + int playTimeDuration = 0; + + if (m_startPlayTime > 0) + playTimeDuration = static_cast(::time(NULL) - m_startPlayTime); + + return CalendarTime::convertSecondsToHMS(static_cast(playTimeDuration)); +} + +//----------------------------------------------------------------------- + +std::string ClientConnection::getActivePlayTimeDuration() const +{ + int activePlayTimeDuration = static_cast(m_activePlayTimeDuration); + + if (m_lastActiveTime > 0) + activePlayTimeDuration += static_cast(::time(NULL) - m_lastActiveTime); + + return CalendarTime::convertSecondsToHMS(static_cast(activePlayTimeDuration)); +} + +//----------------------------------------------------------------------- + +std::string ClientConnection::getCurrentActivePlayTimeDuration() const +{ + int activePlayTimeDuration = 0; + + if (m_lastActiveTime > 0) + activePlayTimeDuration = static_cast(::time(NULL) - m_lastActiveTime); + + return CalendarTime::convertSecondsToHMS(static_cast(activePlayTimeDuration)); +} + +//----------------------------------------------------------------------- + +void ClientConnection::sendPlayTimeInfoToGameServer() const +{ + if (m_client && m_client->getGameConnection()) + { + // update the game server with play time info + GenericValueTypeMessage > > const msgPlayTimeInfo( + "UpdateSessionPlayTimeInfo", + std::make_pair(static_cast(m_startPlayTime), + std::make_pair(static_cast(m_lastActiveTime), m_activePlayTimeDuration) + ) + ); + + std::vector v; + v.push_back(m_client->getNetworkId()); + GameClientMessage const gcm(v, true, msgPlayTimeInfo); + m_client->getGameConnection()->send(gcm, true); + } +} + +// ---------------------------------------------------------------------- + +void ClientConnection::handleSelectCharacterMessage(const SelectCharacter& msg) +{ + //Only accept this message from clients who have been validated and + //haven't already selected. + if (m_hasSelectedCharacter || m_validatingCharacter || !m_hasBeenValidated || !m_sessionValidated) + { + if(m_hasSelectedCharacter) + { + LOG("TraceCharacterSelection", ("%d cannot select a character because the client has already selected a character", getSUID())); + } + if(m_validatingCharacter) + { + LOG("TraceCharacterSelection", ("%d cannot select a character because the client has not yet received validation", getSUID())); + } + if(!m_hasBeenValidated) + { + LOG("TraceCharacterSelection", ("%d cannot select a character because the client has not been validated", getSUID())); + } + if (!m_sessionValidated) + { + LOG("TraceCharacterSelection", ("%d cannot select a character because the client has not been session validated", getSUID())); + } + + return; + } + + m_validatingCharacter = true; + + // The client is picking a character from the list the Login Server gave him. + // But we don't trust him not to cheat, so we double-check that he really + // owns the character he selected. + + ValidateCharacterForLoginMessage vclm(getSUID(), msg.getId()); + ConnectionServer::sendToCentralProcess(vclm); + LOG("TraceCharacterSelection", ("%d selected %s for login. Sending a validation request to CentralServer to verify this client can use this character", getSUID(), msg.getId().getValueString().c_str())); + +} + +// ---------------------------------------------------------------------- + +/** + * We got a message telling us what game server to use for the player (who + * is in the process of logging in). + * Connect the player with the game server. + */ +void ClientConnection::handleGameServerForLoginMessage(uint32 serverId) +{ + DEBUG_WARNING(serverId==0,("Got handleGameServerForLoginMessage with serverId=0.\n")); + IGNORE_RETURN( sendToGameServer(serverId) ); +} + +//---------------------------------------------------------------------- + +/** + * Examine the ID the client sends us. If it looks OK, send it to Central + * to be validated. Central will reply with a list of permissions. + * @see onIdValidated + */ +void ClientConnection::handleClientIdMessage(const ClientIdMsg& msg) +{ + //Only check clients that have not been validated. + if (m_hasBeenValidated) + return; + + DEBUG_FATAL(m_hasSelectedCharacter, ("Trying to validate a client who already has a character selected.\n")); + bool result = false; + char sessionId[apiSessionIdWidth]; + + m_gameBitsToClear = msg.getGameBitsToClear(); + + if(msg.getTokenSize() > 0) + { + Archive::ByteStream t(msg.getToken(), msg.getTokenSize()); + Archive::ReadIterator ri(t); + KeyShare::Token token(ri); + + if (!ConfigConnectionServer::getValidateStationKey()) + { + // get SUID from token + result = ConnectionServer::decryptToken(token, m_suid, m_isSecure, m_accountName); + } + else + { + result = ConnectionServer::decryptToken(token, sessionId, m_requestedSuid); + } + + static const std::string loginTrace("TRACE_LOGIN"); + LOG(loginTrace, ("ClientConnection SUID = %d", m_suid)); + + } + if (result) + { + //check for duplicate login + ClientConnection * oldConnection = ConnectionServer::getClientConnection(m_suid); + if (oldConnection) + { + //There is already someone connected to this cluster with this suid. + LOG("Network", ("SUID %d already logged in, disconnecting client.\n", m_suid)); + + ConnectionServer::dropClient(oldConnection, "Already Connected"); + + disconnect(); + return; + } + + // verify version + if (ConfigConnectionServer::getValidateClientVersion() && msg.getVersion() != GameNetworkMessage::NetworkVersionId) + { + std::string strSessionId(sessionId, apiSessionIdWidth); + strSessionId += '\0'; + + const int bufferSize = 255 + apiSessionIdWidth; + char * buffer = new char[bufferSize]; + snprintf(buffer, bufferSize-1, "network version mismatch: got (ip=[%s], sessionId=[%s], version=[%s]), required (version=[%s])", getRemoteAddress().c_str(), strSessionId.c_str(), msg.getVersion().c_str(), GameNetworkMessage::NetworkVersionId.c_str()); + buffer[bufferSize-1] = '\0'; + + ConnectionServer::dropClient(this, std::string(buffer)); + disconnect(); + + delete[] buffer; + + return; + } + + if (ConfigConnectionServer::getValidateStationKey()) + { + SessionApiClient * session = ConnectionServer::getSessionApiClient(); + NOT_NULL(session); + if(session) + { + session->validateClient(this, sessionId); + } + else + { + ConnectionServer::dropClient(this, "SessionApiClient is not available!"); + disconnect(); + } + } + else + { + m_suid = atoi(m_accountName.c_str()); + if (m_suid == 0) + { + std::hash h; + m_suid = h(m_accountName.c_str()); + } + onValidateClient(m_suid, m_accountName, m_isSecure, NULL, ConfigConnectionServer::getDefaultGameFeatures(), ConfigConnectionServer::getDefaultSubscriptionFeatures(), 0, 0, 0, 0, ConfigConnectionServer::getFakeBuddyPoints()); + } + } + else + { + // They sent us a token that was no good -- either a hack attempt, or + // possibly it was just too old. + LOG("ClientDisconnect", ("SUID %d passed a bad token to the connections erver. Disconnecting.", m_suid)); + disconnect(); + } +} + +//----------------------------------------------------------------------- + +void ClientConnection::onIdValidated(bool canLogin, bool canCreateRegularCharacter, bool canCreateJediCharacter, bool canSkipTutorial, std::vector > const & consumedRewardEvents, std::vector > const & claimedRewardItems) +{ + //@todo start session with station. + //@todo add more permissions to this message as needed. + + // resume character creation + if (m_pendingCharacterCreate) + { + if (!m_pendingCharacterCreate->getUseNewbieTutorial() && !canSkipTutorial) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to skip the tutorial", getSUID())); + // This is probably a hack attempt, because the Client was already told they couldn't skip the tutorial + LOG("ClientDisconnect", ("Disconnecting %u because they tried to skip the tutorial without permission.\n",getSUID())); + disconnect(); + } + else if (m_pendingCharacterCreate->getJedi() && !canCreateJediCharacter) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The request character type was Jedi, but this client cannot create a Jedi character", getSUID())); + // This is probably a hack attempt, because the Client was already told they couldn't create a character + LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a Jedi character without permission.\n",getSUID())); + disconnect(); + } + else if (!m_pendingCharacterCreate->getJedi() && !canCreateRegularCharacter) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to create any characters", getSUID())); + // This is probably a hack attempt, because the Client was already told they couldn't create a character + LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a regular character without permission.\n",getSUID())); + disconnect(); + } + else + { + ConnectionServer::sendToCentralProcess(*m_pendingCharacterCreate); + LOG("TraceCharacterCreation", ("%d character creation request sent to CentralServer", getSUID())); + + m_hasRequestedCharacterCreate = true; + } + + delete m_pendingCharacterCreate; + m_pendingCharacterCreate = NULL; + + return; + } + + // Save lists of claimed rewards, which won't be used again until later in the login sequence + m_consumedRewardEvents = consumedRewardEvents; + m_claimedRewardItems = claimedRewardItems; + + + int level=0; + if (AdminAccountManager::isAdminAccount(Unicode::toLower(getAccountName()),level) && (level !=0)) // Note: not checking IP, so that owners of god accounts can create characters to play from home without having to erase the characters they use for work + { + canLogin = true; + canCreateRegularCharacter = true; + canSkipTutorial = true; + m_isAdminAccount = true; + } + + ClientPermissionsMessage c(canLogin, canCreateRegularCharacter, canCreateJediCharacter, canSkipTutorial); + send(c, true); + + DEBUG_REPORT_LOG(true,("Permissions for %lu:\n",getSUID())); + DEBUG_REPORT_LOG(canLogin,("\tcanLogin\n")); + DEBUG_REPORT_LOG(canCreateRegularCharacter,("\tcanCreateRegularCharacter\n")); + DEBUG_REPORT_LOG(canCreateJediCharacter,("\tcanCreateJediCharacter\n")); + DEBUG_REPORT_LOG(canSkipTutorial,("\tcanSkipTutorial\n")); + DEBUG_REPORT_LOG(!(canLogin || canCreateRegularCharacter || canCreateJediCharacter || canSkipTutorial),("\tnone\n")); + + if (canLogin) + { + m_hasBeenValidated = true; + m_canCreateRegularCharacter = canCreateRegularCharacter; + m_canCreateJediCharacter = canCreateJediCharacter; + m_canSkipTutorial = canSkipTutorial; + } + else + { + LOG("TRACE_LOGIN", ("%d does not have permissions to log in", getSUID())); + LOG("ClientDisconnect", ("Client (SUID %u) does not have permissions to log in. Disconnecting.", getSUID())); + disconnect(); + } +} + +//----------------------------------------------------------------------- + +void ClientConnection::onConnectionClosed() +{ + ServerConnection::onConnectionClosed(); + static MessageConnectionCallback m("ClientConnectionClosed"); + emitMessage(m); + + LOG("TRACE_LOGIN", ("%d closed connection", getSUID())); + if (m_client) + { + if (!m_client->hasBeenKicked()) + { + LOG("CustomerService", ("Login:%s Dropped Reason: Client Dropped Connection. Character: %s (%s). Play time: %s. Active play time: %s", describeAccount(this).c_str(), getCharacterName().c_str(), getCharacterId().getValueString().c_str(), getPlayTimeDuration().c_str(), getActivePlayTimeDuration().c_str())); + } + ChatServerConnection * chatConnection = m_client->getChatConnection(); + if(chatConnection) + { + ChatDisconnectAvatar m(m_characterId); + chatConnection->send(m, true); + } + // We cannot do this here, as this connection will be deleted on + // return from this function already. + //m_client->kick(); + } +} + +//----------------------------------------------------------------------- + +void ClientConnection::onConnectionOpened() +{ + ServerConnection::onConnectionOpened(); + static MessageConnectionCallback m("ClientConnectionOpened"); + emitMessage(m); + setOverflowLimit(ConfigConnectionServer::getClientOverflowLimit()); +} + +//----------------------------------------------------------------------- + +void ClientConnection::onConnectionOverflowing (const unsigned int bytesPending) +{ + char errbuf[1024]; + snprintf(errbuf, sizeof(errbuf), "Connection overflow from server to client, %d bytes. Disconnected.", bytesPending); + std::string name("Connection overflow server->client"); + std::string desc(errbuf); + LOG("Network", ("Disconnect: Client connection overflowing. %d bytes pending", bytesPending)); + + std::vector >::const_iterator i; + for(i = m_pendingPackets.begin(); i != m_pendingPackets.end(); ++i) + { + LOG("Network", ("Overflow packets this frame: [%s] %d bytes", i->first.c_str(), i->second)); + } + +// ErrorMessage err(name, desc, false); +// send(err, true); + WARNING(true, (errbuf)); + LOG("ClientDisconnect", ("About to drop client (character) %s because the connection is overflowing\n", m_characterName.c_str())); + + snprintf(errbuf, sizeof(errbuf)-1, "Connection Overflow (bytes pending=%u)", bytesPending); + errbuf[sizeof(errbuf)-1] = '\0'; + ConnectionServer::dropClient(this, std::string(errbuf)); +} + +//----------------------------------------------------------------------- + +bool ClientConnection::checkSpamLimit(unsigned int messageSize) +{ + if (!ConfigConnectionServer::getSpamLimitEnabled()) + return true; + + unsigned long curTimeMs = Clock::timeMs(); + if (m_receiveLastTimeMs) + { + ++m_receiveHistoryPackets; + m_receiveHistoryBytes += messageSize; + m_receiveHistoryMs += curTimeMs-m_receiveLastTimeMs; + + // rescale the history information if we've exceeded the reset time; this + // must be done before the spam check below or else we may run into overflow + // issues because m_receiveHistoryMs could be pretty large if we haven't + // received anything from the client for a while + while (m_receiveHistoryMs > ConfigConnectionServer::getSpamLimitResetTimeMs()) + { + ++m_countSpamLimitResetTime; + + unsigned int resetScale = ConfigConnectionServer::getSpamLimitResetScaleFactor(); + m_receiveHistoryMs /= resetScale; + m_receiveHistoryBytes /= resetScale; + m_receiveHistoryPackets /= resetScale; + } + + // check for exceeding limits, but wait for at least + // one reset cycle so that there has been enough + // elapsed time, so we won't get a false positive + if (m_countSpamLimitResetTime) + { + if (m_receiveHistoryBytes >= m_receiveHistoryMs*ConfigConnectionServer::getSpamLimitBytesPerSec()/1000) + { + LOG("Network", ("Client %s disconnected for exceeding bytes/sec limit (bytes=%u, time=%lums)\n", getCharacterId().getValueString().c_str(), m_receiveHistoryBytes, m_receiveHistoryMs)); + return false; + } + if (m_receiveHistoryPackets >= m_receiveHistoryMs*ConfigConnectionServer::getSpamLimitPacketsPerSec()/1000) + { + LOG("Network", ("Client %s disconnected for exceeding packets/sec limit (packets=%u, time=%lums)\n", getCharacterId().getValueString().c_str(), m_receiveHistoryPackets, m_receiveHistoryMs)); + return false; + } + } + } + m_receiveLastTimeMs = curTimeMs; + return true; +} + +//----------------------------------------------------------------------- + +void ClientConnection::onReceive(const Archive::ByteStream & message) +{ + try + { + if (!checkSpamLimit(message.getSize())) + { + ConnectionServer::dropClient(this, "Spam Detected"); + return; + } + + unsigned long curTimeMs = Clock::timeMs(); + if (m_sendLastTimeMs + std::min(gs_receiveDelayMaxMs, static_cast(Clock::frameTime()*1000.0f)) < curTimeMs) + { + static HeartBeat h; + send(h, false); + } + + Archive::ReadIterator ri = message.begin(); + GameNetworkMessage m(ri); + ri = message.begin(); + + //Clients with a selected character get routed to a game server. + //@todo check for filtering out bad messages. + if (m_hasSelectedCharacter) + { + // if it is a chat message, send it directly to the chat server + if( + m.isType("ChatAddFriend") || + m.isType("ChatAddModeratorToRoom") || + m.isType("ChatBanAvatarFromRoom") || + m.isType("ChatCreateRoom") || + m.isType("ChatDeletePersistentMessage") || + m.isType("ChatDeleteAllPersistentMessages") || + m.isType("ChatDestroyRoom") || + m.isType("ChatInstantMessageToCharacter") || + m.isType("ChatInviteAvatarToRoom") || + m.isType("ChatKickAvatarFromRoom") || + m.isType("ChatRemoveAvatarFromRoom") || + m.isType("ChatRemoveFriend") || + m.isType("ChatRemoveModeratorFromRoom") || + m.isType("ChatRequestPersistentMessage") || + m.isType("ChatRequestRoomList") || + m.isType("ChatSendToRoom") || + m.isType("ChatUninviteFromRoom") || + m.isType("ChatUnbanAvatarFromRoom") || + m.isType("VerifyPlayerNameMessage") || + m.isType("VoiceChatRequestPersonalChannel") || + m.isType("VoiceChatInvite") || + m.isType("VoiceChatKick") || + m.isType("VoiceChatRequestChannelInfo") + ) + { + DEBUG_REPORT_LOG(true, ("ConnServ: ClientConnection::onReceive()\n")); + + NOT_NULL(m_client); + if(m_client) + { + static std::vector v; + v.clear(); + v.push_back(m_client->getNetworkId()); + GameClientMessage gcm(v, true, ri); + if(m_client->getChatConnection()) + { + m_client->getChatConnection()->send(gcm , true); + } + else + { + // defer chat messages until a server is back online + Archive::ByteStream bs; + m.pack(bs); + m_client->deferChatMessage(bs); + } + } + else + { + ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); + disconnect(); + } + } + // ChatEnterRoom and ChatEnterRoomById needs to go to the game server to determine + // if the character is not allowed to enter the room because of game rule restrictions; + // only if that test pass do we forward the message on to the chat server to request + // to enter the room + else if (m.isType("ChatEnterRoom") || + m.isType("ChatEnterRoomById") + ) + { + NOT_NULL(m_client); + + unsigned int sequence; + std::string roomName; + + Archive::ReadIterator cri = message.begin(); + if (m.isType("ChatEnterRoom")) + { + ChatEnterRoom const cer(cri); + sequence = cer.getSequence(); + roomName = cer.getRoomName(); + } + else + { + ChatEnterRoomById const cerbi(cri); + sequence = cerbi.getSequence(); + roomName = cerbi.getRoomName(); + } + + if(m_client && m_client->getGameConnection()) + { + if (m_pendingChatEnterRoomRequests.count(sequence) == 0) + { + GenericValueTypeMessage, unsigned int> > const cervr( + "ChatEnterRoomValidationRequest", + std::make_pair( + std::make_pair(m_client->getNetworkId(), roomName), + sequence)); + + m_client->getGameConnection()->send(cervr, true); + + // queue up request until game server responds + static std::vector v; + v.clear(); + v.push_back(m_client->getNetworkId()); + m_pendingChatEnterRoomRequests[sequence] = new GameClientMessage(v, true, ri); + } + } + else + { + // send back response to client saying game server not available + + // the client only cares about sequence and result when it's a failure + ChatOnEnteredRoom fail(sequence, SWG_CHAT_ERR_NO_GAME_SERVER, 0, ChatAvatarId()); + send(fail, true); + } + } + // ChatQueryRoom needs to go to the game server to determine if the character is + // not allowed to query the room because of game rule restrictions; only if that + // test pass do we forward the message on to the chat server for completion + else if (m.isType("ChatQueryRoom")) + { + NOT_NULL(m_client); + + Archive::ReadIterator cri = message.begin(); + ChatQueryRoom cqr(cri); + + if(m_client && m_client->getGameConnection()) + { + if (m_pendingChatQueryRoomRequests.count(cqr.getSequence()) == 0) + { + GenericValueTypeMessage, unsigned int> > const cqrvr( + "ChatQueryRoomValidationRequest", + std::make_pair( + std::make_pair(m_client->getNetworkId(), cqr.getRoomName()), + cqr.getSequence())); + + m_client->getGameConnection()->send(cqrvr, true); + + // queue up request until game server responds + static std::vector v; + v.clear(); + v.push_back(m_client->getNetworkId()); + m_pendingChatQueryRoomRequests[cqr.getSequence()] = new GameClientMessage(v, true, ri); + } + } + } + // ChatInviteGroupToRoom needs to go to the game server to get group information + else if (m.isType("ChatInviteGroupToRoom")) + { + NOT_NULL(m_client); + if(m_client) + { + if (m_client->getGameConnection()) + { + static std::vector v; + v.clear(); + v.push_back(m_client->getNetworkId()); + GameClientMessage gcm(v, true, ri); + m_client->getGameConnection()->send(gcm, true); + } + else + { + // defer chat messages until a server is back online + Archive::ByteStream bs; + m.pack(bs); + m_client->deferChatMessage(bs); + } + } + else + { + ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); + disconnect(); + } + } + // ChatPersistentMessageToServer may need to be passed off to the game server for guild or citizens messages + else if (m.isType("ChatPersistentMessageToServer")) + { + NOT_NULL(m_client); + if(m_client) + { + static std::vector v; + v.clear(); + v.push_back(m_client->getNetworkId()); + + Archive::ReadIterator cri = message.begin(); + ChatPersistentMessageToServer chat(cri); + std::string const &toName = chat.getToCharacterName().name; + if (!_stricmp(toName.c_str(), "guild") || !_strnicmp(toName.c_str(), "guild ", 6) || !_stricmp(toName.c_str(), "citizens")) + { + if (m_client->getGameConnection()) + { + GameClientMessage gcm(v, true, ri); + m_client->getGameConnection()->send(gcm, true); + } + } + else + { + if (m_client->getChatConnection()) + { + GameClientMessage gcm(v, true, ri); + m_client->getChatConnection()->send(gcm, true); + } + else + { + // defer chat messages until a server is back online + Archive::ByteStream bs; + m.pack(bs); + m_client->deferChatMessage(bs); + } + } + } + else + { + ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); + disconnect(); + } + } + // if it is a cs message, send it directly to the cs server + else if ( + m.isType("ConnectPlayerMessage") || + m.isType("DisconnectPlayerMessage") || + m.isType("CreateTicketMessage") || + m.isType("AppendCommentMessage") || + m.isType("CancelTicketMessage") || + m.isType("GetTicketsMessage") || + m.isType("GetCommentsMessage") || + m.isType("SearchKnowledgeBaseMessage") || + m.isType("GetArticleMessage") || + m.isType("RequestCategoriesMessage") || + m.isType("NewTicketActivityMessage") + ) + { + NOT_NULL(m_client); + if(m_client) + { + CustomerServiceConnection *customerServiceConnection = m_client->getCustomerServiceConnection(); + + //DEBUG_REPORT_LOG(true, ("CONSRV::CS - suid: %i\n", getSUID())); + + if (customerServiceConnection != NULL) + { + static std::vector v; + v.clear(); + v.push_back(m_client->getNetworkId()); + if (m.isType("ConnectPlayerMessage")) + { + ConnectPlayerMessage message(ri); + message.setStationId(getSUID()); + + GameClientMessage gcm(v, true, message); + customerServiceConnection->send(gcm , true); + } + else if (m.isType("CreateTicketMessage")) + { + CreateTicketMessage message(ri); + message.setStationId(getSUID()); + + GameClientMessage gcm(v, true, message); + customerServiceConnection->send(gcm , true); + } + else if (m.isType("AppendCommentMessage")) + { + AppendCommentMessage message(ri); + message.setStationId(getSUID()); + + GameClientMessage gcm(v, true, message); + customerServiceConnection->send(gcm , true); + } + else if (m.isType("CancelTicketMessage")) + { + CancelTicketMessage message(ri); + message.setStationId(getSUID()); + + GameClientMessage gcm(v, true, message); + customerServiceConnection->send(gcm , true); + } + else if (m.isType("GetTicketsMessage")) + { + GetTicketsMessage message(ri); + message.setStationId(getSUID()); + + GameClientMessage gcm(v, true, message); + customerServiceConnection->send(gcm , true); + } + else if (m.isType("NewTicketActivityMessage")) + { + NewTicketActivityMessage message(ri); + message.setStationId(getSUID()); + + GameClientMessage gcm(v, true, message); + customerServiceConnection->send(gcm , true); + } + else + { + GameClientMessage gcm(v, true, ri); + customerServiceConnection->send(gcm , true); + } + //else + //{ + // /*// defer chat messages until a server is back online + // Archive::ByteStream bs; + // m.pack(bs); + // m_client->deferChatMessage(bs); + // */ + //} + } + } + else + { + ConnectionServer::dropClient(this, "m_client is null while receiving a message!"); + disconnect(); + } + } + else if (m.isType("28afefcc187a11dc888b001")) // obfuscation for ClientInactivityMessage message + { + GenericValueTypeMessage msg(ri); + + if (m_hasBeenValidated && m_sessionValidated) + { + // client went inactive + if (msg.getValue()) + { + if (m_lastActiveTime > 0) + { + // record the amount of active time + m_activePlayTimeDuration += static_cast(::time(NULL) - m_lastActiveTime); + + // tell Session to stop recording play time for the character + if (ConnectionServer::getSessionApiClient() && ConfigConnectionServer::getSessionRecordPlayTime()) + { + LOG("CustomerService", ("Login:%s calling SessionStopPlay() for %s/%s/%s (%s). Active play time: %s", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str(), this->getCurrentActivePlayTimeDuration().c_str())); + ConnectionServer::getSessionApiClient()->stopPlay(*this); + } + + // client is no longer active; this needs to be set after the LOG() statement + // above because getCurrentActivePlayTimeDuration() uses m_lastActiveTime + m_lastActiveTime = 0; + + // update the play time info on the game server + sendPlayTimeInfoToGameServer(); + + // drop inactive character + if (ConfigConnectionServer::getDisconnectOnInactive()) + { + LOG("ClientDisconnect", ("Disconnecting %u because the player was inactive for too long.",getSUID())); + ConnectionServer::dropClient(this, "Client inactivity"); + disconnect(); + } + else if (ConfigConnectionServer::getDisconnectFreeTrialOnInactive() && ((m_featureBitsSubscription & ClientSubscriptionFeature::Base) == 0)) + { + LOG("ClientDisconnect", ("Disconnecting (free trial) %u because the player was inactive for too long.",getSUID())); + ConnectionServer::dropClient(this, "Client inactivity (free trial)"); + disconnect(); + } + } + } + // client went active + else + { + if (m_lastActiveTime == 0) + { + // record the time client went active + m_lastActiveTime = ::time(NULL); + + // tell Session to start recording play time for the character + if (ConnectionServer::getSessionApiClient() && ConfigConnectionServer::getSessionRecordPlayTime()) + { + LOG("CustomerService", ("Login:%s calling SessionStartPlay() for %s/%s/%s (%s)", ClientConnection::describeAccount(this).c_str(), this->getSessionId().c_str(), ConfigConnectionServer::getClusterName(), this->getCharacterName().c_str(), this->getCharacterId().getValueString().c_str())); + ConnectionServer::getSessionApiClient()->startPlay(*this); + } + + // update the play time info on the game server + sendPlayTimeInfoToGameServer(); + } + } + } + } + else + { + //Forward on to Game Server + DEBUG_REPORT_LOG((!m_client || !m_client->getGameConnection()), ("Warn, received game message with no game connection. This may happen for a short time after a GameServer crashes. If it continues to happen, it indicates a bug.\n")); + + if (m_client && m_client->getGameConnection()) + { + static std::vector v; + v.clear(); + v.push_back(m_client->getNetworkId()); + GameClientMessage gcm(v, true, ri); + m_client->getGameConnection()->send(gcm, true); + } + } + } + + else if(m.isType("ClientIdMsg")) + { + DEBUG_REPORT_LOG(true,("Recieved ClientIdMsg\n")); + ClientIdMsg k(ri); + + handleClientIdMessage(k); + } + else if(m.isType("SelectCharacter")) + { + SelectCharacter s(ri); + DEBUG_REPORT_LOG(true,("Recvd SelectCharacter message for %s.\n", s.getId().getValueString().c_str())); + + handleSelectCharacterMessage(s); + } + else if(m.isType("ClientCreateCharacter")) + { + if (m_hasBeenValidated && !m_hasSelectedCharacter) //lint !e774 no this doesn't always eval to true + { + ClientCreateCharacter clientCreate(ri); + DEBUG_REPORT_LOG(true,("Got ClientCreateCharacter message for %lu with name %s\n", m_suid, Unicode::wideToNarrow(clientCreate.getCharacterName()).c_str())); + LOG("TraceCharacterCreation", ("%d sent ClientCreateCharacter(charaterName=%s, templateName=%s, scaleFactor=%f, startingLocation=%s, hairTemplateName=%s, profession=%s, jedi=%d, useNewbieTutorial=%d, skillTemplate=%s, workingSkill=%s)", + getSUID(), + Unicode::wideToNarrow(clientCreate.getCharacterName()).c_str(), + clientCreate.getTemplateName().c_str(), + clientCreate.getScaleFactor(), + clientCreate.getStartingLocation().c_str(), + clientCreate.getHairTemplateName().c_str(), + clientCreate.getProfession().c_str(), + static_cast(clientCreate.getJedi()), + static_cast(clientCreate.getUseNewbieTutorial()), + clientCreate.getSkillTemplate().c_str(), + clientCreate.getWorkingSkill().c_str())); + + if (!clientCreate.getUseNewbieTutorial() && !m_canSkipTutorial) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to skip the tutorial", getSUID())); + // This is probably a hack attempt, because the Client was already told they couldn't skip the tutorial + LOG("ClientDisconnect", ("Disconnecting %u because they tried to skip the tutorial without permission.\n",getSUID())); + disconnect(); + } + else if (clientCreate.getJedi() && !m_canCreateJediCharacter) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The request character type was Jedi, but this client cannot create a Jedi character", getSUID())); + // This is probably a hack attempt, because the Client was already told they couldn't create a character + LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a Jedi character without permission.\n",getSUID())); + disconnect(); + } + else if (!clientCreate.getJedi() && !m_canCreateRegularCharacter) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The client is not allowed to create any characters", getSUID())); + // This is probably a hack attempt, because the Client was already told they couldn't create a character + LOG("ClientDisconnect", ("Disconnecting %u because they tried to create a regular character without permission.\n",getSUID())); + disconnect(); + } + else if (m_hasRequestedCharacterCreate) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The client has already requested character creation on this connection", getSUID())); + LOG("ClientDisconnect", ("Disconnecting %u because the client has already requested character creation on this connection.\n",getSUID())); + disconnect(); + } + else if (m_hasCreatedCharacter) + { + LOG("TraceCharacterCreation", ("%d failed character creation. A character has been created on this or another galaxy for this account while this connection was up", getSUID())); + LOG("ClientDisconnect", ("Disconnecting %u because a character has been created on this or another galaxy for this account while this connection was up.\n",getSUID())); + disconnect(); + } + else if (clientCreate.getCharacterName().length()==0) + { + LOG("TraceCharacterCreation", ("%d failed character creation. The character's name is empty", getSUID())); + LOG("ClientDisconnect",("Disconnecting %u because they tried to create a character with no name.\n",getSUID())); + disconnect(); + } + else + { + Unicode::String biography(clientCreate.getBiography()); + if (biography.length() > 1024) + { + IGNORE_RETURN( biography.erase(1024) ); + DEBUG_REPORT_LOG(true,("Biography shortened to 1024 characters.\n")); + } + + if (m_isAdminAccount) + { + ConnectionCreateCharacter connectionCreate( + m_suid, + clientCreate.getCharacterName(), + clientCreate.getTemplateName(), + clientCreate.getScaleFactor(), + clientCreate.getStartingLocation(), + clientCreate.getAppearanceData(), + clientCreate.getHairTemplateName(), + clientCreate.getHairAppearanceData(), + clientCreate.getProfession(), + clientCreate.getJedi(), + biography, + clientCreate.getUseNewbieTutorial(), + clientCreate.getSkillTemplate(), + clientCreate.getWorkingSkill(), + m_isAdminAccount, + false, + m_featureBitsGame); + + ConnectionServer::sendToCentralProcess(connectionCreate); + LOG("TraceCharacterCreation", ("%d character creation request sent to CentralServer", getSUID())); + } + else + { + // for regular players, do one final check with the LoginServer + // to make sure the character can be created (i.e. that character + // limits have not been exceeded) + delete m_pendingCharacterCreate; + m_pendingCharacterCreate = new ConnectionCreateCharacter( + m_suid, + clientCreate.getCharacterName(), + clientCreate.getTemplateName(), + clientCreate.getScaleFactor(), + clientCreate.getStartingLocation(), + clientCreate.getAppearanceData(), + clientCreate.getHairTemplateName(), + clientCreate.getHairAppearanceData(), + clientCreate.getProfession(), + clientCreate.getJedi(), + biography, + clientCreate.getUseNewbieTutorial(), + clientCreate.getSkillTemplate(), + clientCreate.getWorkingSkill(), + m_isAdminAccount, + false, + m_featureBitsGame); + + LOG("TraceCharacterCreation", ("%d character creation request awaiting final verification from LoginServer", getSUID())); + + ValidateAccountMessage vcm(m_suid, 0, m_featureBitsSubscription); + ConnectionServer::sendToCentralProcess(vcm); + } + + m_hasRequestedCharacterCreate = true; + } + } + } + else if(m.isType("ClientRandomNameRequest")) + { + ClientRandomNameRequest clientRandomName(ri); + + RandomNameRequest randomNameRequest(m_suid, clientRandomName.getCreatureTemplate()); + ConnectionServer::sendToCentralProcess(randomNameRequest); + LOG("TraceCharacterCreation", ("%d requested a random name. Request sent to CentralServer", getSUID())); + } + else if(m.isType("ClientVerifyAndLockNameRequest")) + { + ClientVerifyAndLockNameRequest clientVerifyAndLockNameRequest(ri); + + VerifyAndLockNameRequest verifyAndLockNameRequest(m_suid, NetworkId::cms_invalid, clientVerifyAndLockNameRequest.getTemplateName(), clientVerifyAndLockNameRequest.getCharacterName(), m_featureBitsGame); + ConnectionServer::sendToCentralProcess(verifyAndLockNameRequest); + LOG("TraceCharacterCreation", ("%d requested a verify and lock of name: %s. Request sent to CentralServer", getSUID(), Unicode::wideToNarrow(verifyAndLockNameRequest.getCharacterName()).c_str())); + } + else if(m.isType("LagRequest")) + { + /* + handleLagRequest(); + */ + } + } + catch(const Archive::ReadException & readException) + { + WARNING(true, ("Archive read error (%s) from client. Disconnecting client", readException.what())); + LOG("ClientDisconnect", ("Archive read error (%s) from client. Disconnecting client", readException.what())); + disconnect(); + } +} + +//----------------------------------------------------------------------- + +void ClientConnection::handleLagRequest() +{ + // client is requesting a lag ping (reliable trace) + GameNetworkMessage response("ConnectionServerLagResponse"); + send(response, true); + + if(m_hasSelectedCharacter && m_client && m_client->getGameConnection()) + { + // send to game server + GameNetworkMessage request("LagRequest"); + std::vector v; + v.push_back(m_characterId); + GameClientMessage gcm(v, true, request); + m_client->getGameConnection()->send(gcm, true); + } + else + { + // send game response immediately + GameNetworkMessage gameResponse("GameServerLagResponse"); + send(gameResponse, true); + } + +} + +//----------------------------------------------------------------------- + +/** character has selected a character and calls this function +* to associate the connection with the new client they created with that +* character. We no longer need the character map. +*/ +void ClientConnection::setClient(Client* newClient) +{ + //This fatal is here to try to catch the reconnect bug. + WARNING_STRICT_FATAL(m_client, ("Attempting to set the client on a connection that already has one. Client %s\n", getCharacterName().c_str())); + // jrandall - I've removed the fatal because it is blocking some people from getting some work + // done. I'm on a high priority fix at the moment. If this warning starts appearing, + // set a break point or something. + //DEBUG_FATAL(client, ("Attempting to set the client on a connection that already has one.\n")); + m_client = newClient; + + // todo put this in: characterMap.clear(); +} + +//----------------------------------------------------------------------- + +void ClientConnection::send(const GameNetworkMessage & message, const bool reliable) +{ + m_sendLastTimeMs = Clock::timeMs(); + + + if ( sm_outgoingBytesMap_Worktime == 0 ) + sm_outgoingBytesMap_Worktime = m_sendLastTimeMs; + else if ( (m_sendLastTimeMs - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds + { + sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; + std::map< std::string, uint32 >::iterator iter; + for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) + { + iter->second = 0; + } + sm_outgoingBytesMap_Worktime = m_sendLastTimeMs; + } + sm_outgoingBytesMap_Working[ message.getCmdName() ] += message.getByteStream().getSize(); + + + ServerConnection::send(message, reliable); +} + +//----------------------------------------------------------------------- + +std::map< std::string, uint32 >& ClientConnection::getPacketBytesPerMinStats() +{ + uint32 now = Clock::timeMs(); + if ( sm_outgoingBytesMap_Worktime == 0 ) + sm_outgoingBytesMap_Worktime = now; + else if ( (now - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds + { + sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; + std::map< std::string, uint32 >::iterator iter; + for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) + { + iter->second = 0; + } + sm_outgoingBytesMap_Worktime = now; + } + + return sm_outgoingBytesMap_Stats; +} + +//----------------------------------------------------------------------- + +void ClientConnection::handleChatEnterRoomValidationResponse(unsigned int sequence, unsigned int result) +{ + std::map::iterator iterFind = m_pendingChatEnterRoomRequests.find(sequence); + if (iterFind != m_pendingChatEnterRoomRequests.end()) + { + if (result == CHATRESULT_SUCCESS) + { + if (m_client && m_client->getChatConnection()) + { + // game server says it's ok to enter the chat room, + // so forward the request on to the chat server + m_client->getChatConnection()->send(*(iterFind->second), true); + } + else + { + // send back response to client saying chat server not available + + // the client only cares about sequence and result when it's a failure + ChatOnEnteredRoom fail(sequence, SWG_CHAT_ERR_CHAT_SERVER_UNAVAILABLE, 0, ChatAvatarId()); + send(fail, true); + } + } + else + { + // send back response to client saying game server denied enter room request + + // the client only cares about sequence and result when it's a failure + ChatOnEnteredRoom fail(sequence, result, 0, ChatAvatarId()); + send(fail, true); + } + + delete iterFind->second; + m_pendingChatEnterRoomRequests.erase(iterFind); + } +} + +//----------------------------------------------------------------------- + +void ClientConnection::handleChatQueryRoomValidationResponse(unsigned int sequence, bool success) +{ + std::map::iterator iterFind = m_pendingChatQueryRoomRequests.find(sequence); + if (iterFind != m_pendingChatQueryRoomRequests.end()) + { + if (success) + { + if (m_client && m_client->getChatConnection()) + { + // game server says it's ok to query the chat room, + // so forward the request on to the chat server + m_client->getChatConnection()->send(*(iterFind->second), true); + } + } + + delete iterFind->second; + m_pendingChatQueryRoomRequests.erase(iterFind); + } +} + +//----------------------------------------------------------------------- + +void ClientConnection::sendByteStream(const Archive::ByteStream& bs, bool reliable) +{ + Connection::send(bs, reliable); +} + +//----------------------------------------------------------------------- + +/** + * Send the client to an arbitratry game server based on the current scene + */ +const bool ClientConnection::sendToGameServer() +{ + GameConnection * c = const_cast(ConnectionServer::getGameConnection(m_targetScene)); + return sendToGameServer(c); +} + +// ---------------------------------------------------------------------- + +/** + * Send the client to a particular game server, sepcified by process id. + */ + +const bool ClientConnection::sendToGameServer(uint32 gameServerId) +{ + GameConnection * c = const_cast(ConnectionServer::getGameConnection(gameServerId)); + return sendToGameServer(c); +} + +// ---------------------------------------------------------------------- + +bool ClientConnection::sendToGameServer(GameConnection *c) +{ + bool result = false; + + if(c && m_hasSelectedCharacter && m_hasBeenValidated) + { + //create a new client + ConnectionServer::addNewClient(this, + m_characterId, + c, + m_targetScene, + m_sendToStarport); + + LoggedInMessage m(m_suid); + ConnectionServer::sendToCentralProcess(m); + result = true; + m_hasBeenSentToGameServer = true; + } + return result; +} + +//----------------------------------------------------------------------- + +/** + * Called when DBProcess responds to our ValidateCharacterForLoginMessage. + * Now we know whether the character is valid and where in the world it + * is located. + */ +void ClientConnection::onCharacterValidated(bool isValid, const NetworkId &character, const std::string &characterName, const NetworkId &container, const std::string &scene, const Vector &coordinates) +{ + if (!m_validatingCharacter) + { + LOG("TraceCharacterSelection", ("%d received a validation response, but is not in the process of validation", getSUID())); + DEBUG_REPORT_LOG(true,("Got unexpected onCharacterValidated() for account %lu.\n",getSUID())); + return; + } + m_validatingCharacter=false; + + if (isValid) + { + + LOG("TraceCharacterSelection", ("%d received a validation response. The character (%s: %s) at (%s,%f,%f,%f,%s) selected is valid", getSUID(), character.getValueString().c_str(), characterName.c_str(), scene.c_str(), coordinates.x, coordinates.y, coordinates.z, container.getValueString().c_str())); + LOG("CustomerService", ("Login:%s received a validation response. The character (%s: %s) at (%s,%f,%f,%f,%s) selected is valid", describeAccount(this).c_str(), character.getValueString().c_str(), characterName.c_str(), scene.c_str(), coordinates.x, coordinates.y, coordinates.z, container.getValueString().c_str())); + m_targetScene = scene; + m_targetCoordinates = coordinates; + m_characterId = character; + m_containerId = container; + m_characterName = characterName; + + m_hasSelectedCharacter = true; + + + + // If they don't have access to mustafar but are on the planet, move them to a safe spot + uint32 features = getGameFeatures(); + if ( (strncmp(scene.c_str(), "mustafar", strlen("mustafar")) == 0 ) && + ( (features & ClientGameFeature::TrialsOfObiwanRetail) == 0 ) ) + { + // mos eisley starport + m_sendToStarport = true; + m_targetScene = "tatooine"; + m_targetCoordinates.x = 3528; + m_targetCoordinates.y = 4; + m_targetCoordinates.z = -4804; + + // Make sure Central knows the right sceneId for the player + GenericValueTypeMessage > > const msg( + "SetSceneForPlayer", + std::make_pair( + m_characterId, + std::make_pair("tatooine", false))); + ConnectionServer::sendToCentralProcess(msg); + + + LOG("TraceCharacterSelection", ("Character didn't have Mustafar feature bit, moving to Tattoine.")); + } + + + // ask CentralServer to suggest a game server for this character + // (Central will forward the request to a Planet Server) + + RequestGameServerForLoginMessage requestmsg(getSUID(), m_characterId, m_containerId, m_targetScene, m_targetCoordinates, false); + if(ConnectionServer::getCentralConnection()) + ConnectionServer::getCentralConnection()->send(requestmsg, true); + else + { + LOG("ClientDisconnect",("Can't handle login of character %s because there is no connection to Central.\n",m_characterId.getValueString().c_str())); + ErrorMessage err("Validation Failed", "The connection to the central server is down. Please try again later."); + send(err, true); + + disconnect(); + } + } + else + { + LOG("TraceCharacterSelection", ("%d validation failed, disconnecting client", getSUID())); + ErrorMessage err("Validation Failed", "Your character was denied login by the database."); + send(err, true); + + LOG("ClientDisconnect", ("Denying login for account %u.\n",getSUID())); + disconnect(); + } +} + +//------------------------------------------------------------------------------------------ + +void ClientConnection::onValidateClient (uint32 suid, const std::string & username, bool secure, const char* id, const uint32 gameFeatures, const uint32 subscriptionFeatures, unsigned int entitlementTotalTime, unsigned int entitlementEntitledTime, unsigned int entitlementTotalTimeSinceLastLogin, unsigned int entitlementEntitledTimeSinceLastLogin, int buddyPoints) +{ + UNREF(id); + m_sessionValidated = true; + m_suid = suid; + m_accountName = username; + m_featureBitsGame = gameFeatures; + m_featureBitsSubscription = subscriptionFeatures; + m_isSecure = secure; + m_entitlementTotalTime = entitlementTotalTime; + m_entitlementEntitledTime = entitlementEntitledTime; + m_entitlementTotalTimeSinceLastLogin = entitlementTotalTimeSinceLastLogin; + m_entitlementEntitledTimeSinceLastLogin = entitlementEntitledTimeSinceLastLogin; + m_buddyPoints = buddyPoints; + + if (id) + m_sessionId = id; + + if (m_requestedSuid != 0 && suid != m_requestedSuid) + { + //verify internal, secure, is on the god list + bool loginOK=false; + if(!secure) + LOG("CustomerService",("AdminLogin: User %s (account %li) attempted to log into account %li, but was not using a SecureID token", username.c_str(),suid, m_requestedSuid)); + else + { + if (!AdminAccountManager::isInternalIp(getRemoteAddress())) + LOG("CustomerService",("AdminLogin: User %s (account %li) attempted to log into account %li, but was not logging in from an internal IP", username.c_str(),suid, m_requestedSuid)); + else + { + int adminLevel=0; + if (!AdminAccountManager::isAdminAccount(Unicode::toLower(username), adminLevel) || adminLevel < 10) + LOG("CustomerService",("AdminLogin: User %s (account %li) attempted to log into account %li, but did not have sufficient permissions", username.c_str(),suid, m_requestedSuid)); + else + { + LOG("CustomerService",("AdminLogin: User %s (account %li) logged into account %li", username.c_str(),m_suid,m_requestedSuid)); + DEBUG_REPORT_LOG(true,("AdminLogin: User %s (account %li) logged into account %li\n", username.c_str(),m_suid,m_requestedSuid)); + m_suid = m_requestedSuid; + m_usingAdminLogin = true; + loginOK=true; + } + } + } + if (!loginOK) + { + disconnect(); + return; + } + } + + m_featureBitsGame &= ~ConfigConnectionServer::getDisabledFeatureBits(); + + //Configoption to enable JTL features for beta players so that our code can pretend everything uses the JTL Retail bit + if (ConfigConnectionServer::getSetJtlRetailIfBetaIsSet()) + { + if (ClientGameFeature::SpaceExpansionBeta & m_featureBitsGame) + { + m_featureBitsGame |= ClientGameFeature::SpaceExpansionRetail; + } + } + + //Configoption to enable Obiwan features for beta players so that our code can pretend everything uses the Obiwan Retail bit + if (ConfigConnectionServer::getSetTrialsOfObiwanRetailIfBetaIsSet()) + { + if (ClientGameFeature::TrialsOfObiwanBeta & m_featureBitsGame) + { + //-- add retail bit only if player does not have the preorder bit + if ((m_featureBitsGame & ClientGameFeature::TrialsOfObiwanPreorder) == 0) + m_featureBitsGame |= ClientGameFeature::TrialsOfObiwanRetail; + } + else + { + // Clear bits from players who might have them for real, but aren't in the beta + m_featureBitsGame &= ~ClientGameFeature::TrialsOfObiwanRetail; + m_featureBitsGame &= ~ClientGameFeature::TrialsOfObiwanPreorder; + } + } + + //-- Obiwan Preorders get the Retail bit as well... All rewards etc... + if (ClientGameFeature::TrialsOfObiwanPreorder & m_featureBitsGame) + { + m_featureBitsGame |= ClientGameFeature::TrialsOfObiwanRetail; + } + + // Restrictions for "new free trial" account + if ( ((m_featureBitsSubscription & ClientSubscriptionFeature::FreeTrial2) != 0) + && ((m_featureBitsSubscription & ClientSubscriptionFeature::Base) == 0)) + { + // "new free trial" account don't have access to RoW until they convert + m_featureBitsGame &= ~ClientGameFeature::Episode3ExpansionRetail; + m_featureBitsGame &= ~ClientGameFeature::Episode3PreorderDownload; + + // ClientGameFeature::FreeTrial2 indicates this is a converted "new free trial" + // account, and since this account hasn't converted yet, we remove this bit + m_featureBitsGame &= ~ClientGameFeature::FreeTrial2; + } + + // Clear feature bits that only apply if the account is paying (i.e. the sub base bit is set) + if ((m_featureBitsSubscription & ClientSubscriptionFeature::Base) == 0) + { + m_featureBitsGame &= ~ClientGameFeature::HousePackupReward; + m_featureBitsGame &= ~ClientGameFeature::BuddyProgramReward; + } + + //hack to prevent non-jtl users from using jtl assets. In this hack, clients who didn't patch through jtl patcher will send us information requesting we clear their jtl bit since they are supposed to go through the jtl patcher. We can remove this hack once the launch pad takes care of this for us. + m_featureBitsGame &= ~m_gameBitsToClear; + //end hack + + ValidateAccountMessage vcm(m_suid, 0, m_featureBitsSubscription); + ConnectionServer::sendToCentralProcess(vcm); + ConnectionServer::addConnectedClient(m_suid, this); + + uint32 const requiredSubscriptionBits = ConfigConnectionServer::getRequiredSubscriptionBits(); + if (requiredSubscriptionBits != 0) + { + if ((subscriptionFeatures & requiredSubscriptionBits) != requiredSubscriptionBits) + { + LOG("ClientDisconnect", ("Suid %d (%s) by session denial reason 'Invalid Subscription Bits'.", suid, username.c_str())); + LOG("CustomerService", ("Login: %s by session denial reason 'Invalid Subscription Bits'.", describeAccount(this).c_str())); + disconnect(); + return; + } + } + + uint32 const requiredGameBits = ConfigConnectionServer::getRequiredGameBits(); + if (requiredGameBits != 0) + { + if ((gameFeatures & requiredGameBits) != requiredGameBits) + { + LOG("ClientDisconnect", ("Suid %d (%s) by session denial reason 'Invalid Game Bits'.", suid, username.c_str())); + LOG("CustomerService", ("Login: %s by session denial reason 'Invalid Game Bits'.", describeAccount(this).c_str())); + disconnect(); + return; + } + } + + // tell client the server-side game and subscription feature bits and which ConnectionServer we are and the current server Epoch time + GenericValueTypeMessage, std::pair > > const msgFeatureBits("AccountFeatureBits", std::make_pair(std::make_pair(gameFeatures, subscriptionFeatures), std::make_pair(ConfigConnectionServer::getConnectionServerNumber(), static_cast(::time(NULL))))); + send(msgFeatureBits, true); + + std::string const gameFeaturesDescription = ClientGameFeature::getDescription(gameFeatures); + std::string const subscriptionFeaturesDescription = ClientSubscriptionFeature::getDescription(subscriptionFeatures); + + LOG("CustomerService", ("Login:%s at IP: %s:%hu has connected with game code 0x%x (%s) and sub code 0x%x (%s) (entitlement total: %u/%u, since last login: %u/%u)", describeAccount(this).c_str(), getRemoteAddress().c_str(), getRemotePort(), gameFeatures, gameFeaturesDescription.c_str(), subscriptionFeatures, subscriptionFeaturesDescription.c_str(), m_entitlementEntitledTime, m_entitlementTotalTime, m_entitlementEntitledTimeSinceLastLogin, m_entitlementTotalTimeSinceLastLogin)); + + // ask CentralServer to tell all other ConnectionServers on this galaxy to drop duplicate connections for this account + // and ask CentralServer (via LoginServer) to tell all ConnectionServers on other galaxies to drop duplicate connections for this account + if (!m_usingAdminLogin && !m_isSecure) + { + GenericValueTypeMessage > const dropDuplicateConnections("ConnSrvDropDupeConns", std::make_pair(m_suid, m_sessionId)); + ConnectionServer::sendToCentralProcess(dropDuplicateConnections); + } +} + +//----------------------------------------------------------------------- + +std::string ClientConnection::describeAccount(const ClientConnection * c) +{ + std::string result = ""; + if(c) + { + char idbuf[512] = {"\0"}; + const std::string & sessionId = c->getSessionId(); + if (sessionId.empty()) + { + snprintf(idbuf, sizeof(idbuf), " (%lu)", c->m_suid); + } + else + { + snprintf(idbuf, sizeof(idbuf), " (%lu, %s)", c->m_suid, sessionId.c_str()); + } + + result = c->m_accountName; + result += idbuf; + } + return result; +} + +// ---------------------------------------------------------------------- + +std::vector > const & ClientConnection::getConsumedRewardEvents() const +{ + return m_consumedRewardEvents; +} + +// ---------------------------------------------------------------------- + +std::vector > const & ClientConnection::getClaimedRewardItems() const +{ + return m_claimedRewardItems; +} + +// ---------------------------------------------------------------------- + +bool ClientConnection::isUsingAdminLogin() const +{ + return m_usingAdminLogin; +} + +// ---------------------------------------------------------------------- + +int ClientConnection::getBuddyPoints() const +{ + return m_buddyPoints; +} + +// ====================================================================== diff --git a/src/engine/server/application/ConnectionServer/src/shared/ConfigConnectionServer.cpp b/src/engine/server/application/ConnectionServer/src/shared/ConfigConnectionServer.cpp index 672584a7e..f98eee214 100644 --- a/src/engine/server/application/ConnectionServer/src/shared/ConfigConnectionServer.cpp +++ b/src/engine/server/application/ConnectionServer/src/shared/ConfigConnectionServer.cpp @@ -1,166 +1,166 @@ -// ConfigConnectionServer.cpp -// copyright 2001 Verant Interactive - - -//----------------------------------------------------------------------- - -#include "FirstConnectionServer.h" -#include "ConfigConnectionServer.h" -#include "SessionApiClient.h" -#include "serverUtility/ConfigServerUtility.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedGame/PlatformFeatureBits.h" -#include "sharedNetwork/SetupSharedNetwork.h" - -//----------------------------------------------------------------------- - -ConfigConnectionServer::Data * ConfigConnectionServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("ConnectionServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("ConnectionServer", #a, b)) -#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("ConnectionServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("ConnectionServer", #a, b)) - -//----------------------------------------------------------------------- - -namespace ConfigConnectionServerNamespace -{ - typedef std::vector StringPtrArray; - StringPtrArray ms_sessionServer; // ConfigFile owns the pointer -} - -using namespace ConfigConnectionServerNamespace; - -// ====================================================================== - -int ConfigConnectionServer::getNumberOfSessionServers() -{ - return static_cast(ms_sessionServer.size()); -} - -// ---------------------------------------------------------------------- - -char const * ConfigConnectionServer::getSessionServer(int index) -{ - VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfSessionServers()); - return ms_sessionServer[static_cast(index)]; -} - -void ConfigConnectionServer::install(void) -{ - ConfigServerUtility::install(); - - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - SetupSharedNetwork::install(networkSetupData); - - data = new ConfigConnectionServer::Data; - - KEY_STRING (centralServerAddress, "localhost"); - KEY_INT (centralServerPort, 0); - KEY_STRING (clientServiceBindInterface, ""); - KEY_INT (clientServicePortPrivate, 44464); - KEY_INT (clientServicePortPublic, 44463); - KEY_INT (clientOverflowLimit, 1024 * 1024); // 1MB overflow - KEY_INT (gameServicePort, 0); - KEY_INT (pingPort, 0); - KEY_STRING (clusterName, "devcluster"); - KEY_INT (maxClients, 200); - KEY_BOOL (spamLimitEnabled, false); - KEY_INT (spamLimitResetTimeMs, 30*1000); - KEY_INT (spamLimitResetScaleFactor, 8); - KEY_INT (spamLimitBytesPerSec, 32000); - KEY_INT (spamLimitPacketsPerSec, 50); - KEY_BOOL (startPublicServer, true); - KEY_BOOL (disableWorldSnapshot, true); - KEY_STRING (gameServiceBindInterface, ""); - KEY_STRING (chatServiceBindInterface, ""); - KEY_STRING (customerServiceBindInterface, ""); - KEY_BOOL (compressClientNetworkTraffic, true); - KEY_INT (crashRecoveryTimeout, 15*1000); // timeout for players to recover from a server crash - KEY_BOOL (shouldSleep, true); - KEY_INT (clientMaxOutstandingPackets, 1000); - KEY_INT (clientMaxRawPacketSize, 500); - KEY_INT (clientMaxConnections, 200); - KEY_INT (clientFragmentSize, 500); - KEY_INT (clientMaxDataHoldTime, 20); - KEY_INT (clientHashTableSize, 200); - KEY_INT (lagReportThreshold, 10000); - KEY_INT (defaultGameFeatures, 0xFFFFFFFF); - KEY_INT (defaultSubscriptionFeatures, 0xFFFFFFFF); - - KEY_BOOL (validateStationKey, false); - KEY_STRING (sessionServers, ""); - KEY_INT (sessionType, SESSION_TYPE_STARWARS); - KEY_BOOL (disableSessionLogout, false); - KEY_BOOL (sessionRecordPlayTime, true); - KEY_BOOL (disconnectOnInactive, false); - KEY_BOOL (disconnectFreeTrialOnInactive, false); - - KEY_STRING (adminAccountDataTable, "datatables/admin/us_admin.iff"); - - KEY_INT (requiredSubscriptionBits, 0); - KEY_INT (requiredGameBits, 0); - KEY_BOOL (setJtlRetailIfBetaIsSet, false); - - KEY_BOOL (validateClientVersion, true); - KEY_BOOL (setEpisode3RetailIfBetaIsSet, false); - KEY_BOOL (setTrialsOfObiwanRetailIfBetaIsSet, false); - KEY_INT (disabledFeatureBits, 0); - - KEY_FLOAT (timeBetweenSessionUpdates, 60.0f * 5.0f); - - KEY_INT (connectionServerNumber, 0); - KEY_INT (fakeBuddyPoints, 0); - - int index = 0; - char const * result = 0; - do - { - result = ConfigFile::getKeyString("ConnectionServer", "sessionServer", index++, 0); - if (result != 0) - { - ms_sessionServer.push_back(result); - } - } - while (result); -} - -//----------------------------------------------------------------------- - -void ConfigConnectionServer::remove(void) -{ - delete data; - data = 0; - ConfigServerUtility::remove(); -} - -//----------------------------------------------------------------------- - -int ConfigConnectionServer::getDisabledFeatureBits() -{ - return data->disabledFeatureBits; -} - -// ---------------------------------------------------------------------- - -bool ConfigConnectionServer::getDisconnectOnInactive() -{ - return data->disconnectOnInactive; -} - -// ---------------------------------------------------------------------- - -bool ConfigConnectionServer::getDisconnectFreeTrialOnInactive() -{ - return data->disconnectFreeTrialOnInactive; -} - -// ---------------------------------------------------------------------- - -int ConfigConnectionServer::getFakeBuddyPoints() -{ - return data->fakeBuddyPoints; -} - -// ====================================================================== +// ConfigConnectionServer.cpp +// copyright 2001 Verant Interactive + + +//----------------------------------------------------------------------- + +#include "FirstConnectionServer.h" +#include "ConfigConnectionServer.h" +#include "SessionApiClient.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedGame/PlatformFeatureBits.h" +#include "sharedNetwork/SetupSharedNetwork.h" + +//----------------------------------------------------------------------- + +ConfigConnectionServer::Data * ConfigConnectionServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("ConnectionServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("ConnectionServer", #a, b)) +#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("ConnectionServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("ConnectionServer", #a, b)) + +//----------------------------------------------------------------------- + +namespace ConfigConnectionServerNamespace +{ + typedef std::vector StringPtrArray; + StringPtrArray ms_sessionServer; // ConfigFile owns the pointer +} + +using namespace ConfigConnectionServerNamespace; + +// ====================================================================== + +int ConfigConnectionServer::getNumberOfSessionServers() +{ + return static_cast(ms_sessionServer.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigConnectionServer::getSessionServer(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfSessionServers()); + return ms_sessionServer[static_cast(index)]; +} + +void ConfigConnectionServer::install(void) +{ + ConfigServerUtility::install(); + + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + data = new ConfigConnectionServer::Data; + + KEY_STRING (centralServerAddress, "localhost"); + KEY_INT (centralServerPort, 0); + KEY_STRING (clientServiceBindInterface, ""); + KEY_INT (clientServicePortPrivate, 44464); + KEY_INT (clientServicePortPublic, 44463); + KEY_INT (clientOverflowLimit, 1024 * 1024); // 1MB overflow + KEY_INT (gameServicePort, 0); + KEY_INT (pingPort, 0); + KEY_STRING (clusterName, "devcluster"); + KEY_INT (maxClients, 200); + KEY_BOOL (spamLimitEnabled, false); + KEY_INT (spamLimitResetTimeMs, 30*1000); + KEY_INT (spamLimitResetScaleFactor, 8); + KEY_INT (spamLimitBytesPerSec, 32000); + KEY_INT (spamLimitPacketsPerSec, 50); + KEY_BOOL (startPublicServer, true); + KEY_BOOL (disableWorldSnapshot, true); + KEY_STRING (gameServiceBindInterface, ""); + KEY_STRING (chatServiceBindInterface, ""); + KEY_STRING (customerServiceBindInterface, ""); + KEY_BOOL (compressClientNetworkTraffic, true); + KEY_INT (crashRecoveryTimeout, 15*1000); // timeout for players to recover from a server crash + KEY_BOOL (shouldSleep, true); + KEY_INT (clientMaxOutstandingPackets, 1000); + KEY_INT (clientMaxRawPacketSize, 500); + KEY_INT (clientMaxConnections, 200); + KEY_INT (clientFragmentSize, 500); + KEY_INT (clientMaxDataHoldTime, 20); + KEY_INT (clientHashTableSize, 200); + KEY_INT (lagReportThreshold, 10000); + KEY_INT (defaultGameFeatures, 0xFFFFFFFF); + KEY_INT (defaultSubscriptionFeatures, 0xFFFFFFFF); + + KEY_BOOL (validateStationKey, false); + KEY_STRING (sessionServers, ""); + KEY_INT (sessionType, SESSION_TYPE_STARWARS); + KEY_BOOL (disableSessionLogout, false); + KEY_BOOL (sessionRecordPlayTime, true); + KEY_BOOL (disconnectOnInactive, false); + KEY_BOOL (disconnectFreeTrialOnInactive, false); + + KEY_STRING (adminAccountDataTable, "datatables/admin/us_admin.iff"); + + KEY_INT (requiredSubscriptionBits, 0); + KEY_INT (requiredGameBits, 0); + KEY_BOOL (setJtlRetailIfBetaIsSet, false); + + KEY_BOOL (validateClientVersion, true); + KEY_BOOL (setEpisode3RetailIfBetaIsSet, false); + KEY_BOOL (setTrialsOfObiwanRetailIfBetaIsSet, false); + KEY_INT (disabledFeatureBits, 0); + + KEY_FLOAT (timeBetweenSessionUpdates, 60.0f * 5.0f); + + KEY_INT (connectionServerNumber, 0); + KEY_INT (fakeBuddyPoints, 0); + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("ConnectionServer", "sessionServer", index++, 0); + if (result != 0) + { + ms_sessionServer.push_back(result); + } + } + while (result); +} + +//----------------------------------------------------------------------- + +void ConfigConnectionServer::remove(void) +{ + delete data; + data = 0; + ConfigServerUtility::remove(); +} + +//----------------------------------------------------------------------- + +int ConfigConnectionServer::getDisabledFeatureBits() +{ + return data->disabledFeatureBits; +} + +// ---------------------------------------------------------------------- + +bool ConfigConnectionServer::getDisconnectOnInactive() +{ + return data->disconnectOnInactive; +} + +// ---------------------------------------------------------------------- + +bool ConfigConnectionServer::getDisconnectFreeTrialOnInactive() +{ + return data->disconnectFreeTrialOnInactive; +} + +// ---------------------------------------------------------------------- + +int ConfigConnectionServer::getFakeBuddyPoints() +{ + return data->fakeBuddyPoints; +} + +// ====================================================================== diff --git a/src/engine/server/application/CustomerServiceServer/src/shared/ConfigCustomerServiceServer.cpp b/src/engine/server/application/CustomerServiceServer/src/shared/ConfigCustomerServiceServer.cpp index f744897f7..eff05cf2d 100644 --- a/src/engine/server/application/CustomerServiceServer/src/shared/ConfigCustomerServiceServer.cpp +++ b/src/engine/server/application/CustomerServiceServer/src/shared/ConfigCustomerServiceServer.cpp @@ -1,167 +1,167 @@ -// ConfigCustomerServiceServer.cpp -// copyright 2000 Verant Interactive - -//----------------------------------------------------------------------- - -#include "FirstCustomerServiceServer.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedNetwork/SetupSharedNetwork.h" -#include "ConfigCustomerServiceServer.h" - -//----------------------------------------------------------------------- - -namespace ConfigCustomerServiceServerNamespace -{ - const char * s_clusterName = NULL; - const char * s_centralServerAddress = NULL; - int s_centralServerPort = 0; - const char * s_gameCode = NULL; - const char * s_csServerAddress = NULL; - int s_csServerPort = 0; - int s_maxPacketsPerSecond = 50; - int s_requestTimeoutSeconds = 300; - int s_maxAllowedNumberOfTickets = 1; - int s_gameServicePort = 0; - int s_chatServicePort = 0; - const char* s_chatServiceBindInterface = NULL; - const char* s_gameServiceBindInterface = NULL; - bool s_writeTicketToBugLog = false; -}; - -using namespace ConfigCustomerServiceServerNamespace; - -//----------------------------------------------------------------------- - -#define KEY_INT(a,b) (s_ ## a = ConfigFile::getKeyInt("CustomerServiceServer", #a, b)) -#define KEY_STRING(a,b) (s_ ## a = ConfigFile::getKeyString("CustomerServiceServer", #a, b)) -#define KEY_BOOL(a,b) (s_ ## a = ConfigFile::getKeyBool("CustomerServiceServer", #a, b)) - -//----------------------------------------------------------------------- - -void ConfigCustomerServiceServer::install() -{ - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - SetupSharedNetwork::install(networkSetupData); - - KEY_STRING (clusterName, "devcluster"); - KEY_STRING (centralServerAddress, "localhost"); - KEY_INT (centralServerPort, 61242); - KEY_STRING (gameCode, "SWG"); - KEY_STRING (csServerAddress, "localhost"); - KEY_INT (csServerPort, 3016); - KEY_INT (maxPacketsPerSecond, 50); - KEY_INT (requestTimeoutSeconds, 300); - KEY_INT (maxAllowedNumberOfTickets, 1); - KEY_INT (gameServicePort, 50010); - KEY_STRING (gameServiceBindInterface, ""); - KEY_INT (chatServicePort, 50011); - KEY_STRING (chatServiceBindInterface, ""); - KEY_BOOL (writeTicketToBugLog, false); -} - -//----------------------------------------------------------------------- - -void ConfigCustomerServiceServer::remove() -{ -} - -//----------------------------------------------------------------------- - -int ConfigCustomerServiceServer::getMaxPacketsPerSecond() -{ - return s_maxPacketsPerSecond; -} - -//----------------------------------------------------------------------- - -unsigned int ConfigCustomerServiceServer::getRequestTimeoutSeconds() -{ - return static_cast(s_requestTimeoutSeconds); -} - -//----------------------------------------------------------------------- - -const char * ConfigCustomerServiceServer::getCustomerServiceServerAddress() -{ - return s_csServerAddress; -} - -//----------------------------------------------------------------------- - -unsigned short ConfigCustomerServiceServer::getCustomerServiceServerPort() -{ - return static_cast(s_csServerPort); -} - -//----------------------------------------------------------------------- - -const char * ConfigCustomerServiceServer::getCentralServerAddress() -{ - return s_centralServerAddress; -} - -//----------------------------------------------------------------------- - -unsigned short ConfigCustomerServiceServer::getCentralServerPort() -{ - return static_cast(s_centralServerPort); -} - -//----------------------------------------------------------------------- - -const char * ConfigCustomerServiceServer::getClusterName() -{ - return s_clusterName; -} - -//----------------------------------------------------------------------- - -const char * ConfigCustomerServiceServer::getGameCode() -{ - return s_gameCode; -} - -//----------------------------------------------------------------------- - -int ConfigCustomerServiceServer::getMaxAllowedNumberOfTickets() -{ - return s_maxAllowedNumberOfTickets; -} - -//----------------------------------------------------------------------- - -unsigned short ConfigCustomerServiceServer::getGameServicePort() -{ - return static_cast(s_gameServicePort); -} - -//----------------------------------------------------------------------- - -unsigned short ConfigCustomerServiceServer::getChatServicePort() -{ - return static_cast(s_chatServicePort); -} - -//----------------------------------------------------------------------- - -const char* ConfigCustomerServiceServer::getGameServiceBindInterface() -{ - return s_gameServiceBindInterface; -} - -//----------------------------------------------------------------------- - -const char* ConfigCustomerServiceServer::getChatServiceBindInterface() -{ - return s_chatServiceBindInterface; -} - -//----------------------------------------------------------------------- - -bool ConfigCustomerServiceServer::getWriteTicketToBugLog() -{ - return s_writeTicketToBugLog; -} - -//----------------------------------------------------------------------- +// ConfigCustomerServiceServer.cpp +// copyright 2000 Verant Interactive + +//----------------------------------------------------------------------- + +#include "FirstCustomerServiceServer.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigCustomerServiceServer.h" + +//----------------------------------------------------------------------- + +namespace ConfigCustomerServiceServerNamespace +{ + const char * s_clusterName = NULL; + const char * s_centralServerAddress = NULL; + int s_centralServerPort = 0; + const char * s_gameCode = NULL; + const char * s_csServerAddress = NULL; + int s_csServerPort = 0; + int s_maxPacketsPerSecond = 50; + int s_requestTimeoutSeconds = 300; + int s_maxAllowedNumberOfTickets = 1; + int s_gameServicePort = 0; + int s_chatServicePort = 0; + const char* s_chatServiceBindInterface = NULL; + const char* s_gameServiceBindInterface = NULL; + bool s_writeTicketToBugLog = false; +}; + +using namespace ConfigCustomerServiceServerNamespace; + +//----------------------------------------------------------------------- + +#define KEY_INT(a,b) (s_ ## a = ConfigFile::getKeyInt("CustomerServiceServer", #a, b)) +#define KEY_STRING(a,b) (s_ ## a = ConfigFile::getKeyString("CustomerServiceServer", #a, b)) +#define KEY_BOOL(a,b) (s_ ## a = ConfigFile::getKeyBool("CustomerServiceServer", #a, b)) + +//----------------------------------------------------------------------- + +void ConfigCustomerServiceServer::install() +{ + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + KEY_STRING (clusterName, "devcluster"); + KEY_STRING (centralServerAddress, "localhost"); + KEY_INT (centralServerPort, 61242); + KEY_STRING (gameCode, "SWG"); + KEY_STRING (csServerAddress, "localhost"); + KEY_INT (csServerPort, 3016); + KEY_INT (maxPacketsPerSecond, 50); + KEY_INT (requestTimeoutSeconds, 300); + KEY_INT (maxAllowedNumberOfTickets, 1); + KEY_INT (gameServicePort, 50010); + KEY_STRING (gameServiceBindInterface, ""); + KEY_INT (chatServicePort, 50011); + KEY_STRING (chatServiceBindInterface, ""); + KEY_BOOL (writeTicketToBugLog, false); +} + +//----------------------------------------------------------------------- + +void ConfigCustomerServiceServer::remove() +{ +} + +//----------------------------------------------------------------------- + +int ConfigCustomerServiceServer::getMaxPacketsPerSecond() +{ + return s_maxPacketsPerSecond; +} + +//----------------------------------------------------------------------- + +unsigned int ConfigCustomerServiceServer::getRequestTimeoutSeconds() +{ + return static_cast(s_requestTimeoutSeconds); +} + +//----------------------------------------------------------------------- + +const char * ConfigCustomerServiceServer::getCustomerServiceServerAddress() +{ + return s_csServerAddress; +} + +//----------------------------------------------------------------------- + +unsigned short ConfigCustomerServiceServer::getCustomerServiceServerPort() +{ + return static_cast(s_csServerPort); +} + +//----------------------------------------------------------------------- + +const char * ConfigCustomerServiceServer::getCentralServerAddress() +{ + return s_centralServerAddress; +} + +//----------------------------------------------------------------------- + +unsigned short ConfigCustomerServiceServer::getCentralServerPort() +{ + return static_cast(s_centralServerPort); +} + +//----------------------------------------------------------------------- + +const char * ConfigCustomerServiceServer::getClusterName() +{ + return s_clusterName; +} + +//----------------------------------------------------------------------- + +const char * ConfigCustomerServiceServer::getGameCode() +{ + return s_gameCode; +} + +//----------------------------------------------------------------------- + +int ConfigCustomerServiceServer::getMaxAllowedNumberOfTickets() +{ + return s_maxAllowedNumberOfTickets; +} + +//----------------------------------------------------------------------- + +unsigned short ConfigCustomerServiceServer::getGameServicePort() +{ + return static_cast(s_gameServicePort); +} + +//----------------------------------------------------------------------- + +unsigned short ConfigCustomerServiceServer::getChatServicePort() +{ + return static_cast(s_chatServicePort); +} + +//----------------------------------------------------------------------- + +const char* ConfigCustomerServiceServer::getGameServiceBindInterface() +{ + return s_gameServiceBindInterface; +} + +//----------------------------------------------------------------------- + +const char* ConfigCustomerServiceServer::getChatServiceBindInterface() +{ + return s_chatServiceBindInterface; +} + +//----------------------------------------------------------------------- + +bool ConfigCustomerServiceServer::getWriteTicketToBugLog() +{ + return s_writeTicketToBugLog; +} + +//----------------------------------------------------------------------- diff --git a/src/engine/server/application/LogServer/src/shared/ConfigLogServer.cpp b/src/engine/server/application/LogServer/src/shared/ConfigLogServer.cpp index 3f3b78b26..c2240c1b7 100644 --- a/src/engine/server/application/LogServer/src/shared/ConfigLogServer.cpp +++ b/src/engine/server/application/LogServer/src/shared/ConfigLogServer.cpp @@ -1,55 +1,55 @@ -// ====================================================================== -// -// ConfigLogServer.cpp -// -// Copyright 2002 Sony Online Entertainment -// -// ====================================================================== - -#include "FirstLogServer.h" -#include "ConfigLogServer.h" -#include "serverUtility/ConfigServerUtility.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedNetwork/SetupSharedNetwork.h" - -// ====================================================================== - -ConfigLogServer::Data *ConfigLogServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("LogServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("LogServer", #a, b)) - -// ====================================================================== - -void ConfigLogServer::install() -{ - ConfigServerUtility::install(); - - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - SetupSharedNetwork::install(networkSetupData); - - data = new ConfigLogServer::Data; - - KEY_INT (logServicePort, 44467); - KEY_STRING (logServiceBindInterface, ""); - KEY_STRING (loggingServerApiAddress, "localhost"); - KEY_STRING (loggingServerApiLoginName, "MISCONFIGURED_LOG_SERVER_LOGIN_NAME"); - KEY_STRING (loggingServerApiPassword, "pacman"); - KEY_STRING (loggingServerApiDefaultDirectory, "swg"); - KEY_STRING (clusterName, "MISCONFIGURED_LOG_SERVER"); - KEY_INT (logServiceMaxConnections, 150); - KEY_INT (loggingServerApiQueueSize, 4096); -} - -// ---------------------------------------------------------------------- - -void ConfigLogServer::remove() -{ - delete data; - data = 0; - ConfigServerUtility::remove(); -} - -// ====================================================================== - +// ====================================================================== +// +// ConfigLogServer.cpp +// +// Copyright 2002 Sony Online Entertainment +// +// ====================================================================== + +#include "FirstLogServer.h" +#include "ConfigLogServer.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" + +// ====================================================================== + +ConfigLogServer::Data *ConfigLogServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("LogServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("LogServer", #a, b)) + +// ====================================================================== + +void ConfigLogServer::install() +{ + ConfigServerUtility::install(); + + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + data = new ConfigLogServer::Data; + + KEY_INT (logServicePort, 44467); + KEY_STRING (logServiceBindInterface, ""); + KEY_STRING (loggingServerApiAddress, "localhost"); + KEY_STRING (loggingServerApiLoginName, "MISCONFIGURED_LOG_SERVER_LOGIN_NAME"); + KEY_STRING (loggingServerApiPassword, "pacman"); + KEY_STRING (loggingServerApiDefaultDirectory, "swg"); + KEY_STRING (clusterName, "MISCONFIGURED_LOG_SERVER"); + KEY_INT (logServiceMaxConnections, 150); + KEY_INT (loggingServerApiQueueSize, 4096); +} + +// ---------------------------------------------------------------------- + +void ConfigLogServer::remove() +{ + delete data; + data = 0; + ConfigServerUtility::remove(); +} + +// ====================================================================== + diff --git a/src/engine/server/application/LoginServer/src/shared/ConfigLoginServer.h b/src/engine/server/application/LoginServer/src/shared/ConfigLoginServer.h index d923b2289..7bd948805 100644 --- a/src/engine/server/application/LoginServer/src/shared/ConfigLoginServer.h +++ b/src/engine/server/application/LoginServer/src/shared/ConfigLoginServer.h @@ -1,472 +1,472 @@ -// ConfigLoginServer.h -// copyright 2000 Verant Interactive -// Author: Justin Randall - -#ifndef _ConfigLoginServer_H -#define _ConfigLoginServer_H - -//----------------------------------------------------------------------- - -class ConfigLoginServer -{ - public: - struct Data - { - int centralServicePort; - int clientServicePort; - int maxClients; - int taskServicePort; - int pingServicePort; - int httpServicePort; - bool validateClientVersion; - bool validateStationKey; - bool doSessionLogin; - bool doConsumption; - const char * sessionServers; - int sessionType; - - const char * DSN; - const char * databaseUID; - const char * schemaOwner; - const char * databasePWD; - const char * databaseProtocol; - bool enableQueryProfile; - bool verboseQueryMode; - bool logWorkerThreads; - - const char * privateIpMask; - int maxPlayersPerCluster; - int maxCharactersPerCluster; - int maxCharactersPerAccount; - int clientOverflowLimit; - bool developmentMode; - int databaseThreads; - bool compressClientNetworkTraffic; - int metricsListenerPort; - float defaultDBQueueUpdateTimeLimit; - int disconnectSleepTime; - int clusterGroup; - int maxSimultaneousPurgeAccounts; - int purgeSleepTime; - bool enableStructurePurge; - bool enableCharacterPurge; - int updatePurgeAccountListTime; - const char * purgeAccountSourceTable; - const char * adminAccountDataTable; - bool allowSkipTutorialToAll; - - bool internalBypassOnlineLimit; - - int populationExtremelyHeavyThresholdPercent; - int populationVeryHeavyThresholdPercent; - int populationHeavyThresholdPercent; - int populationMediumThresholdPercent; - int populationLightThresholdPercent; - int csToolPort; - - bool requireSecureLoginForCsTool; - }; - - static const uint16 getCentralServicePort(); - static const uint16 getClientServicePort(); - static const int getClientOverflowLimit(); - static const uint16 getTaskServicePort(); - static const uint16 getPingServicePort(); - static const uint16 getHttpServicePort(); - static const bool getValidateClientVersion(); - static const bool getValidateStationKey(); - static const bool getDoSessionLogin(); - static const bool getDoConsumption(); - static const char * getSessionServers(); - static const int getSessionType(); - - static const int getMaxClients (); - static const char * getPrivateIpMask(); - static const char * getDSN(); - static const char * getDatabaseUID(); - static const char * getSchemaOwner(); - static const char * getDatabasePWD(); - static const char * getDatabaseProtocol(); - static const bool getEnableQueryProfile(); - static const bool getVerboseQueryMode(); - static const bool getLogWorkerThreads(); - static int getMaxPlayersPerCluster(); - static int getMaxCharactersPerCluster(); - static int getMaxCharactersPerAccount(); - //static int getMaxCharactersPerAccountPerCluster(); - static const bool getDevelopmentMode(); - static int getDatabaseThreads(); - static bool getCompressClientNetworkTraffic(); - static uint16 getMetricsListenerPort(); - static float getDefaultDBQueueUpdateTimeLimit(); - static void install (); - static void remove (); - - static int getNumberOfSessionServers(); - static char const * getSessionServer(int index); - static const int getDisconnectSleepTime (void); - static const int getClusterGroup(); - static int getMaxSimultaneousPurgeAccounts(); - static int getPurgeSleepTime(); - static bool getEnableStructurePurge(); - static bool getEnableCharacterPurge(); - static int getUpdatePurgeAccountListTime(); - static const char * getPurgeAccountSourceTable(); - static int getPurgePhaseAdvanceDays(int purgePhase); - static const char * getAdminAccountDataTable(); - static bool getAllowSkipTutorialToAll(); - - static bool getInternalBypassOnlineLimit(); - static const int getCSToolPort(); - - static bool getRequireSecureLoginForCsTool(); - - static int getPopulationExtremelyHeavyThresholdPercent(); - static int getPopulationVeryHeavyThresholdPercent(); - static int getPopulationHeavyThresholdPercent(); - static int getPopulationMediumThresholdPercent(); - static int getPopulationLightThresholdPercent(); - - // has character creation for this cluster been disabled through config option - static bool isCharacterCreationDisabled(std::string const & cluster); - static stdset::fwd const & getCharacterCreationDisabledClusterList(); - -private: - static Data * data; -}; - -//----------------------------------------------------------------------- - -inline const uint16 ConfigLoginServer::getCentralServicePort() -{ - return static_cast(data->centralServicePort); -} - -//----------------------------------------------------------------------- - -inline const uint16 ConfigLoginServer::getHttpServicePort() -{ - return static_cast(data->httpServicePort); -} - -//----------------------------------------------------------------------- - -inline const uint16 ConfigLoginServer::getClientServicePort() -{ - return static_cast(data->clientServicePort); -} - -//----------------------------------------------------------------------- - -inline const int ConfigLoginServer::getClientOverflowLimit() -{ - return data->clientOverflowLimit; -} - -//----------------------------------------------------------------------- - - -inline const int ConfigLoginServer::getMaxClients() -{ - return data->maxClients; -} - -//----------------------------------------------------------------------- - -inline const char * ConfigLoginServer::getPrivateIpMask() -{ - return data->privateIpMask; -} - -//----------------------------------------------------------------------- - -inline const uint16 ConfigLoginServer::getTaskServicePort() -{ - return static_cast(data->taskServicePort); -} - -//----------------------------------------------------------------------- - -inline const uint16 ConfigLoginServer::getPingServicePort() -{ - return static_cast(data->pingServicePort); -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getValidateClientVersion() -{ - return (data->validateClientVersion); -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getValidateStationKey() -{ - return (data->validateStationKey); -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getDoSessionLogin() -{ - return (data->doSessionLogin); -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getDoConsumption() -{ - return (data->doConsumption); -} - -// ---------------------------------------------------------------------- - -inline const char * ConfigLoginServer::getSessionServers() -{ - return (data->sessionServers); -} - -//------------------------------------------------------------------------------------------ - -inline const int ConfigLoginServer::getSessionType() -{ - return data->sessionType; -} - -// ---------------------------------------------------------------------- - -inline const char * ConfigLoginServer::getDSN() -{ - return (data->DSN); -} - -// ---------------------------------------------------------------------- - -inline const char * ConfigLoginServer::getDatabaseUID() -{ - return (data->databaseUID); -} - -// ---------------------------------------------------------------------- - -inline const char * ConfigLoginServer::getDatabasePWD() -{ - return (data->databasePWD); -} - -// ---------------------------------------------------------------------- - -inline const char * ConfigLoginServer::getDatabaseProtocol() -{ - return (data->databaseProtocol); -} - -//----------------------------------------------------------------------- - -inline int ConfigLoginServer::getMaxPlayersPerCluster() -{ - return (data->maxPlayersPerCluster); -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getMaxCharactersPerCluster() -{ - return (data->maxCharactersPerCluster); -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getMaxCharactersPerAccount() -{ - return (data->maxCharactersPerAccount); -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getEnableQueryProfile() -{ - return (data->enableQueryProfile); -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getVerboseQueryMode() -{ - return (data->verboseQueryMode); -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getLogWorkerThreads() -{ - return data->logWorkerThreads; -} - -// ---------------------------------------------------------------------- - -inline const bool ConfigLoginServer::getDevelopmentMode() -{ - return (data->developmentMode); -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getDatabaseThreads() -{ - return (data->databaseThreads); -} - -// ---------------------------------------------------------------------- - -inline bool ConfigLoginServer::getCompressClientNetworkTraffic() -{ - return data->compressClientNetworkTraffic; -} - -// ---------------------------------------------------------------------- - -inline uint16 ConfigLoginServer::getMetricsListenerPort() -{ - return static_cast(data->metricsListenerPort); -} - -// ---------------------------------------------------------------------- - -inline const char *ConfigLoginServer::getSchemaOwner() -{ - return data->schemaOwner; -} - -// ---------------------------------------------------------------------- - -inline float ConfigLoginServer::getDefaultDBQueueUpdateTimeLimit() -{ - return data->defaultDBQueueUpdateTimeLimit; -} - -// ---------------------------------------------------------------------- - -inline const int ConfigLoginServer::getDisconnectSleepTime(void) -{ - return data->disconnectSleepTime; -} - -// ---------------------------------------------------------------------- - -inline const int ConfigLoginServer::getClusterGroup() -{ - return data->clusterGroup; -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getMaxSimultaneousPurgeAccounts() -{ - return data->maxSimultaneousPurgeAccounts; -} - -//----------------------------------------------------------------------- - -inline int ConfigLoginServer::getPurgeSleepTime() -{ - return data->purgeSleepTime; -} - -// ---------------------------------------------------------------------- - -inline bool ConfigLoginServer::getEnableStructurePurge() -{ - return data->enableStructurePurge; -} - -// ---------------------------------------------------------------------- - -inline bool ConfigLoginServer::getEnableCharacterPurge() -{ - return data->enableCharacterPurge; -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getUpdatePurgeAccountListTime() -{ - return data->updatePurgeAccountListTime; -} - -// ---------------------------------------------------------------------- - -inline char const * ConfigLoginServer::getPurgeAccountSourceTable() -{ - return data->purgeAccountSourceTable; -} - -// ---------------------------------------------------------------------- - -inline const char * ConfigLoginServer::getAdminAccountDataTable() -{ - return data->adminAccountDataTable; -} - -// ---------------------------------------------------------------------- - -inline bool ConfigLoginServer::getAllowSkipTutorialToAll() -{ - return data->allowSkipTutorialToAll; -} - -// ---------------------------------------------------------------------- - -inline bool ConfigLoginServer::getInternalBypassOnlineLimit() -{ - return data->internalBypassOnlineLimit; -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getPopulationExtremelyHeavyThresholdPercent() -{ - return data->populationExtremelyHeavyThresholdPercent; -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getPopulationVeryHeavyThresholdPercent() -{ - return data->populationVeryHeavyThresholdPercent; -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getPopulationHeavyThresholdPercent() -{ - return data->populationHeavyThresholdPercent; -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getPopulationMediumThresholdPercent() -{ - return data->populationMediumThresholdPercent; -} - -// ---------------------------------------------------------------------- - -inline int ConfigLoginServer::getPopulationLightThresholdPercent() -{ - return data->populationLightThresholdPercent; -} - -inline bool ConfigLoginServer::getRequireSecureLoginForCsTool() -{ - return data->requireSecureLoginForCsTool; -} - -inline const int ConfigLoginServer::getCSToolPort() -{ - return data->csToolPort; -} -// ====================================================================== - -#endif // _ConfigLoginServer_H +// ConfigLoginServer.h +// copyright 2000 Verant Interactive +// Author: Justin Randall + +#ifndef _ConfigLoginServer_H +#define _ConfigLoginServer_H + +//----------------------------------------------------------------------- + +class ConfigLoginServer +{ + public: + struct Data + { + int centralServicePort; + int clientServicePort; + int maxClients; + int taskServicePort; + int pingServicePort; + int httpServicePort; + bool validateClientVersion; + bool validateStationKey; + bool doSessionLogin; + bool doConsumption; + const char * sessionServers; + int sessionType; + + const char * DSN; + const char * databaseUID; + const char * schemaOwner; + const char * databasePWD; + const char * databaseProtocol; + bool enableQueryProfile; + bool verboseQueryMode; + bool logWorkerThreads; + + const char * privateIpMask; + int maxPlayersPerCluster; + int maxCharactersPerCluster; + int maxCharactersPerAccount; + int clientOverflowLimit; + bool developmentMode; + int databaseThreads; + bool compressClientNetworkTraffic; + int metricsListenerPort; + float defaultDBQueueUpdateTimeLimit; + int disconnectSleepTime; + int clusterGroup; + int maxSimultaneousPurgeAccounts; + int purgeSleepTime; + bool enableStructurePurge; + bool enableCharacterPurge; + int updatePurgeAccountListTime; + const char * purgeAccountSourceTable; + const char * adminAccountDataTable; + bool allowSkipTutorialToAll; + + bool internalBypassOnlineLimit; + + int populationExtremelyHeavyThresholdPercent; + int populationVeryHeavyThresholdPercent; + int populationHeavyThresholdPercent; + int populationMediumThresholdPercent; + int populationLightThresholdPercent; + int csToolPort; + + bool requireSecureLoginForCsTool; + }; + + static const uint16 getCentralServicePort(); + static const uint16 getClientServicePort(); + static const int getClientOverflowLimit(); + static const uint16 getTaskServicePort(); + static const uint16 getPingServicePort(); + static const uint16 getHttpServicePort(); + static const bool getValidateClientVersion(); + static const bool getValidateStationKey(); + static const bool getDoSessionLogin(); + static const bool getDoConsumption(); + static const char * getSessionServers(); + static const int getSessionType(); + + static const int getMaxClients (); + static const char * getPrivateIpMask(); + static const char * getDSN(); + static const char * getDatabaseUID(); + static const char * getSchemaOwner(); + static const char * getDatabasePWD(); + static const char * getDatabaseProtocol(); + static const bool getEnableQueryProfile(); + static const bool getVerboseQueryMode(); + static const bool getLogWorkerThreads(); + static int getMaxPlayersPerCluster(); + static int getMaxCharactersPerCluster(); + static int getMaxCharactersPerAccount(); + //static int getMaxCharactersPerAccountPerCluster(); + static const bool getDevelopmentMode(); + static int getDatabaseThreads(); + static bool getCompressClientNetworkTraffic(); + static uint16 getMetricsListenerPort(); + static float getDefaultDBQueueUpdateTimeLimit(); + static void install (); + static void remove (); + + static int getNumberOfSessionServers(); + static char const * getSessionServer(int index); + static const int getDisconnectSleepTime (void); + static const int getClusterGroup(); + static int getMaxSimultaneousPurgeAccounts(); + static int getPurgeSleepTime(); + static bool getEnableStructurePurge(); + static bool getEnableCharacterPurge(); + static int getUpdatePurgeAccountListTime(); + static const char * getPurgeAccountSourceTable(); + static int getPurgePhaseAdvanceDays(int purgePhase); + static const char * getAdminAccountDataTable(); + static bool getAllowSkipTutorialToAll(); + + static bool getInternalBypassOnlineLimit(); + static const int getCSToolPort(); + + static bool getRequireSecureLoginForCsTool(); + + static int getPopulationExtremelyHeavyThresholdPercent(); + static int getPopulationVeryHeavyThresholdPercent(); + static int getPopulationHeavyThresholdPercent(); + static int getPopulationMediumThresholdPercent(); + static int getPopulationLightThresholdPercent(); + + // has character creation for this cluster been disabled through config option + static bool isCharacterCreationDisabled(std::string const & cluster); + static stdset::fwd const & getCharacterCreationDisabledClusterList(); + +private: + static Data * data; +}; + +//----------------------------------------------------------------------- + +inline const uint16 ConfigLoginServer::getCentralServicePort() +{ + return static_cast(data->centralServicePort); +} + +//----------------------------------------------------------------------- + +inline const uint16 ConfigLoginServer::getHttpServicePort() +{ + return static_cast(data->httpServicePort); +} + +//----------------------------------------------------------------------- + +inline const uint16 ConfigLoginServer::getClientServicePort() +{ + return static_cast(data->clientServicePort); +} + +//----------------------------------------------------------------------- + +inline const int ConfigLoginServer::getClientOverflowLimit() +{ + return data->clientOverflowLimit; +} + +//----------------------------------------------------------------------- + + +inline const int ConfigLoginServer::getMaxClients() +{ + return data->maxClients; +} + +//----------------------------------------------------------------------- + +inline const char * ConfigLoginServer::getPrivateIpMask() +{ + return data->privateIpMask; +} + +//----------------------------------------------------------------------- + +inline const uint16 ConfigLoginServer::getTaskServicePort() +{ + return static_cast(data->taskServicePort); +} + +//----------------------------------------------------------------------- + +inline const uint16 ConfigLoginServer::getPingServicePort() +{ + return static_cast(data->pingServicePort); +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getValidateClientVersion() +{ + return (data->validateClientVersion); +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getValidateStationKey() +{ + return (data->validateStationKey); +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getDoSessionLogin() +{ + return (data->doSessionLogin); +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getDoConsumption() +{ + return (data->doConsumption); +} + +// ---------------------------------------------------------------------- + +inline const char * ConfigLoginServer::getSessionServers() +{ + return (data->sessionServers); +} + +//------------------------------------------------------------------------------------------ + +inline const int ConfigLoginServer::getSessionType() +{ + return data->sessionType; +} + +// ---------------------------------------------------------------------- + +inline const char * ConfigLoginServer::getDSN() +{ + return (data->DSN); +} + +// ---------------------------------------------------------------------- + +inline const char * ConfigLoginServer::getDatabaseUID() +{ + return (data->databaseUID); +} + +// ---------------------------------------------------------------------- + +inline const char * ConfigLoginServer::getDatabasePWD() +{ + return (data->databasePWD); +} + +// ---------------------------------------------------------------------- + +inline const char * ConfigLoginServer::getDatabaseProtocol() +{ + return (data->databaseProtocol); +} + +//----------------------------------------------------------------------- + +inline int ConfigLoginServer::getMaxPlayersPerCluster() +{ + return (data->maxPlayersPerCluster); +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getMaxCharactersPerCluster() +{ + return (data->maxCharactersPerCluster); +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getMaxCharactersPerAccount() +{ + return (data->maxCharactersPerAccount); +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getEnableQueryProfile() +{ + return (data->enableQueryProfile); +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getVerboseQueryMode() +{ + return (data->verboseQueryMode); +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getLogWorkerThreads() +{ + return data->logWorkerThreads; +} + +// ---------------------------------------------------------------------- + +inline const bool ConfigLoginServer::getDevelopmentMode() +{ + return (data->developmentMode); +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getDatabaseThreads() +{ + return (data->databaseThreads); +} + +// ---------------------------------------------------------------------- + +inline bool ConfigLoginServer::getCompressClientNetworkTraffic() +{ + return data->compressClientNetworkTraffic; +} + +// ---------------------------------------------------------------------- + +inline uint16 ConfigLoginServer::getMetricsListenerPort() +{ + return static_cast(data->metricsListenerPort); +} + +// ---------------------------------------------------------------------- + +inline const char *ConfigLoginServer::getSchemaOwner() +{ + return data->schemaOwner; +} + +// ---------------------------------------------------------------------- + +inline float ConfigLoginServer::getDefaultDBQueueUpdateTimeLimit() +{ + return data->defaultDBQueueUpdateTimeLimit; +} + +// ---------------------------------------------------------------------- + +inline const int ConfigLoginServer::getDisconnectSleepTime(void) +{ + return data->disconnectSleepTime; +} + +// ---------------------------------------------------------------------- + +inline const int ConfigLoginServer::getClusterGroup() +{ + return data->clusterGroup; +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getMaxSimultaneousPurgeAccounts() +{ + return data->maxSimultaneousPurgeAccounts; +} + +//----------------------------------------------------------------------- + +inline int ConfigLoginServer::getPurgeSleepTime() +{ + return data->purgeSleepTime; +} + +// ---------------------------------------------------------------------- + +inline bool ConfigLoginServer::getEnableStructurePurge() +{ + return data->enableStructurePurge; +} + +// ---------------------------------------------------------------------- + +inline bool ConfigLoginServer::getEnableCharacterPurge() +{ + return data->enableCharacterPurge; +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getUpdatePurgeAccountListTime() +{ + return data->updatePurgeAccountListTime; +} + +// ---------------------------------------------------------------------- + +inline char const * ConfigLoginServer::getPurgeAccountSourceTable() +{ + return data->purgeAccountSourceTable; +} + +// ---------------------------------------------------------------------- + +inline const char * ConfigLoginServer::getAdminAccountDataTable() +{ + return data->adminAccountDataTable; +} + +// ---------------------------------------------------------------------- + +inline bool ConfigLoginServer::getAllowSkipTutorialToAll() +{ + return data->allowSkipTutorialToAll; +} + +// ---------------------------------------------------------------------- + +inline bool ConfigLoginServer::getInternalBypassOnlineLimit() +{ + return data->internalBypassOnlineLimit; +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getPopulationExtremelyHeavyThresholdPercent() +{ + return data->populationExtremelyHeavyThresholdPercent; +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getPopulationVeryHeavyThresholdPercent() +{ + return data->populationVeryHeavyThresholdPercent; +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getPopulationHeavyThresholdPercent() +{ + return data->populationHeavyThresholdPercent; +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getPopulationMediumThresholdPercent() +{ + return data->populationMediumThresholdPercent; +} + +// ---------------------------------------------------------------------- + +inline int ConfigLoginServer::getPopulationLightThresholdPercent() +{ + return data->populationLightThresholdPercent; +} + +inline bool ConfigLoginServer::getRequireSecureLoginForCsTool() +{ + return data->requireSecureLoginForCsTool; +} + +inline const int ConfigLoginServer::getCSToolPort() +{ + return data->csToolPort; +} +// ====================================================================== + +#endif // _ConfigLoginServer_H diff --git a/src/engine/server/application/LoginServer/src/shared/LoginServerRemoteDebugSetup.cpp b/src/engine/server/application/LoginServer/src/shared/LoginServerRemoteDebugSetup.cpp index 449266e00..fa78a1c2c 100644 --- a/src/engine/server/application/LoginServer/src/shared/LoginServerRemoteDebugSetup.cpp +++ b/src/engine/server/application/LoginServer/src/shared/LoginServerRemoteDebugSetup.cpp @@ -1,96 +1,96 @@ -// ====================================================================== -// -// LoginServerRemoteDebugSetup.cpp -// copyright 2001 Sony Online Entertainment -// -// ====================================================================== - -#include "FirstLoginServer.h" -#include "Archive/ByteStream.h" -#include "sharedFoundation/ConfigSharedFoundation.h" -#include "LoginServerRemoteDebugSetup.h" -#include "LoginServerRemoteDebugConnection.h" -#include "sharedDebug/RemoteDebug_inner.h" -#include "sharedNetwork/Connection.h" -#include "sharedNetwork/NetworkSetupData.h" -#include "sharedNetwork/Service.h" - -//static definitions -//Network::Address *LoginServerRemoteDebugSetup::ms_remoteDebugService; -bool LoginServerRemoteDebugSetup::ms_installed; -unsigned int LoginServerRemoteDebugSetup::ms_remoteDebugToolChannelID; -Connection *LoginServerRemoteDebugSetup::ms_connection; -Service *LoginServerRemoteDebugSetup::ms_remoteDebugService; - -void LoginServerRemoteDebugSetup::install(void) -{ - if (ms_installed) - { - //TODO bad - return; - } - - if (!ConfigSharedFoundation::getUseRemoteDebug()) - return; - - NetworkSetupData setup; - setup.port = 4446; - setup.maxConnections = 16; - ms_remoteDebugService = new Service(ConnectionAllocator(), setup); - - RemoteDebugServer::install(remove, open, close, send, 0);//, receive); - ms_installed = true; -} - -void LoginServerRemoteDebugSetup::remove(void) -{ - if (!ms_installed) - { - //TODO bad - return; - } - delete ms_remoteDebugService; - - RemoteDebugServer::remove(); - ms_installed = false; -} - -void LoginServerRemoteDebugSetup::open(const char *, uint16) -{ - DEBUG_WARNING(true, ("not implemented! Fix ME!")); - /* - //TODO config file this? - //attempt to auto-connect to a localhost client app (if it's auto-listening) - if (ms_remoteDebugService->getHostPort()) - Network::connect(ms_connection, "127.0.0.1", port); - else - { - //TODO bad - } - */ -} - -void LoginServerRemoteDebugSetup::close(void) -{ - if (!ms_installed) - { - //TODO bad - return; - } -} - -void LoginServerRemoteDebugSetup::send(void *, uint32) -{ - DEBUG_WARNING(true, ("not implemented! Fix ME!")); - /* - if (!ms_installed) - { - //TODO bad - return; - } - //always send on VNL channel 0, send the buffer, it's length, and reliable=1 - NOT_NULL(ms_connection); - static Archive::ByteStream bs(reinterpret_cast(buffer), bufferLen); - ms_connection->send(bs, true); - */ -}//lint !e818 // parameter bufffer could be declared as pointint to const (but the function prototype beyond this class cannot) +// ====================================================================== +// +// LoginServerRemoteDebugSetup.cpp +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "FirstLoginServer.h" +#include "Archive/ByteStream.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "LoginServerRemoteDebugSetup.h" +#include "LoginServerRemoteDebugConnection.h" +#include "sharedDebug/RemoteDebug_inner.h" +#include "sharedNetwork/Connection.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetwork/Service.h" + +//static definitions +//Network::Address *LoginServerRemoteDebugSetup::ms_remoteDebugService; +bool LoginServerRemoteDebugSetup::ms_installed; +unsigned int LoginServerRemoteDebugSetup::ms_remoteDebugToolChannelID; +Connection *LoginServerRemoteDebugSetup::ms_connection; +Service *LoginServerRemoteDebugSetup::ms_remoteDebugService; + +void LoginServerRemoteDebugSetup::install(void) +{ + if (ms_installed) + { + //TODO bad + return; + } + + if (!ConfigSharedFoundation::getUseRemoteDebug()) + return; + + NetworkSetupData setup; + setup.port = 4446; + setup.maxConnections = 16; + ms_remoteDebugService = new Service(ConnectionAllocator(), setup); + + RemoteDebugServer::install(remove, open, close, send, 0);//, receive); + ms_installed = true; +} + +void LoginServerRemoteDebugSetup::remove(void) +{ + if (!ms_installed) + { + //TODO bad + return; + } + delete ms_remoteDebugService; + + RemoteDebugServer::remove(); + ms_installed = false; +} + +void LoginServerRemoteDebugSetup::open(const char *, uint16) +{ + DEBUG_WARNING(true, ("not implemented! Fix ME!")); + /* + //TODO config file this? + //attempt to auto-connect to a localhost client app (if it's auto-listening) + if (ms_remoteDebugService->getHostPort()) + Network::connect(ms_connection, "127.0.0.1", port); + else + { + //TODO bad + } + */ +} + +void LoginServerRemoteDebugSetup::close(void) +{ + if (!ms_installed) + { + //TODO bad + return; + } +} + +void LoginServerRemoteDebugSetup::send(void *, uint32) +{ + DEBUG_WARNING(true, ("not implemented! Fix ME!")); + /* + if (!ms_installed) + { + //TODO bad + return; + } + //always send on VNL channel 0, send the buffer, it's length, and reliable=1 + NOT_NULL(ms_connection); + static Archive::ByteStream bs(reinterpret_cast(buffer), bufferLen); + ms_connection->send(bs, true); + */ +}//lint !e818 // parameter bufffer could be declared as pointint to const (but the function prototype beyond this class cannot) diff --git a/src/engine/server/application/MetricsServer/src/shared/ConfigMetricsServer.cpp b/src/engine/server/application/MetricsServer/src/shared/ConfigMetricsServer.cpp index 277f89a5d..469d7efe9 100644 --- a/src/engine/server/application/MetricsServer/src/shared/ConfigMetricsServer.cpp +++ b/src/engine/server/application/MetricsServer/src/shared/ConfigMetricsServer.cpp @@ -1,45 +1,45 @@ -// ConfigMetricsServer.cpp -// copyright 2000 Verant Interactive -// Author: Justin Randall - - -//----------------------------------------------------------------------- - -#include "FirstMetricsServer.h" -#include "sharedFoundation/ConfigFile.h" -#include "ConfigMetricsServer.h" - -//----------------------------------------------------------------------- - -ConfigMetricsServer::Data * ConfigMetricsServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("MetricsServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("MetricsServer", #a, b)) -#define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("MetricsServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("MetricsServer", #a, b)) - -//----------------------------------------------------------------------- - -void ConfigMetricsServer::install(void) -{ - data = new ConfigMetricsServer::Data; - - KEY_STRING(authenticationFileName, "../../exe/shared/metricsAuthentication.cfg"); - KEY_STRING(clusterName, "DevCluster"); - KEY_INT(metricsListenerPort, 2200); - KEY_INT(metricsServicePort, 44480); - KEY_BOOL(runTestStats, false); - KEY_INT(taskManagerPort, 60001); - KEY_STRING(metricsServiceBindInterface, ""); -} - -//----------------------------------------------------------------------- - -void ConfigMetricsServer::remove(void) -{ - delete data; - data = 0; -} - -//----------------------------------------------------------------------- - +// ConfigMetricsServer.cpp +// copyright 2000 Verant Interactive +// Author: Justin Randall + + +//----------------------------------------------------------------------- + +#include "FirstMetricsServer.h" +#include "sharedFoundation/ConfigFile.h" +#include "ConfigMetricsServer.h" + +//----------------------------------------------------------------------- + +ConfigMetricsServer::Data * ConfigMetricsServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("MetricsServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("MetricsServer", #a, b)) +#define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("MetricsServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("MetricsServer", #a, b)) + +//----------------------------------------------------------------------- + +void ConfigMetricsServer::install(void) +{ + data = new ConfigMetricsServer::Data; + + KEY_STRING(authenticationFileName, "../../exe/shared/metricsAuthentication.cfg"); + KEY_STRING(clusterName, "DevCluster"); + KEY_INT(metricsListenerPort, 2200); + KEY_INT(metricsServicePort, 44480); + KEY_BOOL(runTestStats, false); + KEY_INT(taskManagerPort, 60001); + KEY_STRING(metricsServiceBindInterface, ""); +} + +//----------------------------------------------------------------------- + +void ConfigMetricsServer::remove(void) +{ + delete data; + data = 0; +} + +//----------------------------------------------------------------------- + diff --git a/src/engine/server/application/PlanetServer/src/shared/ConfigPlanetServer.cpp b/src/engine/server/application/PlanetServer/src/shared/ConfigPlanetServer.cpp index 9ba0eca3d..85e2c38ee 100644 --- a/src/engine/server/application/PlanetServer/src/shared/ConfigPlanetServer.cpp +++ b/src/engine/server/application/PlanetServer/src/shared/ConfigPlanetServer.cpp @@ -1,97 +1,97 @@ -// ====================================================================== -// -// ConfigPlanetServer.cpp -// copyright (c) 2001 Sony Online Entertainment -// -// ====================================================================== - -#include "FirstPlanetServer.h" -#include "ConfigPlanetServer.h" -#include "QuadtreeNode.h" -#include "serverUtility/ConfigServerUtility.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/ExitChain.h" - -//----------------------------------------------------------------------- - -ConfigPlanetServer::Data * ConfigPlanetServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("PlanetServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("PlanetServer", #a, b)) -//#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("PlanetServer", #a, b)) // commented out for Lint. Uncomment if you need this macro again -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("PlanetServer", #a, b)) - -// ====================================================================== - -void ConfigPlanetServer::install(void) -{ - - ConfigServerUtility::install(); - ExitChain::add(&remove, "ConfigPlanetServer::remove"); - - data = new ConfigPlanetServer::Data; - - KEY_STRING (centralServerAddress, "localhost"); - KEY_INT (centralServerPort, 44455); - KEY_STRING (sceneID, "default"); - KEY_INT (gameServicePort, 0); - KEY_INT (taskManagerPort, 60001); - KEY_INT (watcherServicePort, 60002); - KEY_INT (maxWatcherConnections, 1); - KEY_INT (watcherOverflowLimit, 1024 * 1024 * 8); // 8MB overflow for CS PlanetWatcher tool - KEY_BOOL (logObjectLoading, false); - KEY_INT (maxWatcherUpdatesPerMessage,500); // Max object updates to send to the watcher in a single message - KEY_STRING (gameServiceBindInterface, ""); - KEY_STRING (watcherServiceBindInterface, ""); - KEY_BOOL (loadWholePlanet, false); - KEY_BOOL (loadWholePlanetMultiserver, false); - KEY_BOOL (logPreloading, false); - KEY_INT (numTutorialServers, 1); - KEY_INT (maxInterestRadius, Node::getNodeSize()); - KEY_INT (populationCountTime, 60); // seconds - KEY_BOOL (logChunkLoading, false); - KEY_INT (preloadBailoutTime, 0); // seconds - KEY_STRING (preloadDataTableName, "datatables/planet_server/preload_list.iff"); - KEY_INT (authTransferSanityCheckTimeMs, 15000); - KEY_INT (gameServerRestartDelayTimeSeconds, 60); - KEY_BOOL (enableContentsChecking, false); - KEY_INT (maxGameServers, 0); - KEY_BOOL (enableStartupCreateProxies, true); - KEY_BOOL (requestDbSaveOnGameServerCrash, true); - KEY_BOOL (gameServerProfiling, false); - KEY_BOOL (gameServerDebugging, false); - KEY_INT (gameServerDebuggingPortBase, 0); - KEY_INT (maxTimeToWaitForGameServerStartSeconds, 5*60); // seconds -} - -//----------------------------------------------------------------------- - -bool ConfigPlanetServer::getGameServerProfiling() -{ - return data->gameServerProfiling; -} - -//----------------------------------------------------------------------- - -bool ConfigPlanetServer::getGameServerDebugging() -{ - return data->gameServerDebugging; -} - -//----------------------------------------------------------------------- - -void ConfigPlanetServer::remove(void) -{ - delete data; - data = 0; - ConfigServerUtility::remove(); -} - -//----------------------------------------------------------------------- - -int ConfigPlanetServer::getGameServerDebuggingPortBase() -{ - return data->gameServerDebuggingPortBase; -} - -//----------------------------------------------------------------------- +// ====================================================================== +// +// ConfigPlanetServer.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "FirstPlanetServer.h" +#include "ConfigPlanetServer.h" +#include "QuadtreeNode.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ExitChain.h" + +//----------------------------------------------------------------------- + +ConfigPlanetServer::Data * ConfigPlanetServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("PlanetServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("PlanetServer", #a, b)) +//#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("PlanetServer", #a, b)) // commented out for Lint. Uncomment if you need this macro again +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("PlanetServer", #a, b)) + +// ====================================================================== + +void ConfigPlanetServer::install(void) +{ + + ConfigServerUtility::install(); + ExitChain::add(&remove, "ConfigPlanetServer::remove"); + + data = new ConfigPlanetServer::Data; + + KEY_STRING (centralServerAddress, "localhost"); + KEY_INT (centralServerPort, 44455); + KEY_STRING (sceneID, "default"); + KEY_INT (gameServicePort, 0); + KEY_INT (taskManagerPort, 60001); + KEY_INT (watcherServicePort, 60002); + KEY_INT (maxWatcherConnections, 1); + KEY_INT (watcherOverflowLimit, 1024 * 1024 * 8); // 8MB overflow for CS PlanetWatcher tool + KEY_BOOL (logObjectLoading, false); + KEY_INT (maxWatcherUpdatesPerMessage,500); // Max object updates to send to the watcher in a single message + KEY_STRING (gameServiceBindInterface, ""); + KEY_STRING (watcherServiceBindInterface, ""); + KEY_BOOL (loadWholePlanet, false); + KEY_BOOL (loadWholePlanetMultiserver, false); + KEY_BOOL (logPreloading, false); + KEY_INT (numTutorialServers, 1); + KEY_INT (maxInterestRadius, Node::getNodeSize()); + KEY_INT (populationCountTime, 60); // seconds + KEY_BOOL (logChunkLoading, false); + KEY_INT (preloadBailoutTime, 0); // seconds + KEY_STRING (preloadDataTableName, "datatables/planet_server/preload_list.iff"); + KEY_INT (authTransferSanityCheckTimeMs, 15000); + KEY_INT (gameServerRestartDelayTimeSeconds, 60); + KEY_BOOL (enableContentsChecking, false); + KEY_INT (maxGameServers, 0); + KEY_BOOL (enableStartupCreateProxies, true); + KEY_BOOL (requestDbSaveOnGameServerCrash, true); + KEY_BOOL (gameServerProfiling, false); + KEY_BOOL (gameServerDebugging, false); + KEY_INT (gameServerDebuggingPortBase, 0); + KEY_INT (maxTimeToWaitForGameServerStartSeconds, 5*60); // seconds +} + +//----------------------------------------------------------------------- + +bool ConfigPlanetServer::getGameServerProfiling() +{ + return data->gameServerProfiling; +} + +//----------------------------------------------------------------------- + +bool ConfigPlanetServer::getGameServerDebugging() +{ + return data->gameServerDebugging; +} + +//----------------------------------------------------------------------- + +void ConfigPlanetServer::remove(void) +{ + delete data; + data = 0; + ConfigServerUtility::remove(); +} + +//----------------------------------------------------------------------- + +int ConfigPlanetServer::getGameServerDebuggingPortBase() +{ + return data->gameServerDebuggingPortBase; +} + +//----------------------------------------------------------------------- diff --git a/src/engine/server/application/ServerConsole/src/shared/ConfigServerConsole.cpp b/src/engine/server/application/ServerConsole/src/shared/ConfigServerConsole.cpp index cc3d96cf2..539552755 100644 --- a/src/engine/server/application/ServerConsole/src/shared/ConfigServerConsole.cpp +++ b/src/engine/server/application/ServerConsole/src/shared/ConfigServerConsole.cpp @@ -1,68 +1,68 @@ -// ConfigServerConsole.cpp -// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. -// Author: Justin Randall - -//----------------------------------------------------------------------- - -#include "FirstServerConsole.h" -#include "sharedFoundation/ConfigFile.h" -#include "ConfigServerConsole.h" - - -//----------------------------------------------------------------------- - -namespace ConfigServerConsoleNamespace -{ - const char * serverAddress; - int serverPort; -} - -using namespace ConfigServerConsoleNamespace; - -#define KEY_INT(a,b) (a = ConfigFile::getKeyInt("ServerConsole", #a, b)) -#define KEY_BOOL(a,b) (a = ConfigFile::getKeyBool("ServerConsole", #a, b)) -// #define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("LoginServer", #a, b)) -#define KEY_STRING(a,b) (a = ConfigFile::getKeyString("ServerConsole", #a, b)) - -//----------------------------------------------------------------------- - -ConfigServerConsole::ConfigServerConsole() -{ -} - -//----------------------------------------------------------------------- - -ConfigServerConsole::~ConfigServerConsole() -{ -} - -//----------------------------------------------------------------------- - -const char * const ConfigServerConsole::getServerAddress() -{ - return serverAddress; -} - -//----------------------------------------------------------------------- - -unsigned short ConfigServerConsole::getServerPort() -{ - return static_cast(serverPort); -} - -//----------------------------------------------------------------------- - -void ConfigServerConsole::install() -{ - KEY_STRING(serverAddress, "127.0.0.1"); - KEY_INT(serverPort, 61000); -} - -//----------------------------------------------------------------------- - -void ConfigServerConsole::remove() -{ -} - -//----------------------------------------------------------------------- - +// ConfigServerConsole.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstServerConsole.h" +#include "sharedFoundation/ConfigFile.h" +#include "ConfigServerConsole.h" + + +//----------------------------------------------------------------------- + +namespace ConfigServerConsoleNamespace +{ + const char * serverAddress; + int serverPort; +} + +using namespace ConfigServerConsoleNamespace; + +#define KEY_INT(a,b) (a = ConfigFile::getKeyInt("ServerConsole", #a, b)) +#define KEY_BOOL(a,b) (a = ConfigFile::getKeyBool("ServerConsole", #a, b)) +// #define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("LoginServer", #a, b)) +#define KEY_STRING(a,b) (a = ConfigFile::getKeyString("ServerConsole", #a, b)) + +//----------------------------------------------------------------------- + +ConfigServerConsole::ConfigServerConsole() +{ +} + +//----------------------------------------------------------------------- + +ConfigServerConsole::~ConfigServerConsole() +{ +} + +//----------------------------------------------------------------------- + +const char * const ConfigServerConsole::getServerAddress() +{ + return serverAddress; +} + +//----------------------------------------------------------------------- + +unsigned short ConfigServerConsole::getServerPort() +{ + return static_cast(serverPort); +} + +//----------------------------------------------------------------------- + +void ConfigServerConsole::install() +{ + KEY_STRING(serverAddress, "127.0.0.1"); + KEY_INT(serverPort, 61000); +} + +//----------------------------------------------------------------------- + +void ConfigServerConsole::remove() +{ +} + +//----------------------------------------------------------------------- + diff --git a/src/engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp b/src/engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp index 1f64c9cd3..20c68e81f 100644 --- a/src/engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp +++ b/src/engine/server/application/TaskManager/src/shared/ConfigTaskManager.cpp @@ -1,108 +1,108 @@ -// ConfigTaskManager.cpp -// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. -// Author: Justin Randall - -//----------------------------------------------------------------------- - -#include "FirstTaskManager.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedNetwork/SetupSharedNetwork.h" -#include "ConfigTaskManager.h" - -#include - -//----------------------------------------------------------------------- - -ConfigTaskManager::Data * ConfigTaskManager::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("TaskManager", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("TaskManager", #a, b)) -#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("TaskManager", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("TaskManager", #a, b)) - -//----------------------------------------------------------------------- - -namespace ConfigTaskManagerNamespace -{ - typedef std::vector StringPtrArray; - StringPtrArray ms_environmentVariable; // ConfigFile owns the pointer -} - -using namespace ConfigTaskManagerNamespace; - -// ====================================================================== - -int ConfigTaskManager::getNumberOfEnvironmentVariables() -{ - return static_cast(ms_environmentVariable.size()); -} - -// ---------------------------------------------------------------------- - -char const * ConfigTaskManager::getEnvironmentVariable(int index) -{ - VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfEnvironmentVariables()); - return ms_environmentVariable[static_cast(index)]; -} - -// ---------------------------------------------------------------------- - -void ConfigTaskManager::install(void) -{ - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - SetupSharedNetwork::install(networkSetupData); - - data = new ConfigTaskManager::Data; - - KEY_BOOL (autoStart, true); - KEY_STRING (clusterName, "devcluster"); - KEY_BOOL (verifyClusterName, false); - KEY_INT (gameServerTimeout, 600); - KEY_STRING (gameServiceBindInterface, ""); - KEY_INT (gameServicePort, 60001); - KEY_INT (consoleConnectionPort, 60000); - KEY_STRING (consoleServiceBindInterface, ""); - KEY_STRING (loginServerAddress, "localhost"); - KEY_INT (loginServerTaskServicePort, 44459); - KEY_FLOAT (maximumLoad, 3.0f); - KEY_FLOAT (loadConnectionServer, 0.5f); - KEY_FLOAT (loadPlanetServer, 0.128f); - KEY_FLOAT (loadGameServer, 1.0f); - KEY_BOOL (publishMode, false); - KEY_STRING (rcFileName, "taskmanager.rc"); - KEY_BOOL (restartCentral, false); - KEY_INT (restartDelayCentralServer, 60); // seconds - KEY_INT (restartDelayLogServer, 30); - KEY_INT (restartDelayMetricsServer, 60); - KEY_INT (restartDelayCommoditiesServer, 60); - KEY_INT (restartDelayTransferServer, 30); - KEY_STRING (taskManagerServiceBindInterface, ""); - KEY_INT (taskManagerServicePort, 50001); - KEY_INT (maximumClockDriftToleranceSeconds, 10); // seconds - KEY_INT (systemTimeCheckIntervalSeconds, 60); // seconds - KEY_INT (clockDriftFatalIntervalSeconds, 1*60*60); // seconds - - int index = 0; - char const * result = 0; - do - { - result = ConfigFile::getKeyString("TaskManager", "environmentVariable", index++, 0); - if (result != 0) - { - ms_environmentVariable.push_back(result); - } - } - while (result); -} - -//----------------------------------------------------------------------- - -void ConfigTaskManager::remove(void) -{ - delete data; - data = 0; -} - -//----------------------------------------------------------------------- - +// ConfigTaskManager.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTaskManager.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigTaskManager.h" + +#include + +//----------------------------------------------------------------------- + +ConfigTaskManager::Data * ConfigTaskManager::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("TaskManager", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("TaskManager", #a, b)) +#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("TaskManager", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("TaskManager", #a, b)) + +//----------------------------------------------------------------------- + +namespace ConfigTaskManagerNamespace +{ + typedef std::vector StringPtrArray; + StringPtrArray ms_environmentVariable; // ConfigFile owns the pointer +} + +using namespace ConfigTaskManagerNamespace; + +// ====================================================================== + +int ConfigTaskManager::getNumberOfEnvironmentVariables() +{ + return static_cast(ms_environmentVariable.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigTaskManager::getEnvironmentVariable(int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfEnvironmentVariables()); + return ms_environmentVariable[static_cast(index)]; +} + +// ---------------------------------------------------------------------- + +void ConfigTaskManager::install(void) +{ + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + data = new ConfigTaskManager::Data; + + KEY_BOOL (autoStart, true); + KEY_STRING (clusterName, "devcluster"); + KEY_BOOL (verifyClusterName, false); + KEY_INT (gameServerTimeout, 600); + KEY_STRING (gameServiceBindInterface, ""); + KEY_INT (gameServicePort, 60001); + KEY_INT (consoleConnectionPort, 60000); + KEY_STRING (consoleServiceBindInterface, ""); + KEY_STRING (loginServerAddress, "localhost"); + KEY_INT (loginServerTaskServicePort, 44459); + KEY_FLOAT (maximumLoad, 3.0f); + KEY_FLOAT (loadConnectionServer, 0.5f); + KEY_FLOAT (loadPlanetServer, 0.128f); + KEY_FLOAT (loadGameServer, 1.0f); + KEY_BOOL (publishMode, false); + KEY_STRING (rcFileName, "taskmanager.rc"); + KEY_BOOL (restartCentral, false); + KEY_INT (restartDelayCentralServer, 60); // seconds + KEY_INT (restartDelayLogServer, 30); + KEY_INT (restartDelayMetricsServer, 60); + KEY_INT (restartDelayCommoditiesServer, 60); + KEY_INT (restartDelayTransferServer, 30); + KEY_STRING (taskManagerServiceBindInterface, ""); + KEY_INT (taskManagerServicePort, 50001); + KEY_INT (maximumClockDriftToleranceSeconds, 10); // seconds + KEY_INT (systemTimeCheckIntervalSeconds, 60); // seconds + KEY_INT (clockDriftFatalIntervalSeconds, 1*60*60); // seconds + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("TaskManager", "environmentVariable", index++, 0); + if (result != 0) + { + ms_environmentVariable.push_back(result); + } + } + while (result); +} + +//----------------------------------------------------------------------- + +void ConfigTaskManager::remove(void) +{ + delete data; + data = 0; +} + +//----------------------------------------------------------------------- + diff --git a/src/engine/server/application/TransferServer/src/shared/ConfigTransferServer.cpp b/src/engine/server/application/TransferServer/src/shared/ConfigTransferServer.cpp index 7f62fee02..fcff5b325 100644 --- a/src/engine/server/application/TransferServer/src/shared/ConfigTransferServer.cpp +++ b/src/engine/server/application/TransferServer/src/shared/ConfigTransferServer.cpp @@ -1,137 +1,137 @@ -// ConfigTransferServer.cpp -// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. -// Author: Justin Randall - -//----------------------------------------------------------------------- - -#include "FirstTransferServer.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedNetwork/SetupSharedNetwork.h" -#include "ConfigTransferServer.h" - -#include - -//----------------------------------------------------------------------- - -ConfigTransferServer::Data * ConfigTransferServer::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("TransferServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("TransferServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("TransferServer", #a, b)) - -//----------------------------------------------------------------------- - -namespace ConfigTransferServerNamespace -{ - std::vector s_serversAllowedToUploadCharacterData; - std::vector s_serversAllowedToDownloadCharacterData; -} - -using namespace ConfigTransferServerNamespace; - -// ---------------------------------------------------------------------- - -const std::vector & ConfigTransferServer::getServersAllowedToUploadCharacterData() -{ - return s_serversAllowedToUploadCharacterData; -} - -// ---------------------------------------------------------------------- - -const std::vector & ConfigTransferServer::getServersAllowedToDownloadCharacterData() -{ - return s_serversAllowedToDownloadCharacterData; -} - -// ---------------------------------------------------------------------- - -void ConfigTransferServer::install(void) -{ - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - - data = new ConfigTransferServer::Data; - - KEY_INT (centralServerServiceBindPort, 50005); - KEY_STRING (centralServerServiceBindInterface, ""); - KEY_BOOL (allowSameServerTransfers, false); - KEY_BOOL (allowAccountTransfers, true); - KEY_STRING (apiServerHostAddress, ""); - KEY_BOOL (transferChatAvatar, false); - - int index = 0; - char const * result = 0; - do - { - result = ConfigFile::getKeyString("TransferServer", "serverAllowedToUploadCharacterData", index++, 0); - if (result != 0) - { - s_serversAllowedToUploadCharacterData.push_back(result); - } - } - while (result); - - index = 0; - result = 0; - do - { - result = ConfigFile::getKeyString("TransferServer", "serverAllowedToDownloadCharacterData", index++, 0); - if (result != 0) - { - s_serversAllowedToDownloadCharacterData.push_back(result); - } - } - while (result); -} - -//----------------------------------------------------------------------- - -void ConfigTransferServer::remove(void) -{ - delete data; - data = 0; -} - -//----------------------------------------------------------------------- - -unsigned short ConfigTransferServer::getCentralServerServiceBindPort() -{ - return static_cast(data->centralServerServiceBindPort); -} - -//----------------------------------------------------------------------- - -const char * ConfigTransferServer::getCentralServerServiceBindInterface() -{ - return data->centralServerServiceBindInterface; -} - -//----------------------------------------------------------------------- - -bool ConfigTransferServer::getAllowSameServerTransfers() -{ - return data->allowSameServerTransfers; -} - -//----------------------------------------------------------------------- - -bool ConfigTransferServer::getAllowAccountTransfers() -{ - return data->allowAccountTransfers; -} - -//----------------------------------------------------------------------- - -const char * ConfigTransferServer::getApiServerHostAddress() -{ - return data->apiServerHostAddress; -} - -//----------------------------------------------------------------------- - -const bool ConfigTransferServer::getTransferChatAvatar() -{ - return data->transferChatAvatar; -} - -//----------------------------------------------------------------------- +// ConfigTransferServer.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstTransferServer.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "ConfigTransferServer.h" + +#include + +//----------------------------------------------------------------------- + +ConfigTransferServer::Data * ConfigTransferServer::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("TransferServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("TransferServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("TransferServer", #a, b)) + +//----------------------------------------------------------------------- + +namespace ConfigTransferServerNamespace +{ + std::vector s_serversAllowedToUploadCharacterData; + std::vector s_serversAllowedToDownloadCharacterData; +} + +using namespace ConfigTransferServerNamespace; + +// ---------------------------------------------------------------------- + +const std::vector & ConfigTransferServer::getServersAllowedToUploadCharacterData() +{ + return s_serversAllowedToUploadCharacterData; +} + +// ---------------------------------------------------------------------- + +const std::vector & ConfigTransferServer::getServersAllowedToDownloadCharacterData() +{ + return s_serversAllowedToDownloadCharacterData; +} + +// ---------------------------------------------------------------------- + +void ConfigTransferServer::install(void) +{ + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + + data = new ConfigTransferServer::Data; + + KEY_INT (centralServerServiceBindPort, 50005); + KEY_STRING (centralServerServiceBindInterface, ""); + KEY_BOOL (allowSameServerTransfers, false); + KEY_BOOL (allowAccountTransfers, true); + KEY_STRING (apiServerHostAddress, ""); + KEY_BOOL (transferChatAvatar, false); + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("TransferServer", "serverAllowedToUploadCharacterData", index++, 0); + if (result != 0) + { + s_serversAllowedToUploadCharacterData.push_back(result); + } + } + while (result); + + index = 0; + result = 0; + do + { + result = ConfigFile::getKeyString("TransferServer", "serverAllowedToDownloadCharacterData", index++, 0); + if (result != 0) + { + s_serversAllowedToDownloadCharacterData.push_back(result); + } + } + while (result); +} + +//----------------------------------------------------------------------- + +void ConfigTransferServer::remove(void) +{ + delete data; + data = 0; +} + +//----------------------------------------------------------------------- + +unsigned short ConfigTransferServer::getCentralServerServiceBindPort() +{ + return static_cast(data->centralServerServiceBindPort); +} + +//----------------------------------------------------------------------- + +const char * ConfigTransferServer::getCentralServerServiceBindInterface() +{ + return data->centralServerServiceBindInterface; +} + +//----------------------------------------------------------------------- + +bool ConfigTransferServer::getAllowSameServerTransfers() +{ + return data->allowSameServerTransfers; +} + +//----------------------------------------------------------------------- + +bool ConfigTransferServer::getAllowAccountTransfers() +{ + return data->allowAccountTransfers; +} + +//----------------------------------------------------------------------- + +const char * ConfigTransferServer::getApiServerHostAddress() +{ + return data->apiServerHostAddress; +} + +//----------------------------------------------------------------------- + +const bool ConfigTransferServer::getTransferChatAvatar() +{ + return data->transferChatAvatar; +} + +//----------------------------------------------------------------------- diff --git a/src/engine/server/library/codegen/package_data.txt b/src/engine/server/library/codegen/package_data.txt index 2a3af5e58..296a24f04 100644 --- a/src/engine/server/library/codegen/package_data.txt +++ b/src/engine/server/library/codegen/package_data.txt @@ -1,614 +1,614 @@ -#TODO: get rid of "Cached" because it makes no sense for DBProcess -#A class with '-' denotes the class does not have any persisted variables. - -#class parent -ServerObject -BuildingObject TangibleObject -CellObject ServerObject -CreatureObject TangibleObject -FactoryObject TangibleObject -HarvesterInstallationObject InstallationObject -InstallationObject TangibleObject -IntangibleObject ServerObject -ManufactureInstallationObject InstallationObject -ManufactureSchematicObject IntangibleObject -MissionObject IntangibleObject -PlanetObject UniverseObject -PlayerObject IntangibleObject -ResourceContainerObject TangibleObject -ShipObject TangibleObject -StaticObject ServerObject -TangibleObject ServerObject -UniverseObject ServerObject -VehicleObject TangibleObject -WeaponObject TangibleObject --GroupObject UniverseObject -GuildObject UniverseObject -BattlefieldMarkerObject TangibleObject -CityObject UniverseObject -PlayerQuestObject TangibleObject -end - -#Note: The datatype in the following table is the datatype to use in SwgDatabaseServer. Therefore, use NetworkId instead of CachedNetworkId, etc. -#Note: The parser for this file uses spaces as separators. Be careful not to put extra spaces in commands. - -#class member name package datatype add-to-package command persist function load function - -BuildingObject m_allowed server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data); decodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data,isBaseline); -BuildingObject m_banned server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Banned,data); decodePropertyList(objectId,PropertyListBuffer::LI_Banned,data,isBaseline); -BuildingObject m_isPublic server bool -BuildingObject m_maintenanceCost server int -BuildingObject m_timeLastChecked server real -BuildingObject m_cityId server int -BuildingObject m_contentsLoaded server_np bool - -CellObject m_allowed server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data); decodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data,isBaseline); -CellObject m_banned server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Banned,data); decodePropertyList(objectId,PropertyListBuffer::LI_Banned,data,isBaseline); -CellObject m_isPublic shared bool -CellObject m_cellNumber shared int -CellObject m_cellLabel shared_np Unicode::String -CellObject m_labelLocationOffset shared_np Vector - -CreatureObject m_maxAttributes authClientServer Attributes::Value - encodeAttributes(objectId,data,9); decodeAttributes(objectId,data,isBaseline,9); -CreatureObject m_skills authClientServer SkillObject* - encodePropertyList(objectId,PropertyListBuffer::LI_Skills,data); decodePropertyList(objectId,PropertyListBuffer::LI_Skills,data,isBaseline); - -CreatureObject m_accelPercent authClientServer_np float -CreatureObject m_accelScale authClientServer_np float -CreatureObject m_attribBonus authClientServer_np std::vector -CreatureObject m_modMap authClientServer_np map -CreatureObject m_movementPercent authClientServer_np float -CreatureObject m_movementScale authClientServer_np float -CreatureObject m_performanceListenTarget authClientServer_np NetworkId -CreatureObject m_runSpeed authClientServer_np float -CreatureObject m_slopeModAngle authClientServer_np float -CreatureObject m_slopeModPercent authClientServer_np float -CreatureObject m_turnScale authClientServer_np float -CreatureObject m_walkSpeed authClientServer_np float -CreatureObject m_waterModPercent authClientServer_np float -CreatureObject m_notifyRegions server_np set -CreatureObject m_missionCriticalObjectSet server_np set -CreatureObject m_groupMissionCriticalObjectSet authClientServer_np set -CreatureObject m_commands authClientServer_np std::map - -CreatureObject m_attributes server Attributes::Value - encodeAttributes(objectId,data,0); decodeAttributes(objectId,data,isBaseline,0); -CreatureObject m_baseRunSpeed server float -CreatureObject m_baseWalkSpeed server float -CreatureObject m_persistedBuffs server packed_map - encodePersistedBuffs(data,row->persisted_buffs); decodePersistedBuffs(data,row->persisted_buffs); - -CreatureObject m_attributeModList server_np std::vector -CreatureObject m_baseSlopeModPercent server_np float -CreatureObject m_cachedCurrentAttributeModValues server_np std::vector -CreatureObject m_cachedMaxAttributeModValues server_np std::vector -CreatureObject m_commandQueue server_np commandqueue getCommandQueue()->addToPackage(m_serverPackage_np); -CreatureObject m_cover server_np int -CreatureObject m_currentAttitude server_np Attitude -CreatureObject m_isStatic server_np bool -CreatureObject m_lastBehavior server_np int -CreatureObject m_lastMonitorReportPosition server_np Vector -CreatureObject m_locomotion server_np Locomotions::Enumerator -CreatureObject m_maxMentalStates server_np MentalStates::Value -CreatureObject m_mentalStateDecays server_np float -CreatureObject m_mentalStatesToward server_np map -CreatureObject m_monitoredCreatureMovements server_np map -CreatureObject m_performanceWatchTarget server_np NetworkId -CreatureObject m_stopWalkRun server_np int -CreatureObject m_timeToUpdateGuildWarPvpStatus server_np uint32 -CreatureObject m_guildWarEnabled server_np bool -CreatureObject m_militiaOfCityId server_np int -CreatureObject m_locatedInCityId server_np int -CreatureObject m_invulnerabilityTimer server_np float -CreatureObject m_allowSARegen server_np bool -CreatureObject m_totalLevelXp authClientServer_np int - -CreatureObject m_posture shared Postures::Enumerator -CreatureObject m_rank shared uint8 -CreatureObject m_masterId shared NetworkId -CreatureObject m_scaleFactor shared float -CreatureObject m_shockWounds shared int -CreatureObject m_states shared uint64 -CreatureObject m_level shared_np int16 -CreatureObject m_levelHealthGranted shared_np int -CreatureObject m_animatingSkillData shared_np std::string -CreatureObject m_animationMood shared_np std::string -CreatureObject m_currentWeapon shared_np NetworkId -CreatureObject m_group shared_np NetworkId -CreatureObject m_groupInviter shared_np NetworkId -CreatureObject m_inviterForPendingGroup server_np NetworkId -CreatureObject m_guildId shared_np int -CreatureObject m_lookAtTarget shared_np NetworkId -CreatureObject m_intendedTarget shared_np NetworkId -CreatureObject m_mood shared_np char -CreatureObject m_performanceStartTime shared_np int -CreatureObject m_performanceType shared_np int -CreatureObject m_totalAttributes shared_np Attributes::Value - encodeAttributes(objectId,data,0); decodeAttributes(objectId,data,isBaseline,0); -CreatureObject m_totalMaxAttributes shared_np Attributes::Value - encodeAttributes(objectId,data,9); decodeAttributes(objectId,data,isBaseline,9); -CreatureObject m_wearableData shared_np vector -CreatureObject m_alternateAppearanceSharedObjectTemplateName shared_np std::string -CreatureObject m_timedMod server_np std::vector -CreatureObject m_timedModDuration server_np std::vector -CreatureObject m_timedModUpdateTime server_np std::vector -CreatureObject m_coverVisibility shared_np bool -CreatureObject m_buffs shared_np map - -CreatureObject m_loiterRange none float -CreatureObject m_animState none char -CreatureObject m_sayMode none char - -CreatureObject m_clientUsesAnimationLocomotion shared_np bool -CreatureObject m_difficulty shared_np char -CreatureObject m_hologramType shared_np int32 -CreatureObject m_visibleOnMapAndRadar shared_np bool -CreatureObject m_wsX server float -CreatureObject m_wsY server float -CreatureObject m_wsZ server float - -CreatureObject m_isBeast shared_np bool -CreatureObject m_forceShowHam shared_np bool -CreatureObject m_wearableAppearanceData shared_np vector -CreatureObject m_decoyOrigin shared_np NetworkId - -FactoryObject m_craftingCount server_np int -FactoryObject m_craftingSchematic server_np NetworkId -FactoryObject m_attributes server_np std::map - -HarvesterInstallationObject m_installedEfficiency server float -HarvesterInstallationObject m_resourceType server NetworkId -HarvesterInstallationObject m_maxExtractionRate server int -HarvesterInstallationObject m_currentExtractionRate server float -HarvesterInstallationObject m_maxHopperAmount server int -HarvesterInstallationObject m_hopperResource server NetworkId -HarvesterInstallationObject m_hopperAmount server float - -InstallationObject m_installationType server int32 -InstallationObject m_tickCount server float -InstallationObject m_activateStartTime server float -InstallationObject m_activated shared bool -InstallationObject m_power shared float -InstallationObject m_powerRate shared float - -IntangibleObject m_crcs server_np std::vector -IntangibleObject m_positions server_np std::vector -IntangibleObject m_headings server_np std::vector -IntangibleObject m_scripts server_np std::vector -IntangibleObject m_player server_np NetworkId -IntangibleObject m_objects server_np std::vector -IntangibleObject m_center server_np Vector -IntangibleObject m_radius server_np float -IntangibleObject m_creator server_np NetworkId -IntangibleObject m_theaterName server_np std::string -IntangibleObject m_count shared int - -ManufactureSchematicObject m_draftSchematic server int -ManufactureSchematicObject m_creatorId server NetworkId -ManufactureSchematicObject m_creatorName server Unicode::String -ManufactureSchematicObject m_factories server_np std::vector -ManufactureSchematicObject m_resourceMaxAttributes server_np std::map - -ManufactureSchematicObject m_attributes shared std::map - encodeManufactureSchematicAttributes(objectId,data); decodeManufactureSchematicAttributes(objectId,data,isBaseline); -ManufactureSchematicObject m_itemsPerContainer shared int -ManufactureSchematicObject m_manufactureTime shared float -ManufactureSchematicObject m_appearanceData shared_np std::string -ManufactureSchematicObject m_customAppearance shared_np std::string -ManufactureSchematicObject m_draftSchematicSharedTemplate shared_np std::string -ManufactureSchematicObject m_isCrafting shared_np bool -ManufactureSchematicObject m_schematicChangedSignal shared_np char - -MissionObject m_difficulty shared int -MissionObject m_endLocation shared Location - encodeLocation(data,row->end_x,row->end_y,row->end_z,row->end_cell,row->end_scene); decodeLocation(data,row->end_x,row->end_y,row->end_z,row->end_cell,row->end_scene); -MissionObject m_missionCreator shared Unicode::String -MissionObject m_reward shared int -MissionObject m_rootScriptName server std::string -MissionObject m_startLocation shared Location - encodeLocation(data,row->start_x,row->start_y,row->start_z,row->start_cell,row->start_scene); decodeLocation(data,row->start_x,row->start_y,row->start_z,row->start_cell,row->start_scene); -MissionObject m_targetAppearance shared uint32 -MissionObject m_description shared StringId - encodeStringId(data,row->description_table,row->description_text); decodeStringId(data,row->description_table,row->description_text); -MissionObject m_title shared StringId - encodeStringId(data,row->title_table,row->title_text); decodeStringId(data,row->title_table,row->title_text); -MissionObject m_missionHolderId server NetworkId -MissionObject m_status shared int -MissionObject m_missionType shared uint32 -MissionObject m_targetName shared std::string -MissionObject m_waypoint shared map - encodeSingleWaypoint(objectId,data); decodeSingleWaypoint(objectId,data,isBaseline); - -PlanetObject m_planetName server std::string -PlanetObject m_travelPointList server_np TravelPoint* -PlanetObject m_weatherIndex server_np int -PlanetObject m_windVelocityX server_np float -PlanetObject m_windVelocityY server_np float -PlanetObject m_windVelocityZ server_np float -PlanetObject m_mapLocationMapStatic server_np map -PlanetObject m_mapLocationMapDynamic server_np map -PlanetObject m_mapLocationMapPersist server_np map -PlanetObject m_mapLocationVersionStatic server_np int -PlanetObject m_mapLocationVersionDynamic server_np int -PlanetObject m_mapLocationVersionPersist server_np int -PlanetObject m_collectionServerFirst server_np set -PlanetObject m_collectionServerFirstUpdateNumber server_np int -PlanetObject m_connectedCharacterLfgData server_np map -PlanetObject m_connectedCharacterLfgDataFactionalPresence server_np map -PlanetObject m_connectedCharacterLfgDataFactionalPresenceGrid server_np map -PlanetObject m_connectedCharacterBiographyData server_np map -PlanetObject m_currentEvents server_np std::string -PlanetObject m_gcwImperialScore server_np map -PlanetObject m_gcwRebelScore server_np map - -PlayerObject m_craftingLevel firstParentAuthClientServer_np int -PlayerObject m_craftingStage firstParentAuthClientServer_np int -PlayerObject m_craftingStation firstParentAuthClientServer_np NetworkId -PlayerObject m_draftSchematics firstParentAuthClientServer_np std::map,int> -PlayerObject m_craftingComponentBioLink firstParentAuthClientServer_np NetworkId -PlayerObject m_experimentPoints firstParentAuthClientServer_np int -PlayerObject m_expModified firstParentAuthClientServer_np int -PlayerObject m_friendList firstParentAuthClientServer_np std::vector -PlayerObject m_ignoreList firstParentAuthClientServer_np std::vector -PlayerObject m_spokenLanguage firstParentAuthClientServer_np int -PlayerObject m_food firstParentAuthClientServer_np int -PlayerObject m_maxFood firstParentAuthClientServer_np int -PlayerObject m_drink firstParentAuthClientServer_np int -PlayerObject m_maxDrink firstParentAuthClientServer_np int -PlayerObject m_meds firstParentAuthClientServer_np int -PlayerObject m_maxMeds firstParentAuthClientServer_np int -PlayerObject m_groupWaypoints firstParentAuthClientServer_np map - encodeWaypoints(objectId,data); decodeWaypoints(objectId,data,isBaseline); -PlayerObject m_playerHateList firstParentAuthClientServer_np set -PlayerObject m_killMeter firstParentAuthClientServer_np int32 -PlayerObject m_experiencePoints parentClient map - encodeExperience(objectId,data); decodeExperience(objectId,data,isBaseline); -PlayerObject m_waypoints parentClient map - encodeWaypoints(objectId,data); decodeWaypoints(objectId,data,isBaseline); -PlayerObject m_forcePower parentClient int -PlayerObject m_maxForcePower parentClient int -PlayerObject m_completedQuests parentClient BitArray -PlayerObject m_activeQuests parentClient BitArray -PlayerObject m_currentQuest parentClient uint32 -PlayerObject m_quests parentClient packed_map - encodeQuests(data,row->quests,row->quests2,row->quests3,row->quests4); decodeQuests(objectId,data,row->quests,row->quests2,row->quests3,row->quests4); -PlayerObject m_stationId server StationId -PlayerObject m_houseId server NetworkId -PlayerObject m_accountNumLots server int -PlayerObject m_accountNumLotsOverLimitSpam firstParentAuthClientServer_np int -PlayerObject m_accountMaxLotsAdjustment server int -PlayerObject m_accountIsOutcast server bool -PlayerObject m_accountCheaterLevel server float -PlayerObject m_forceRegenRate server float -PlayerObject m_craftingTool server_np NetworkId -PlayerObject m_forceRegenValue server_np float -PlayerObject m_theaterDatatable server_np std::string -PlayerObject m_theaterPosition server_np Vector -PlayerObject m_theaterScene server_np std::string -PlayerObject m_theaterScript server_np std::string -PlayerObject m_theaterNumObjects server_np int -PlayerObject m_theaterRadius server_np float -PlayerObject m_theaterCreator server_np NetworkId -PlayerObject m_theaterName server_np std::string -PlayerObject m_theaterId server_np NetworkId -PlayerObject m_theaterLocationType server_np int -PlayerObject m_matchMakingCharacterProfileId shared MatchMakingId - encodeMatchMakingId(data,row->character_profile_id); decodeMatchMakingId(data,row->character_profile_id); -PlayerObject m_matchMakingPersonalProfileId shared MatchMakingId - encodeMatchMakingId(data,row->personal_profile_id); decodeMatchMakingId(data,row->personal_profile_id); -PlayerObject m_skillTitle shared NullEncodedStandardString -PlayerObject m_bornDate shared int -PlayerObject m_playedTime shared int -PlayerObject m_sessionStartPlayTime server_np int32 -PlayerObject m_sessionLastActiveTime server_np int32 -PlayerObject m_sessionActivePlayTimeDuration server_np uint32 -PlayerObject m_privledgedTitle shared_np int8 -PlayerObject m_roleIconChoice shared int -PlayerObject m_aggroImmuneStartTime server_np uint32 -PlayerObject m_aggroImmuneDuration server_np uint32 -PlayerObject m_skillTemplate shared std::string -PlayerObject m_workingSkill parentClient std::string -PlayerObject m_isFromLogin server_np bool -PlayerObject m_currentGcwPoints shared int32 -PlayerObject m_currentGcwRating server int32 -PlayerObject m_currentPvpKills shared int32 -PlayerObject m_lifetimeGcwPoints shared int64 -PlayerObject m_maxGcwImperialRating server int32 -PlayerObject m_maxGcwRebelRating server int32 -PlayerObject m_lifetimePvpKills shared int32 -PlayerObject m_nextGcwRatingCalcTime server int32 -PlayerObject m_currentGcwRank shared_np int -PlayerObject m_currentGcwRankProgress shared_np float -PlayerObject m_maxGcwImperialRank shared_np int -PlayerObject m_maxGcwRebelRank shared_np int -PlayerObject m_gcwRatingActualCalcTime shared_np int32 -PlayerObject m_sessionActivity server_np uint32 -PlayerObject m_petId firstParentAuthClientServer_np NetworkId -PlayerObject m_petCommandList firstParentAuthClientServer_np std::vector -PlayerObject m_petToggledCommands firstParentAuthClientServer_np std::vector -PlayerObject m_collections shared BitArray -PlayerObject m_collections2 shared BitArray -PlayerObject m_chatSpamSpatialNumCharacters server_np int -PlayerObject m_chatSpamNonSpatialNumCharacters server_np int -PlayerObject m_chatSpamTimeEndInterval server_np int -PlayerObject m_chatSpamNextTimeToSyncWithChatServer server_np int -PlayerObject m_citizenshipCity shared_np std::string -PlayerObject m_citizenshipType shared_np int8 -PlayerObject m_currentGcwRegion server_np std::string -PlayerObject m_cityGcwDefenderRegion shared_np std::pair> -PlayerObject m_guildGcwDefenderRegion shared_np std::pair> -PlayerObject m_squelchedById shared_np NetworkId -PlayerObject m_squelchedByName shared_np std::string -PlayerObject m_squelchExpireTime shared_np int32 -PlayerObject m_showBackpack shared bool -PlayerObject m_showHelmet shared bool -PlayerObject m_environmentFlags shared_np int32 -PlayerObject m_defaultAttackOverride shared_np std::string -PlayerObject m_guildRank firstParentAuthClientServer_np BitArray -PlayerObject m_citizenRank firstParentAuthClientServer_np BitArray -PlayerObject m_galacticReserveDeposit firstParentAuthClientServer_np int8 -PlayerObject m_pgcRatingCount firstParentAuthClientServer_np int64 -PlayerObject m_pgcRatingTotal firstParentAuthClientServer_np int64 -PlayerObject m_pgcLastRatingTime firstParentAuthClientServer_np int - -ResourceContainerObject m_quantity shared int -ResourceContainerObject m_resourceType shared NetworkId -ResourceContainerObject m_source server NetworkId -ResourceContainerObject m_maxQuantity shared_np int -ResourceContainerObject m_parentName shared_np std::string -ResourceContainerObject m_resourceName shared_np Unicode::String -ResourceContainerObject m_resourceNameId shared_np StringId - -ServerObject m_bankBalance authClientServer int -ServerObject m_cashBalance authClientServer int -ServerObject m_cacheVersion server int -ServerObject m_loadContents server bool -ServerObject m_objVarFreeFlags server int ; encodeObjVarFreeFlags(objectId,data); decodeObjVarFreeFlags(objectId,data,isBaseline); -ServerObject m_objVars server objvarlist m_objVars.addToPackage(m_serverPackage,m_serverPackage_np); encodeObjVars(objectId,data); decodeObjVars(objectId,data,isBaseline); -ServerObject m_persisted server bool - Archive::put(data,true); ignorePersistedFlag(objectId,data); -ServerObject m_playerControlled server bool -ServerObject m_sceneId server std::string -ServerObject m_scriptList server std::string m_scriptObject->addToPackage(m_serverPackage); encodeScriptObject(objectId,data); decodeScriptObject(objectId,data,isBaseline); -ServerObject m_attributesAttained server_np BitArray -ServerObject m_attributesInterested server_np BitArray -ServerObject m_proxyServerProcessIds server_np std::vector -ServerObject m_transformSequence server_np uint32 -ServerObject m_triggerVolumeInfo server_np std::vector -ServerObject m_contentsLoaded server_np bool -ServerObject m_contentsRequested server_np bool -ServerObject m_messageTos server_np map -ServerObject m_defaultAlterTime server_np float -ServerObject m_observersCount server_np int -ServerObject m_complexity shared float -ServerObject m_nameStringId shared StringId - encodeStringId(data,row->name_string_table,row->name_string_text); decodeStringId(data,row->name_string_table,row->name_string_text); -ServerObject m_objectName shared NullEncodedUnicodeString -ServerObject m_volume shared int -ServerObject m_authServerProcessId shared_np uint32 -ServerObject m_descriptionStringId shared_np StringId -ServerObject m_refCount none int -ServerObject m_includeInBuildout server_np bool -ServerObject m_conversionId server int -ServerObject m_staticItemName server std::string -ServerObject m_staticItemVersion server int -ServerObject m_broadcastListeners server_np set -ServerObject m_broadcastBroadcasters server_np set - -ShipObject m_slideDampener shared float -ShipObject m_currentChassisHitPoints shared float -ShipObject m_maximumChassisHitPoints shared float -ShipObject m_chassisType shared uint32 -ShipObject m_componentArmorHitpointsMaximum shared packed_map -ShipObject m_componentArmorHitpointsCurrent shared packed_map -ShipObject m_componentHitpointsCurrent shared packed_map -ShipObject m_componentHitpointsMaximum shared packed_map -ShipObject m_componentFlags shared packed_map -ShipObject m_shieldHitpointsFrontMaximum shared float -ShipObject m_shieldHitpointsBackMaximum shared float - -ShipObject m_componentCrc server packed_map - -ShipObject m_shipId shared_np uint16 -ShipObject m_shipActualAccelerationRate shared_np float -ShipObject m_shipActualDecelerationRate shared_np float -ShipObject m_shipActualPitchAccelerationRate shared_np float -ShipObject m_shipActualYawAccelerationRate shared_np float -ShipObject m_shipActualRollAccelerationRate shared_np float -ShipObject m_shipActualPitchRateMaximum shared_np float -ShipObject m_shipActualYawRateMaximum shared_np float -ShipObject m_shipActualRollRateMaximum shared_np float -ShipObject m_shipActualSpeedMaximum shared_np float -ShipObject m_pilotLookAtTarget shared_np NetworkId -ShipObject m_pilotLookAtTargetSlot shared_np int -ShipObject m_targetableSlotBitfield shared_np BitArray -ShipObject m_componentCrcForClient shared_np map -ShipObject m_wingName shared_np std::string -ShipObject m_typeName shared_np std::string -ShipObject m_difficulty shared_np std::string -ShipObject m_faction shared_np std::string -ShipObject m_shieldHitpointsFrontCurrent shared_np float -ShipObject m_shieldHitpointsBackCurrent shared_np float -ShipObject m_guildId shared_np int - -ShipObject m_componentEfficiencyGeneral authClientServer packed_map -ShipObject m_componentEfficiencyEnergy authClientServer packed_map -ShipObject m_componentEnergyMaintenanceRequirement authClientServer packed_map -ShipObject m_componentMass authClientServer packed_map -ShipObject m_componentNames authClientServer packed_map -ShipObject m_componentCreators authClientServer packed_map -ShipObject m_weaponDamageMaximum authClientServer packed_map -ShipObject m_weaponDamageMinimum authClientServer packed_map -ShipObject m_weaponEffectivenessShields authClientServer packed_map -ShipObject m_weaponEffectivenessArmor authClientServer packed_map -ShipObject m_weaponEnergyPerShot authClientServer packed_map -ShipObject m_weaponRefireRate authClientServer packed_map -ShipObject m_weaponAmmoCurrent authClientServer packed_map -ShipObject m_weaponAmmoMaximum authClientServer packed_map -ShipObject m_weaponAmmoType authClientServer packed_map - -ShipObject m_chassisComponentMassMaximum authClientServer float -ShipObject m_chassisComponentMassCurrent authClientServer_np float -ShipObject m_chassisSpeedMaximumModifier authClientServer_np float -ShipObject m_shieldRechargeRate authClientServer float -ShipObject m_capacitorEnergyCurrent authClientServer_np float -ShipObject m_capacitorEnergyMaximum authClientServer float -ShipObject m_capacitorEnergyRechargeRate authClientServer float -ShipObject m_engineAccelerationRate authClientServer float -ShipObject m_engineDecelerationRate authClientServer float -ShipObject m_enginePitchAccelerationRate authClientServer float -ShipObject m_engineYawAccelerationRate authClientServer float -ShipObject m_engineRollAccelerationRate authClientServer float -ShipObject m_enginePitchRateMaximum authClientServer float -ShipObject m_engineYawRateMaximum authClientServer float -ShipObject m_engineRollRateMaximum authClientServer float -ShipObject m_engineSpeedMaximum authClientServer float -ShipObject m_reactorEnergyGenerationRate authClientServer float -ShipObject m_boosterEnergyCurrent authClientServer_np float -ShipObject m_weaponEfficiencyRefireRate authClientServer_np packed_map -ShipObject m_boosterEnergyMaximum authClientServer float -ShipObject m_boosterEnergyRechargeRate authClientServer float -ShipObject m_boosterEnergyConsumptionRate authClientServer float -ShipObject m_boosterAcceleration authClientServer float -ShipObject m_boosterSpeedMaximum authClientServer float -ShipObject m_droidInterfaceCommandSpeed authClientServer float -ShipObject m_installedDroidControlDevice authClientServer NetworkId -ShipObject m_cargoHoldContentsMaximum authClientServer int -ShipObject m_cargoHoldContentsCurrent authClientServer int -ShipObject m_cargoHoldContents authClientServer packed_map -ShipObject m_cargoHoldContentsResourceTypeInfo authClientServer_np map - -ShipObject m_engineSpeedRotationFactorMaximum server_np float -ShipObject m_engineSpeedRotationFactorMinimum server_np float -ShipObject m_engineSpeedRotationFactorOptimal server_np float - -TangibleObject m_customAppearance server std::string -TangibleObject m_locationTargets server LocationData - encodeLocationDataList(objectId,1,data); decodeLocationDataList(objectId,1,data,isBaseline); -TangibleObject m_ownerId server NetworkId -TangibleObject m_pvpEnemies server_np std::vector -TangibleObject m_pvpFaction shared uint32 -TangibleObject m_pvpMercenaryFaction server_np uint32 -TangibleObject m_pvpType shared int -TangibleObject m_pvpMercenaryType server_np int -TangibleObject m_pvpFutureType server_np int -TangibleObject m_creatorId server NetworkId -TangibleObject m_sourceDraftSchematic server uint32 -TangibleObject m_hateOverTime server_np map -TangibleObject m_pvpRegionCrc server_np uint32 -TangibleObject m_appearanceData shared std::string -TangibleObject m_components shared std::set - encodeComponents(objectId,data); decodeComponents(objectId,data,isBaseline); -TangibleObject m_condition shared int -TangibleObject m_count shared int -TangibleObject m_damageTaken shared int -TangibleObject m_maxHitPoints shared int -TangibleObject m_visible shared bool -TangibleObject m_conversations server_np NetworkId -TangibleObject m_hideFromClient server_np bool -TangibleObject m_inCombat shared_np bool -TangibleObject m_combatStartTime server_np time_t -TangibleObject m_attackableOverride server_np bool -TangibleObject m_passiveReveal server_np map -TangibleObject m_passiveRevealPlayerCharacter shared_np set -TangibleObject m_mapColorOverride shared_np uint32 -TangibleObject m_accessList shared_np set -TangibleObject m_guildAccessList shared_np set -TangibleObject m_effectsMap shared_np map - -VehicleObject m_bogus server int - -WeaponObject m_minDamage server int -WeaponObject m_maxDamage server int -WeaponObject m_attackSpeed shared float -WeaponObject m_woundChance server float -WeaponObject m_attackCost server int -WeaponObject m_damageRadius server float -WeaponObject m_isDefaultWeapon server_np bool -WeaponObject m_accuracy shared int -WeaponObject m_minRange shared float -WeaponObject m_maxRange shared float -WeaponObject m_damageType shared int -WeaponObject m_elementalType shared int -WeaponObject m_elementalValue shared int -WeaponObject m_weaponType shared_np int - -GroupObject m_groupMembers shared_np std::vector -GroupObject m_groupShipFormationMembers shared_np std::vector -GroupObject m_groupPOBShipAndOwners server_np std::vector -GroupObject m_groupName shared_np std::string -GroupObject m_groupLevel shared_np int16 -GroupObject m_groupMemberLevels server_np std::vector -GroupObject m_groupMemberProfessions server_np std::vector -GroupObject m_formationNameCrc shared_np uint32 -GroupObject m_allMembers server_np set -GroupObject m_nonPCMembers server_np set -GroupObject m_lootMaster shared_np NetworkId -GroupObject m_lootRule shared_np uint32 -GroupObject m_groupPickupTimer shared_np std::pair -GroupObject m_groupPickupLocation shared_np std::pair - -GuildObject m_names server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildNames,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildNames,data,isBaseline); -GuildObject m_leaders server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildLeaders,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildLeaders,data,isBaseline); -GuildObject m_members server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildMembers,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildMembers,data,isBaseline); -GuildObject m_enemies server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildEnemies,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildEnemies,data,isBaseline); -GuildObject m_abbrevs shared std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildAbbrevs,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildAbbrevs,data,isBaseline); -GuildObject m_guildsInfo server_np map -GuildObject m_membersInfo server_np map -GuildObject m_fullMembers server_np map -GuildObject m_sponsoredMembers server_np map -GuildObject m_guildLeaders server_np map -GuildObject m_gcwImperialScorePercentileThisGalaxy shared_np map -GuildObject m_gcwRegionDefenderBonus server_np map -GuildObject m_gcwGroupImperialScorePercentileThisGalaxy shared_np map -GuildObject m_gcwImperialScorePercentileHistoryThisGalaxy shared_np map -GuildObject m_gcwGroupImperialScorePercentileHistoryThisGalaxy shared_np map -GuildObject m_gcwImperialScorePercentileHistoryCountThisGalaxy server_np map -GuildObject m_gcwGroupImperialScorePercentileHistoryCountThisGalaxy server_np map -GuildObject m_gcwImperialScorePercentileOtherGalaxies shared_np map -GuildObject m_gcwGroupImperialScorePercentileOtherGalaxies shared_np map -GuildObject m_gcwGroupCategoryImperialScoreRawThisGalaxy server_np map -GuildObject m_gcwGroupImperialScoreRawThisGalaxy server_np map -GuildObject m_gcwImperialScoreOtherGalaxies server_np map -GuildObject m_gcwRebelScoreOtherGalaxies server_np map -GuildObject m_gcwRegionDefenderGuilds server_np map -GuildObject m_gcwRegionDefenderGuildsCount server_np map -GuildObject m_gcwRegionDefenderGuildsVersion server_np int - -BattlefieldMarkerObject m_regionName server std::string -BattlefieldMarkerObject m_battlefieldParticipants server map - encodeBattlefieldParticipants(objectId,data); decodeBattlefieldParticipants(objectId,data,isBaseline); - -CityObject m_cities server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Cities,data); decodePropertyList(objectId,PropertyListBuffer::LI_Cities,data,isBaseline); -CityObject m_citizens server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Citizens,data); decodePropertyList(objectId,PropertyListBuffer::LI_Citizens,data,isBaseline); -CityObject m_structures server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_CityStructures,data); decodePropertyList(objectId,PropertyListBuffer::LI_CityStructures,data,isBaseline); -CityObject m_citiesInfo server_np map -CityObject m_citizensInfo server_np map -CityObject m_structuresInfo server_np map -CityObject m_citizenToCityId server_np map -CityObject m_pgcRatingInfo server_np map -CityObject m_pgcRatingChroniclerId server_np set -CityObject m_gcwRegionDefenderCities server_np map -CityObject m_gcwRegionDefenderCitiesCount server_np map -CityObject m_gcwRegionDefenderCitiesVersion server_np int - -PlayerQuestObject m_tasks shared_np std::vector -PlayerQuestObject m_taskCounters shared_np std::vector> -PlayerQuestObject m_taskStatus shared_np std::vector -PlayerQuestObject m_waypoints shared_np std::vector -PlayerQuestObject m_rewards shared_np std::string -PlayerQuestObject m_creatorName shared_np std::string -PlayerQuestObject m_completed shared_np bool -PlayerQuestObject m_recipe shared_np bool -PlayerQuestObject m_title shared std::string -PlayerQuestObject m_description shared std::string -PlayerQuestObject m_creator shared NetworkId -PlayerQuestObject m_totalTasks shared int -PlayerQuestObject m_difficulty shared int -PlayerQuestObject m_taskTitle1 shared std::string -PlayerQuestObject m_taskDescription1 shared std::string -PlayerQuestObject m_taskTitle2 shared std::string -PlayerQuestObject m_taskDescription2 shared std::string -PlayerQuestObject m_taskTitle3 shared std::string -PlayerQuestObject m_taskDescription3 shared std::string -PlayerQuestObject m_taskTitle4 shared std::string -PlayerQuestObject m_taskDescription4 shared std::string -PlayerQuestObject m_taskTitle5 shared std::string -PlayerQuestObject m_taskDescription5 shared std::string -PlayerQuestObject m_taskTitle6 shared std::string -PlayerQuestObject m_taskDescription6 shared std::string -PlayerQuestObject m_taskTitle7 shared std::string -PlayerQuestObject m_taskDescription7 shared std::string -PlayerQuestObject m_taskTitle8 shared std::string -PlayerQuestObject m_taskDescription8 shared std::string -PlayerQuestObject m_taskTitle9 shared std::string -PlayerQuestObject m_taskDescription9 shared std::string -PlayerQuestObject m_taskTitle10 shared std::string -PlayerQuestObject m_taskDescription10 shared std::string -PlayerQuestObject m_taskTitle11 shared std::string -PlayerQuestObject m_taskDescription11 shared std::string -PlayerQuestObject m_taskTitle12 shared std::string -PlayerQuestObject m_taskDescription12 shared std::string - - - - -# not persistable yet +#TODO: get rid of "Cached" because it makes no sense for DBProcess +#A class with '-' denotes the class does not have any persisted variables. + +#class parent +ServerObject +BuildingObject TangibleObject +CellObject ServerObject +CreatureObject TangibleObject +FactoryObject TangibleObject +HarvesterInstallationObject InstallationObject +InstallationObject TangibleObject +IntangibleObject ServerObject +ManufactureInstallationObject InstallationObject +ManufactureSchematicObject IntangibleObject +MissionObject IntangibleObject +PlanetObject UniverseObject +PlayerObject IntangibleObject +ResourceContainerObject TangibleObject +ShipObject TangibleObject +StaticObject ServerObject +TangibleObject ServerObject +UniverseObject ServerObject +VehicleObject TangibleObject +WeaponObject TangibleObject +-GroupObject UniverseObject +GuildObject UniverseObject +BattlefieldMarkerObject TangibleObject +CityObject UniverseObject +PlayerQuestObject TangibleObject +end + +#Note: The datatype in the following table is the datatype to use in SwgDatabaseServer. Therefore, use NetworkId instead of CachedNetworkId, etc. +#Note: The parser for this file uses spaces as separators. Be careful not to put extra spaces in commands. + +#class member name package datatype add-to-package command persist function load function + +BuildingObject m_allowed server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data); decodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data,isBaseline); +BuildingObject m_banned server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Banned,data); decodePropertyList(objectId,PropertyListBuffer::LI_Banned,data,isBaseline); +BuildingObject m_isPublic server bool +BuildingObject m_maintenanceCost server int +BuildingObject m_timeLastChecked server real +BuildingObject m_cityId server int +BuildingObject m_contentsLoaded server_np bool + +CellObject m_allowed server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data); decodePropertyList(objectId,PropertyListBuffer::LI_Allowed,data,isBaseline); +CellObject m_banned server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Banned,data); decodePropertyList(objectId,PropertyListBuffer::LI_Banned,data,isBaseline); +CellObject m_isPublic shared bool +CellObject m_cellNumber shared int +CellObject m_cellLabel shared_np Unicode::String +CellObject m_labelLocationOffset shared_np Vector + +CreatureObject m_maxAttributes authClientServer Attributes::Value - encodeAttributes(objectId,data,9); decodeAttributes(objectId,data,isBaseline,9); +CreatureObject m_skills authClientServer SkillObject* - encodePropertyList(objectId,PropertyListBuffer::LI_Skills,data); decodePropertyList(objectId,PropertyListBuffer::LI_Skills,data,isBaseline); + +CreatureObject m_accelPercent authClientServer_np float +CreatureObject m_accelScale authClientServer_np float +CreatureObject m_attribBonus authClientServer_np std::vector +CreatureObject m_modMap authClientServer_np map +CreatureObject m_movementPercent authClientServer_np float +CreatureObject m_movementScale authClientServer_np float +CreatureObject m_performanceListenTarget authClientServer_np NetworkId +CreatureObject m_runSpeed authClientServer_np float +CreatureObject m_slopeModAngle authClientServer_np float +CreatureObject m_slopeModPercent authClientServer_np float +CreatureObject m_turnScale authClientServer_np float +CreatureObject m_walkSpeed authClientServer_np float +CreatureObject m_waterModPercent authClientServer_np float +CreatureObject m_notifyRegions server_np set +CreatureObject m_missionCriticalObjectSet server_np set +CreatureObject m_groupMissionCriticalObjectSet authClientServer_np set +CreatureObject m_commands authClientServer_np std::map + +CreatureObject m_attributes server Attributes::Value - encodeAttributes(objectId,data,0); decodeAttributes(objectId,data,isBaseline,0); +CreatureObject m_baseRunSpeed server float +CreatureObject m_baseWalkSpeed server float +CreatureObject m_persistedBuffs server packed_map - encodePersistedBuffs(data,row->persisted_buffs); decodePersistedBuffs(data,row->persisted_buffs); + +CreatureObject m_attributeModList server_np std::vector +CreatureObject m_baseSlopeModPercent server_np float +CreatureObject m_cachedCurrentAttributeModValues server_np std::vector +CreatureObject m_cachedMaxAttributeModValues server_np std::vector +CreatureObject m_commandQueue server_np commandqueue getCommandQueue()->addToPackage(m_serverPackage_np); +CreatureObject m_cover server_np int +CreatureObject m_currentAttitude server_np Attitude +CreatureObject m_isStatic server_np bool +CreatureObject m_lastBehavior server_np int +CreatureObject m_lastMonitorReportPosition server_np Vector +CreatureObject m_locomotion server_np Locomotions::Enumerator +CreatureObject m_maxMentalStates server_np MentalStates::Value +CreatureObject m_mentalStateDecays server_np float +CreatureObject m_mentalStatesToward server_np map +CreatureObject m_monitoredCreatureMovements server_np map +CreatureObject m_performanceWatchTarget server_np NetworkId +CreatureObject m_stopWalkRun server_np int +CreatureObject m_timeToUpdateGuildWarPvpStatus server_np uint32 +CreatureObject m_guildWarEnabled server_np bool +CreatureObject m_militiaOfCityId server_np int +CreatureObject m_locatedInCityId server_np int +CreatureObject m_invulnerabilityTimer server_np float +CreatureObject m_allowSARegen server_np bool +CreatureObject m_totalLevelXp authClientServer_np int + +CreatureObject m_posture shared Postures::Enumerator +CreatureObject m_rank shared uint8 +CreatureObject m_masterId shared NetworkId +CreatureObject m_scaleFactor shared float +CreatureObject m_shockWounds shared int +CreatureObject m_states shared uint64 +CreatureObject m_level shared_np int16 +CreatureObject m_levelHealthGranted shared_np int +CreatureObject m_animatingSkillData shared_np std::string +CreatureObject m_animationMood shared_np std::string +CreatureObject m_currentWeapon shared_np NetworkId +CreatureObject m_group shared_np NetworkId +CreatureObject m_groupInviter shared_np NetworkId +CreatureObject m_inviterForPendingGroup server_np NetworkId +CreatureObject m_guildId shared_np int +CreatureObject m_lookAtTarget shared_np NetworkId +CreatureObject m_intendedTarget shared_np NetworkId +CreatureObject m_mood shared_np char +CreatureObject m_performanceStartTime shared_np int +CreatureObject m_performanceType shared_np int +CreatureObject m_totalAttributes shared_np Attributes::Value - encodeAttributes(objectId,data,0); decodeAttributes(objectId,data,isBaseline,0); +CreatureObject m_totalMaxAttributes shared_np Attributes::Value - encodeAttributes(objectId,data,9); decodeAttributes(objectId,data,isBaseline,9); +CreatureObject m_wearableData shared_np vector +CreatureObject m_alternateAppearanceSharedObjectTemplateName shared_np std::string +CreatureObject m_timedMod server_np std::vector +CreatureObject m_timedModDuration server_np std::vector +CreatureObject m_timedModUpdateTime server_np std::vector +CreatureObject m_coverVisibility shared_np bool +CreatureObject m_buffs shared_np map + +CreatureObject m_loiterRange none float +CreatureObject m_animState none char +CreatureObject m_sayMode none char + +CreatureObject m_clientUsesAnimationLocomotion shared_np bool +CreatureObject m_difficulty shared_np char +CreatureObject m_hologramType shared_np int32 +CreatureObject m_visibleOnMapAndRadar shared_np bool +CreatureObject m_wsX server float +CreatureObject m_wsY server float +CreatureObject m_wsZ server float + +CreatureObject m_isBeast shared_np bool +CreatureObject m_forceShowHam shared_np bool +CreatureObject m_wearableAppearanceData shared_np vector +CreatureObject m_decoyOrigin shared_np NetworkId + +FactoryObject m_craftingCount server_np int +FactoryObject m_craftingSchematic server_np NetworkId +FactoryObject m_attributes server_np std::map + +HarvesterInstallationObject m_installedEfficiency server float +HarvesterInstallationObject m_resourceType server NetworkId +HarvesterInstallationObject m_maxExtractionRate server int +HarvesterInstallationObject m_currentExtractionRate server float +HarvesterInstallationObject m_maxHopperAmount server int +HarvesterInstallationObject m_hopperResource server NetworkId +HarvesterInstallationObject m_hopperAmount server float + +InstallationObject m_installationType server int32 +InstallationObject m_tickCount server float +InstallationObject m_activateStartTime server float +InstallationObject m_activated shared bool +InstallationObject m_power shared float +InstallationObject m_powerRate shared float + +IntangibleObject m_crcs server_np std::vector +IntangibleObject m_positions server_np std::vector +IntangibleObject m_headings server_np std::vector +IntangibleObject m_scripts server_np std::vector +IntangibleObject m_player server_np NetworkId +IntangibleObject m_objects server_np std::vector +IntangibleObject m_center server_np Vector +IntangibleObject m_radius server_np float +IntangibleObject m_creator server_np NetworkId +IntangibleObject m_theaterName server_np std::string +IntangibleObject m_count shared int + +ManufactureSchematicObject m_draftSchematic server int +ManufactureSchematicObject m_creatorId server NetworkId +ManufactureSchematicObject m_creatorName server Unicode::String +ManufactureSchematicObject m_factories server_np std::vector +ManufactureSchematicObject m_resourceMaxAttributes server_np std::map + +ManufactureSchematicObject m_attributes shared std::map - encodeManufactureSchematicAttributes(objectId,data); decodeManufactureSchematicAttributes(objectId,data,isBaseline); +ManufactureSchematicObject m_itemsPerContainer shared int +ManufactureSchematicObject m_manufactureTime shared float +ManufactureSchematicObject m_appearanceData shared_np std::string +ManufactureSchematicObject m_customAppearance shared_np std::string +ManufactureSchematicObject m_draftSchematicSharedTemplate shared_np std::string +ManufactureSchematicObject m_isCrafting shared_np bool +ManufactureSchematicObject m_schematicChangedSignal shared_np char + +MissionObject m_difficulty shared int +MissionObject m_endLocation shared Location - encodeLocation(data,row->end_x,row->end_y,row->end_z,row->end_cell,row->end_scene); decodeLocation(data,row->end_x,row->end_y,row->end_z,row->end_cell,row->end_scene); +MissionObject m_missionCreator shared Unicode::String +MissionObject m_reward shared int +MissionObject m_rootScriptName server std::string +MissionObject m_startLocation shared Location - encodeLocation(data,row->start_x,row->start_y,row->start_z,row->start_cell,row->start_scene); decodeLocation(data,row->start_x,row->start_y,row->start_z,row->start_cell,row->start_scene); +MissionObject m_targetAppearance shared uint32 +MissionObject m_description shared StringId - encodeStringId(data,row->description_table,row->description_text); decodeStringId(data,row->description_table,row->description_text); +MissionObject m_title shared StringId - encodeStringId(data,row->title_table,row->title_text); decodeStringId(data,row->title_table,row->title_text); +MissionObject m_missionHolderId server NetworkId +MissionObject m_status shared int +MissionObject m_missionType shared uint32 +MissionObject m_targetName shared std::string +MissionObject m_waypoint shared map - encodeSingleWaypoint(objectId,data); decodeSingleWaypoint(objectId,data,isBaseline); + +PlanetObject m_planetName server std::string +PlanetObject m_travelPointList server_np TravelPoint* +PlanetObject m_weatherIndex server_np int +PlanetObject m_windVelocityX server_np float +PlanetObject m_windVelocityY server_np float +PlanetObject m_windVelocityZ server_np float +PlanetObject m_mapLocationMapStatic server_np map +PlanetObject m_mapLocationMapDynamic server_np map +PlanetObject m_mapLocationMapPersist server_np map +PlanetObject m_mapLocationVersionStatic server_np int +PlanetObject m_mapLocationVersionDynamic server_np int +PlanetObject m_mapLocationVersionPersist server_np int +PlanetObject m_collectionServerFirst server_np set +PlanetObject m_collectionServerFirstUpdateNumber server_np int +PlanetObject m_connectedCharacterLfgData server_np map +PlanetObject m_connectedCharacterLfgDataFactionalPresence server_np map +PlanetObject m_connectedCharacterLfgDataFactionalPresenceGrid server_np map +PlanetObject m_connectedCharacterBiographyData server_np map +PlanetObject m_currentEvents server_np std::string +PlanetObject m_gcwImperialScore server_np map +PlanetObject m_gcwRebelScore server_np map + +PlayerObject m_craftingLevel firstParentAuthClientServer_np int +PlayerObject m_craftingStage firstParentAuthClientServer_np int +PlayerObject m_craftingStation firstParentAuthClientServer_np NetworkId +PlayerObject m_draftSchematics firstParentAuthClientServer_np std::map,int> +PlayerObject m_craftingComponentBioLink firstParentAuthClientServer_np NetworkId +PlayerObject m_experimentPoints firstParentAuthClientServer_np int +PlayerObject m_expModified firstParentAuthClientServer_np int +PlayerObject m_friendList firstParentAuthClientServer_np std::vector +PlayerObject m_ignoreList firstParentAuthClientServer_np std::vector +PlayerObject m_spokenLanguage firstParentAuthClientServer_np int +PlayerObject m_food firstParentAuthClientServer_np int +PlayerObject m_maxFood firstParentAuthClientServer_np int +PlayerObject m_drink firstParentAuthClientServer_np int +PlayerObject m_maxDrink firstParentAuthClientServer_np int +PlayerObject m_meds firstParentAuthClientServer_np int +PlayerObject m_maxMeds firstParentAuthClientServer_np int +PlayerObject m_groupWaypoints firstParentAuthClientServer_np map - encodeWaypoints(objectId,data); decodeWaypoints(objectId,data,isBaseline); +PlayerObject m_playerHateList firstParentAuthClientServer_np set +PlayerObject m_killMeter firstParentAuthClientServer_np int32 +PlayerObject m_experiencePoints parentClient map - encodeExperience(objectId,data); decodeExperience(objectId,data,isBaseline); +PlayerObject m_waypoints parentClient map - encodeWaypoints(objectId,data); decodeWaypoints(objectId,data,isBaseline); +PlayerObject m_forcePower parentClient int +PlayerObject m_maxForcePower parentClient int +PlayerObject m_completedQuests parentClient BitArray +PlayerObject m_activeQuests parentClient BitArray +PlayerObject m_currentQuest parentClient uint32 +PlayerObject m_quests parentClient packed_map - encodeQuests(data,row->quests,row->quests2,row->quests3,row->quests4); decodeQuests(objectId,data,row->quests,row->quests2,row->quests3,row->quests4); +PlayerObject m_stationId server StationId +PlayerObject m_houseId server NetworkId +PlayerObject m_accountNumLots server int +PlayerObject m_accountNumLotsOverLimitSpam firstParentAuthClientServer_np int +PlayerObject m_accountMaxLotsAdjustment server int +PlayerObject m_accountIsOutcast server bool +PlayerObject m_accountCheaterLevel server float +PlayerObject m_forceRegenRate server float +PlayerObject m_craftingTool server_np NetworkId +PlayerObject m_forceRegenValue server_np float +PlayerObject m_theaterDatatable server_np std::string +PlayerObject m_theaterPosition server_np Vector +PlayerObject m_theaterScene server_np std::string +PlayerObject m_theaterScript server_np std::string +PlayerObject m_theaterNumObjects server_np int +PlayerObject m_theaterRadius server_np float +PlayerObject m_theaterCreator server_np NetworkId +PlayerObject m_theaterName server_np std::string +PlayerObject m_theaterId server_np NetworkId +PlayerObject m_theaterLocationType server_np int +PlayerObject m_matchMakingCharacterProfileId shared MatchMakingId - encodeMatchMakingId(data,row->character_profile_id); decodeMatchMakingId(data,row->character_profile_id); +PlayerObject m_matchMakingPersonalProfileId shared MatchMakingId - encodeMatchMakingId(data,row->personal_profile_id); decodeMatchMakingId(data,row->personal_profile_id); +PlayerObject m_skillTitle shared NullEncodedStandardString +PlayerObject m_bornDate shared int +PlayerObject m_playedTime shared int +PlayerObject m_sessionStartPlayTime server_np int32 +PlayerObject m_sessionLastActiveTime server_np int32 +PlayerObject m_sessionActivePlayTimeDuration server_np uint32 +PlayerObject m_privledgedTitle shared_np int8 +PlayerObject m_roleIconChoice shared int +PlayerObject m_aggroImmuneStartTime server_np uint32 +PlayerObject m_aggroImmuneDuration server_np uint32 +PlayerObject m_skillTemplate shared std::string +PlayerObject m_workingSkill parentClient std::string +PlayerObject m_isFromLogin server_np bool +PlayerObject m_currentGcwPoints shared int32 +PlayerObject m_currentGcwRating server int32 +PlayerObject m_currentPvpKills shared int32 +PlayerObject m_lifetimeGcwPoints shared int64 +PlayerObject m_maxGcwImperialRating server int32 +PlayerObject m_maxGcwRebelRating server int32 +PlayerObject m_lifetimePvpKills shared int32 +PlayerObject m_nextGcwRatingCalcTime server int32 +PlayerObject m_currentGcwRank shared_np int +PlayerObject m_currentGcwRankProgress shared_np float +PlayerObject m_maxGcwImperialRank shared_np int +PlayerObject m_maxGcwRebelRank shared_np int +PlayerObject m_gcwRatingActualCalcTime shared_np int32 +PlayerObject m_sessionActivity server_np uint32 +PlayerObject m_petId firstParentAuthClientServer_np NetworkId +PlayerObject m_petCommandList firstParentAuthClientServer_np std::vector +PlayerObject m_petToggledCommands firstParentAuthClientServer_np std::vector +PlayerObject m_collections shared BitArray +PlayerObject m_collections2 shared BitArray +PlayerObject m_chatSpamSpatialNumCharacters server_np int +PlayerObject m_chatSpamNonSpatialNumCharacters server_np int +PlayerObject m_chatSpamTimeEndInterval server_np int +PlayerObject m_chatSpamNextTimeToSyncWithChatServer server_np int +PlayerObject m_citizenshipCity shared_np std::string +PlayerObject m_citizenshipType shared_np int8 +PlayerObject m_currentGcwRegion server_np std::string +PlayerObject m_cityGcwDefenderRegion shared_np std::pair> +PlayerObject m_guildGcwDefenderRegion shared_np std::pair> +PlayerObject m_squelchedById shared_np NetworkId +PlayerObject m_squelchedByName shared_np std::string +PlayerObject m_squelchExpireTime shared_np int32 +PlayerObject m_showBackpack shared bool +PlayerObject m_showHelmet shared bool +PlayerObject m_environmentFlags shared_np int32 +PlayerObject m_defaultAttackOverride shared_np std::string +PlayerObject m_guildRank firstParentAuthClientServer_np BitArray +PlayerObject m_citizenRank firstParentAuthClientServer_np BitArray +PlayerObject m_galacticReserveDeposit firstParentAuthClientServer_np int8 +PlayerObject m_pgcRatingCount firstParentAuthClientServer_np int64 +PlayerObject m_pgcRatingTotal firstParentAuthClientServer_np int64 +PlayerObject m_pgcLastRatingTime firstParentAuthClientServer_np int + +ResourceContainerObject m_quantity shared int +ResourceContainerObject m_resourceType shared NetworkId +ResourceContainerObject m_source server NetworkId +ResourceContainerObject m_maxQuantity shared_np int +ResourceContainerObject m_parentName shared_np std::string +ResourceContainerObject m_resourceName shared_np Unicode::String +ResourceContainerObject m_resourceNameId shared_np StringId + +ServerObject m_bankBalance authClientServer int +ServerObject m_cashBalance authClientServer int +ServerObject m_cacheVersion server int +ServerObject m_loadContents server bool +ServerObject m_objVarFreeFlags server int ; encodeObjVarFreeFlags(objectId,data); decodeObjVarFreeFlags(objectId,data,isBaseline); +ServerObject m_objVars server objvarlist m_objVars.addToPackage(m_serverPackage,m_serverPackage_np); encodeObjVars(objectId,data); decodeObjVars(objectId,data,isBaseline); +ServerObject m_persisted server bool - Archive::put(data,true); ignorePersistedFlag(objectId,data); +ServerObject m_playerControlled server bool +ServerObject m_sceneId server std::string +ServerObject m_scriptList server std::string m_scriptObject->addToPackage(m_serverPackage); encodeScriptObject(objectId,data); decodeScriptObject(objectId,data,isBaseline); +ServerObject m_attributesAttained server_np BitArray +ServerObject m_attributesInterested server_np BitArray +ServerObject m_proxyServerProcessIds server_np std::vector +ServerObject m_transformSequence server_np uint32 +ServerObject m_triggerVolumeInfo server_np std::vector +ServerObject m_contentsLoaded server_np bool +ServerObject m_contentsRequested server_np bool +ServerObject m_messageTos server_np map +ServerObject m_defaultAlterTime server_np float +ServerObject m_observersCount server_np int +ServerObject m_complexity shared float +ServerObject m_nameStringId shared StringId - encodeStringId(data,row->name_string_table,row->name_string_text); decodeStringId(data,row->name_string_table,row->name_string_text); +ServerObject m_objectName shared NullEncodedUnicodeString +ServerObject m_volume shared int +ServerObject m_authServerProcessId shared_np uint32 +ServerObject m_descriptionStringId shared_np StringId +ServerObject m_refCount none int +ServerObject m_includeInBuildout server_np bool +ServerObject m_conversionId server int +ServerObject m_staticItemName server std::string +ServerObject m_staticItemVersion server int +ServerObject m_broadcastListeners server_np set +ServerObject m_broadcastBroadcasters server_np set + +ShipObject m_slideDampener shared float +ShipObject m_currentChassisHitPoints shared float +ShipObject m_maximumChassisHitPoints shared float +ShipObject m_chassisType shared uint32 +ShipObject m_componentArmorHitpointsMaximum shared packed_map +ShipObject m_componentArmorHitpointsCurrent shared packed_map +ShipObject m_componentHitpointsCurrent shared packed_map +ShipObject m_componentHitpointsMaximum shared packed_map +ShipObject m_componentFlags shared packed_map +ShipObject m_shieldHitpointsFrontMaximum shared float +ShipObject m_shieldHitpointsBackMaximum shared float + +ShipObject m_componentCrc server packed_map + +ShipObject m_shipId shared_np uint16 +ShipObject m_shipActualAccelerationRate shared_np float +ShipObject m_shipActualDecelerationRate shared_np float +ShipObject m_shipActualPitchAccelerationRate shared_np float +ShipObject m_shipActualYawAccelerationRate shared_np float +ShipObject m_shipActualRollAccelerationRate shared_np float +ShipObject m_shipActualPitchRateMaximum shared_np float +ShipObject m_shipActualYawRateMaximum shared_np float +ShipObject m_shipActualRollRateMaximum shared_np float +ShipObject m_shipActualSpeedMaximum shared_np float +ShipObject m_pilotLookAtTarget shared_np NetworkId +ShipObject m_pilotLookAtTargetSlot shared_np int +ShipObject m_targetableSlotBitfield shared_np BitArray +ShipObject m_componentCrcForClient shared_np map +ShipObject m_wingName shared_np std::string +ShipObject m_typeName shared_np std::string +ShipObject m_difficulty shared_np std::string +ShipObject m_faction shared_np std::string +ShipObject m_shieldHitpointsFrontCurrent shared_np float +ShipObject m_shieldHitpointsBackCurrent shared_np float +ShipObject m_guildId shared_np int + +ShipObject m_componentEfficiencyGeneral authClientServer packed_map +ShipObject m_componentEfficiencyEnergy authClientServer packed_map +ShipObject m_componentEnergyMaintenanceRequirement authClientServer packed_map +ShipObject m_componentMass authClientServer packed_map +ShipObject m_componentNames authClientServer packed_map +ShipObject m_componentCreators authClientServer packed_map +ShipObject m_weaponDamageMaximum authClientServer packed_map +ShipObject m_weaponDamageMinimum authClientServer packed_map +ShipObject m_weaponEffectivenessShields authClientServer packed_map +ShipObject m_weaponEffectivenessArmor authClientServer packed_map +ShipObject m_weaponEnergyPerShot authClientServer packed_map +ShipObject m_weaponRefireRate authClientServer packed_map +ShipObject m_weaponAmmoCurrent authClientServer packed_map +ShipObject m_weaponAmmoMaximum authClientServer packed_map +ShipObject m_weaponAmmoType authClientServer packed_map + +ShipObject m_chassisComponentMassMaximum authClientServer float +ShipObject m_chassisComponentMassCurrent authClientServer_np float +ShipObject m_chassisSpeedMaximumModifier authClientServer_np float +ShipObject m_shieldRechargeRate authClientServer float +ShipObject m_capacitorEnergyCurrent authClientServer_np float +ShipObject m_capacitorEnergyMaximum authClientServer float +ShipObject m_capacitorEnergyRechargeRate authClientServer float +ShipObject m_engineAccelerationRate authClientServer float +ShipObject m_engineDecelerationRate authClientServer float +ShipObject m_enginePitchAccelerationRate authClientServer float +ShipObject m_engineYawAccelerationRate authClientServer float +ShipObject m_engineRollAccelerationRate authClientServer float +ShipObject m_enginePitchRateMaximum authClientServer float +ShipObject m_engineYawRateMaximum authClientServer float +ShipObject m_engineRollRateMaximum authClientServer float +ShipObject m_engineSpeedMaximum authClientServer float +ShipObject m_reactorEnergyGenerationRate authClientServer float +ShipObject m_boosterEnergyCurrent authClientServer_np float +ShipObject m_weaponEfficiencyRefireRate authClientServer_np packed_map +ShipObject m_boosterEnergyMaximum authClientServer float +ShipObject m_boosterEnergyRechargeRate authClientServer float +ShipObject m_boosterEnergyConsumptionRate authClientServer float +ShipObject m_boosterAcceleration authClientServer float +ShipObject m_boosterSpeedMaximum authClientServer float +ShipObject m_droidInterfaceCommandSpeed authClientServer float +ShipObject m_installedDroidControlDevice authClientServer NetworkId +ShipObject m_cargoHoldContentsMaximum authClientServer int +ShipObject m_cargoHoldContentsCurrent authClientServer int +ShipObject m_cargoHoldContents authClientServer packed_map +ShipObject m_cargoHoldContentsResourceTypeInfo authClientServer_np map + +ShipObject m_engineSpeedRotationFactorMaximum server_np float +ShipObject m_engineSpeedRotationFactorMinimum server_np float +ShipObject m_engineSpeedRotationFactorOptimal server_np float + +TangibleObject m_customAppearance server std::string +TangibleObject m_locationTargets server LocationData - encodeLocationDataList(objectId,1,data); decodeLocationDataList(objectId,1,data,isBaseline); +TangibleObject m_ownerId server NetworkId +TangibleObject m_pvpEnemies server_np std::vector +TangibleObject m_pvpFaction shared uint32 +TangibleObject m_pvpMercenaryFaction server_np uint32 +TangibleObject m_pvpType shared int +TangibleObject m_pvpMercenaryType server_np int +TangibleObject m_pvpFutureType server_np int +TangibleObject m_creatorId server NetworkId +TangibleObject m_sourceDraftSchematic server uint32 +TangibleObject m_hateOverTime server_np map +TangibleObject m_pvpRegionCrc server_np uint32 +TangibleObject m_appearanceData shared std::string +TangibleObject m_components shared std::set - encodeComponents(objectId,data); decodeComponents(objectId,data,isBaseline); +TangibleObject m_condition shared int +TangibleObject m_count shared int +TangibleObject m_damageTaken shared int +TangibleObject m_maxHitPoints shared int +TangibleObject m_visible shared bool +TangibleObject m_conversations server_np NetworkId +TangibleObject m_hideFromClient server_np bool +TangibleObject m_inCombat shared_np bool +TangibleObject m_combatStartTime server_np time_t +TangibleObject m_attackableOverride server_np bool +TangibleObject m_passiveReveal server_np map +TangibleObject m_passiveRevealPlayerCharacter shared_np set +TangibleObject m_mapColorOverride shared_np uint32 +TangibleObject m_accessList shared_np set +TangibleObject m_guildAccessList shared_np set +TangibleObject m_effectsMap shared_np map + +VehicleObject m_bogus server int + +WeaponObject m_minDamage server int +WeaponObject m_maxDamage server int +WeaponObject m_attackSpeed shared float +WeaponObject m_woundChance server float +WeaponObject m_attackCost server int +WeaponObject m_damageRadius server float +WeaponObject m_isDefaultWeapon server_np bool +WeaponObject m_accuracy shared int +WeaponObject m_minRange shared float +WeaponObject m_maxRange shared float +WeaponObject m_damageType shared int +WeaponObject m_elementalType shared int +WeaponObject m_elementalValue shared int +WeaponObject m_weaponType shared_np int + +GroupObject m_groupMembers shared_np std::vector +GroupObject m_groupShipFormationMembers shared_np std::vector +GroupObject m_groupPOBShipAndOwners server_np std::vector +GroupObject m_groupName shared_np std::string +GroupObject m_groupLevel shared_np int16 +GroupObject m_groupMemberLevels server_np std::vector +GroupObject m_groupMemberProfessions server_np std::vector +GroupObject m_formationNameCrc shared_np uint32 +GroupObject m_allMembers server_np set +GroupObject m_nonPCMembers server_np set +GroupObject m_lootMaster shared_np NetworkId +GroupObject m_lootRule shared_np uint32 +GroupObject m_groupPickupTimer shared_np std::pair +GroupObject m_groupPickupLocation shared_np std::pair + +GuildObject m_names server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildNames,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildNames,data,isBaseline); +GuildObject m_leaders server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildLeaders,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildLeaders,data,isBaseline); +GuildObject m_members server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildMembers,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildMembers,data,isBaseline); +GuildObject m_enemies server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildEnemies,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildEnemies,data,isBaseline); +GuildObject m_abbrevs shared std::string - encodePropertyList(objectId,PropertyListBuffer::LI_GuildAbbrevs,data); decodePropertyList(objectId,PropertyListBuffer::LI_GuildAbbrevs,data,isBaseline); +GuildObject m_guildsInfo server_np map +GuildObject m_membersInfo server_np map +GuildObject m_fullMembers server_np map +GuildObject m_sponsoredMembers server_np map +GuildObject m_guildLeaders server_np map +GuildObject m_gcwImperialScorePercentileThisGalaxy shared_np map +GuildObject m_gcwRegionDefenderBonus server_np map +GuildObject m_gcwGroupImperialScorePercentileThisGalaxy shared_np map +GuildObject m_gcwImperialScorePercentileHistoryThisGalaxy shared_np map +GuildObject m_gcwGroupImperialScorePercentileHistoryThisGalaxy shared_np map +GuildObject m_gcwImperialScorePercentileHistoryCountThisGalaxy server_np map +GuildObject m_gcwGroupImperialScorePercentileHistoryCountThisGalaxy server_np map +GuildObject m_gcwImperialScorePercentileOtherGalaxies shared_np map +GuildObject m_gcwGroupImperialScorePercentileOtherGalaxies shared_np map +GuildObject m_gcwGroupCategoryImperialScoreRawThisGalaxy server_np map +GuildObject m_gcwGroupImperialScoreRawThisGalaxy server_np map +GuildObject m_gcwImperialScoreOtherGalaxies server_np map +GuildObject m_gcwRebelScoreOtherGalaxies server_np map +GuildObject m_gcwRegionDefenderGuilds server_np map +GuildObject m_gcwRegionDefenderGuildsCount server_np map +GuildObject m_gcwRegionDefenderGuildsVersion server_np int + +BattlefieldMarkerObject m_regionName server std::string +BattlefieldMarkerObject m_battlefieldParticipants server map - encodeBattlefieldParticipants(objectId,data); decodeBattlefieldParticipants(objectId,data,isBaseline); + +CityObject m_cities server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Cities,data); decodePropertyList(objectId,PropertyListBuffer::LI_Cities,data,isBaseline); +CityObject m_citizens server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_Citizens,data); decodePropertyList(objectId,PropertyListBuffer::LI_Citizens,data,isBaseline); +CityObject m_structures server std::string - encodePropertyList(objectId,PropertyListBuffer::LI_CityStructures,data); decodePropertyList(objectId,PropertyListBuffer::LI_CityStructures,data,isBaseline); +CityObject m_citiesInfo server_np map +CityObject m_citizensInfo server_np map +CityObject m_structuresInfo server_np map +CityObject m_citizenToCityId server_np map +CityObject m_pgcRatingInfo server_np map +CityObject m_pgcRatingChroniclerId server_np set +CityObject m_gcwRegionDefenderCities server_np map +CityObject m_gcwRegionDefenderCitiesCount server_np map +CityObject m_gcwRegionDefenderCitiesVersion server_np int + +PlayerQuestObject m_tasks shared_np std::vector +PlayerQuestObject m_taskCounters shared_np std::vector> +PlayerQuestObject m_taskStatus shared_np std::vector +PlayerQuestObject m_waypoints shared_np std::vector +PlayerQuestObject m_rewards shared_np std::string +PlayerQuestObject m_creatorName shared_np std::string +PlayerQuestObject m_completed shared_np bool +PlayerQuestObject m_recipe shared_np bool +PlayerQuestObject m_title shared std::string +PlayerQuestObject m_description shared std::string +PlayerQuestObject m_creator shared NetworkId +PlayerQuestObject m_totalTasks shared int +PlayerQuestObject m_difficulty shared int +PlayerQuestObject m_taskTitle1 shared std::string +PlayerQuestObject m_taskDescription1 shared std::string +PlayerQuestObject m_taskTitle2 shared std::string +PlayerQuestObject m_taskDescription2 shared std::string +PlayerQuestObject m_taskTitle3 shared std::string +PlayerQuestObject m_taskDescription3 shared std::string +PlayerQuestObject m_taskTitle4 shared std::string +PlayerQuestObject m_taskDescription4 shared std::string +PlayerQuestObject m_taskTitle5 shared std::string +PlayerQuestObject m_taskDescription5 shared std::string +PlayerQuestObject m_taskTitle6 shared std::string +PlayerQuestObject m_taskDescription6 shared std::string +PlayerQuestObject m_taskTitle7 shared std::string +PlayerQuestObject m_taskDescription7 shared std::string +PlayerQuestObject m_taskTitle8 shared std::string +PlayerQuestObject m_taskDescription8 shared std::string +PlayerQuestObject m_taskTitle9 shared std::string +PlayerQuestObject m_taskDescription9 shared std::string +PlayerQuestObject m_taskTitle10 shared std::string +PlayerQuestObject m_taskDescription10 shared std::string +PlayerQuestObject m_taskTitle11 shared std::string +PlayerQuestObject m_taskDescription11 shared std::string +PlayerQuestObject m_taskTitle12 shared std::string +PlayerQuestObject m_taskDescription12 shared std::string + + + + +# not persistable yet diff --git a/src/engine/server/library/serverDatabase/src/shared/ConfigServerDatabase.cpp b/src/engine/server/library/serverDatabase/src/shared/ConfigServerDatabase.cpp index 506e4bc3b..2760bb316 100644 --- a/src/engine/server/library/serverDatabase/src/shared/ConfigServerDatabase.cpp +++ b/src/engine/server/library/serverDatabase/src/shared/ConfigServerDatabase.cpp @@ -1,136 +1,136 @@ -// ====================================================================== -// -// ConfigServerDatabase.cpp -// copyright (c) 2001 Sony Online Entertainment -// -// ====================================================================== - -#include "serverDatabase/FirstServerDatabase.h" -#include "serverDatabase/ConfigServerDatabase.h" -#include "serverUtility/ConfigServerUtility.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/ExitChain.h" -#include "sharedFoundation/NetworkId.h" -#include - -//------------------------------------------------------------------- - -ConfigServerDatabase::Data* ConfigServerDatabase::data; -static ConfigServerDatabase::Data staticData; - -//------------------------------------------------------------------- - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("dbProcess", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("dbProcess", #a, b)) -#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("dbProcess", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("dbProcess", #a, b)) - -//------------------------------------------------------------------- - -void ConfigServerDatabase::install(void) -{ - ExitChain::add(ConfigServerDatabase::remove,"ConfigServerDatabase::remove"); - - ConfigServerUtility::install(); - data = &staticData; - - KEY_INT (objvarNameCleanupTime, 0); - KEY_INT (orphanedObjectCleanupTime, 0); - KEY_INT (marketAttributesCleanupTime, 0); - KEY_INT (messagesCleanupTime, 0); - KEY_INT (brokenObjectCleanupTime, 0); - KEY_INT (vendorObjectCleanupTime, 0); - KEY_STRING (customSQLFilename,""); - KEY_BOOL (enableFixBadCells, false); - KEY_STRING (objectTemplateListUpdateFilename,""); - - KEY_STRING (DSN,"gameserver"); - KEY_STRING (alternateDSN,""); - KEY_STRING (databaseUID,"gameserver"); - KEY_STRING (databasePWD,"gameserver"); - KEY_STRING (databaseProtocol,"DEFAULT"); - KEY_STRING (centralServerAddress, "localhost"); - KEY_INT (centralServerPort, 44451); - KEY_STRING (commoditiesServerAddress, "localhost"); - KEY_INT (commoditiesServerPort, 44457); //todo: confirm that this is a good port MSH - KEY_INT (taskManagerPort, 60001); - KEY_INT (expectedDBVersion, 270); - KEY_BOOL (correctDBVersionRequired,true); - KEY_INT (saveFrequencyLimit,10); - KEY_STRING (schemaOwner, ""); - KEY_STRING (goldSchemaOwner, ""); - KEY_FLOAT (uniqueMessageCacheTimeSec, 30.0f); - KEY_INT (loaderThreads,2); - KEY_INT (persisterThreads,1); - KEY_INT (newCharacterThreads,1); - KEY_INT (characterImmediateDeleteMinutes,120); - KEY_BOOL (logObjectLoading, false); - KEY_BOOL (enableQueryProfile, false); - KEY_BOOL (verboseQueryMode, false); - KEY_BOOL (logWorkerThreads, false); - KEY_STRING (gameServiceBindInterface, ""); - KEY_BOOL (reportSaveTimes, false); - KEY_BOOL (shouldSleep, true); - KEY_BOOL (enableLoadLocks, true); - KEY_INT (databaseReconnectTime, 0); - KEY_BOOL (logChunkLoading,false); - KEY_BOOL (useMemoryManagerForOCI,true); - KEY_INT (maxCharactersPerLoadRequest,10); - KEY_INT (maxChunksPerLoadRequest,200); - KEY_FLOAT (maxLoadStartDelay,300.0f); - KEY_INT (maxErrorCountBeforeDisconnect,5); - KEY_INT (maxErrorCountBeforeBailout,15); - KEY_INT (errorSleepTime,5000); - KEY_INT (disconnectSleepTime,30000); - KEY_INT (saveAtModulus,-1); - KEY_INT (saveAtDivisor,10); - KEY_INT (backloggedQueueSize,50); - KEY_INT (backloggedRecoveryQueueSize,25); - KEY_INT (maxTimewarp,data->saveFrequencyLimit * 2 < 600 ? 600 : data->saveFrequencyLimit * 2); - KEY_BOOL (enableObjvarPacking, true); - KEY_INT (prefetchNumRows,0); - KEY_INT (prefetchMemory,0); - KEY_INT (defaultFetchBatchSize,1000); - KEY_INT (queryReportingRate,60); - KEY_INT (enableDatabaseErrorLogging, 0); - KEY_INT (defaultMessageBulkBindSize, 1000); - KEY_BOOL (enableGoldDatabase, false); - KEY_STRING (maxGoldNetworkId, "10000000"); - KEY_FLOAT (defaultQueueUpdateTimeLimit, 0.25f); - KEY_BOOL (enableDataCleanup, false); - KEY_INT (defaultLazyDeleteBulkBindSize, 100); - KEY_INT (defaultLazyDeleteSleepTime, 1000); - KEY_INT (writeDelay, 0); - KEY_BOOL (delayUnloadIfObjectStillHasData, true); - KEY_FLOAT (experienceConsolidationTime, 0.0f); - KEY_INT (maxLoaderFinishedTasks, 100); - KEY_FLOAT (reportLongFrameTime, 1.0f); - KEY_BOOL (enableVerboseMessageLogging, false); - KEY_BOOL (profilerExpandAll, true); - KEY_INT (profilerDisplayPercentageMinimum, 0); - KEY_BOOL (fatalOnDataError, false); - KEY_INT (maxUnackedLoadCount, 1000000000); // by default, set to an "unlimited" number, and use maxUnackedLoadCountPerServer as the cap - KEY_INT (maxUnackedLoadCountPerServer, 2); - KEY_INT (auctionLocationLoadBatchSize, 100); - KEY_INT (auctionLoadBatchSize, 100); - KEY_INT (auctionAttributeLoadBatchSize, 100); - KEY_INT (auctionBidLoadBatchSize, 100); - KEY_INT (oldestUnackedLoadAlertThresholdSeconds, 10*60); // seconds -} - -//------------------------------------------------------------------- - -void ConfigServerDatabase::remove(void) -{ - ConfigServerUtility::remove(); -} - -// ---------------------------------------------------------------------- - -const NetworkId & ConfigServerDatabase::getMaxGoldNetworkId(void) -{ - static const NetworkId theValue(std::string(data->maxGoldNetworkId)); - return theValue; -} - -// ====================================================================== +// ====================================================================== +// +// ConfigServerDatabase.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverDatabase/FirstServerDatabase.h" +#include "serverDatabase/ConfigServerDatabase.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/NetworkId.h" +#include + +//------------------------------------------------------------------- + +ConfigServerDatabase::Data* ConfigServerDatabase::data; +static ConfigServerDatabase::Data staticData; + +//------------------------------------------------------------------- + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("dbProcess", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("dbProcess", #a, b)) +#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("dbProcess", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("dbProcess", #a, b)) + +//------------------------------------------------------------------- + +void ConfigServerDatabase::install(void) +{ + ExitChain::add(ConfigServerDatabase::remove,"ConfigServerDatabase::remove"); + + ConfigServerUtility::install(); + data = &staticData; + + KEY_INT (objvarNameCleanupTime, 0); + KEY_INT (orphanedObjectCleanupTime, 0); + KEY_INT (marketAttributesCleanupTime, 0); + KEY_INT (messagesCleanupTime, 0); + KEY_INT (brokenObjectCleanupTime, 0); + KEY_INT (vendorObjectCleanupTime, 0); + KEY_STRING (customSQLFilename,""); + KEY_BOOL (enableFixBadCells, false); + KEY_STRING (objectTemplateListUpdateFilename,""); + + KEY_STRING (DSN,"gameserver"); + KEY_STRING (alternateDSN,""); + KEY_STRING (databaseUID,"gameserver"); + KEY_STRING (databasePWD,"gameserver"); + KEY_STRING (databaseProtocol,"DEFAULT"); + KEY_STRING (centralServerAddress, "localhost"); + KEY_INT (centralServerPort, 44451); + KEY_STRING (commoditiesServerAddress, "localhost"); + KEY_INT (commoditiesServerPort, 44457); //todo: confirm that this is a good port MSH + KEY_INT (taskManagerPort, 60001); + KEY_INT (expectedDBVersion, 270); + KEY_BOOL (correctDBVersionRequired,true); + KEY_INT (saveFrequencyLimit,10); + KEY_STRING (schemaOwner, ""); + KEY_STRING (goldSchemaOwner, ""); + KEY_FLOAT (uniqueMessageCacheTimeSec, 30.0f); + KEY_INT (loaderThreads,2); + KEY_INT (persisterThreads,1); + KEY_INT (newCharacterThreads,1); + KEY_INT (characterImmediateDeleteMinutes,120); + KEY_BOOL (logObjectLoading, false); + KEY_BOOL (enableQueryProfile, false); + KEY_BOOL (verboseQueryMode, false); + KEY_BOOL (logWorkerThreads, false); + KEY_STRING (gameServiceBindInterface, ""); + KEY_BOOL (reportSaveTimes, false); + KEY_BOOL (shouldSleep, true); + KEY_BOOL (enableLoadLocks, true); + KEY_INT (databaseReconnectTime, 0); + KEY_BOOL (logChunkLoading,false); + KEY_BOOL (useMemoryManagerForOCI,true); + KEY_INT (maxCharactersPerLoadRequest,10); + KEY_INT (maxChunksPerLoadRequest,200); + KEY_FLOAT (maxLoadStartDelay,300.0f); + KEY_INT (maxErrorCountBeforeDisconnect,5); + KEY_INT (maxErrorCountBeforeBailout,15); + KEY_INT (errorSleepTime,5000); + KEY_INT (disconnectSleepTime,30000); + KEY_INT (saveAtModulus,-1); + KEY_INT (saveAtDivisor,10); + KEY_INT (backloggedQueueSize,50); + KEY_INT (backloggedRecoveryQueueSize,25); + KEY_INT (maxTimewarp,data->saveFrequencyLimit * 2 < 600 ? 600 : data->saveFrequencyLimit * 2); + KEY_BOOL (enableObjvarPacking, true); + KEY_INT (prefetchNumRows,0); + KEY_INT (prefetchMemory,0); + KEY_INT (defaultFetchBatchSize,1000); + KEY_INT (queryReportingRate,60); + KEY_INT (enableDatabaseErrorLogging, 0); + KEY_INT (defaultMessageBulkBindSize, 1000); + KEY_BOOL (enableGoldDatabase, false); + KEY_STRING (maxGoldNetworkId, "10000000"); + KEY_FLOAT (defaultQueueUpdateTimeLimit, 0.25f); + KEY_BOOL (enableDataCleanup, false); + KEY_INT (defaultLazyDeleteBulkBindSize, 100); + KEY_INT (defaultLazyDeleteSleepTime, 1000); + KEY_INT (writeDelay, 0); + KEY_BOOL (delayUnloadIfObjectStillHasData, true); + KEY_FLOAT (experienceConsolidationTime, 0.0f); + KEY_INT (maxLoaderFinishedTasks, 100); + KEY_FLOAT (reportLongFrameTime, 1.0f); + KEY_BOOL (enableVerboseMessageLogging, false); + KEY_BOOL (profilerExpandAll, true); + KEY_INT (profilerDisplayPercentageMinimum, 0); + KEY_BOOL (fatalOnDataError, false); + KEY_INT (maxUnackedLoadCount, 1000000000); // by default, set to an "unlimited" number, and use maxUnackedLoadCountPerServer as the cap + KEY_INT (maxUnackedLoadCountPerServer, 2); + KEY_INT (auctionLocationLoadBatchSize, 100); + KEY_INT (auctionLoadBatchSize, 100); + KEY_INT (auctionAttributeLoadBatchSize, 100); + KEY_INT (auctionBidLoadBatchSize, 100); + KEY_INT (oldestUnackedLoadAlertThresholdSeconds, 10*60); // seconds +} + +//------------------------------------------------------------------- + +void ConfigServerDatabase::remove(void) +{ + ConfigServerUtility::remove(); +} + +// ---------------------------------------------------------------------- + +const NetworkId & ConfigServerDatabase::getMaxGoldNetworkId(void) +{ + static const NetworkId theValue(std::string(data->maxGoldNetworkId)); + return theValue; +} + +// ====================================================================== diff --git a/src/engine/server/library/serverDatabase/src/shared/DatabaseProcess.cpp b/src/engine/server/library/serverDatabase/src/shared/DatabaseProcess.cpp index f27df9a78..c247838b6 100644 --- a/src/engine/server/library/serverDatabase/src/shared/DatabaseProcess.cpp +++ b/src/engine/server/library/serverDatabase/src/shared/DatabaseProcess.cpp @@ -193,7 +193,6 @@ DatabaseProcess::~DatabaseProcess() void DatabaseProcess::run(void) { static bool shouldSleep = ConfigServerDatabase::getShouldSleep(); - unsigned long startTime; bool idle=false; int loopcount=0; float nextMemoryReportTime=0; @@ -205,8 +204,6 @@ void DatabaseProcess::run(void) { PROFILER_AUTO_BLOCK_DEFINE("main loop"); - startTime = Clock::timeMs(); - if (!Os::update()) setDone("OS condition (Parent pid change)"); diff --git a/src/engine/server/library/serverGame/src/shared/city/CityInfo.h b/src/engine/server/library/serverGame/src/shared/city/CityInfo.h index 52b041af6..3fa709461 100644 --- a/src/engine/server/library/serverGame/src/shared/city/CityInfo.h +++ b/src/engine/server/library/serverGame/src/shared/city/CityInfo.h @@ -34,8 +34,8 @@ namespace Archive class CityInfo { - friend void Archive::get(ReadIterator & source, CityInfo & target); - friend void Archive::put(ByteStream & target, const CityInfo & source); + friend void Archive::get(Archive::ReadIterator & source, CityInfo & target); + friend void Archive::put(Archive::ByteStream & target, const CityInfo & source); public: CityInfo(); diff --git a/src/engine/server/library/serverGame/src/shared/city/CityStructureInfo.h b/src/engine/server/library/serverGame/src/shared/city/CityStructureInfo.h index f99738daf..13a090a63 100644 --- a/src/engine/server/library/serverGame/src/shared/city/CityStructureInfo.h +++ b/src/engine/server/library/serverGame/src/shared/city/CityStructureInfo.h @@ -30,8 +30,8 @@ namespace Archive class CityStructureInfo { - friend void Archive::get(ReadIterator & source, CityStructureInfo & target); - friend void Archive::put(ByteStream & target, const CityStructureInfo & source); + friend void Archive::get(Archive::ReadIterator & source, CityStructureInfo & target); + friend void Archive::put(Archive::ByteStream & target, const CityStructureInfo & source); public: bool operator== (const CityStructureInfo& rhs) const; diff --git a/src/engine/server/library/serverGame/src/shared/command/CommandCppFuncs.cpp b/src/engine/server/library/serverGame/src/shared/command/CommandCppFuncs.cpp index ece0ba3c2..ff3f058cc 100644 --- a/src/engine/server/library/serverGame/src/shared/command/CommandCppFuncs.cpp +++ b/src/engine/server/library/serverGame/src/shared/command/CommandCppFuncs.cpp @@ -1,9873 +1,9873 @@ -// ====================================================================== -// -// CommandCppFuncs.cpp -// Copyright 2002-2004, Sony Online Entertainment, Inc. -// All Rights Reserved. -// -// ====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/CommandCppFuncs.h" - -#include "UnicodeUtils.h" -#include "serverGame/BiographyManager.h" -#include "serverGame/BuildingObject.h" -#include "serverGame/BuffManager.h" -#include "serverGame/CellObject.h" -#include "serverGame/CharacterMatchManager.h" -#include "serverGame/Chat.h" -#include "serverGame/CitizenInfo.h" -#include "serverGame/CityInfo.h" -#include "serverGame/CityInterface.h" -#include "serverGame/Client.h" -#include "serverGame/CommandStringId.h" -#include "serverGame/CommandQueue.h" -#include "serverGame/CommoditiesMarket.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ConsoleManager.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureController.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/DraftSchematicObject.h" -#include "serverGame/FactoryObject.h" -#include "serverGame/FormManagerServer.h" -#include "serverGame/GameServer.h" -#include "serverGame/GroupObject.h" -#include "serverGame/GroupStringId.h" -#include "serverGame/GuildInterface.h" -#include "serverGame/GuildMemberInfo.h" -#include "serverGame/HarvesterInstallationObject.h" -#include "serverGame/ServerImageDesignerManager.h" -#include "serverGame/ManufactureSchematicObject.h" -#include "serverGame/MessageToQueue.h" -#include "serverGame/NameManager.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PlanetObject.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/ProsePackageManagerServer.h" -#include "serverGame/ReportManager.h" -#include "serverGame/ResourceContainerObject.h" -#include "serverGame/ResourceTypeObject.h" -#include "serverGame/ServerAsteroidManager.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/ShipController.h" -#include "serverGame/ShipObject.h" -#include "serverGame/TaskGetAttributes.h" -#include "serverGame/VeteranRewardManager.h" -#include "serverNetworkMessages/DownloadCharacterMessage.h" -#include "serverNetworkMessages/ExchangeListCreditsMessage.h" -#include "serverNetworkMessages/GameConnectionServerMessages.h" -#include "serverNetworkMessages/GroupMemberParam.h" -#include "serverNetworkMessages/UploadCharacterMessage.h" -#include "serverNetworkMessages/TeleportToMessage.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptDictionary.h" -#include "serverScript/ScriptFunctionTable.h" -#include "serverScript/ScriptParameters.h" -#include "sharedCollision/CollisionProperty.h" -#include "sharedCollision/CollisionWorld.h" -#include "sharedCollision/Footprint.h" -#include "sharedFile/TreeFile.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/CrcLowerString.h" -#include "sharedFoundation/DynamicVariableLocationData.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/GameControllerMessage.h" -#include "sharedFoundation/NetworkId.h" -#include "sharedGame/CitizenRankDataTable.h" -#include "sharedGame/Command.h" -#include "sharedGame/CommandTable.h" -#include "sharedGame/CustomizationManager.h" -#include "sharedGame/GroupPickupPoint.h" -#include "sharedGame/GuildRankDataTable.h" -#include "sharedGame/PlayerFormationManager.h" -#include "sharedGame/GameLanguageManager.h" -#include "sharedGame/GameObjectTypes.h" -#include "sharedGame/TravelPoint.h" -#include "sharedUtility/Location.h" -#include "sharedGame/MatchMakingCharacterPreferenceId.h" -#include "sharedGame/MatchMakingCharacterProfileId.h" -#include "sharedGame/MatchMakingId.h" -#include "sharedGame/MoodManager.h" -#include "sharedGame/OutOfBandPackager.h" -#include "sharedGame/PlatformFeatureBits.h" -#include "sharedGame/ProsePackage.h" -#include "sharedGame/Quest.h" -#include "sharedGame/QuestManager.h" -#include "sharedGame/SharedStringIds.h" -#include "sharedGame/ShipChassisSlotType.h" -#include "sharedGame/SocialsManager.h" -#include "sharedGame/SpatialChatManager.h" -#include "sharedGame/TextIterator.h" -#include "sharedGame/Waypoint.h" -#include "sharedLog/Log.h" -#include "sharedMath/MultiShape.h" -#include "sharedNetworkMessages/CharacterSheetResponseMessage.h" -#include "sharedNetworkMessages/ChatAvatarId.h" -#include "sharedNetworkMessages/ChatRequestLog.h" -#include "sharedNetworkMessages/ClientEffectMessages.h" -#include "sharedNetworkMessages/ConsoleChannelMessages.h" -#include "sharedNetworkMessages/EditAppearanceMessage.h" -#include "sharedNetworkMessages/EditStatsMessage.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/MessageQueueCombatSpam.h" -#include "sharedNetworkMessages/MessageQueueDraftSlotsQueryResponse.h" -#include "sharedNetworkMessages/MessageQueueGenericIntResponse.h" -#include "sharedNetworkMessages/MessageQueueGenericResponse.h" -#include "sharedNetworkMessages/MessageQueueGenericValueType.h" -#include "sharedNetworkMessages/MessageQueueNetworkId.h" -#include "sharedNetworkMessages/MessageQueuePosture.h" -#include "sharedNetworkMessages/MessageQueueSitOnObject.h" -#include "sharedNetworkMessages/MessageQueueSpatialChat.h" -#include "sharedObject/CachedNetworkId.h" -#include "sharedObject/CellProperty.h" -#include "sharedObject/ContainedByProperty.h" -#include "sharedObject/CustomizationData.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/PaletteColorCustomizationVariable.h" -#include "sharedObject/SlotIdManager.h" -#include "sharedObject/SlottedContainer.h" -#include "sharedObject/SlottedContainmentProperty.h" -#include "sharedObject/VolumeContainer.h" -#include "sharedSkillSystem/SkillManager.h" -#include "sharedSkillSystem/SkillObject.h" -#include "sharedTerrain/TerrainObject.h" - -#include - -namespace CommandCppFuncsNamespace -{ - const std::string BEAST_SCRIPT = "ai.beast"; - - void internalSetBoosterOnOff(NetworkId const & actor, bool onOff) - { - ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); - CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; - - if (actorCreature == NULL) - return; - - ShipObject * const shipObject = actorCreature->getPilotedShip(); - if (shipObject == NULL) - return; - - if (!shipObject->isSlotInstalled(ShipChassisSlotType::SCST_booster)) - { - Chat::sendSystemMessage(*actorCreature, SharedStringIds::no_booster, Unicode::emptyString); - return; - } - - if (!shipObject->isComponentFunctional(ShipChassisSlotType::SCST_booster)) - { - Chat::sendSystemMessage(*actorCreature, SharedStringIds::booster_disabled, Unicode::emptyString); - return; - } - - if (onOff && shipObject->getBoosterEnergyCurrent() < shipObject->getBoosterEnergyRechargeRate()) - { - Chat::sendSystemMessage(*actorCreature, SharedStringIds::booster_low_energy, Unicode::emptyString); - return; - } - - if (onOff && !shipObject->isBoosterReady()) - { - Chat::sendSystemMessage(*actorCreature, SharedStringIds::booster_not_ready, Unicode::emptyString); - return; - } - - shipObject->setComponentActive(ShipChassisSlotType::SCST_booster, onOff); - shipObject->restartBoosterTimer(); - } - - ServerObject const *getFirstParentInWorldOrPlayer(ServerObject const *o) - { - while (o && !o->isInWorld() && !o->isPlayerControlled()) - o = safe_cast(ContainerInterface::getContainedByObject(*o)); - return o; - } - - ServerObject const *getFirstCreatureContainer(ServerObject const *o) - { - while (o && !o->isInWorld() && !o->asCreatureObject()) - o = safe_cast(ContainerInterface::getContainedByObject(*o)); - return o; - } - - - ShipObject *getAttachedShip(CreatureObject *creature) - { - // The "attached" ship is the ship which must move along with the creature. - // This means if the creature is piloting, the ship is is piloting, - // or the containing ship if the creature is the ship's owner. - ShipObject * const ship = ShipObject::getContainingShipObject(creature); - if ( ship - && ( ship->getOwnerId() == creature->getNetworkId() - || creature->getPilotedShip() == ship)) - return ship; - return 0; - } - - CreatureObject * findAndResolveCreatureByNetworkId(NetworkId const & targetId) - { - CreatureObject * targetCreatureObject = NULL; - - { - // find the target. the target could be either a creature or ship - ServerObject * const serverObject = ServerWorld::findObjectByNetworkId(targetId); - targetCreatureObject = (serverObject != NULL) ? serverObject->asCreatureObject() : NULL; - - if (targetCreatureObject == NULL) - { - ShipObject * const shipObject = (serverObject != NULL) ? serverObject->asShipObject() : NULL; - - if (shipObject != NULL) - { - targetCreatureObject = shipObject->getPilot(); - - if (targetCreatureObject == NULL) - { - // this means that it is a POB ship that doesn't have a pilot - // in this case we find the owner - std::vector passengers; - shipObject->findAllPassengers(passengers, true); - - std::vector::const_iterator ii = passengers.begin(); - std::vector::const_iterator iiEnd = passengers.end(); - - for (; ii != iiEnd && targetCreatureObject == NULL; ++ii) - { - if ((*ii)->getNetworkId() == shipObject->getOwnerId()) - { - targetCreatureObject = *ii; - break; - } - } - } - } - } - } - return targetCreatureObject; - } - - ShipObject const *getFirstPackedShipForCreature(CreatureObject const &creature) - { - ServerObject const * const datapad = creature.getDatapad(); - if (datapad) - { - Container const * const container = ContainerInterface::getContainer(*datapad); - if (container) - { - for (ContainerConstIterator i = container->begin(); i != container->end(); ++i) - { - ServerObject const * const content = safe_cast((*i).getObject()); - if ( content - && content->getGameObjectType() == SharedObjectTemplate::GOT_data_ship_control_device - && !content->isBeingDestroyed()) - { - Container const * const scdContainer = ContainerInterface::getContainer(*content); - if (scdContainer) - { - for (ContainerConstIterator j = scdContainer->begin(); j != scdContainer->end(); ++j) - { - ServerObject const * const scdContent = safe_cast((*j).getObject()); - if (scdContent && !scdContent->isBeingDestroyed() && scdContent->asShipObject()) - return scdContent->asShipObject(); - } - } - } - } - } - } - return 0; - } - - // Move a list of items back into their slots. We assume the items were just in their slots and can be moved back with no problems. - void reequipItems(ServerObject & destination, const std::vector > & oldItems) - { - Container::ContainerErrorCode errorCode = Container::CEC_Success; - for (std::vector >::const_iterator i = oldItems.begin(); i != oldItems.end(); ++i) - { - IGNORE_RETURN(ContainerInterface::transferItemToSlottedContainer(destination, *((*i).first), (*i).second, NULL, errorCode)); - } - } - - void doSocial(ServerObject & actor, NetworkId const & targetId, uint32 socialType) - { - if (actor.getClient()) - { - ServerObject const * const target = ServerWorld::findObjectByNetworkId(targetId); - if (target && ObserveTracker::isObserving(*(actor.getClient()), *target)) - { - actor.performSocial(targetId, socialType, true, true); - } - } - } - - namespace GroupHelpers - { - bool creatureIsContainedInPOBShip(CreatureObject const * creatureObject); - void removeFromGroupAndCreatePOBGroup(GroupObject * groupToRemoveFrom, - GroupMemberParam const & leader, - GroupObject::GroupMemberParamVector & membersInsidePOB); - // The owner of the POB ship is not included in the inside POB member lists - void separateGroupBasedOffofPOBShip(GroupObject * groupObj, - NetworkId const & ownerOfThePOBShipId, - NetworkId const & POBShipId, - GroupObject::GroupMemberParamVector & membersInsidePOB, - GroupObject::GroupMemberParamVector & membersOutsidePOB); - - TravelPoint const * getNearestTravelPoint(std::string const & planetName, Vector const & location, std::vector const & cityBanList, uint32 faction, bool starPortAndShuttleportOnly); - } - - void triggerSpaceEjectPlayerFromShip(CreatureObject * creatureObject); - - int const cs_spaceSpeechMultiple = 10; -} - -// ====================================================================== - -bool CommandCppFuncsNamespace::GroupHelpers::creatureIsContainedInPOBShip(CreatureObject const * const creatureObject) -{ - NOT_NULL(creatureObject); - - ShipObject const * const shipObject = ShipObject::getContainingShipObject(creatureObject); - return shipObject && shipObject->getPortalProperty(); -} - -// ---------------------------------------------------------------------- - -void CommandCppFuncsNamespace::GroupHelpers::removeFromGroupAndCreatePOBGroup(GroupObject * const groupToRemoveFrom, - GroupMemberParam const & leader, - GroupObject::GroupMemberParamVector & membersInsidePOB) -{ - if (groupToRemoveFrom != 0) - { - GroupObject::GroupMemberParamVector::const_iterator ii = membersInsidePOB.begin(); - GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersInsidePOB.end(); - - for (; ii != iiEnd; ++ii) - { - NetworkId const & memberId = (*ii).m_memberId; - groupToRemoveFrom->removeGroupMember(memberId); - - CreatureObject * const memberCreatureObject = dynamic_cast(ServerWorld::findObjectByNetworkId(memberId)); - if (memberCreatureObject != 0) - { - if (memberCreatureObject->getGroup() == groupToRemoveFrom) - memberCreatureObject->getGroup()->onGroupMemberRemoved(memberCreatureObject->getNetworkId(), false); - } - } - } - - if (!membersInsidePOB.empty()) - { - ServerUniverse::getInstance().createGroup(leader, membersInsidePOB); - } -} - -// ---------------------------------------------------------------------- - -// The owner of the POB ship is not included in the inside POB member lists -void CommandCppFuncsNamespace::GroupHelpers::separateGroupBasedOffofPOBShip(GroupObject * const groupObj, - NetworkId const & ownerOfThePOBShipId, - NetworkId const & POBShipId, - GroupObject::GroupMemberParamVector & membersInsidePOB, - GroupObject::GroupMemberParamVector & membersOutsidePOB) -{ - NOT_NULL(groupObj); - - GroupObject::GroupMemberVector const & groupMembers = groupObj->getGroupMembers(); - GroupObject::GroupMemberVector::const_iterator ii = groupMembers.begin(); - GroupObject::GroupMemberVector::const_iterator iiEnd = groupMembers.end(); - - for (; ii != iiEnd; ++ii) - { - NetworkId const & memberId = ii->first; - NetworkId const & POBShipMemberIsContainedInId = groupObj->getPOBShipMemberIsContainedIn(memberId); - GroupMemberParam const & groupMemberParam = groupObj->createGroupMemberParamForMember(memberId); - - if (POBShipMemberIsContainedInId == POBShipId) - { - // this member is contained in the same POB - if (memberId != ownerOfThePOBShipId) - { - // and is not the owner of the POB - membersInsidePOB.push_back(groupMemberParam); - } - } - else - { - membersOutsidePOB.push_back(groupMemberParam); - } - } -} - -// ---------------------------------------------------------------------- - -void CommandCppFuncsNamespace::triggerSpaceEjectPlayerFromShip(CreatureObject * const creatureObject) -{ - if (creatureObject == 0) - { - WARNING(true, ("CommandCppFuncsNamespace::triggerSpaceEjectPlayerFromShip: NULL CreatureObject.")); - return; - } - - GameScriptObject * gameScriptObject = creatureObject->getScriptObject(); - - if(gameScriptObject != 0) - { - ScriptParams scriptParams; - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_EJECT_PLAYER_FROM_SHIP, scriptParams)); - } - else - { - WARNING(true, ("CommandCppFuncsNamespace::triggerSpaceEjectPlayerFromShip: NULL ScriptObject.")); - } -} - -// ---------------------------------------------------------------------- - -TravelPoint const * CommandCppFuncsNamespace::GroupHelpers::getNearestTravelPoint(std::string const & planetName, Vector const & location, std::vector const & cityBanList, uint32 faction, bool starPortAndShuttleportOnly) -{ - TravelPoint const * nearestTravelPoint = NULL; - PlanetObject const * const planetObject = ServerUniverse::getInstance().getPlanetByName(planetName); - if (planetObject) - { - int const numberOfTravelPoints = planetObject->getNumberOfTravelPoints(); - for (int i = 0; i < numberOfTravelPoints; ++i) - { - TravelPoint const * tp = planetObject->getTravelPoint(i); - if (!tp) - continue; - - if (starPortAndShuttleportOnly && ((tp->getType() & TravelPoint::TPT_PC_CampShuttleBeacon) || (tp->getType() & TravelPoint::TPT_NPC_StaticBaseBeacon))) - continue; - - // need to check factional alignment in order to use the gcw static base travel point - std::string const & tpName = tp->getName(); - if (tpName.find("gcwstaticbase") != std::string::npos) - { - if ((tpName.find("rebel") != std::string::npos) && !PvpData::isRebelFactionId(faction)) - continue; - else if ((tpName.find("imperial") != std::string::npos) && !PvpData::isImperialFactionId(faction)) - continue; - } - - // if the travel point is inside a player city, make sure player is not banned in that city - if (!cityBanList.empty()) - { - int const cityAtTp = CityInterface::getCityAtLocation(planetName, static_cast(tp->getPosition_w().x), static_cast(tp->getPosition_w().z), 0); - if ((cityAtTp > 0) && (std::find(cityBanList.begin(), cityBanList.end(), cityAtTp) != cityBanList.end())) - continue; - } - - if (!nearestTravelPoint || (location.magnitudeBetweenSquared(tp->getPosition_w()) < location.magnitudeBetweenSquared(nearestTravelPoint->getPosition_w()))) - nearestTravelPoint = tp; - } - } - - return nearestTravelPoint; -} - -// ====================================================================== - -using namespace CommandCppFuncsNamespace; - -// ====================================================================== - -static const std::string OBJVAR_PLAYERS_CAN_ACCESS_CONTAINER("players_can_access_container"); - -// ====================================================================== - -static void sendProseMessage(const CreatureObject &actor, const ServerObject * const target, StringId const &stringId) -{ - Chat::sendSystemMessageSimple (actor, stringId, target); -} - -// ====================================================================== - -static Client *getClientFromCharacterId(NetworkId const &charId) -{ - ServerObject *obj = safe_cast(NetworkIdManager::getObjectById(charId)); - if (obj) - return obj->getClient(); - return 0; -} - -// ---------------------------------------------------------------------- - -static std::string nextStringParm(Unicode::String const &str, size_t &curpos) -{ - size_t endpos = 0; - Unicode::String token; - if (!Unicode::getFirstToken(str, curpos, endpos, token)) - return std::string (); - curpos = endpos; - return Unicode::wideToNarrow(token); -} - -// ---------------------------------------------------------------------- - -static int nextIntParm(Unicode::String const &str, size_t &curpos) -{ - std::string strParm = nextStringParm(str, curpos); - if (strParm.empty()) - return -1; - return atoi(strParm.c_str()); -} - -// ---------------------------------------------------------------------- - -static NetworkId nextOidParm(Unicode::String const &str, size_t &curpos) -{ - std::string const &s = nextStringParm(str, curpos); - if (!s.empty()) - { - if ((!isdigit(s.c_str()[0])) && ((s.c_str()[0]) != '-')) - return NameManager::getInstance().getPlayerId(NameManager::normalizeName(s)); - return NetworkId(s); - } - return NetworkId::cms_invalid; -} - -// ---------------------------------------------------------------------- - -static float nextFloatParm(Unicode::String const &str, size_t &curpos) -{ - return static_cast(strtod(nextStringParm(str, curpos).c_str(), NULL)); -} - - -// ---------------------------------------------------------------------- - -static bool nextBoolParm(Unicode::String const &str, size_t &curpos) -{ - return (nextIntParm(str, curpos) != 0); -} - -// ---------------------------------------------------------------------- - -static Vector nextVectorParm(Unicode::String const &str, size_t &curpos) -{ - float x=nextFloatParm(str,curpos); - float y=nextFloatParm(str,curpos); - float z=nextFloatParm(str,curpos); - - return Vector(x,y,z); -} - -// ====================================================================== - -static void commandFuncConsoleAll(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - if (actor != NetworkId::cms_invalid) - { - ServerObject *obj = safe_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - Client *client = obj->getClient(); - if (client && client->isGod()) - { - LOG("CustomerService",("Avatar:%s executing command: %s", PlayerObject::getAccountDescription(client->getCharacterObjectId()).c_str(), Unicode::wideToNarrow(params).c_str())); - ConsoleMgr::processString(Unicode::wideToNarrow(params), client, 0); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleCategory(NetworkId const &actor, - std::string const &category, Unicode::String const ¶ms) -{ - if (actor != NetworkId::cms_invalid) - { - ServerObject *obj = safe_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - Client *client = obj->getClient(); - if (client) - { - ConsoleMgr::processString(category + " " + Unicode::wideToNarrow(params), client, 0); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleCombat(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "combat", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleCraft(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "craft", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleDatabase(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "database", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleManufacture(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "manufacture", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleMoney(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "money", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleNpc(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "npc", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleObject(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "object", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleObjvar(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "objvar", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleResource(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "resource", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleScript(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "script", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleServer(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "server", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncConsoleSkill(Command const &command, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - UNREF(target); - commandFuncConsoleCategory(actor, "skill", params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminSetGodMode(Command const &, NetworkId const &actor, - NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - bool enable = nextBoolParm(params, pos); - - Client *client = getClientFromCharacterId(actor); - if (client) - IGNORE_RETURN(client->setGodMode(enable)); -} - -// ---------------------------------------------------------------------- - -static void commandFuncResetCooldowns(Command const &, NetworkId const &actor, - NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (actorObj) - { - actorObj->getCommandQueue()->resetCooldowns(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSpewCommandQueue(Command const &, NetworkId const &actor, - NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (actorObj) - { - actorObj->getCommandQueue()->spew(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminKick(Command const &, NetworkId const &actor, - NetworkId const &target, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (actorObj) - { - NetworkId who(target); - if (who == NetworkId::cms_invalid) - { - size_t curpos = 0; - who = nextOidParm(params, curpos); - if (who == NetworkId::cms_invalid) - return; - } - - ShipObject * const shipObject = dynamic_cast(NetworkIdManager::getObjectById(who)); - if (shipObject) - { - // If the target is a ship, kick all the people in the ship - std::vector passengers; - shipObject->findAllPassengers(passengers, true); - for (std::vector::const_iterator i=passengers.begin(); i!=passengers.end(); ++i) - { - KickPlayer const kickMessage((*i)->getNetworkId(), "Admin Kick"); - GameServer::getInstance().sendToConnectionServers(kickMessage); - } - } - else - { - KickPlayer const kickMessage(who, "Admin Kick"); - GameServer::getInstance().sendToConnectionServers(kickMessage); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncLocateStructure(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); - if (!playerObj) - return; - - Client * const clientObj = actorObj->getClient(); - if (!clientObj) - return; - - bool const isGod = clientObj->isGod(); - NetworkId ownerId = actor; - - // god mode can specify a different player to search for - if (isGod && !params.empty()) - { - ownerId = NetworkId(Unicode::wideToNarrow(params)); - if (!ownerId.isValid()) - ownerId = actor; - } - - int const timeNow = static_cast(::time(NULL)); - if (!isGod && actorObj->getObjVars().hasItem("timeNextLocateStructureCommandAllowed") && (actorObj->getObjVars().getType("timeNextLocateStructureCommandAllowed") == DynamicVariable::INT)) - { - int timeNextLocateStructureCommandAllowed = 0; - if (actorObj->getObjVars().getItem("timeNextLocateStructureCommandAllowed", timeNextLocateStructureCommandAllowed)) - { - if (timeNextLocateStructureCommandAllowed > timeNow) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("player_structure", "locate_structure_command_too_fast"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextLocateStructureCommandAllowed - timeNow))); - Chat::sendSystemMessage(*actorObj, prosePackage); - - return; - } - } - } - - NetworkId ownerResidenceId; - if (ownerId == actor) - { - ownerResidenceId = actorObj->getHouse(); - - StringId::LocUnicodeString response; - if (StringId("player_structure", "locate_structure_command_executing").localize(response)) - ConsoleMgr::broadcastString(Unicode::wideToNarrow(response), clientObj); - } - else - { - // should only be here for god mode - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Searching galaxy for all unpacked structures and installations owned by %s.", ownerId.getValueString().c_str()), - clientObj); - } - - GenericValueTypeMessage, std::pair, NetworkId> > > locateStructureByOwnerIdReq("LSBOIReq", std::make_pair(std::make_pair(GameServer::getInstance().getProcessId(), isGod), std::make_pair(std::make_pair(ownerId, ownerResidenceId), actor))); - GameServer::getInstance().sendToCentralServer(locateStructureByOwnerIdReq); - - if (!isGod) - IGNORE_RETURN(actorObj->setObjVarItem("timeNextLocateStructureCommandAllowed", (timeNow + ConfigServerGame::getLocateStructureCommandIntervalSeconds()))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncLocateVendor(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); - if (!playerObj) - return; - - Client * const clientObj = actorObj->getClient(); - if (!clientObj) - return; - - bool const isGod = clientObj->isGod(); - NetworkId ownerId = actor; - - // god mode can specify a different player to search for - if (isGod && !params.empty()) - { - ownerId = NetworkId(Unicode::wideToNarrow(params)); - if (!ownerId.isValid()) - ownerId = actor; - } - - int const timeNow = static_cast(::time(NULL)); - if (!isGod && actorObj->getObjVars().hasItem("timeNextLocateVendorCommandAllowed") && (actorObj->getObjVars().getType("timeNextLocateVendorCommandAllowed") == DynamicVariable::INT)) - { - int timeNextLocateVendorCommandAllowed = 0; - if (actorObj->getObjVars().getItem("timeNextLocateVendorCommandAllowed", timeNextLocateVendorCommandAllowed)) - { - if (timeNextLocateVendorCommandAllowed > timeNow) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("player_vendor", "locate_vendor_command_too_fast"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToMS(static_cast(timeNextLocateVendorCommandAllowed - timeNow))); - Chat::sendSystemMessage(*actorObj, prosePackage); - - return; - } - } - } - - if (ownerId == actor) - { - StringId::LocUnicodeString response; - if (StringId("player_vendor", "locate_vendor_command_executing").localize(response)) - ConsoleMgr::broadcastString(Unicode::wideToNarrow(response), clientObj); - } - else - { - // should only be here for god mode - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Searching the commodities system for all initialized vendors owned by %s.", ownerId.getValueString().c_str()), - clientObj); - } - - GenericValueTypeMessage, bool> > const msg("GetVendorInfoForPlayer", std::make_pair(std::make_pair(actor, ownerId), isGod)); - CommoditiesMarket::sendToCommoditiesServer(msg); - - if (!isGod) - IGNORE_RETURN(actorObj->setObjVarItem("timeNextLocateVendorCommandAllowed", (timeNow + ConfigServerGame::getLocateVendorCommandIntervalSeconds()))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncShowCtsHistory(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject const * targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - Client * const clientObj = targetObj->getClient(); - if (!clientObj) - return; - - NetworkId target = actor; - - // god mode can specify a different player to show CTS history for - if (clientObj->isGod() && !params.empty()) - { - target = NetworkId(Unicode::wideToNarrow(params)); - if (!target.isValid()) - target = actor; - } - - if (target != actor) - { - targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(target)); - targetPlayerObj = (targetObj ? PlayerCreatureController::getPlayerObject(targetObj) : NULL); - if (!targetPlayerObj) - { - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%s is not a valid or nearby player character.", target.getValueString().c_str()), clientObj); - return; - } - - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Retrieving CTS history for %s.", target.getValueString().c_str()), clientObj); - } - else - { - ConsoleMgr::broadcastString("Retrieving CTS history for this character.", clientObj); - } - - // we need to return the CTS history ordered by transfer time - std::multimap > orderedCtsHistory; - - DynamicVariableList::NestedList const ctsTransactions(targetObj->getObjVars(), "ctsHistory"); - for (DynamicVariableList::NestedList::const_iterator i = ctsTransactions.begin(); i != ctsTransactions.end(); ++i) - { - Unicode::String ctsTransactionDetail; - if (i.getValue(ctsTransactionDetail)) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(ctsTransactionDetail, tokens, NULL, NULL) && (tokens.size() >= 4)) - { - Unicode::String characterName; - for (size_t i = 3, j = tokens.size(); i < j; ++i) - { - if (!characterName.empty()) - characterName += Unicode::narrowToWide(" "); - - characterName += tokens[i]; - } - - IGNORE_RETURN(orderedCtsHistory.insert(std::make_pair(atoi(Unicode::wideToNarrow(tokens[0]).c_str()), std::make_pair(Unicode::wideToNarrow(characterName), Unicode::wideToNarrow(tokens[1]))))); - } - } - } - - if (orderedCtsHistory.empty()) - { - ConsoleMgr::broadcastString("No CTS history found.", clientObj); - } - else - { - int count = 0; - for (std::multimap >::const_iterator iter = orderedCtsHistory.begin(); iter != orderedCtsHistory.end(); ++iter) - { - ++count; - - if (orderedCtsHistory.size() == 1) - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Transferred from %s, %s on %s.", iter->second.first.c_str(), iter->second.second.c_str(), CalendarTime::convertEpochToTimeStringLocal(iter->first).c_str()), clientObj); - else - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%d) Transferred from %s, %s on %s.", count, iter->second.first.c_str(), iter->second.second.c_str(), CalendarTime::convertEpochToTimeStringLocal(iter->first).c_str()), clientObj); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminPlanetwarp(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - size_t pos = 0; - std::string const planetName = nextStringParm(params, pos); - Vector const newPosition_w = nextVectorParm(params, pos); - NetworkId const newContainer = nextOidParm(params, pos); - Vector const newPosition_p = nextVectorParm(params, pos); - - CreatureObject * const actorCreature = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorCreature) - { - TangibleObject *targetTangible = actorCreature; - if (target != NetworkId::cms_invalid) - targetTangible = dynamic_cast(ServerWorld::findObjectByNetworkId(target)); - - if (targetTangible) - { - if (!ServerWorld::isSpaceScene() && !strncmp(planetName.c_str(), "space_", 5) && targetTangible->asCreatureObject()) - { - // going to space from the ground, so require a ship and set launch information - ShipObject const * const ship = getFirstPackedShipForCreature(*targetTangible->asCreatureObject()); - if (!ship) - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("No valid ship, cannot warp to space scene."), Unicode::emptyString); - return; - } - - DynamicVariableLocationData const loc(targetTangible->getPosition_w(), ServerWorld::getSceneId(), NetworkId::cms_invalid); - targetTangible->setObjVarItem("space.launch.worldLoc", loc); - targetTangible->setObjVarItem("space.launch.ship", ship->getNetworkId()); - targetTangible->setObjVarItem("space.launch.startIndex", static_cast(0)); - } - - GameServer::getInstance().requestSceneWarp(CachedNetworkId(*targetTangible), planetName, newPosition_w, newContainer, newPosition_p); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminTeleport(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - size_t pos = 0; - Vector position_w = nextVectorParm(params, pos); - NetworkId targetCell = nextOidParm(params, pos); - Vector position_p = nextVectorParm(params, pos); - - // make sure coordinates are sane - float const maxSaneCoordinate = 100000; - if ((position_w.x < -maxSaneCoordinate) || - (position_w.x > maxSaneCoordinate) || - (position_w.y < -maxSaneCoordinate) || - (position_w.y > maxSaneCoordinate) || - (position_w.z < -maxSaneCoordinate) || - (position_w.z > maxSaneCoordinate) || - (position_p.x < -maxSaneCoordinate) || - (position_p.x > maxSaneCoordinate) || - (position_p.y < -maxSaneCoordinate) || - (position_p.y > maxSaneCoordinate) || - (position_p.z < -maxSaneCoordinate) || - (position_p.z > maxSaneCoordinate)) - { - const Object * const actorObj = NetworkIdManager::getObjectById(actor); - if (actorObj && actorObj->asServerObject()) - { - Client * const actorClient = actorObj->asServerObject()->getClient(); - if (actorClient) - { - char buffer[512]; - snprintf(buffer, sizeof(buffer)-1, "specified coordinate (%.2f,%.2f,%.2f) (%.2f,%.2f,%.2f) is out of range", - position_w.x, position_w.y, position_w.z, - position_p.x, position_p.y, position_p.z); - buffer[sizeof(buffer)-1] = '\0'; - - ConsoleMgr::broadcastString(buffer, actorClient); - } - } - - return; - } - - ServerObject *teleportObj = 0; - if (target != NetworkId::cms_invalid) - teleportObj = ServerWorld::findObjectByNetworkId(target); - else - teleportObj = ServerWorld::findObjectByNetworkId(actor); - - if (teleportObj) - { - // if the person teleporting is the owner of the containing ship, move the ship instead - ShipObject * const ship = getAttachedShip(teleportObj->asCreatureObject()); - if (ship) - ship->teleportObject(position_w, NetworkId::cms_invalid, "", position_w, ""); - else - teleportObj->teleportObject(position_w, targetCell, "", position_p, ""); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminTeleportTo(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - CreatureObject * const actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (actorObj) - { - CachedNetworkId who(target); - if (who == NetworkId::cms_invalid) - { - size_t curpos = 0; - who = nextOidParm(params, curpos); - } - // if the object exists locally, just teleport to it, otherwise send to db server for scatter/gather - Object * const destObj = who.getObject(); - if (destObj) - { - // if the person teleporting has a ship that must go with it, move the ship instead - ShipObject * const ship = getAttachedShip(actorObj->asCreatureObject()); - if (ship) - ship->teleportObject(destObj->findPosition_w(), NetworkId::cms_invalid, "", destObj->findPosition_w(), ""); - else - { - Object const * const firstParent = ContainerInterface::getFirstParentInWorld(*destObj); - if (firstParent) - { - actorObj->teleportObject( - firstParent->getPosition_w(), - firstParent->getAttachedTo() ? firstParent->getAttachedTo()->getNetworkId() : NetworkId::cms_invalid, - "", - firstParent->getPosition_p(), - ""); - } - } - } - else - { - TeleportToMessage const teleportToMessage(actor, who, GameServer::getInstance().getProcessId()); - GameServer::getInstance().sendToCentralServer(teleportToMessage); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminListGuilds(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - Object *actorObj = NetworkIdManager::getObjectById(actor); - if (actorObj && actorObj->asServerObject()) - { - Client *client = actorObj->asServerObject()->getClient(); - if (client) - { - char buf[512]; - std::vector guildIds; - - GuildInterface::getAllGuildIds(guildIds); - for (std::vector::const_iterator i = guildIds.begin(); i != guildIds.end(); ++i) - { - snprintf(buf, 511, "id:%-8d name:%s abbrev:%s leaderId:%s", - *i, - GuildInterface::getGuildName(*i).c_str(), - GuildInterface::getGuildAbbrev(*i).c_str(), - GuildInterface::getGuildLeaderId(*i).getValueString().c_str()); - buf[511] = '\0'; - ConsoleMgr::broadcastString(buf, client); - } - snprintf(buf, 511, "%d guilds total.", guildIds.size()); - ConsoleMgr::broadcastString(buf, client); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminEditBank(Command const &cmd, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - CreatureObject * actorCreature = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - CreatureObject * targetCreature = safe_cast(ServerWorld::findObjectByNetworkId(target)); - if (!targetCreature || !actorCreature) - { - DEBUG_REPORT_LOG(true, ("Received open command for null player or target.\n")); - return; - } - - ServerObject * targetBank = targetCreature->getBankContainer(); - if(!targetBank) - { - DEBUG_REPORT_LOG(true, ("Couldn't get bank for player %s.\n", target.getValueString().c_str())); - return; - } - - if (targetBank->isAuthoritative()) - { - ScriptParams params; - params.addParam(actor); - if (targetBank->getScriptObject()->trigAllScripts(Scripting::TRIG_ABOUT_TO_OPEN_CONTAINER, params) == SCRIPT_CONTINUE) - { - Client *client = actorCreature->getClient(); - if (client) - client->openContainer(*targetBank, 0, std::string()); - } - } - else - { - GenericValueTypeMessage > const rssMessage( - "RequestSameServer", - std::make_pair( - ContainerInterface::getTopmostContainer(*actorCreature)->getNetworkId(), - ContainerInterface::getTopmostContainer(*targetBank)->getNetworkId())); - GameServer::getInstance().sendToPlanetServer(rssMessage); - ContainerInterface::sendContainerMessageToClient(*actorCreature, Container::CEC_TryAgain, targetBank); - - //actorCreature->transferAuthority(targetBank->getAuthServerProcessId(), true, false); - //actorCreature->commandQueueEnqueue(cmd, target, params, 0, false, Command::CP_Normal, false); - //LOG("container", ("Received open editBank. Player not on same server as the target's bank. Migrating player")); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminEditStats(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject* const creatureActor = dynamic_cast(NetworkIdManager::getObjectById (actor)); - if (!creatureActor) - { - WARNING (true, ("commandFuncAdminEditStats: null actor")); - return; - } - - CreatureObject* const creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (target)); - if (!creatureTarget) - { - WARNING (true, ("commandFuncAdminEditStats: null target")); - return; - } - - EditStatsMessage const esm(target); - Client * const client = creatureActor->getClient(); - if (client) - client->send(esm, true); -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminEditAppearance(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject* const creatureActor = dynamic_cast(NetworkIdManager::getObjectById (actor)); - if (!creatureActor) - { - WARNING (true, ("commandFuncAdminEditAppearance: null actor")); - return; - } - - CreatureObject* const creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (target)); - if (!creatureTarget) - { - WARNING (true, ("commandFuncAdminEditAppearance: null target")); - return; - } - - EditAppearanceMessage const eam(target); - Client * const client = creatureActor->getClient(); - if (client) - client->send(eam, true); -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminGrantTitle(Command const &, NetworkId const &, NetworkId const &, Unicode::String const &) -{ -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminCredits(Command const &, NetworkId const &, NetworkId const &, Unicode::String const &) -{ -} - -// ---------------------------------------------------------------------- - -static void commandFuncAdminGetStationName(Command const &, NetworkId const & actor, NetworkId const & target , Unicode::String const & params) -{ - const Object * const actorObj = NetworkIdManager::getObjectById(actor); - if (actorObj && actorObj->asServerObject()) - { - Client * const actorClient = actorObj->asServerObject()->getClient(); - if (actorClient) - { - const CreatureObject* creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (target)); - if (!creatureTarget) - { - size_t pos = 0; - NetworkId targetId(nextOidParm(params, pos)); - creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (targetId)); - } - - if(!creatureTarget) - { - ConsoleMgr::broadcastString("Could not resolve target passed to getStationName", actorClient); - return; - } - - const Client * const clientTarget = creatureTarget->getClient(); - if(clientTarget) - { - const std::string & stationName = clientTarget->getAccountName(); - char buf [512]; - snprintf(buf, 511, "Station name is: %s.", stationName.c_str()); - ConsoleMgr::broadcastString(buf, actorClient); - } - else - DEBUG_WARNING(true, ("Could not get the target Client in commandFuncAdminGetStationName")); - } - else - DEBUG_WARNING(true, ("Could not get the actor Client in commandFuncAdminGetStationName")); - } - else - DEBUG_WARNING(true, ("Could not get the actor object in commandFuncAdminGetStationName")); -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionCreate(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - - /*printf("!!!!AUCTION: process = %i\n", (int)GameServer::getInstance().getProcessId()); - printf("!!!!PID = %i\n", (int)getpid()); - - Chat::getFriendsList("SWG.msivertson.Orami"); - - return;*/ - - size_t pos = 0; - NetworkId itemId(nextOidParm(params, pos)); - NetworkId auctionContainerId(nextOidParm(params, pos)); - int minBid = nextIntParm(params, pos); - int timer = nextIntParm(params, pos); - Unicode::String userDescription = Unicode::narrowToWide(nextStringParm(params, pos)); - - UNREF(timer); - - CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - TangibleObject *itemTangible = dynamic_cast(NetworkIdManager::getObjectById(itemId)); - ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); - - if (actorCreature && itemTangible && auctionContainer) - { - CommoditiesMarket::auctionCreatePermanent( - "Test Name", - *itemTangible, - *auctionContainer, - minBid, - userDescription); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionCreateImmediate(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - NetworkId itemId(nextOidParm(params, pos)); - NetworkId auctionContainerId(nextOidParm(params, pos)); - int price = nextIntParm(params, pos); - int timer = nextIntParm(params, pos); - Unicode::String userDescription = Unicode::narrowToWide(nextStringParm(params, pos)); - - CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - - - - TangibleObject *itemTangible = dynamic_cast(NetworkIdManager::getObjectById(itemId)); - ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); - - if (actorCreature && itemTangible && auctionContainer) - { - CommoditiesMarket::auctionCreateImmediate( - *actorCreature, - *itemTangible, - Unicode::String(), - *auctionContainer, - price, - timer, - userDescription); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionBid(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - NetworkId auctionId(nextOidParm(params, pos)); - int bidAmount = nextIntParm(params, pos); - int maxProxyBid = nextIntParm(params, pos); - CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - - CommoditiesMarket::getAuctionDetails(*actorCreature, auctionId); - - if (actorCreature) - { - CommoditiesMarket::auctionBid( - *actorCreature, - auctionId.getValue(), - bidAmount, - maxProxyBid); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionCancel(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - NetworkId auctionId(nextOidParm(params, pos)); - - CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - - if (actorCreature) - { - CommoditiesMarket::auctionCancel( - *actorCreature, - auctionId.getValue()); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionAccept(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - NetworkId auctionId(nextOidParm(params, pos)); - - CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - - if (actorCreature) - { - CommoditiesMarket::auctionAccept( - *actorCreature, - auctionId.getValue()); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionQuery(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ -#if 0 - size_t pos = 0; - NetworkId auctionContainerId(nextOidParm(params, pos)); - int requestId = nextIntParm(params, pos); - int type = nextIntParm(params, pos); - int category = nextIntParm(params, pos); - - CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); - - if (actorCreature && auctionContainer) - { - CommoditiesMarket::auctionQuery( - *actorCreature, - requestId, - type, - category, - *auctionContainer); - } -#endif -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionRetrieve(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - NetworkId itemId(nextOidParm(params, pos)); - NetworkId auctionId(nextOidParm(params, pos)); - NetworkId auctionContainerId(nextOidParm(params, pos)); - - CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); - - if (actorCreature && auctionContainer && actorCreature->isAuthoritative() && auctionContainer->isAuthoritative()) - { - CommoditiesMarket::auctionRetrieve( - *actorCreature, - auctionId.getValue(), - itemId, - *auctionContainer); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSocial(Command const &command, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - UNREF(command); - if (actor != NetworkId::cms_invalid) - { - ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - Unicode::UnicodeStringVector sv; - Unicode::tokenize (params, sv); - - if (sv.empty ()) - { - WARNING (true, ("commandFuncSocial no params")); - return; - } - - const std::string & socialName = Unicode::wideToNarrow (sv [0]); - const uint32 socialType = SocialsManager::getSocialTypeByName (socialName); - - if (!socialType) - WARNING (true, ("commandFuncSocial Bad social type specified: [%s]", socialName.c_str ())); - else - { - bool animationOk = true; - bool textOk = true; - if (sv.size () > 1) - animationOk = !sv [1].empty () && sv [1][0] == '1'; - if (sv.size () > 2) - textOk = !sv [2].empty () && sv [2][0] == '1'; - - obj->performSocial (target, socialType, animationOk, textOk); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSocialInternal (Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - UNREF(command); - if (actor != NetworkId::cms_invalid) - { - ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - Unicode::UnicodeStringVector sv; - Unicode::tokenize (params, sv); - - if (sv.size () < 2) - { - WARNING (true, ("commandFuncSocial not enough params")); - return; - } - - const NetworkId targetId (Unicode::wideToNarrow (sv [0])); - const uint32 socialType = atoi (Unicode::wideToNarrow (sv [1]).c_str()); - - if (!socialType) - WARNING (true, ("commandFuncSocialInternal Bad social type specified: '%d'", socialType)); - else - { - bool animationOk = true; - bool textOk = true; - if (sv.size () > 3) - { - animationOk = !sv [2].empty () && sv [2][0] == '1'; - textOk = !sv [3].empty () && sv [3][0] == '1'; - } - obj->performSocial (targetId, socialType, animationOk, textOk); - } - } - } -} - -//---------------------------------------------------------------------- - -static void commandFuncSetMood (Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - UNREF(command); - if (actor != NetworkId::cms_invalid) - { - CreatureObject * const obj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - const std::string moodName = Unicode::wideToNarrow (params); - - if (moodName == "none") - { - obj->setMood (0); - } - else - { - const uint32 moodType = MoodManager::getMoodByCanonicalName (moodName); - if (moodType) - obj->setMood (moodType); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetMoodInternal (Command const &command, NetworkId const &actor, - NetworkId const &, Unicode::String const ¶ms) -{ - UNREF(command); - if (actor != NetworkId::cms_invalid) - { - CreatureObject * const obj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - const uint32 moodType = atoi(Unicode::wideToNarrow(params).c_str()); - obj->setMood (moodType); - } - } -} - -//---------------------------------------------------------------------- - -static void commandFuncRequestWaypointAtPosition (Command const &command, NetworkId const &actor, - NetworkId const &, Unicode::String const ¶ms) -{ - UNREF(command); - if (actor != NetworkId::cms_invalid) - { - CreatureObject * const obj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - if(obj->isPlayerControlled()) - { - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(obj); - if(playerObject) - { - size_t curpos = 0; - - uint8 color = static_cast(Waypoint::Blue); - std::string planet = nextStringParm (params, curpos); - - // the first parameter may be the name of the planet or an unsigned - // int specifying the color of the waypoint, in which case the - // second parameter is the name of the planet - - // obfuscation to prevent player from manually entering the - // requestWaypointAtPosition command and specifying the waypoint color - char buffer[256]; - snprintf(buffer, sizeof(buffer)-1, "(^-,=+_)color_%s(,+-=_^)=", actor.getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - - if (planet.find(buffer) == 0) - { - size_t const bufferLength = strlen(buffer); - if (planet.size() > bufferLength) - { - std::string const colorStr = planet.substr(bufferLength); - color = static_cast(atoi(colorStr.c_str())); - - if ((color >= static_cast(Waypoint::NumColors)) || (color == static_cast(Waypoint::Invisible))) - color = static_cast(Waypoint::Blue); - } - - planet = nextStringParm(params, curpos); - } - - const float x = nextFloatParm (params, curpos); - const float y = nextFloatParm (params, curpos); - const float z = nextFloatParm (params, curpos); - curpos = Unicode::skipWhitespace (params, curpos); - - const std::string& sceneId = ServerWorld::getSceneId(); - StringId s("planet_n", sceneId); - - const Unicode::String & name = ((curpos != Unicode::String::npos) ? (params.substr (curpos)) : (Unicode::narrowToWide("@" + s.getCanonicalRepresentation()))); - - // get player object - Waypoint waypoint(playerObject->createWaypoint(Location(Vector(x, y, z), NetworkId::cms_invalid, Location::getCrcBySceneName(planet)),false)); - if (waypoint.isValid()) - { - waypoint.setName(name); // Waypoints are a bit like smart pointers, so this is changing the data on the PlayerObject, not just on a local variable - waypoint.setColor(color); - } - else - { - Chat::sendSystemMessage(*obj, SharedStringIds::too_many_waypoints, Unicode::emptyString); - } - } - } - } - } -} - -// ---------------------------------------------------------------------- - -/** -* Parameters: -* All parameters except text are integers -*/ - -static void commandFuncSpatialChatInternal(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - if (actor != NetworkId::cms_invalid) - { - ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - - size_t curpos = 0; - - const NetworkId targetId (nextStringParm (params, curpos)); - const int chatType = nextIntParm (params, curpos); - const int mood = nextIntParm (params, curpos); - int flags = nextIntParm (params, curpos); - int language = nextIntParm (params, curpos); - - // Verify the language parameter - - if (!GameLanguageManager::isLanguageValid(language)) - { - language = GameLanguageManager::getBasicLanguageId(); - } - - curpos = Unicode::skipWhitespace (params, curpos); - - if (curpos == Unicode::String::npos) - { - DEBUG_WARNING (true, ("empty string in spatial chat")); - return; - } - - const size_t nullpos = params.find (static_cast(0), curpos); - - Unicode::String text; - Unicode::String oob; - - if (nullpos != Unicode::String::npos) - { - text = params.substr (curpos, nullpos - curpos); - oob = params.substr (nullpos + 1); - } - else - { - // Strip any color codes the user may have entered - - text = TextIterator(params.substr (curpos)).getPrintableText(); - } - - if (text.empty()) - { - return; - } - - const bool isPrivate = SpatialChatManager::isPrivate (chatType); - - if (isPrivate) - flags |= MessageQueueSpatialChat::F_isPrivate; - - if (chatType != -1 && mood != -1 && flags != -1 && curpos != Unicode::String::npos) - { - uint16 volume = SpatialChatManager::getVolume (chatType); - - CreatureObject * const creatureActor = obj->asCreatureObject(); - - //speak cs_spaceSpeechMultiple times when piloting a ship - if(creatureActor && creatureActor->getPilotedShip()) - volume *= cs_spaceSpeechMultiple; - - // track amount of spatial chat for the character - bool allowToSpeak = true; - bool squelched = false; - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureActor); - if (playerObject) - { - // update chat character count - playerObject->updateChatSpamSpatialNumCharacters(actor, text.size()); - - // see if player has exceeded chat limit - if (ConfigServerGame::getChatSpamLimiterEnabledForFreeTrial() && - obj->getClient() && - ((obj->getClient()->getSubscriptionFeatures() & ClientSubscriptionFeature::Base) == 0) && - ((playerObject->getChatSpamSpatialNumCharacters() + playerObject->getChatSpamNonSpatialNumCharacters()) > ConfigServerGame::getChatSpamLimiterNumCharacters())) - { - allowToSpeak = false; - } - // see if the player is squelched - else if (0 != playerObject->getSecondsUntilUnsquelched()) - { - allowToSpeak = false; - squelched = true; - } - } - - if (allowToSpeak) - { - // character allowed to talk - obj->speakText( - MessageQueueSpatialChat( - CachedNetworkId(actor), - CachedNetworkId(targetId), - text, - volume, - static_cast(chatType), - static_cast(mood), - flags, - language, - oob)); - } - else if (!squelched && (ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds() > 0) && obj->getClient()) - { - // send message telling character he can no longer talk - const int timeNow = static_cast(::time(NULL)); - const int chatSpamTimeEndInterval = playerObject->getChatSpamTimeEndInterval(); - if ((chatSpamTimeEndInterval > timeNow) && (timeNow >= playerObject->getChatSpamNextTimeToNotifyPlayerWhenLimited())) - { - GenericValueTypeMessage csl("ChatSpamLimited", (chatSpamTimeEndInterval - timeNow)); - obj->getClient()->send(csl, true); - - playerObject->setChatSpamNextTimeToNotifyPlayerWhenLimited((timeNow + ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds())); - } - } - } - } - } -} - -// ---------------------------------------------------------------------- - -/** -* Parameters: [null terminator + oob] -* All parameters are strings -*/ - -static void commandFuncSpatialChat(Command const &, NetworkId const &actor, NetworkId const & targetId, Unicode::String const ¶ms) -{ - if (actor != NetworkId::cms_invalid) - { - ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); - if (obj) - { - size_t curpos = 0; - - Unicode::String chatTypeName; - Unicode::String moodTypeName; - Unicode::String flagsString; - - if (!Unicode::getFirstToken (params, curpos, curpos, chatTypeName) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncSpatialChat (no chat type)")); - return; - } - - if (!Unicode::getFirstToken (params, ++curpos, curpos, moodTypeName) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncSpatialChat (no mood type)")); - return; - } - - if (!Unicode::getFirstToken (params, ++curpos, curpos, flagsString) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncSpatialChat (no flags)")); - return; - } - - curpos = Unicode::skipWhitespace(params, ++curpos); - - const std::string & narrow_chatTypeName = Unicode::wideToNarrow (chatTypeName); - const std::string & narrow_moodTypeName = Unicode::wideToNarrow (moodTypeName); - - const uint32 chatType = SpatialChatManager::getChatTypeByName (narrow_chatTypeName); - - curpos = Unicode::skipWhitespace (params, curpos); - - if (curpos == Unicode::String::npos) - { - DEBUG_WARNING (true, ("empty string in spatial chat")); - return; - } - - size_t nullpos = params.find (static_cast(0), curpos); - - Unicode::String text; - Unicode::String oob; - - if (nullpos != Unicode::String::npos) - { - text = params.substr (curpos, nullpos - curpos); - oob = params.substr (nullpos + 1); - } - else - { - text = params.substr (curpos); - - } - - if (curpos != Unicode::String::npos) - { - const uint32 moodType = MoodManager::getMoodByCanonicalName (narrow_moodTypeName); - const bool isPrivate = SpatialChatManager::isPrivate (chatType); - - uint32 flags = atoi (Unicode::wideToNarrow (flagsString).c_str ()); - if (isPrivate) - flags |= MessageQueueSpatialChat::F_isPrivate; - - const uint16 volume = SpatialChatManager::getVolume (chatType); - - // track amount of spatial chat for the character - bool allowToSpeak = true; - bool squelched = false; - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(obj->asCreatureObject()); - if (playerObject) - { - // update chat character count - playerObject->updateChatSpamSpatialNumCharacters(actor, text.size()); - - // see if player has exceeded chat limit - if (ConfigServerGame::getChatSpamLimiterEnabledForFreeTrial() && - obj->getClient() && - ((obj->getClient()->getSubscriptionFeatures() & ClientSubscriptionFeature::Base) == 0) && - ((playerObject->getChatSpamSpatialNumCharacters() + playerObject->getChatSpamNonSpatialNumCharacters()) > ConfigServerGame::getChatSpamLimiterNumCharacters())) - { - allowToSpeak = false; - } - // see if the player is squelched - else if (0 != playerObject->getSecondsUntilUnsquelched()) - { - allowToSpeak = false; - squelched = true; - } - } - - if (allowToSpeak) - { - // character allowed to talk - obj->speakText( - MessageQueueSpatialChat( - CachedNetworkId(actor), - CachedNetworkId(targetId), - text, - volume, - static_cast(chatType), - static_cast(moodType), - flags, - 0, - oob)); - } - else if (!squelched && (ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds() > 0) && obj->getClient()) - { - // send message telling character he can no longer talk - const int timeNow = static_cast(::time(NULL)); - const int chatSpamTimeEndInterval = playerObject->getChatSpamTimeEndInterval(); - if ((chatSpamTimeEndInterval > timeNow) && (timeNow >= playerObject->getChatSpamNextTimeToNotifyPlayerWhenLimited())) - { - GenericValueTypeMessage csl("ChatSpamLimited", (chatSpamTimeEndInterval - timeNow)); - obj->getClient()->send(csl, true); - - playerObject->setChatSpamNextTimeToNotifyPlayerWhenLimited((timeNow + ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds())); - } - } - } - else - WARNING (true, ("Invalid empty output string in commandFuncSpatialChat")); - } - } -} - -//---------------------------------------------------------------------- - -/** -* -* string Params: -* - string networkId of 'other' participant -* - integer numeric value -* - integer bitflags for transmission (0x01 == sendToActor, 0x02 == sendToTarget, 0x04 == sendToBystanders) -* - string or stringID. StringId is preceded with a '@' -* -static void commandFuncCombatSpam (Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - const CachedNetworkId actorId (actor); - const CachedNetworkId targetId (target); - - ServerObject * const obj = safe_cast(actorId.getObject ()); - if (!obj) - { - WARNING (true, ("null actor in commandFuncCombatSpam")); - return; - } - - size_t curpos = 0; - - Unicode::String otherIdStr; - Unicode::String intValueStr; - Unicode::String bitflagsStr; - Unicode::String stringId; - Unicode::String combatSpamType; - - if (!Unicode::getFirstToken (params, curpos, curpos, otherIdStr) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing networkId value)")); - return; - } - - if (!Unicode::getFirstToken (params, ++curpos, curpos, intValueStr) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing int value)")); - return; - } - - if (!Unicode::getFirstToken (params, ++curpos, curpos, bitflagsStr) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing bitflags)")); - return; - } - - if (!Unicode::getFirstToken (params, ++curpos, curpos, stringId) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing stringId)")); - return; - } - - if (!Unicode::getFirstToken (params, ++curpos, curpos, combatSpamType)) - { - WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing combatSpamType)")); - return; - } - - //DEBUG_REPORT_LOG(true, ("Combat spam type: %d\n", Unicode::toInt(combatSpamType))); - - const CachedNetworkId otherId (Unicode::wideToNarrow (otherIdStr)); - - MessageQueueCombatSpam msg (actorId, (actor.getObject() ? actor.getObject()->getPosition_w() : Vector::zero), targetId, (target.getObject() ? target.getObject()->getPosition_w() : Vector::zero), otherId, 0, Unicode::String (), static_cast(Unicode::toInt(combatSpamType))); - - curpos = Unicode::skipWhitespace(params, ++curpos); - - const int intValue = atoi (Unicode::wideToNarrow (intValueStr).c_str ()); - const int bitflags = atoi (Unicode::wideToNarrow (bitflagsStr).c_str ()); - - if (bitflags == 0) - { - WARNING_STRICT_FATAL (true, ("Got a commandFuncCombatSpam with no recepients specified.")); - } - - msg.m_intValue = intValue; - - if (stringId [0] == '@') - { - stringId.erase (static_cast(0), 1); - msg.m_msgId = StringId (Unicode::wideToNarrow (stringId)); - } - else - msg.m_msg = stringId; - - enum Bitflags - { - B_sendToActor = 0x01, - B_sendToTarget = 0x02, - B_sendToBystanders = 0x04 - }; - - const bool sendToSelf = (bitflags & B_sendToActor) != 0; - const bool sendToTarget = (bitflags & B_sendToTarget) != 0; - const bool sendToBystanders = (bitflags & B_sendToBystanders) != 0; - - obj->performCombatSpam (msg, sendToSelf, sendToTarget, sendToBystanders); -} -*/ -//---------------------------------------------------------------------- - -/** -* -* string Params: -* - string target type (Player or ChatChannel) -* - string target id (Player name or chat channel name, e.g. SWG.betaGalaxy.Justin or SWG.betaGalaxy.system) -* - string message -*/ - -static void commandFuncSystemMessage(Command const &, NetworkId const &, NetworkId const &, Unicode::String const ¶ms) -{ - size_t curpos = 0; - - Unicode::String targetTypeStr; - Unicode::String targetIdStr; - - if (!Unicode::getFirstToken (params, curpos, curpos, targetTypeStr) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing int value)")); - return; - } - - if (!Unicode::getFirstToken (params, ++curpos, curpos, targetIdStr) || curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing bitflags)")); - return; - } - - if (curpos == Unicode::String::npos) - { - WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing msg)")); - return; - } - - curpos = Unicode::skipWhitespace(params, ++curpos); - - Unicode::String output = params.substr (curpos); - - if (output.empty ()) - { - WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing msg)")); - return; - } - - std::string targetType = Unicode::wideToNarrow(targetTypeStr); - std::string targetId = Unicode::wideToNarrow(targetIdStr); - static const Unicode::String oob; - - if(targetType == "Player") - { - Chat::sendInstantMessage("SYSTEM", targetId, output, oob); - } - else if(targetType == "ChatChannel") - { - Chat::sendToRoom("SYSTEM", targetId, output, oob); - } -} - -//----------------------------------------------------------------------- - -static void commandFuncSetWaypointActiveStatus(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) -{ - CachedNetworkId actorId(actor); - WARNING(! actorId.getObject(), ("commandSetWaypointActiveStatus: Could not get an object for actor id %s\n", actor.getValueString().c_str())); - if(actorId.getObject()) - { - CreatureObject * creature = dynamic_cast(actorId.getObject()); - if(creature) - { - if(creature->isPlayerControlled()) - { - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creature); - if(playerObject) - { - Waypoint w = playerObject->getWaypoint(target); - if (w.isValid()) - { - Unicode::String status; - size_t curpos = 0; - if (!Unicode::getFirstToken (params, curpos, curpos, status)) - { - WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing int value)")); - return; - } - if(status == Unicode::narrowToWide("on")) - { - w.setActive(true); - } - else if(status == Unicode::narrowToWide("off")) - { - w.setActive(false); - } - } - } - } - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncSetWaypointName(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) -{ - CachedNetworkId actorId(actor); - WARNING(! actorId.getObject(), ("commandFuncSetWaypointName: Could not get an object for actor id %s\n", actor.getValueString().c_str())); - if(actorId.getObject()) - { - CreatureObject * creature = dynamic_cast(actorId.getObject()); - if(creature) - { - if(creature->isPlayerControlled()) - { - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creature); - if(playerObject) - { - Waypoint w = playerObject->getWaypoint(target); - if (w.isValid()) - { - Unicode::String name; - size_t curpos = 0; - if (!Unicode::getFirstToken (params, curpos, curpos, name)) - { - WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing text value)")); - return; - } - w.setName(params); - } - } - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandSetPosture(Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CachedNetworkId actorId(actor); - if (actorId.getObject() != NULL) - { - CreatureController * const controller = dynamic_cast(actorId.getObject()->getController()); - if (controller != NULL) - { - CreatureObject * const creature = safe_cast(actorId.getObject()); - NOT_NULL (creature); - Postures::Enumerator const posture = creature->getPosture(); - - // send the creature's posture to it - MessageQueuePosture * message = new MessageQueuePosture(posture, true); - controller->appendMessage( - CM_setPosture, - 0.0f, - message, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_ALL_CLIENT - ); - - // Ensure the chair sitting state is off if the player is not sitting. - if (posture != Postures::Sitting) - { - creature->setState(States::SittingOnChair, false); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncJumpServer(Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CachedNetworkId actorId(actor); - if (actorId.getObject() != NULL) - { - CreatureController * const controller = dynamic_cast(actorId.getObject()->getController()); - if (controller != NULL) - { - controller->appendMessage( - CM_jump, - 0.0f, - NULL, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_ALL_CLIENT - ); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAddBannedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t curpos = 0; - NetworkId objId(nextOidParm(params, curpos)); - curpos = Unicode::skipWhitespace(params, curpos); - - Object *obj = NetworkIdManager::getObjectById(objId); - Client *client = getClientFromCharacterId(actor); - if (obj) - { - CellObject *cell = dynamic_cast(obj); - if (cell) - { - BuildingObject *building = cell->getOwnerBuilding(); - if (building && building->isOwner(actor, client)) - cell->addBanned(Unicode::wideToNarrow(params.substr(curpos))); - } - else - { - BuildingObject *building = dynamic_cast(obj); - if (building && building->isOwner(actor, client)) - building->addBanned(Unicode::wideToNarrow(params.substr(curpos))); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRemoveBannedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t curpos = 0; - NetworkId objId(nextOidParm(params, curpos)); - curpos = Unicode::skipWhitespace(params, curpos); - - Object *obj = NetworkIdManager::getObjectById(objId); - Client *client = getClientFromCharacterId(actor); - if (obj) - { - CellObject *cell = dynamic_cast(obj); - if (cell) - { - BuildingObject *building = cell->getOwnerBuilding(); - if (building && building->isOwner(actor, client)) - cell->removeBanned(Unicode::wideToNarrow(params.substr(curpos))); - } - else - { - BuildingObject *building = dynamic_cast(obj); - if (building && building->isOwner(actor, client)) - building->removeBanned(Unicode::wideToNarrow(params.substr(curpos))); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAddAllowedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t curpos = 0; - NetworkId objId(nextOidParm(params, curpos)); - curpos = Unicode::skipWhitespace(params, curpos); - - Object *obj = NetworkIdManager::getObjectById(objId); - Client *client = getClientFromCharacterId(actor); - if (obj) - { - CellObject *cell = dynamic_cast(obj); - if (cell) - { - BuildingObject *building = cell->getOwnerBuilding(); - if (building && building->isOwner(actor, client)) - cell->addAllowed(Unicode::wideToNarrow(params.substr(curpos))); - } - else - { - BuildingObject *building = dynamic_cast(obj); - if (building && building->isOwner(actor, client)) - building->addAllowed(Unicode::wideToNarrow(params.substr(curpos))); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRemoveAllowedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t curpos = 0; - NetworkId objId(nextOidParm(params, curpos)); - curpos = Unicode::skipWhitespace(params, curpos); - - Object *obj = NetworkIdManager::getObjectById(objId); - Client *client = getClientFromCharacterId(actor); - if (obj) - { - CellObject *cell = dynamic_cast(obj); - if (cell) - { - BuildingObject *building = cell->getOwnerBuilding(); - if (building && building->isOwner(actor, client)) - cell->removeAllowed(Unicode::wideToNarrow(params.substr(curpos))); - } - else - { - BuildingObject *building = dynamic_cast(obj); - if (building && building->isOwner(actor, client)) - building->removeAllowed(Unicode::wideToNarrow(params.substr(curpos))); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetPublicState(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t curpos = 0; - NetworkId objId(nextOidParm(params, curpos)); - int publicState = nextIntParm(params, curpos); - - Object *obj = NetworkIdManager::getObjectById(objId); - Client *client = getClientFromCharacterId(actor); - if (obj) - { - CellObject *cell = dynamic_cast(obj); - if (cell) - { - BuildingObject *building = cell->getOwnerBuilding(); - if (building && building->isOwner(actor, client)) - cell->setIsPublic(publicState ? true : false); - } - else - { - BuildingObject *building = dynamic_cast(obj); - if (building && building->isOwner(actor, client)) - building->setIsPublic(publicState ? true : false); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetOwner(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t curpos = 0; - NetworkId objId(nextOidParm(params, curpos)); - NetworkId ownerId(nextOidParm(params, curpos)); - - Object *obj = NetworkIdManager::getObjectById(objId); - Client *client = getClientFromCharacterId(actor); - if (obj) - { - ServerObject *tangibleObj = safe_cast(obj); - if (tangibleObj && tangibleObj->isOwner(actor, client)) - { - tangibleObj->setOwnerId(ownerId); - } - } -} - -// ---------------------------------------------------------------------- - -static void resolveDuelParticipants(CreatureObject &actor, TangibleObject &target, TangibleObject *&actorFlagObj, CreatureObject *&targetMessageObj) -{ - ShipObject * const targetShip = target.asShipObject(); - if (targetShip) - { - // Dueling a ship - // actorFlagObj is the containing ship of the actor if he owns it - ShipObject * const actorShip = ShipObject::getContainingShipObject(&actor); - if ( actorShip - && actorShip->isPlayerShip() - && actor.getNetworkId() == actorShip->getOwnerId()) - actorFlagObj = actorShip; - // targetMessageObj is the owner of the target ship - if (targetShip->isPlayerShip()) - { - Object * const o = NetworkIdManager::getObjectById(targetShip->getOwnerId()); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so) - targetMessageObj = so->asCreatureObject(); - } - } - } - else - { - actorFlagObj = &actor; - targetMessageObj = target.asCreatureObject(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncDuel(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - if (target != NetworkId::cms_invalid && target != actor) - { - CreatureObject * const actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - TangibleObject * const targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (actorObj && targetObj) - { - TangibleObject *actorFlagObj = 0; - CreatureObject *targetMessageObj = 0; - resolveDuelParticipants(*actorObj, *targetObj, actorFlagObj, targetMessageObj); - - if (actorFlagObj && targetMessageObj && actorObj != targetMessageObj) - { - if (PlayerObject::isIgnoring(actor, targetMessageObj->getNetworkId())) - return; - - if (actorObj->hasAutoDeclineDuel()) - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_CANNOT_DUEL_AUTO_DECLINE); - return; - } - - if (Pvp::canAttack(*actorObj, *targetObj)) - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ALREADY_CAN_ATTACK); - return; - } - - if (Pvp::canAttack(*targetObj, *actorObj)) - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_AVAILABLE_TO_DUEL); - return; - } - - if (targetObj->hasAutoDeclineDuel()) - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_AVAILABLE_TO_DUEL); - sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_AUTO_DECLINED_DUEL); - return; - } - - if(targetObj->getObjVars().hasItem("hologram_performer")) - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_HOLOGRAM); - } - else if (!Pvp::isDuelingAllowed(*actorFlagObj, *targetObj)) - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_HERE); - } - else if (Pvp::hasDuelEnemyFlag(*actorFlagObj, targetObj->getNetworkId())) - { - if (Pvp::hasDuelEnemyFlag(*targetObj, actorFlagObj->getNetworkId())) - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ALREADY_DUELING); - else - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ALREADY_CHALLENGED); - } - else if (Pvp::hasDuelEnemyFlag(*targetObj, actorFlagObj->getNetworkId())) - { - // Duel Accepted and Starting. - Pvp::setDuelEnemyFlag(*actorFlagObj, *targetObj); - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ACCEPT_SELF); - sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_ACCEPT_TARGET); - - // Call their Script Triggers - ServerObject* serverActor = actorObj->asServerObject(); - if(serverActor) - { - ScriptParams params; - params.addParam(actor); - params.addParam(target); - if(serverActor->getScriptObject()) - { - IGNORE_RETURN(serverActor->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_START, params)); - - } - } - - ServerObject* serverTarget = targetObj->asServerObject(); - if(serverTarget) - { - ScriptParams params; - params.addParam(actor); - params.addParam(target); - if(serverTarget->getScriptObject()) - { - IGNORE_RETURN( serverTarget->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_START, params)); - } - } - /// End script triggers. - - } - else - { - // Duel Request - // Call their Script Triggers - ServerObject* serverActor = actorObj->asServerObject(); - if(serverActor) - { - ScriptParams params; - params.addParam(actor); - params.addParam(target); - if(serverActor->getScriptObject()) - { - if( serverActor->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_REQUEST, params) == SCRIPT_OVERRIDE ) - return; - } - } - - ServerObject* serverTarget = targetObj->asServerObject(); - if(serverTarget) - { - ScriptParams params; - params.addParam(actor); - params.addParam(target); - if(serverTarget->getScriptObject()) - { - if( serverTarget->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_REQUEST, params) == SCRIPT_OVERRIDE ) - return; - } - } - /// End script triggers. - Pvp::setDuelEnemyFlag(*actorFlagObj, *targetObj); - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_CHALLENGE_SELF); - sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_CHALLENGE_TARGET); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncEndDuel(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - if (target != NetworkId::cms_invalid) - { - CreatureObject * const actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - TangibleObject * const targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (actorObj && targetObj) - { - TangibleObject *actorFlagObj = 0; - CreatureObject *targetMessageObj = 0; - resolveDuelParticipants(*actorObj, *targetObj, actorFlagObj, targetMessageObj); - - if (actorFlagObj && targetMessageObj) - { - if (Pvp::hasDuelEnemyFlag(*targetObj, actorFlagObj->getNetworkId())) - { - Pvp::removeDuelEnemyFlags(*targetObj, actorFlagObj->getNetworkId()); - if (Pvp::hasDuelEnemyFlag(*actorFlagObj, targetObj->getNetworkId())) - { - Pvp::removeDuelEnemyFlags(*actorFlagObj, targetObj->getNetworkId()); - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_END_SELF); - sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_END_TARGET); - - // notify script that the duel has ended because of the EndDuel command - { - ScriptParams params; - params.addParam(targetObj->getNetworkId(), "target"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(actorFlagObj->getNetworkId(), - "endDuelCommandNotification", dictionary->getSerializedData(), 0, false); - } - } - - { - ScriptParams params; - params.addParam(actorFlagObj->getNetworkId(), "target"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(targetObj->getNetworkId(), - "endDuelCommandNotification", dictionary->getSerializedData(), 0, false); - } - } - } - else - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_REJECT_SELF); - sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_REJECT_TARGET); - } - } - else if (Pvp::hasDuelEnemyFlag(*actorFlagObj, targetObj->getNetworkId())) - { - Pvp::removeDuelEnemyFlags(*actorFlagObj, targetObj->getNetworkId()); - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_CANCEL_SELF); - sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_CANCEL_TARGET); - } - else - { - sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_DUELING); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncHarvesterActivate(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) - targetObj->activate(actor); -} - -// ---------------------------------------------------------------------- - -static void commandFuncHarvesterDeactivate(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (targetObj && actorObj &&targetObj->isOnAdminList(*actorObj)) - targetObj->deactivate(); - -} - -// ---------------------------------------------------------------------- - -static void commandFuncHarvesterHarvest(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) - targetObj->harvest(); -} - -// ---------------------------------------------------------------------- - -static void commandFuncHarvesterSelectResource(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶meter) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - NetworkId poolId(Unicode::wideToNarrow(parameter)); - if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) - targetObj->selectResource(poolId, actor); -} - -// ---------------------------------------------------------------------- - -static void commandFuncHarvesterDiscardHopper(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (targetObj && actorObj &&targetObj->isOnAdminList(*actorObj)) - targetObj->discardAllHopperContents(); -} - -// ---------------------------------------------------------------------- - -static void commandFuncHarvesterMakeCrate(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - size_t pos=0; - const NetworkId resourceId = nextOidParm(params,pos); - const int amount = nextIntParm(params,pos); - const bool discard = nextBoolParm(params,pos); - const uint8 sequenceId = static_cast(nextIntParm(params,pos)); - - if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) - targetObj->emptyHopper(actor,resourceId,amount,discard,sequenceId); -} - -// ---------------------------------------------------------------------- - -static void commandFuncResourceSetName(Command const &, NetworkId const &, NetworkId const &target, Unicode::String const ¶ms) -{ - ResourceTypeObject * const targetObj = ServerUniverse::getInstance().getResourceTypeById(target); - if (targetObj) - targetObj->setName(Unicode::wideToNarrow(params)); -} - -// ---------------------------------------------------------------------- - -static void commandFuncResourceContainerTransfer(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!player) - return; - - ResourceContainerObject *sourceObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - size_t pos = 0; - NetworkId destId = nextOidParm(params,pos); - ResourceContainerObject *destObj = dynamic_cast(NetworkIdManager::getObjectById(destId)); - int amount = nextIntParm(params,pos); - - - if (!sourceObj || !destObj || amount <= 0) - return; - - Container::ContainerErrorCode error = Container::CEC_Success; - if (!player->canManipulateObject(*sourceObj, true, true, true, 10.0f, error)) - { - ContainerInterface::sendContainerMessageToClient(*player, error, sourceObj); - return; - } - if (!player->canManipulateObject(*destObj, true, true, true, 10.0f, error)) - { - ContainerInterface::sendContainerMessageToClient(*player, error, destObj); - return; - } - - sourceObj->transferTo(*destObj, amount); -} - -// ---------------------------------------------------------------------- - -static void commandFuncMakeSurvey(Command const &, NetworkId const &, NetworkId const &, Unicode::String const &) -{ - //TODO: Do something here someday -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestSurvey(Command const &, NetworkId const &actor, NetworkId const &tool, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (actorObj && actorObj->getClient()) - { - size_t curpos = 0; - Unicode::String resourceName = Unicode::narrowToWide(nextStringParm (params, curpos)); - - ScriptParams params; - params.addParam(actor); - params.addParam(resourceName); - - //now trigger the script, the actor should have exactly one on himself - ServerObject *toolObj = safe_cast(NetworkIdManager::getObjectById(tool)); - if (toolObj) - toolObj->getScriptObject()->trigAllScripts(Scripting::TRIG_REQUEST_SURVEY, params); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestCoreSample(Command const &, NetworkId const &actor, NetworkId const &tool, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (actorObj && actorObj->getClient()) - { - size_t curpos = 0; - Unicode::String resourceName = Unicode::narrowToWide(nextStringParm (params, curpos)); - - ScriptParams params; - params.addParam(actor); - params.addParam(resourceName); - - //now trigger the script, the actor should have exactly one on himself - ServerObject *toolObj = safe_cast(NetworkIdManager::getObjectById(tool)); - if (toolObj) - toolObj->getScriptObject()->trigAllScripts(Scripting::TRIG_REQUEST_CORESAMPLE, params); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncResourceContainerSplit(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - ResourceContainerObject * const sourceObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!sourceObj) - return; - - CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!player) - return; - - size_t pos = 0; - const int amount = nextIntParm(params,pos); - const CachedNetworkId destContainer (nextOidParm(params,pos)); - const int arrangementId = nextIntParm(params,pos); - const Vector & newLocation = nextVectorParm(params,pos); - - Container::ContainerErrorCode error = Container::CEC_Success; - if (!player->canManipulateObject(*sourceObj, true, true, true, 10.0f, error)) - { - ContainerInterface::sendContainerMessageToClient(*player, error, sourceObj); - } - else if (!sourceObj->splitContainer(amount,destContainer,arrangementId,newLocation, safe_cast(NetworkIdManager::getObjectById(actor)))) - { - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_Full, safe_cast(destContainer.getObject ())); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncFactoryCrateSplit(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - FactoryObject * const sourceObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!sourceObj) - return; - - CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!player) - return; - - size_t pos = 0; - const int amount = nextIntParm(params,pos); - const CachedNetworkId destContainerId (nextOidParm(params,pos)); - ServerObject * destContainer = safe_cast(destContainerId.getObject()); - if (destContainer == NULL || ContainerInterface::getVolumeContainer(*destContainer) == NULL) - { - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_NotFound); - return; - } - - Container::ContainerErrorCode error = Container::CEC_Success; - if (!player->canManipulateObject(*sourceObj, true, true, true, 10.0f, error)) - { - ContainerInterface::sendContainerMessageToClient(*player, error, sourceObj); - } - else if (sourceObj->makeCopy(*destContainer, amount) == NULL) - { - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_Full, - destContainer); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncPermissionListModify(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (actorObj && actorObj->getClient()) - { - size_t curpos = 0; - const Unicode::String & playerName = Unicode::narrowToWide(nextStringParm (params, curpos)); - const Unicode::String & listName = Unicode::narrowToWide(nextStringParm (params, curpos)); - const Unicode::String & action = Unicode::narrowToWide(nextStringParm (params, curpos)); - - ScriptParams params; - params.addParam(actor); - params.addParam(playerName); - params.addParam(listName); - params.addParam(action); - - //now trigger the script, the actor should have exactly one on himself - actorObj->getScriptObject()->trigAllScripts(Scripting::TRIG_PERMISSION_LIST_MODIFY, params); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSynchronizedUiListen(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - ServerObject *targetObj = safe_cast(NetworkIdManager::getObjectById(target)); - CreatureObject * const actorObject = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (targetObj && actorObject) - targetObj->addSynchronizedUiClient(*actorObject); -} - -// ---------------------------------------------------------------------- - -static void commandFuncSynchronizedUiStopListening(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - ServerObject *targetObj = safe_cast(NetworkIdManager::getObjectById(target)); - if (targetObj) - targetObj->removeSynchronizedUiClient(actor); -} - -// ---------------------------------------------------------------------- - -static void commandFuncHarvesterGetResourceData(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); - CreatureObject *actorObject = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (targetObj && actorObject && targetObj->isOnAdminList(*actorObject)) - { - targetObj->sendResourceDataToClient(*actorObject); - } -} - -// ---------------------------------------------------------------------- -/** -* @param params the destination container, and an optional arrangement -*/ - -//------------------------------------------------------------------------------------------ -static void commandFuncTransferItem(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) -{ - ServerObject * const item = ServerWorld::findObjectByNetworkId(target); - ServerObject * const playerSo = ServerWorld::findObjectByNetworkId(actor); - - if (!playerSo || !item) - { - DEBUG_REPORT_LOG(true, ("Received transfer item command for null player or target.\n")); - return; - } - - if (item->isPlayerControlled()) - return; - - CreatureObject* const player = playerSo->asCreatureObject(); - if (!player) - return; - - size_t curpos = 0; - const NetworkId & destId = nextOidParm(params, curpos); - const int arrangement = nextIntParm(params, curpos); - const Vector & pos = nextVectorParm(params, curpos); - Transform t; - t.setPosition_p(pos); - - ServerObject * const destination = safe_cast(NetworkIdManager::getObjectById(destId)); - - //@todo this value (6) came from a data table that cannot be referenced. It's the distance you can be from an object for pick up. When we get command table range validation in, we can remove it. - Container::ContainerErrorCode errorCode = Container::CEC_Success; - - // call canManipulateObject telling it to skip the no trade check; - // we'll do the no trade check separately if canManipulateObject passes - bool allowedByGodMode = false; - bool canManipulateTarget = player->canManipulateObject(*item, true, true, true, 6, errorCode, true, &allowedByGodMode); - if (canManipulateTarget && !allowedByGodMode && item->markedNoTrade()) - { - // the item must be owned by this creature - NetworkId ownerId; - if (item->asIntangibleObject()) - { - ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*item)); - ownerId = containedBy ? containedBy->getOwnerId() : NetworkId::cms_invalid; - } - else - { - ownerId = item->getOwnerId(); - } - - if (ownerId != player->getNetworkId()) - { - canManipulateTarget = false; - - if (item->markedNoTradeShared(true)) - { - // if the no trade item is a "shared" no trade item and is immediately - // contained in a structure cell, and is being transferred to the - // transferer's inventory (i.e. picked up), also allow the transfer - // if the transferer is on the same account as the current owner of the item - ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*item)); - if (containedBy && containedBy->asCellObject()) - { - if (destination && (player->getInventory() == destination)) - { - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(player); - if (playerObject && (playerObject->getStationId() == NameManager::getInstance().getPlayerStationId(ownerId))) - canManipulateTarget = true; - } - } - } - } - } - - if (!canManipulateTarget) - { - if(errorCode == Container::CEC_NoPermission) - { - Object * parentObject = ContainerInterface::getContainedByObject(*item); - if(parentObject && parentObject->asServerObject() && parentObject->asServerObject()->asTangibleObject() - && parentObject->asServerObject()->asTangibleObject()->isLocked()) - { - ContainerInterface::sendContainerMessageToClient(*player, errorCode, parentObject->asServerObject()); - return; - } - } - ContainerInterface::sendContainerMessageToClient(*player, errorCode, item); - return; - } - - //-- don't transfer from/to factory crates - { - if (destination && destination->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) - return; - - const ServerObject * const containedBy = safe_cast(ContainerInterface::getContainedByObject (*item)); - - if (containedBy && containedBy->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) - return; - } - - // If our destination is a locked container, make sure we can access it. - bool lockedDestContainer = false; - { - if(destination && destination->asTangibleObject() && destination->asTangibleObject()->isLocked()) - { - lockedDestContainer = true; - TangibleObject * destTangible = destination->asTangibleObject(); - if(!destTangible->isUserOnAccessList(player->getNetworkId()) && !destTangible->isGuildOnAccessList(player->getGuildId()) - && player->getClient() && !player->getClient()->isGod()) - { - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_NoPermission, destination); - return; - } - } - - } - - { - // No Drag and Drop while using Loot rules (especially random). - const ServerObject * source = getFirstCreatureContainer(item); - - if(source && source->asCreatureObject() && source->asCreatureObject()->isDead() && destination) - { - const ServerObject* dest = getFirstCreatureContainer(destination); - if(dest && dest->asCreatureObject() && dest->asCreatureObject()->getGroup()) - { - int lootRule = dest->asCreatureObject()->getGroup()->getLootRule(); - // Random/Lotto Loot Rule, no drag and drop allowed! - if(lootRule == 3 || lootRule == 2) - { - return; - } - } - } - - } - - if (!item->isAuthoritative()) - { - GenericValueTypeMessage > const rssMessage( - "RequestSameServer", - std::make_pair( - ContainerInterface::getTopmostContainer(*player)->getNetworkId(), - ContainerInterface::getTopmostContainer(*item)->getNetworkId())); - GameServer::getInstance().sendToPlanetServer(rssMessage); - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, item); - return; - } - - bool retval = true; - if (destId == NetworkId::cms_invalid) - { - //to world - retval = ContainerInterface::transferItemToWorld(*item, t, player, errorCode); - } - else - { - if (!destination) - { - DEBUG_REPORT_LOG(true, ("Cannot transfer item to unknown destination container\n")); - return; - } - if (!destination->isAuthoritative()) - { - GenericValueTypeMessage > const rssMessage( - "RequestSameServer", - std::make_pair( - ContainerInterface::getTopmostContainer(*player)->getNetworkId(), - ContainerInterface::getTopmostContainer(*destination)->getNetworkId())); - GameServer::getInstance().sendToPlanetServer(rssMessage); - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, destination); - return; - } - - //@todo quick check to make sure people aren't exploiting unlimited volume containers. Really there shouldn't be any of these, but there have been bugs in the past... - VolumeContainer * vol = ContainerInterface::getVolumeContainer(*destination); - if (vol && vol->getTotalVolume() == static_cast(VolumeContainer::VL_NoVolumeLimit)) - { - WARNING(true, ("Player accessing infinite volume container %s", destination->getNetworkId().getValueString().c_str())); - //send error message and return - } - - //Don't allow people to put things in unowned containers. Locked containers are allowed since they enforce their own list. - if (!destination->getObjVars().hasItem(OBJVAR_PLAYERS_CAN_ACCESS_CONTAINER) && !lockedDestContainer && - player->getClient() && !player->getClient()->isGod() && - destination->getOwnerId() == NetworkId::cms_invalid) - { - errorCode = Container::CEC_NoPermission; - ContainerInterface::sendContainerMessageToClient(*player, errorCode, destination); - return; - } - - //Check to make sure you can manipulate the destination - if (!player->canManipulateObject(*destination, false, true, true, 6, errorCode)) - { - ContainerInterface::sendContainerMessageToClient(*player, errorCode, destination); - return; - } - - //special case. If this is our inventory we are unequipping to, allow it to be somewhat overloaded. - const Object * itemParent = ContainerInterface::getContainedByObject(*item); - if (itemParent && itemParent == player && player->getInventory() == destination && item->getVolume() < 2) - { - VolumeContainer * volContainer = ContainerInterface::getVolumeContainer(*destination); - if (!volContainer) - { - errorCode = Container::CEC_Unknown; - } - else - { - const int allowedOverload = volContainer->getTotalVolume() + 2; - if (volContainer->getCurrentVolume() >= allowedOverload) - { - errorCode = Container::CEC_Full; - } - else - { - int oldCap = volContainer->debugDoNotUseSetCapacity(allowedOverload); - retval = ContainerInterface::transferItemToVolumeContainer(*destination, *item, player, errorCode, true); - IGNORE_RETURN( volContainer->debugDoNotUseSetCapacity(oldCap) ); - } - } - } - else - { - const Object * destParent = ContainerInterface::getContainedByObject(*destination); - if(destParent && destParent == player->getAppearanceInventory()) - { - // Trying to transfer to a container currently in our Appearance inventory. Not allowed. - StringId const code("container_error_message", "container34_prose"); - - ProsePackage pp; - pp.stringId = code; - pp.actor.id = player->getNetworkId (); - - // Send to the player. - Chat::sendSystemMessage (*player, pp); - - retval = false; - - } - else if (destination == player->getAppearanceInventory() && ContainerInterface::getContainer(*item) != NULL) - { - const Container * itemContainer = ContainerInterface::getContainer(*item); - if(itemContainer && itemContainer->getNumberOfItems() == 0) - { - retval = ContainerInterface::transferItemToUnknownContainer(*destination, *item, arrangement, t, player, errorCode); - } - else - { - StringId const code("container_error_message", "container33_prose"); - - ProsePackage pp; - pp.stringId = code; - pp.actor.id = player->getNetworkId (); - - // Send to the player. - Chat::sendSystemMessage (*player, pp); - } - } - else - { - retval = ContainerInterface::transferItemToUnknownContainer(*destination, *item, arrangement, t, player, errorCode); - - // if we are equipping an object to a filled slot, move the equipped item(s) to our inventory - if (!retval && errorCode == Container::CEC_SlotOccupied && destination->getNetworkId() == player->getNetworkId()) - { - ServerObject * inventory = player->getInventory(); - const SlottedContainer * equipment = ContainerInterface::getSlottedContainer(*player); - const SlottedContainmentProperty * itemContainmentProperty = ContainerInterface::getSlottedContainmentProperty(*item); - - if (inventory != NULL && equipment != NULL && itemContainmentProperty != NULL) - { - std::vector > oldItems; - retval = true; - int slotCount = itemContainmentProperty->getNumberOfSlots(arrangement); - for (int i = 0; i < slotCount && retval; ++i) - { - SlotId slot = itemContainmentProperty->getSlotId(arrangement, i); - const Container::ContainedItem & currentWeaponId = equipment->getObjectInSlot(slot, errorCode); - ServerObject * oldItem = safe_cast(currentWeaponId.getObject()); - if (oldItem != NULL) - { - if (ContainerInterface::transferItemToVolumeContainer(*inventory, *oldItem, player, errorCode, true)) - { - oldItems.push_back(std::make_pair(oldItem, slot)); - } - else - retval = false; - } - } - if (retval) - { - if (!ContainerInterface::transferItemToUnknownContainer(*destination, *item, arrangement, t, player, errorCode)) - { - // move the old items back into their slots - reequipItems(*destination, oldItems); - retval = false; - } - - } - else - { - // move the old items back into their slots - reequipItems(*destination, oldItems); - errorCode = Container::CEC_SlotOccupied; - } - } - } - } - } - } - - if (!retval && player) - { - if(errorCode == Container::CEC_SlotOccupied && destination == player->getAppearanceInventory()) - { - // Failed to place an object in our appearance inventory. Let's flush out some more information. - ServerObject * appearanceInv = player->getAppearanceInventory(); - const SlottedContainer * equipment = ContainerInterface::getSlottedContainer(*appearanceInv); - const SlottedContainmentProperty * itemContainmentProperty = ContainerInterface::getSlottedContainmentProperty(*item); - - if(!itemContainmentProperty || !equipment || arrangement < 0) - { - // This should never happen, but if it does - just send our normal bland error message. - ContainerInterface::sendContainerMessageToClient(*player, errorCode); - return; - } - - int slotCount = itemContainmentProperty->getNumberOfSlots(arrangement); - std::vector objectsToSend; - for (int i = 0; i < slotCount; ++i) - { - SlotId slot = itemContainmentProperty->getSlotId(arrangement, i); - const Container::ContainedItem & currentWeaponId = equipment->getObjectInSlot(slot, errorCode); - ServerObject * oldItem = safe_cast(currentWeaponId.getObject()); - if (oldItem != NULL) - { - if( std::find(objectsToSend.begin(), objectsToSend.end(), oldItem) == objectsToSend.end() ) - objectsToSend.push_back(oldItem); - } - } - - std::vector::iterator iter = objectsToSend.begin(); - for(; iter != objectsToSend.end(); ++iter) - { - // No idea how this could happen, but just incase. - if((*iter) == NULL) - continue; - - StringId const code("container_error_message", "container32_prose"); - - // Setup the prose package with all the %TT and %TO information. - ProsePackage pp; - pp.stringId = code; - - pp.target.id = (*iter)->getNetworkId (); - pp.target.str = (*iter)->getAssignedObjectName (); - if (pp.target.str.empty ()) - pp.target.stringId = (*iter)->getObjectNameStringId (); - - pp.other.id = item->getNetworkId(); - pp.other.str = item->getAssignedObjectName(); - if (pp.other.str.empty()) - pp.other.stringId = item->getObjectNameStringId(); - - pp.actor.id = player->getNetworkId (); - - // Send to the player. - Chat::sendSystemMessage (*player, pp); - } - - return; - } - - ContainerInterface::sendContainerMessageToClient(*player, errorCode); - } -} -// ---------------------------------------------------------------------- - -static bool isGoingInWeaponSlot(const ServerObject& target, int arrangement) -{ - if (arrangement <= 0) - return false; - - const SlottedContainmentProperty * slotted = ContainerInterface::getSlottedContainmentProperty(target); - bool useWeapon = false; - if (slotted) - { - //In this case, the player is transferring something from their equipment, which may be armor or a weapon - static const SlotId right_hand = SlotIdManager::findSlotId(CrcLowerString("hold_r")); - static const SlotId left_hand = SlotIdManager::findSlotId(CrcLowerString("hold_l")); - - const int numSlots = slotted->getNumberOfSlots(arrangement); - for (int i = 0; i < numSlots; ++i) - { - SlotId currentSlot = slotted->getSlotId(arrangement, i); - if (currentSlot == right_hand || currentSlot == left_hand) - { - useWeapon = true; - break; - } - } - } - return useWeapon; -} - -//------------------------------------------------------------------------------------------ - -static void commandFuncTransferWeapon(Command const & c, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) -{ - ServerObject * item = ServerWorld::findObjectByNetworkId(target); - CreatureObject * actorObject = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - - size_t curpos = 0; - const NetworkId & destId = nextOidParm(params, curpos); - const int arrangement = nextIntParm(params, curpos); - UNREF(destId); - - if (item && actorObject && isGoingInWeaponSlot(*item, arrangement)) - { - commandFuncTransferItem(c, actor, target, params); - } - -} - -//------------------------------------------------------------------------------------------ - -static void commandFuncTransferArmor(Command const & c, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) -{ - CreatureObject * actorObject = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObject) - { - commandFuncTransferItem(c, actor, target, params); - } -} - -//------------------------------------------------------------------------------------------ - -void CommandCppFuncs::commandFuncTransferMisc(Command const & c, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) -{ - ServerObject * item = ServerWorld::findObjectByNetworkId(target); - CreatureObject * actorObject = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - - size_t curpos = 0; - const NetworkId & destId = nextOidParm(params, curpos); - const int arrangement = nextIntParm(params, curpos); - - //This command can only be used to transfer non-weapon objects not contained directly by the player unless it is not armor - if (item && actorObject && !isGoingInWeaponSlot(*item, arrangement) && - ( destId != actor || !GameObjectTypes::isTypeOf(item->getGameObjectType(), SharedObjectTemplate::GOT_armor)) ) - { - commandFuncTransferItem(c, actor, target, params); - } -} - -//------------------------------------------------------------------------------------------ -/** -* @param params the slotname, if any, to be echo'd back to the client or passed to the script -*/ - -static void commandFuncOpenContainer(Command const & cmd, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) -{ - ServerObject * container = ServerWorld::findObjectByNetworkId(target); - CreatureObject * player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!container || !player) - { - DEBUG_REPORT_LOG(true, ("Received open command for null player or target.\n")); - return; - } - //@todo check permissions - if (!ContainerInterface::getContainer(*container)) - { - DEBUG_REPORT_LOG(true, ("Received open command on non container object.\n")); - return; - } - - //-- don't open factory crates - if (container->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) - return; - - //-- if they are opening a crafting station, what they really want is the hopper - //-- but only if the object is not a volume container - if (container->getGameObjectType () == SharedObjectTemplate::GOT_misc_crafting_station - && (NULL == ContainerInterface::getVolumeContainer (*container))) - { - static const SlotId inputHopperId(SlotIdManager::findSlotId(CrcLowerString("ingredient_hopper"))); - - ServerObject const * const station = container; - ServerObject * hopper = NULL; - const SlottedContainer * stationContainer = ContainerInterface::getSlottedContainer (*station); - if (stationContainer != NULL) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - Object* tmpHopperObj = (stationContainer->getObjectInSlot (inputHopperId, tmp)).getObject(); - if (tmp == Container::CEC_Success && tmpHopperObj) - { - hopper = tmpHopperObj->asServerObject(); - } - } - - if (hopper) - { - container = hopper; - } - else - { - // report the failure as it indicates a change to some other system - WARNING(true, ("Received open command on a crafting station and failed to open the hopper.\n")); - } - } - - size_t curpos = 0; - - std::string slotName; - int sequence = nextIntParm (params, curpos); - if (curpos != std::string::npos) - { - ++curpos; - slotName = nextStringParm (params, curpos); - } - - if (container->isAuthoritative()) - { - Container::ContainerErrorCode code = Container::CEC_Success; - - bool const isPublicContainer = container->getGameObjectType () == SharedObjectTemplate::GOT_misc_container_public; - - if (isPublicContainer && player->getClient()) - ObserveTracker::onClientAboutToOpenPublicContainer(*player->getClient(), *container); - - bool const doPermissionCheckOnItem = !isPublicContainer; - bool const doPermissionCheckOnParents = !isPublicContainer; - - if (player->canManipulateObject(*container, false, doPermissionCheckOnItem, doPermissionCheckOnParents, 6.0f, code)) - { - // Additional check for Locked containers. - if(container->asTangibleObject() && container->asTangibleObject()->isLocked()) - { - TangibleObject * tangibleTarget = container->asTangibleObject(); - if(!tangibleTarget->isUserOnAccessList(player->getNetworkId()) && !tangibleTarget->isGuildOnAccessList(player->getGuildId())) - { - // Player is NOT on the admin list or guild list, they cannot open the container. - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_NoPermission, container); - return; - } - } - - ScriptParams params; - params.addParam(actor); - if (container->getScriptObject()->trigAllScripts(Scripting::TRIG_ABOUT_TO_OPEN_CONTAINER, params) == SCRIPT_CONTINUE) - { - Client *client = player->getClient(); - if (client) - client->openContainer(*container, sequence, slotName); - } - } - else - { - ContainerInterface::sendContainerMessageToClient(*player, code, container); - } - } - else - { - GenericValueTypeMessage > const rssMessage( - "RequestSameServer", - std::make_pair( - ContainerInterface::getTopmostContainer(*player)->getNetworkId(), - ContainerInterface::getTopmostContainer(*container)->getNetworkId())); - GameServer::getInstance().sendToPlanetServer(rssMessage); - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, container); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncCloseContainer(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - ServerObject * const container = ServerWorld::findObjectByNetworkId(target); - ServerObject * const player = ServerWorld::findObjectByNetworkId(actor); - if (!container || !player) - { - DEBUG_REPORT_LOG(true, ("Received close command for null player or target.\n")); - return; - } - - //-- can't close ourself - if (player == container) - return; - - if (!ContainerInterface::getContainer(*container)) - { - DEBUG_REPORT_LOG(true, ("Received close command on non container object.\n")); - return; - } - - if (container->isAuthoritative()) - { - Client * const client = player->getClient(); - if (client) - client->closeContainer(*container); - } - else - { - DEBUG_REPORT_LOG(true, ("Multi-Server not supported for containers yet")); - //@todo the player is trying to access a container not on this server. Somehow get it here - //Then do the check - } - -} - -//------------------------------------------------------------------------------------------ - -static void commandFuncOpenLotteryContainer(Command const & /*command*/, NetworkId const & /*actor*/, NetworkId const & /*target*/, Unicode::String const & /*params*/) -{ - // moved from a command to a script hook. - // This needs to be removed for the next - // official non-hotfix patch -} - -// ---------------------------------------------------------------------- - -static void commandFuncCloseLotteryContainer(Command const & cmd, NetworkId const & actor, NetworkId const &target, Unicode::String const & params) -{ - ServerObject * const container = ServerWorld::findObjectByNetworkId(target); - if (container == 0) - { - DEBUG_REPORT_LOG(true, ("commandFuncOpenLotteryContainer: container == 0.\n")); - return; - } - - CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); - if (player == 0) - { - DEBUG_REPORT_LOG(true, ("commandFuncOpenLotteryContainer: player == 0.\n")); - return; - } - - if (ContainerInterface::getContainer(*container) == 0) - { - DEBUG_REPORT_LOG(true, ("commandFuncOpenLotteryContainer: ContainerInterface::getContainer == 0.\n")); - return; - } - - Controller * const controller = player->getController(); - - if (controller != 0) - { - typedef MessageQueueGenericValueType Message; - Message * const message = new Message(target); - - controller->appendMessage( - CM_groupCloseLotteryWindowOnClient, - 0.0f, - message, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } -} - -// ---------------------------------------------------------------------- -/** -* @param params the destination container, and an optional arrangement -*/ -static void commandFuncGiveItem(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) -{ - ServerObject * const item = ServerWorld::findObjectByNetworkId(target); - ServerObject * const player = ServerWorld::findObjectByNetworkId(actor); - if (!player || !item) - { - DEBUG_REPORT_LOG(true, ("Received give item command for null player or target.\n")); - return; - } - size_t curpos = 0; - NetworkId destId = nextOidParm(params, curpos); - - //@todo this value (6) came from a data table that cannot be referenced. It's the distance you can be from an object for pick up. When we get command table range validation in, we can remove it. - Container::ContainerErrorCode errorCode = Container::CEC_Success; - if (!player->canManipulateObject(*item, true, true, true, 6, errorCode)) - { - ContainerInterface::sendContainerMessageToClient(*player, errorCode, item); - return; - } - - if (!item->isAuthoritative()) - { - GenericValueTypeMessage > const rssMessage( - "RequestSameServer", - std::make_pair( - ContainerInterface::getTopmostContainer(*player)->getNetworkId(), - ContainerInterface::getTopmostContainer(*item)->getNetworkId())); - GameServer::getInstance().sendToPlanetServer(rssMessage); - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, item); - return; - } - - ServerObject* const destination = safe_cast(NetworkIdManager::getObjectById(destId)); - - if (!destination) - { - DEBUG_REPORT_LOG(true, ("Cannot transfer item to unknown destination container\n")); - return; - } - - if (!destination->isAuthoritative()) - { - GenericValueTypeMessage > const rssMessage( - "RequestSameServer", - std::make_pair( - ContainerInterface::getTopmostContainer(*player)->getNetworkId(), - ContainerInterface::getTopmostContainer(*destination)->getNetworkId())); - GameServer::getInstance().sendToPlanetServer(rssMessage); - ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, destination); - return; - } - - if (!player->canManipulateObject(*destination, false, false, false, 6, errorCode)) - { - ContainerInterface::sendContainerMessageToClient(*player, errorCode, destination); - return; - } - - // check and see if this is a gem->socket operation, which is handled by our code - TangibleObject * const socket = dynamic_cast(destination); - if (socket != NULL) - { - TangibleObject * const gem = dynamic_cast(item); - if (gem != NULL) - { - const int destGot = socket->getGameObjectType(); - const SharedTangibleObjectTemplate * const gemTemplate = safe_cast(gem->getSharedTemplate()); - const int count = gemTemplate->getSocketDestinationsCount(); - - for (int i = 0; i < count; ++i) - { - const int gemSocketGot = gemTemplate->getSocketDestinations(i); - if (destGot == gemSocketGot || GameObjectTypes::isTypeOf (destGot, gemSocketGot)) - { - // make sure the gem and socket are both in the player's inventory - if (!socket->isContainedBy(*player, true) || - !gem->isContainedBy(*player, true)) - { - Chat::sendSystemMessage(*player, SharedStringIds::gem_not_in_inventory, Unicode::emptyString); - return; - } - - // if the socketed item is equipped, unequip it temporarily - CreatureObject * owner = NULL; - Object * container = ContainerInterface::getContainedByObject(*socket); - if (container != NULL && container->asServerObject()->asCreatureObject() != NULL) - { - owner = container->asServerObject()->asCreatureObject(); - // fake unequipping the item - owner->onContainerLostItem(NULL, *socket, NULL); - } - - std::vector > skillModBonuses; - gem->getSkillModBonuses(skillModBonuses, false); - if (socket->addSkillModSocketBonuses(skillModBonuses)) - { - gem->permanentlyDestroy(DeleteReasons::Consumed); - Chat::sendSystemMessage(*player, SharedStringIds::gem_inserted, Unicode::emptyString); - } - else - { - // tell the player they can't use the gem - Chat::sendSystemMessage(*player, SharedStringIds::gem_not_inserted, Unicode::emptyString); - } - if (owner != NULL) - { - // "re-equip" the item - owner->onContainerGainItem(*socket, NULL, NULL); - } - return; - } - } - } - } - - // nope, pass it on to scripts - ScriptParams scriptParameters; - scriptParameters.addParam (target); - scriptParameters.addParam (actor); - - if (destination->getScriptObject()->trigAllScripts(Scripting::TRIG_GIVE_ITEM, scriptParameters) == SCRIPT_OVERRIDE) - { - item->permanentlyDestroy(DeleteReasons::BadContainerTransfer); - } - -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupInvite(Command const & command, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - if (actor == target) - return; - - CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - ShipObject const * const actorShipObject = ShipObject::getContainingShipObject(actorObj); - - GroupObject * const groupObj = actorObj->getGroup(); - if (groupObj) - { - if (groupObj->getGroupLeaderId() != actor) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_LEADER); - return; - } - } - - NetworkId parsedNetworkId = NetworkId::cms_invalid; - if (target.isValid()) - { - CreatureObject * const targetObj = findAndResolveCreatureByNetworkId(target); - if (targetObj) - { - // pointer check is done for space - if (actorObj == targetObj) - { - return; - } - - parsedNetworkId = targetObj->getNetworkId(); - } - } - else if (!params.empty()) - { - // check to see if a target name was specified, and see - // if that resolves into a player character in the galaxy - parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); - } - - if (!parsedNetworkId.isValid()) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_INVITE_NO_TARGET_SELF); - return; - } - - // cannot invite while in combat - if (actorObj->getState(States::Combat) && ConfigServerGame::getGroupInviteInviterCombatRestriction()) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_INVITE_IN_COMBAT); - return; - } - - // send a messageTo to the target to invite to group - char buffer[1024]; - snprintf(buffer, sizeof(buffer)-1, "%s|%s|%s|%s", actor.getValueString().c_str(), (actorShipObject ? actorShipObject->getNetworkId().getValueString().c_str() : "0"), (groupObj ? groupObj->getNetworkId().getValueString().c_str() : "0"), Unicode::wideToNarrow(actorObj->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, - "C++InviteToGroupReq", - buffer, - 0, - false, - actor, - "C++InviteToGroupRspTargetNotFound"); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupUninvite(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - if (actor == target) - return; - - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - NetworkId parsedNetworkId = NetworkId::cms_invalid; - if (target.isValid()) - { - CreatureObject * const targetObj = findAndResolveCreatureByNetworkId(target); - if (targetObj) - { - parsedNetworkId = targetObj->getNetworkId(); - } - } - else if (!params.empty()) - { - // check to see if a target name was specified, and see - // if that resolves into a player character in the galaxy - parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); - } - - if (!parsedNetworkId.isValid()) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_UNINVITE_NO_TARGET_SELF); - return; - } - - // send a messageTo to the target to uninvite - char buffer[1024]; - snprintf(buffer, sizeof(buffer)-1, "%s|%s", actor.getValueString().c_str(), Unicode::wideToNarrow(actorObj->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, - "C++UninviteFromGroupReq", - buffer, - 0, - false, - actor, - "C++UninviteFromGroupRspTargetNotFound"); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupJoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - if ((actorObj->getGroup()) && (!GroupHelpers::creatureIsContainedInPOBShip(actorObj))) - return; - - NetworkId const & inviterId = actorObj->getGroupInviterId(); - if (!inviterId.isValid()) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_INVITED); - return; - } - - // cannot join while in combat - if (actorObj->getState(States::Combat) && ConfigServerGame::getGroupJoinInviteeCombatRestriction()) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_JOIN_IN_COMBAT); - return; - } - - // send a messageTo to the inviter requesting the inviter's - // group/group member information so we can join the group - // or create a new group with the inviter as the group leader - MessageToQueue::getInstance().sendMessageToC(inviterId, - "C++GroupJoinInviterInfoReq", - actorObj->getNetworkId().getValueString(), - 0, - false, - actor, - "C++GroupJoinInviterInfoReqInviterNotFound"); - - actorObj->setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupDecline(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObj) - { - NetworkId inviterId = actorObj->getGroupInviterId(); - if (inviterId.isValid()) - { - // notify invitee - ProsePackage pp; - pp.stringId = GroupStringId::SID_GROUP_DECLINE_SELF; - pp.target.str = Unicode::narrowToWide(actorObj->getGroupInviterName()); - pp.actor.id = actorObj->getNetworkId(); - Chat::sendSystemMessage(*actorObj, pp); - - // notify inviter - StringId responseSid = GroupStringId::SID_GROUP_DECLINE_LEADER; - std::string const inviteeName(Unicode::wideToNarrow(actorObj->getAssignedObjectName())); - std::string response = responseSid.getCanonicalRepresentation(); - response += "|"; - - if (!inviteeName.empty()) - { - response += "nameString|"; - response += inviteeName; - } - else - { - StringId inviteeNameSid = actorObj->getObjectNameStringId(); - response += "nameStringId|"; - response += inviteeNameSid.getCanonicalRepresentation(); - } - - MessageToQueue::getInstance().sendMessageToC(inviterId, - "C++GroupOperationGenericRsp", - response, - 0, - false); - } - - actorObj->setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupDisband(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObj) - { - GroupObject * const groupObj = actorObj->getGroup(); - if (groupObj) - { - if (groupObj->getGroupLeaderId() != actor) - { - // we are not the leader. we are tring to leave the group - NetworkId const & POBShipId = groupObj->getPOBShipMemberIsContainedIn(actor); - - if ((POBShipId.isValid()) && (groupObj->getPOBShipOwnedByMember(actor) == POBShipId)) - { - // we own this POB so we can remove everyone inside it from the group - GroupMemberParam const & leader = groupObj->createGroupMemberParamForMember(actor); - - GroupObject::GroupMemberParamVector membersInsidePOB; - GroupObject::GroupMemberParamVector membersOutsidePOB; - - GroupHelpers::separateGroupBasedOffofPOBShip(groupObj, - actor, - POBShipId, - membersInsidePOB, - membersOutsidePOB); - - // if there are no members outside, then the group only consisted of - // the people in the POB. If that's the case, then don't destroy the - // old group and create a new one - if (!membersOutsidePOB.empty()) - { - groupObj->removeGroupMember(actor); - - if (actorObj->getGroup() == groupObj) - actorObj->getGroup()->onGroupMemberRemoved(actorObj->getNetworkId(), false); - - // remove everyone inside the target POB from the group - GroupHelpers::removeFromGroupAndCreatePOBGroup(groupObj, leader, membersInsidePOB); - } - } - else - { - // we don't own the POB or we are not in a POB ship so just remove us - groupObj->removeGroupMember(actor); - - if (actorObj->getGroup() == groupObj) - actorObj->getGroup()->onGroupMemberRemoved(actorObj->getNetworkId(), false); - } - } - else - { - // we are the group leader, no target is specified, so we disband the group - if (!target.isValid()) - { - // find everyone in a POB and remove them from the group - // and create new POB based groups for them - - // this is done in 2 steps because the second half will actually remove - // members from the group. we don't want to iterate over the members as - // they are being removed - - GroupObject::GroupMemberParamVector membersOwningPOBs; - std::vector membersNotInPOBs; - - { - GroupObject::GroupMemberVector const & groupMembers = groupObj->getGroupMembers(); - GroupObject::GroupMemberVector::const_iterator ii = groupMembers.begin(); - GroupObject::GroupMemberVector::const_iterator iiEnd = groupMembers.end(); - - for (; ii != iiEnd; ++ii) - { - // get the member - NetworkId const & memberId = ii->first; - NetworkId const & POBShipId = groupObj->getPOBShipOwnedByMember(memberId); - - if ((POBShipId.isValid()) && (groupObj->getPOBShipMemberIsContainedIn(memberId).isValid())) - { - GroupMemberParam const & memberWithPOBShip = groupObj->createGroupMemberParamForMember(memberId); - membersOwningPOBs.push_back(memberWithPOBShip); - } - else - { - membersNotInPOBs.push_back(memberId); - } - } - } - - // we build and cache this data for after the GroupObject has been destroyed - std::map membersInsidePOB; - std::map membersOutsidePOB; - - { - // create the new POB ship group data collections for those that need it - GroupObject::GroupMemberParamVector::const_iterator ii = membersOwningPOBs.begin(); - GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersOwningPOBs.end(); - - for (; ii != iiEnd; ++ii) - { - NetworkId const & memberId = (*ii).m_memberId; - NetworkId const & POBShipId = (*ii).m_memberShipId; - - GroupHelpers::separateGroupBasedOffofPOBShip(groupObj, - memberId, - POBShipId, - membersInsidePOB[memberId], - membersOutsidePOB[memberId]); - } - } - - if (membersOwningPOBs.empty()) - { - groupObj->disbandGroup(); - - if (actorObj->getGroup() == groupObj) - actorObj->getGroup()->onGroupMemberRemoved(actorObj->getNetworkId(), true); - } - else - { - // manually remove everyone from the actors group. this helps us avoid - // calling disband and then creteGroup with the actor being set up as - // the leader. Calling disband and create with each group would cause - // the actions to be executed out of order on multiserver due to creates - // message being processed before the controller's remove and disband - // messages were processed - { - std::set membersNotInActorsGroup; - - { - // gather all of the members that are not inside the current - // group leader's ship - - GroupObject::GroupMemberParamVector::const_iterator ii = membersOwningPOBs.begin(); - GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersOwningPOBs.end(); - - for (; ii != iiEnd; ++ii) - { - GroupMemberParam const & owner = *ii; - - if (owner.m_memberId != actor) - { - GroupObject::GroupMemberParamVector const & membersOutsideActorPOB = membersOutsidePOB[owner.m_memberId]; - - GroupObject::GroupMemberParamVector::const_iterator jj = membersOutsideActorPOB.begin(); - GroupObject::GroupMemberParamVector::const_iterator jjEnd = membersOutsideActorPOB.end(); - - for (; jj != jjEnd; ++jj) - { - membersNotInActorsGroup.insert((*jj).m_memberId); - } - } - } - - std::vector::const_iterator jj = membersNotInPOBs.begin(); - std::vector::const_iterator jjEnd = membersNotInPOBs.end(); - - // we need to make sure that we also add in other non POB ships to be removed - - for (; jj != jjEnd; ++jj) - { - if (*jj != actor) - { - membersNotInActorsGroup.insert(*jj); - } - } - } - - // remove everyone that is is not in the original leader's POB from the - // current group - std::set::const_iterator ii = membersNotInActorsGroup.begin(); - std::set::const_iterator iiEnd = membersNotInActorsGroup.end(); - - for (; ii != iiEnd; ++ii) - { - NetworkId const & memberId = *ii; - groupObj->removeGroupMember(memberId); - - CreatureObject * const memberCreatureObject = dynamic_cast(ServerWorld::findObjectByNetworkId(memberId)); - if (memberCreatureObject != 0) - { - if (memberCreatureObject->getGroup() == groupObj) - memberCreatureObject->getGroup()->onGroupMemberRemoved(memberCreatureObject->getNetworkId(), false); - } - } - } - - // now create the POB groups that we just built the data sets for - { - // create the new POB ship groups for those that need it - GroupObject::GroupMemberParamVector::const_iterator ii = membersOwningPOBs.begin(); - GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersOwningPOBs.end(); - - for (; ii != iiEnd; ++ii) - { - GroupMemberParam const & leader = *ii; - - // create the new POB groups. notice NULL is passed in for the - // groupToRemoveFrom because the original group has already had - // all of the members removed - - if (leader.m_memberId != actor) - { - GroupHelpers::removeFromGroupAndCreatePOBGroup(0, leader, membersInsidePOB[leader.m_memberId]); - } - } - } - } - } - - // we are the group leader. a target is specified, so we remove them - else if (groupObj->isGroupMember(target)) - { - // send message to target to leave the group - MessageToQueue::getInstance().sendMessageToC(target, - "C++LeaveGroupReq", - groupObj->getNetworkId().getValueString(), - 0, - false); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncKickFromShip(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) -{ - CreatureObject const * const actorObject = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObject != 0) - { - CreatureObject * const targetObject = dynamic_cast(ServerWorld::findObjectByNetworkId(target)); - if ((targetObject != 0) && (actorObject != targetObject)) - { - ShipObject const * const actorShipObject = ShipObject::getContainingShipObject(actorObject); - - if ((actorShipObject != 0) && (actorShipObject->getOwnerId() == actorObject->getNetworkId())) - { - // check that both are in the same ship - if (ShipObject::getContainingShipObject(targetObject) == actorShipObject) - { - triggerSpaceEjectPlayerFromShip(targetObject); - } - } - else - { - sendProseMessage(*actorObject, 0, GroupStringId::SID_GROUP_NO_KICK_FROM_SHIP_OWNER); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObj) - { - GroupObject *groupObj = actorObj->getGroup(); - if (groupObj) - { - // don't allow if the actor is squelched - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); - if (!playerObj || (playerObj->getSecondsUntilUnsquelched() != 0)) - { - return; - } - - groupObj->sendGroupChat(actor, params); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAuctionChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObj) - { - std::string firstName; - size_t pos = 0; - Unicode::getFirstToken(Unicode::wideToNarrow(actorObj->getObjectName()), 0, pos, firstName); - - const std::string channelName = "SWG." + GameServer::getInstance().getClusterName() + "." + ServerWorld::getSceneId() + ".named.Auction"; - Chat::sendToRoom(firstName, channelName, params, Unicode::String()); - - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncPlanetChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObj) - { - std::string firstName; - size_t pos = 0; - Unicode::getFirstToken(Unicode::wideToNarrow(actorObj->getObjectName()), 0, pos, firstName); - - const std::string channelName = "SWG." + GameServer::getInstance().getClusterName() + "." + ServerWorld::getSceneId() + ".named.Planet"; - Chat::sendToRoom(firstName, channelName, params, Unicode::String()); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupMakeLeader(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - if (actor == target) - return; - - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - if (!target.isValid()) - return; - - GroupObject * const groupObj = actorObj->getGroup(); - if (groupObj) - { - if (groupObj->getGroupLeaderId() != actor) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_LEADER); - return; - } - - groupObj->makeLeader(target); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupMakeMasterLooter(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - GroupObject * const groupObj = actorObj->getGroup(); - if (groupObj != 0) - { - if (groupObj->getGroupLeaderId() != actor) - { - sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_LEADER); - return; - } - - groupObj->makeLootMaster(target.isValid() ? target : actor); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncCreateGroupPickup(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); - if (!playerObj) - return; - - Client * const clientObj = actorObj->getClient(); - if (!clientObj) - return; - - GroupObject * const groupObj = actorObj->getGroup(); - if (!groupObj || ((groupObj->getGroupLeaderId() != actor) && (playerObj->getSkillTemplate().find("officer_") != 0))) - { - sendProseMessage(*actorObj, 0, StringId("group", "create_group_pickup_not_group_leader")); - return; - } - - Vector const currentWorldLocation = actorObj->findPosition_w(); - std::string const currentScene = ServerWorld::getSceneId(); - if (!GroupPickupPoint::isGroupPickupAllowedAtLocation(currentScene, static_cast(currentWorldLocation.x), static_cast(currentWorldLocation.z))) - { - sendProseMessage(*actorObj, 0, StringId("group", "create_group_pickup_unsupported_location")); - return; - } - - if (groupObj->getSecondsLeftOnGroupPickup()) - { - sendProseMessage(*actorObj, 0, StringId("group", "create_group_pickup_existing")); - return; - } - - // see if there are any connected player group members within 20m to assist/approve creating the group pickup point - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - GroupObject::GroupMemberVector const & groupMembers = groupObj->getGroupMembers(); - bool anyConnectedGroupMemberInRange = false; - - GroupObject::GroupMemberVector::const_iterator iterGroupMember; - for (iterGroupMember = groupMembers.begin(); iterGroupMember != groupMembers.end(); ++iterGroupMember) - { - if ((iterGroupMember->first != actor) && groupObj->isMemberPC(iterGroupMember->first) && (connectedCharacterLfgData.count(iterGroupMember->first) > 0)) - { - CreatureObject const * memberObj = dynamic_cast(ServerWorld::findObjectByNetworkId(iterGroupMember->first)); - if (memberObj) - { - Vector const memberWorldLocation = memberObj->findPosition_w(); - if (static_cast(currentWorldLocation.magnitudeBetweenSquared(memberWorldLocation)) <= ConfigServerGame::getGroupPickupPointApprovalRangeSquared()) - { - anyConnectedGroupMemberInRange = true; - break; - } - } - } - } - - // if there are no connected group members within 20m, bail - if (!anyConnectedGroupMemberInRange) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("group", "create_group_pickup_no_assistant"); - prosePackage.digitInteger = static_cast(sqrt(static_cast(ConfigServerGame::getGroupPickupPointApprovalRangeSquared()))); - - Chat::sendSystemMessage(*actorObj, prosePackage); - return; - } - - // tell other group members that the group leader has created the group pickup point; - // we need to contact all other group members, even if they are not currently connected, - // so that we can create the group pickup point waypoint for them when they reconnect - std::string const actorName = Unicode::wideToNarrow(actorObj->getAssignedObjectName()); - for (iterGroupMember = groupMembers.begin(); iterGroupMember != groupMembers.end(); ++iterGroupMember) - { - if ((iterGroupMember->first != actor) && groupObj->isMemberPC(iterGroupMember->first)) - { - char buffer[1024]; - snprintf(buffer, sizeof(buffer)-1, "%s|%d|%d|%d|%s", currentScene.c_str(), static_cast(currentWorldLocation.x), static_cast(currentWorldLocation.y), static_cast(currentWorldLocation.z), actorName.c_str()); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(iterGroupMember->first, - "C++GroupPickupPointCreated", - buffer, - 0, - false); - } - } - - // create the group pickup point - time_t const timeNow = ::time(NULL); - groupObj->setGroupPickupTimer(timeNow, timeNow + static_cast(ConfigServerGame::getGroupPickupPointTimeLimitSeconds())); - groupObj->setGroupPickupLocation(currentScene, currentWorldLocation); - - // tell group leader that the group pickup point has been created - StringId::LocUnicodeString response; - if (StringId("group", "create_group_pickup_success_leader").localize(response)) - { - ConsoleMgr::broadcastString(FormattedString<2048>().sprintf(Unicode::wideToNarrow(response).c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigServerGame::getGroupPickupPointTimeLimitSeconds())).c_str()), - clientObj); - } - - // create/update the group leader's group pickup point waypoint - Location const location(currentWorldLocation, NetworkId::cms_invalid, Location::getCrcBySceneName(currentScene)); - playerObj->createOrUpdateReusableWaypoint(location, "groupPickupWp", Unicode::narrowToWide("Group Pickup Point"), Waypoint::White); -} - -// ---------------------------------------------------------------------- - -static void commandFuncUseGroupPickup(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!actorObj) - return; - - PlayerObject const * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); - if (!playerObj) - return; - - Client const * const clientObj = actorObj->getClient(); - if (!clientObj) - return; - - GameScriptObject * const gameScriptObject = actorObj->getScriptObject(); - if (!gameScriptObject) - return; - - bool starPortAndShuttleportOnly = false; - static Unicode::String const noCampParam = Unicode::narrowToWide("nocamp"); - if (Unicode::caseInsensitiveCompare(params, noCampParam)) - starPortAndShuttleportOnly = true; - - GroupObject * const groupObj = actorObj->getGroup(); - if (!groupObj || (groupObj->getSecondsLeftOnGroupPickup() == 0)) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_none_active")); - return; - } - - Vector const currentWorldLocation = actorObj->findPosition_w(); - std::string const currentScene = ServerWorld::getSceneId(); - if (!GroupPickupPoint::isGroupPickupAllowedAtLocation(currentScene, static_cast(currentWorldLocation.x), static_cast(currentWorldLocation.z))) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_unsupported_location")); - return; - } - - if (actorObj->getState(States::Combat)) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_in_combat")); - return; - } - - if (actorObj->isIncapacitated() || actorObj->isDead()) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_dead_or_incap")); - return; - } - - if (actorObj->getMountedCreature()) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_on_mount")); - return; - } - - // trigger script to make sure script is ok with the player traveling to the group pickup point - ScriptParams sp1; - if (gameScriptObject->trigAllScripts(Scripting::TRIG_ABOUT_TO_TRAVEL_TO_GROUP_PICKUP_POINT, sp1) != SCRIPT_CONTINUE) - return; - - // if group pickup point is in mustafar or any of the kashyyyk zones, - // check to make sure player has the required feature bits to go there - std::pair const & groupPickupLocation = groupObj->getGroupPickupLocation(); - uint32 const gameFeatureBits = clientObj->getGameFeatures(); - - if (groupPickupLocation.first.find("kashyyyk") == 0) - { - if (!((gameFeatureBits & ClientGameFeature::Episode3PreorderDownload) || (gameFeatureBits & ClientGameFeature::Episode3ExpansionRetail))) - { - sendProseMessage(*actorObj, 0, StringId("travel", "kashyyyk_unauthorized")); - return; - } - } - else if (groupPickupLocation.first == "mustafar") - { - if (!((gameFeatureBits & ClientGameFeature::TrialsOfObiwanPreorder) || (gameFeatureBits & ClientGameFeature::TrialsOfObiwanRetail))) - { - sendProseMessage(*actorObj, 0, StringId("travel", "mustafar_unauthorized")); - return; - } - } - - // determine cost, and make sure player has enough credits - int totalCost; - if (!GroupPickupPoint::getGroupPickupTravelCost(currentScene, groupPickupLocation.first, totalCost) || (totalCost <= 0)) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_determine_cost")); - return; - } - - int const bankBalance = actorObj->getBankBalance(); - int const cashBalance = actorObj->getCashBalance(); - - if ((bankBalance + cashBalance) < totalCost) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("group", "use_group_pickup_not_enough_credits"); - prosePackage.digitInteger = totalCost; - - Chat::sendSystemMessage(*actorObj, prosePackage); - return; - } - - // find the travel point (starport, shuttleport, camp with shuttle beacon) - // nearest to the group pickup point - - // get the list of cities the player is currently banned from - std::vector cityBanList; - DynamicVariableList const & objvars = actorObj->getObjVars(); - if (objvars.hasItem("city.banlist") && (objvars.getType("city.banlist") == DynamicVariable::INT_ARRAY)) - IGNORE_RETURN(objvars.getItem("city.banlist", cityBanList)); - - std::string sceneIdOfNearestTravelPoint = groupPickupLocation.first; - TravelPoint const * nearestTravelPoint = GroupHelpers::getNearestTravelPoint(groupPickupLocation.first, groupPickupLocation.second, cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); - - // if no nearest travel point found, and the pickup point is inside one - // of the kashyyyk zones that do not have a starport, use kashyyyk_main - // as the pickup point planet and find the nearest travel point there, - // and that should return at least the kachirho starport - // *****OR***** - // if nearest travel point is found inside any kashyyyk zone other than kashyyyk_main - // and the player is not already in that respective zone, don't allow them to travel - // there as entrance to those zones requires going through kashyyyk_main first, so - // find the nearest travel point in kashyyyk_main and use that as the travel point - bool findNearestTravelPointOnKashyyykMain = false; - if (!nearestTravelPoint && (groupPickupLocation.first.find("kashyyyk") == 0) && (groupPickupLocation.first != "kashyyyk_main")) - { - // if already on the kashyyyk zone where the group pickup point is, player is - // already closest to the group pickup point than any travel point on kashyyyk_main - if (currentScene == groupPickupLocation.first) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_closest_to_group_pickup_point")); - return; - } - - findNearestTravelPointOnKashyyykMain = true; - } - else if (nearestTravelPoint && (groupPickupLocation.first.find("kashyyyk") == 0) && (groupPickupLocation.first != "kashyyyk_main") && (currentScene != groupPickupLocation.first)) - { - findNearestTravelPointOnKashyyykMain = true; - } - - if (findNearestTravelPointOnKashyyykMain) - { - sceneIdOfNearestTravelPoint = "kashyyyk_main"; - - if (groupPickupLocation.first == "kashyyyk_hunting") - { - // we want to find the travel point on kashyyyk_main nearest to the entrance to kashyyyk_hunting which is at (190.0f, 20.0f, -430.0f) - nearestTravelPoint = GroupHelpers::getNearestTravelPoint(sceneIdOfNearestTravelPoint, Vector(190.0f, 20.0f, -430.0f), cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); - } - else if (groupPickupLocation.first == "kashyyyk_dead_forest") - { - // we want to find the travel point on kashyyyk_main nearest to the entrance to kashyyyk_dead_forest which is at (-745.0f, 18.0f, 256.0f) - nearestTravelPoint = GroupHelpers::getNearestTravelPoint(sceneIdOfNearestTravelPoint, Vector(-745.0f, 18.0f, 256.0f), cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); - } - else - { - // (-672.0f, 19.0f, -157.0f) is the kachirho starport - nearestTravelPoint = GroupHelpers::getNearestTravelPoint(sceneIdOfNearestTravelPoint, Vector(-672.0f, 19.0f, -157.0f), cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); - } - } - - if (!nearestTravelPoint) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_find_travelpoint")); - return; - } - - // if nearest travel point and current planet is the same, and the nearest travel point to the - // group pickup point is farther away than the current location to the group pickup point, then - // fail, as there is no need to travel as the player is currently closer to the group pickup point - if ((sceneIdOfNearestTravelPoint == currentScene) && (sceneIdOfNearestTravelPoint == groupPickupLocation.first) && (groupPickupLocation.second.magnitudeBetweenSquared(nearestTravelPoint->getPosition_w()) > groupPickupLocation.second.magnitudeBetweenSquared(currentWorldLocation))) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_closest_to_group_pickup_point")); - return; - } - - // if the nearest travel point is a shuttleport in a player city, the city gets a share of the travel cost - int cityShareOfCost = 0; - int systemShareOfCost = totalCost; - int const cityIdAtNearestTravelPoint = CityInterface::getCityAtLocation(sceneIdOfNearestTravelPoint, static_cast(nearestTravelPoint->getPosition_w().x), static_cast(nearestTravelPoint->getPosition_w().z), 0); - NetworkId cityHallAtNearestTravelPoint; - std::string cityNameAtNearestTravelPoint; - if (cityIdAtNearestTravelPoint > 0) - { - CityInfo const & ci = CityInterface::getCityInfo(cityIdAtNearestTravelPoint); - cityHallAtNearestTravelPoint = ci.getCityHallId(); - if (cityHallAtNearestTravelPoint.isValid()) - { - cityNameAtNearestTravelPoint = ci.getCityName(); - cityShareOfCost = (totalCost * ConfigServerGame::getGroupPickupTravelPlayerCityPercent()) / 100; - systemShareOfCost = totalCost - cityShareOfCost; - } - } - - // if player doesn't have enough money in bank, transfer from cash into back to make up the difference - if (bankBalance < totalCost) - { - if (!actorObj->depositCashToBank(totalCost - bankBalance)) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_move_cash_to_bank")); - return; - } - } - - // transfer the total travel cost from the player - if (!actorObj->transferBankCreditsTo("GroupPickupPointTravel", totalCost)) - { - sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_transfer_payment_from_bank")); - return; - } - - // tell player his credits have been deducted - ProsePackage prosePackage; - prosePackage.stringId = StringId("group", "use_group_pickup_credits_deducted"); - prosePackage.digitInteger = totalCost; - - Chat::sendSystemMessage(*actorObj, prosePackage); - - // if the city gets a share of the travel cost, send message to the city hall to transfer the city's share - if (cityHallAtNearestTravelPoint.isValid() && (cityShareOfCost > 0)) - { - char buffer[64]; - snprintf(buffer, sizeof(buffer)-1, "%d", cityShareOfCost); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(cityHallAtNearestTravelPoint, - "C++CityShareGroupPickupPointTravelCost", - buffer, - 0, - false); - } - - // log the transaction - if (cityHallAtNearestTravelPoint.isValid()) - LOG("CustomerService", ("GroupPickupPointTravel:%s in group %s traveled from %s to %s for a cost of %d (%d to system, %d to %s)", playerObj->getAccountDescription().c_str(), groupObj->getNetworkId().getValueString().c_str(), currentScene.c_str(), groupPickupLocation.first.c_str(), totalCost, systemShareOfCost, cityShareOfCost, cityNameAtNearestTravelPoint.c_str())); - else - LOG("CustomerService", ("GroupPickupPointTravel:%s in group %s traveled from %s to %s for a cost of %d", playerObj->getAccountDescription().c_str(), groupObj->getNetworkId().getValueString().c_str(), currentScene.c_str(), groupPickupLocation.first.c_str(), totalCost)); - - // trigger script to teleport player to the destination travel location; - // script has various "cleanup/setup" it needs to be when the player travels - ScriptParams sp2; - sp2.addParam(sceneIdOfNearestTravelPoint.c_str()); - sp2.addParam(nearestTravelPoint->getName().c_str()); - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_TRAVEL_TO_GROUP_PICKUP_POINT, sp2)); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupPickRandomGroupMember(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - GroupObject const * const group = targetObj->getGroup(); - if (!group) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a group."), Unicode::emptyString); - return; - } - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGroupPickRandomGroupMemberCommandAllowed") && (targetObj->getObjVars().getType("timeNextGroupPickRandomGroupMemberCommandAllowed") == DynamicVariable::INT)) - { - int timeNextGroupPickRandomGroupMemberCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextGroupPickRandomGroupMemberCommandAllowed", timeNextGroupPickRandomGroupMemberCommandAllowed)) - { - if (timeNextGroupPickRandomGroupMemberCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGroupPickRandomGroupMemberCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - // handle options - static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); - uint32 socialType = 0; - - if (!params.empty()) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) - { - static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); - static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); - static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); - static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); - std::string emote; - - for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) - { - if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) - { - socialType = pointatSocialType; - } - else if (iter->find(paramsEmote1) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(7); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - else if (iter->find(paramsEmote2) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(6); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - } - } - } - - GroupObject::GroupMemberVector const & results = group->getGroupMembers(); - if (results.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No group member could be found."), Unicode::emptyString); - } - else - { - GroupObject::GroupMemberVector pcMembers; - for (GroupObject::GroupMemberVector::const_iterator iter = results.begin(); iter != results.end(); ++iter) - { - if (group->isMemberPC(iter->first)) - { - pcMembers.push_back(*iter); - } - } - - if (pcMembers.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No group member could be found."), Unicode::emptyString); - } - else - { - int const random = ::rand() % pcMembers.size(); - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Group member \"%s\" was randomly chosen.", pcMembers[random].second.c_str())), Unicode::emptyString); - - // do emote at the selected player, if requested - if (socialType > 0) - { - // if I'm the one selected, use the /pointat social to point at myself - // since other socials may not make sense when I am the target - doSocial(*targetObj, pcMembers[random].first, ((pcMembers[random].first == targetObj->getNetworkId()) ? pointatSocialType : socialType)); - } - } - } - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextGroupPickRandomGroupMemberCommandAllowed", (timeNow + 30))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGroupTextChatRoomRejoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - GroupObject const * const group = targetObj->getGroup(); - if (!group) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a group."), Unicode::emptyString); - return; - } - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGroupTextChatRoomRejoinCommandAllowed") && (targetObj->getObjVars().getType("timeNextGroupTextChatRoomRejoinCommandAllowed") == DynamicVariable::INT)) - { - int timeNextGroupTextChatRoomRejoinCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextGroupTextChatRoomRejoinCommandAllowed", timeNextGroupTextChatRoomRejoinCommandAllowed)) - { - if (timeNextGroupTextChatRoomRejoinCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGroupTextChatRoomRejoinCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Attempting to leave and rejoin the group text chat room."), Unicode::emptyString); - group->reenterGroupChatRoom(*targetObj); - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextGroupTextChatRoomRejoinCommandAllowed", (timeNow + 60))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGuildChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObj) - { - // don't allow if the actor is squelched - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); - if (!playerObj || (playerObj->getSecondsUntilUnsquelched() != 0)) - { - return; - } - - GuildInterface::sendGuildChat(*actorObj, params); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncGuildTextChatRoomRejoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - if (targetObj->getGuildId() == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a guild."), Unicode::emptyString); - return; - } - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGuildTextChatRoomRejoinCommandAllowed") && (targetObj->getObjVars().getType("timeNextGuildTextChatRoomRejoinCommandAllowed") == DynamicVariable::INT)) - { - int timeNextGuildTextChatRoomRejoinCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextGuildTextChatRoomRejoinCommandAllowed", timeNextGuildTextChatRoomRejoinCommandAllowed)) - { - if (timeNextGuildTextChatRoomRejoinCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGuildTextChatRoomRejoinCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Attempting to leave and rejoin the guild text chat room."), Unicode::emptyString); - GuildInterface::reenterGuildChatRoom(*targetObj); - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextGuildTextChatRoomRejoinCommandAllowed", (timeNow + 60))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGuildPickRandomGuildMember(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - if (targetObj->getGuildId() == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a guild."), Unicode::emptyString); - return; - } - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGuildPickRandomGuildMemberCommandAllowed") && (targetObj->getObjVars().getType("timeNextGuildPickRandomGuildMemberCommandAllowed") == DynamicVariable::INT)) - { - int timeNextGuildPickRandomGuildMemberCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextGuildPickRandomGuildMemberCommandAllowed", timeNextGuildPickRandomGuildMemberCommandAllowed)) - { - if (timeNextGuildPickRandomGuildMemberCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGuildPickRandomGuildMemberCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - // handle options - static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); - uint32 socialType = 0; - bool onlineOption = false; - - if (!params.empty()) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) - { - static Unicode::String const paramsOnline1 = Unicode::narrowToWide("-online"); - static Unicode::String const paramsOnline2 = Unicode::narrowToWide("online"); - static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); - static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); - static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); - static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); - std::string emote; - - for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) - { - if ((*iter == paramsOnline1) || (*iter == paramsOnline2)) - { - onlineOption = true; - } - else if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) - { - socialType = pointatSocialType; - } - else if (iter->find(paramsEmote1) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(7); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - else if (iter->find(paramsEmote2) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(6); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - } - } - } - - std::vector results; - GuildInterface::getGuildMemberIdsWithPermissions(targetObj->getGuildId(), GuildInterface::Member, results); - if (results.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No guild member could be found."), Unicode::emptyString); - } - else - { - std::vector resultsOnline; - if (onlineOption) - { - std::map const & connectedPlayers = ServerUniverse::getConnectedCharacterLfgData(); - for (std::vector::const_iterator iter = results.begin(); iter != results.end(); ++iter) - { - if ((*iter == targetObj->getNetworkId()) || (connectedPlayers.count(*iter) > 0)) - resultsOnline.push_back(*iter); - } - - if (resultsOnline.empty()) - resultsOnline.push_back(targetObj->getNetworkId()); - } - - NetworkId const randomMember = (onlineOption ? resultsOnline[::rand() % resultsOnline.size()] : results[::rand() % results.size()]); - GuildMemberInfo const * const gmi = GuildInterface::getGuildMemberInfo(targetObj->getGuildId(), randomMember); - if (!gmi) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No guild member could be found."), Unicode::emptyString); - } - else - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Guild member \"%s\" was randomly chosen out of %d guild members in guild %s [%s].", gmi->m_name.c_str(), results.size(), GuildInterface::getGuildName(targetObj->getGuildId()).c_str(), GuildInterface::getGuildAbbrev(targetObj->getGuildId()).c_str())), Unicode::emptyString); - - // reminder of the -online option - if (!onlineOption && (randomMember != targetObj->getNetworkId()) && (ServerUniverse::getConnectedCharacterLfgData().count(randomMember) <= 0)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Use \"/guildPickRandomGuildMember -online\" to only select online guild members."), Unicode::emptyString); - } - - // do emote at the selected player, if requested - if (socialType > 0) - { - // if I'm the one selected, use the /pointat social to point at myself - // since other socials may not make sense when I am the target - doSocial(*targetObj, randomMember, ((randomMember == targetObj->getNetworkId()) ? pointatSocialType : socialType)); - } - } - } - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextGuildPickRandomGuildMemberCommandAllowed", (timeNow + 30))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncCityChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (actorObj) - { - // don't allow if the actor is squelched - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); - if (!playerObj || (playerObj->getSecondsUntilUnsquelched() != 0)) - { - return; - } - - CityInterface::sendCityChat(*actorObj, params); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncCityTextChatRoomRejoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - std::vector const & cityIds = CityInterface::getCitizenOfCityId(targetObj->getNetworkId()); - if (cityIds.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently a citizen of a player city."), Unicode::emptyString); - return; - } - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextCityTextChatRoomRejoinCommandAllowed") && (targetObj->getObjVars().getType("timeNextCityTextChatRoomRejoinCommandAllowed") == DynamicVariable::INT)) - { - int timeNextCityTextChatRoomRejoinCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextCityTextChatRoomRejoinCommandAllowed", timeNextCityTextChatRoomRejoinCommandAllowed)) - { - if (timeNextCityTextChatRoomRejoinCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextCityTextChatRoomRejoinCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Attempting to leave and rejoin the city text chat room."), Unicode::emptyString); - CityInterface::reenterCityChatRoom(*targetObj); - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextCityTextChatRoomRejoinCommandAllowed", (timeNow + 60))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncCityPickRandomCitizen(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - std::vector const & cityIds = CityInterface::getCitizenOfCityId(targetObj->getNetworkId()); - if (cityIds.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently a citizen of any city."), Unicode::emptyString); - return; - } - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextCityPickRandomCitizenCommandAllowed") && (targetObj->getObjVars().getType("timeNextCityPickRandomCitizenCommandAllowed") == DynamicVariable::INT)) - { - int timeNextCityPickRandomCitizenCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextCityPickRandomCitizenCommandAllowed", timeNextCityPickRandomCitizenCommandAllowed)) - { - if (timeNextCityPickRandomCitizenCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextCityPickRandomCitizenCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - // handle options - static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); - uint32 socialType = 0; - bool onlineOption = false; - - if (!params.empty()) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) - { - static Unicode::String const paramsOnline1 = Unicode::narrowToWide("-online"); - static Unicode::String const paramsOnline2 = Unicode::narrowToWide("online"); - static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); - static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); - static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); - static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); - std::string emote; - - for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) - { - if ((*iter == paramsOnline1) || (*iter == paramsOnline2)) - { - onlineOption = true; - } - else if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) - { - socialType = pointatSocialType; - } - else if (iter->find(paramsEmote1) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(7); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - else if (iter->find(paramsEmote2) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(6); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - } - } - } - - std::vector results; - CityInterface::getCitizenIds(cityIds[0], results); - if (results.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No citizen could be found."), Unicode::emptyString); - } - else - { - std::vector resultsOnline; - if (onlineOption) - { - std::map const & connectedPlayers = ServerUniverse::getConnectedCharacterLfgData(); - for (std::vector::const_iterator iter = results.begin(); iter != results.end(); ++iter) - { - if ((*iter == targetObj->getNetworkId()) || (connectedPlayers.count(*iter) > 0)) - resultsOnline.push_back(*iter); - } - - if (resultsOnline.empty()) - resultsOnline.push_back(targetObj->getNetworkId()); - } - - NetworkId const randomMember = (onlineOption ? resultsOnline[::rand() % resultsOnline.size()] : results[::rand() % results.size()]); - CitizenInfo const * const ci = CityInterface::getCitizenInfo(cityIds[0], randomMember); - if (!ci) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No citizen could be found."), Unicode::emptyString); - } - else - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Citizen \"%s\" was randomly chosen out of %d citizens in city %s.", ci->m_citizenName.c_str(), results.size(), CityInterface::getCityInfo(cityIds[0]).getCityName().c_str())), Unicode::emptyString); - - // reminder of the -online option - if (!onlineOption && (randomMember != targetObj->getNetworkId()) && (ServerUniverse::getConnectedCharacterLfgData().count(randomMember) <= 0)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Use \"/cityPickRandomCitizen -online\" to only select online citizens."), Unicode::emptyString); - } - - // do emote at the selected player, if requested - if (socialType > 0) - { - // if I'm the one selected, use the /pointat social to point at myself - // since other socials may not make sense when I am the target - doSocial(*targetObj, randomMember, ((randomMember == targetObj->getNetworkId()) ? pointatSocialType : socialType)); - } - } - } - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextCityPickRandomCitizenCommandAllowed", (timeNow + 30))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncShowDanceVisuals(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - bool enable = nextBoolParm(params, pos); - CreatureObject *creature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (creature) - { - IGNORE_RETURN(creature->showDanceVisuals(enable)); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncShowMusicianVisuals(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - bool enable = nextBoolParm(params, pos); - CreatureObject *creature = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (creature) - { - IGNORE_RETURN(creature->showMusicianVisuals(enable)); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncPlaceStructure (const Command& /*command*/, const NetworkId& actor, const NetworkId& /*target*/, const Unicode::String& parameters) -{ - Object* const object = NetworkIdManager::getObjectById (actor); - if (!object) - { - DEBUG_WARNING (true, ("commandFuncPlaceStructure: PB null actor\n")); - return; - } - - ServerObject* const serverObject = dynamic_cast (object); - if (!serverObject) - { - DEBUG_WARNING (true, ("commandFuncPlaceStructure: object is not a server object\n")); - return; - } - - size_t pos = 0; - const NetworkId deedNetworkId = nextOidParm (parameters, pos); - const float x = nextFloatParm (parameters, pos); - const float z = nextFloatParm (parameters, pos); - const Vector position (x, 0.f, z); - const int rotation = nextIntParm (parameters, pos); - - ScriptParams scriptParameters; - scriptParameters.addParam (actor); - scriptParameters.addParam (deedNetworkId); - scriptParameters.addParam (position); - scriptParameters.addParam (rotation); - - if (serverObject->getScriptObject ()->trigAllScripts (Scripting::TRIG_PLACE_STRUCTURE, scriptParameters) != SCRIPT_CONTINUE) - DEBUG_REPORT_LOG (true, ("commandFuncPlaceStructure: did not return SCRIPT_CONTINUE\n")); -} - -// ---------------------------------------------------------------------- -/** - * Change the posture of the player to sitting. - * - * Broadcast the request to sit on a chair. - */ - -static void commandFuncSitServer(const Command& /*command*/, const NetworkId& actorId, const NetworkId& /* targetId */, const Unicode::String& parameters) -{ - // The command handler only runs on the authoratative server for the actor, - // so it should be fine to directly grab the CreatureController from the actor. - - //-- Get the actor object. - Object *const actorObject = NetworkIdManager::getObjectById(actorId); - if (!actorObject) - { - DEBUG_WARNING(true, ("commandFuncPostureSit: failed to lookup Object from actorId network id [%s], aborting sit request.\n", actorId.getValueString().c_str())); - return; - } - - CreatureObject *const creatureActorObject = CreatureObject::asCreatureObject(actorObject); - if (!creatureActorObject) - { - DEBUG_WARNING(true, ("commandFuncPostureSit: Object [%s] is not a creature, aborting sit request.\n", actorId.getValueString().c_str())); - return; - } - - //-- Do not let a player sit on the ground in water. (Sitting on a chair in water is okay, but that implies a designer stuck a chair in water). - bool const sittingOnChair = !parameters.empty(); - NetworkId chairCellId; - Vector chairPosition_p; - - if (sittingOnChair) - { - //-- Pull the chair cell id and position out of the parameters string. - std::string const narrowParameters = Unicode::wideToNarrow(parameters); - - std::string::size_type const lastCommaIndex = narrowParameters.find_last_of(','); - - std::string const chairCellIdString(narrowParameters, lastCommaIndex + 1); - std::string const chairPosition_pString(narrowParameters, 0, lastCommaIndex); - - //-- Get chair position. Abort command if cannot scan vector position from string. - int const scanCount = sscanf(chairPosition_pString.c_str(), "%g,%g,%g", &chairPosition_p.x, &chairPosition_p.y, &chairPosition_p.z); - if (scanCount != 3) - { - DEBUG_WARNING(true, ("commandFuncPostureSit: sitting on chair but chair parameter [%s] was malformed: couldn't be converted to parent x,y,z.", Unicode::wideToNarrow(parameters).c_str())); - return; - } - - chairCellId = NetworkId(chairCellIdString); - } - - if (!sittingOnChair) - { - // Trying to sit on the ground. - const TerrainObject* const terrainObject = TerrainObject::getConstInstance(); - const CollisionProperty* const collisionProperty = actorObject->getCollisionProperty (); - const bool isOnSolidFloor = collisionProperty && collisionProperty->getFootprint() && collisionProperty->getFootprint()->isOnSolidFloor(); - - Vector normal = Vector::unitY; - if (terrainObject && actorObject->isInWorldCell() && !isOnSolidFloor) - { - const Vector position = actorObject->getPosition_w (); - - float terrainHeight; - if (terrainObject->getHeight(position, terrainHeight, normal)) - { - //-- see if the object is swimming - float waterHeight; - if (terrainObject->getWaterHeight(position, waterHeight)) - { - if (waterHeight >terrainHeight) - { - // Client is in the water, abort the command. - Chat::sendSystemMessage (*creatureActorObject, SharedStringIds::no_sitting_in_water, Unicode::emptyString); - return; - } - } - } - } - } - - //-- Get the controller. - Controller *const controller = actorObject->getController(); - if (!controller) - { - DEBUG_WARNING(true, ("commandFuncPostureSit: object [%s] has no controller, aborting sit request.\n", actorId.getValueString().c_str())); - return; - } - - //-- Send the SitOnObject controller message to all clients. - if (!sittingOnChair) - { - //-- Just tell the client to change to the sitting posture immediately. - const_cast(creatureActorObject)->setPosture(Postures::Sitting, true); - } - else - { - //-- Send a SitOnObject message with the chair coordinates. - const_cast(creatureActorObject)->sitOnObject(chairCellId, chairPosition_p); - } - -} - -// ---------------------------------------------------------------------- - -static void commandFuncGetAttributes(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) -{ - size_t curpos = 0; - int const clientRevision = nextIntParm(params, curpos); - TaskGetAttributes * const task = new TaskGetAttributes(actor, target, clientRevision); - NonCriticalTaskQueue::getInstance().addTask(task); -} - -// ---------------------------------------------------------------------- - -static void commandFuncGetAttributesBatch(Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const & params) -{ - size_t curpos = 0; - NetworkId obj = nextOidParm(params, curpos); - while(obj != NetworkId::cms_invalid) - { - int const clientRevision = nextIntParm(params, curpos); - TaskGetAttributes * const task = new TaskGetAttributes(actor, obj, clientRevision); - NonCriticalTaskQueue::getInstance().addTask(task); - obj = nextOidParm(params, curpos); - } -} - -// ---------------------------------------------------------------------- - -static std::string underscoreToSpace (const std::string& source) -{ - std::string result = source; - std::replace (result.begin (), result.end (), '_', ' '); - - return result; -} - -// ---------------------------------------------------------------------- - -static void commandFuncPurchaseTicket (const Command& /*command*/, const NetworkId& actor, const NetworkId& /*target*/, const Unicode::String& parameters) -{ - ServerObject* const serverObject = ServerObject::getServerObject(actor); - if (!serverObject) - { - DEBUG_WARNING (true, ("commandFuncPurchaseTicket: object is not a server object")); - return; - } - - size_t pos = 0; - const Unicode::String planetName1 = Unicode::narrowToWide (nextStringParm (parameters, pos)); - const Unicode::String travelPoint1 = Unicode::narrowToWide (underscoreToSpace (nextStringParm (parameters, pos))); - const Unicode::String planetName2 = Unicode::narrowToWide (nextStringParm (parameters, pos)); - const Unicode::String travelPoint2 = Unicode::narrowToWide (underscoreToSpace (nextStringParm (parameters, pos))); - const bool roundTrip = nextBoolParm (parameters, pos); - const bool instantTravel = nextBoolParm (parameters, pos); - - ScriptParams scriptParameters; - scriptParameters.addParam (actor); - scriptParameters.addParam (planetName1); - scriptParameters.addParam (travelPoint1); - scriptParameters.addParam (planetName2); - scriptParameters.addParam (travelPoint2); - scriptParameters.addParam (roundTrip); - - Scripting::TrigId id = instantTravel ? Scripting::TRIG_PURCHASE_TICKET_INSTANT_TRAVEL : Scripting::TRIG_PURCHASE_TICKET; - - if (serverObject->getScriptObject ()->trigAllScripts (id, scriptParameters) != SCRIPT_CONTINUE) - DEBUG_REPORT_LOG (true, ("commandFuncPurchaseTicket: did not return SCRIPT_CONTINUE\n")); -} - -//---------------------------------------------------------------------- - -static void commandFuncRequestResourceWeights(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncRequestResourceWeights: PB null actor")); - return; - } - - uint32 schematicCrc; - sscanf(Unicode::wideToNarrow(params).c_str(), "%lu", &schematicCrc); - DraftSchematicObject::requestResourceWeights(*creature, schematicCrc); -} - -//---------------------------------------------------------------------- - -static void commandFuncRequestResourceWeightsBatch(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = dynamic_cast(NetworkIdManager::getObjectById (actor)); - if (creature == NULL) - { - WARNING (true, ("commandFuncRequestResourceWeightsBatch: PB null actor")); - return; - } - - int schematicCrc; - - size_t curpos = 0; - schematicCrc = nextIntParm(params, curpos); - while(schematicCrc != -1) - { - DraftSchematicObject::requestResourceWeights(*creature, static_cast(schematicCrc)); - schematicCrc = nextIntParm(params, curpos); - } -} - -//---------------------------------------------------------------------- - -static void commandFuncRequestDraftSlots (const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncRequestDraftSlots: PB null actor")); - return; - } - - PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncRequestDraftSlots: no player object for actor ""%s", actor.getValueString().c_str())); - return; - } - - uint32 serverCrc, sharedCrc; - sscanf(Unicode::wideToNarrow(params).c_str(), "%lu %lu", &serverCrc, &sharedCrc); - - MessageQueueDraftSlotsQueryResponse * const message = new MessageQueueDraftSlotsQueryResponse(std::make_pair(serverCrc, sharedCrc)); - if (!player->requestDraftSlots(serverCrc, NULL, message)) - { - WARNING (true, ("commandFuncRequestDraftSlots failed to request draft slots for %u", serverCrc)); - delete message; - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestDraftSlotsBatch (const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncRequestDraftSlotsBatch: PB null actor")); - return; - } - - PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncRequestDraftSlotsBatch: no player object for actor ""%s", actor.getValueString().c_str())); - return; - } - - uint32 uServerCrc = 0; - uint32 uSharedCrc = 0; - size_t curpos = 0; - - std::string serverCrcString = nextStringParm(params, curpos); - if(serverCrcString.empty()) - return; - sscanf(serverCrcString.c_str(), "%lu", &uServerCrc); - std::string sharedCrcString = nextStringParm(params, curpos); - if(sharedCrcString.empty()) - return; - sscanf(sharedCrcString.c_str(), "%lu", &uSharedCrc); - - bool done = false; - while(uServerCrc != 0 && uSharedCrc != 0 && !done) - { - MessageQueueDraftSlotsQueryResponse * const message = new MessageQueueDraftSlotsQueryResponse(std::make_pair(uServerCrc, uSharedCrc)); - if (!player->requestDraftSlots(uServerCrc, NULL, message)) - { - WARNING (true, ("commandFuncRequestDraftSlotsBatch failed to request draft slots for %lu", uServerCrc)); - delete message; - } - serverCrcString = nextStringParm(params, curpos); - if(serverCrcString.empty()) - done = true; - sscanf(serverCrcString.c_str(), "%lu", &uServerCrc); - sharedCrcString = nextStringParm(params, curpos); - if(sharedCrcString.empty()) - done = true; - sscanf(sharedCrcString.c_str(), "%lu", &uSharedCrc); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestManfSchematicSlots (const Command& , const NetworkId& actor, const NetworkId& target, const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncRequestDraftSlots: PB null actor")); - return; - } - - const ManufactureSchematicObject * schematic = dynamic_cast< - const ManufactureSchematicObject *>(NetworkIdManager::getObjectById(target)); - if (schematic != NULL) - { - schematic->requestSlots(*creature); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestCraftingSession (const Command& , const NetworkId& actor, const NetworkId& target, const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncRequestCraftingSession: PB null actor")); - return; - } - - PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncRequestCraftingSession: no player object for actor " - "%s", actor.getValueString().c_str())); - return; - } - - if (!player->requestCraftingSession(target)) - { - // get the station we are attempting to use. - TangibleObject const * const craftingObject = TangibleObject::getTangibleObject(target); - - // 1 means this request was made on a crafting station versus a crafting tool. - uint8 const sequenceId = static_cast(craftingObject && craftingObject->isCraftingStation() ? 1 : 0); - - MessageQueueGenericIntResponse * response = new MessageQueueGenericIntResponse ( - CM_requestCraftingSession, false, sequenceId); - creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestCraftingSessionFail(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject* const creatureActor = CreatureObject::getCreatureObject(actor); - if (creatureActor) - { - creatureActor->getController()->appendMessage( - CM_craftingResult, - 0.0f, - new MessageQueueGenericIntResponse(CM_requestCraftingSession, false, 0), - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSelectDraftSchematic (const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncSelectDraftSchematic: PB null actor")); - return; - } - - PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncSelectDraftSchematic: no player object for actor " - "%s", actor.getValueString().c_str())); - return; - } - - int schematicIndex = atoi(Unicode::wideToNarrow(params).c_str()); - - player->selectDraftSchematic(schematicIndex); -} - -// ---------------------------------------------------------------------- - -static void commandFuncNextCraftingStage(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncNextCraftingStage: PB null actor")); - return; - } - - PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncNextCraftingStage: no player object for actor " - "%s", actor.getValueString().c_str())); - return; - } - - uint8 sequenceId = static_cast(atoi(Unicode::wideToNarrow(params).c_str())); - int result = player->goToNextCraftingStage(); - - MessageQueueGenericIntResponse * response = new MessageQueueGenericIntResponse ( - CM_nextCraftingStage, result, sequenceId); - creature->getController()->appendMessage(CM_nextCraftingStageResult, 0.0f, response, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); -} - -// ---------------------------------------------------------------------- - -static void commandFuncCreatePrototype(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncCreatePrototype: PB null actor")); - return; - } - - PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncCreatePrototype: no player object for actor %s", actor.getValueString().c_str())); - return; - } - - size_t pos = 0; - const uint8 sequenceId = static_cast(nextIntParm(params, pos)); - bool realPrototype = nextBoolParm(params, pos); - - const bool result = player->createPrototype(realPrototype); - - MessageQueueGenericIntResponse * const response = new MessageQueueGenericIntResponse (CM_createPrototype, result, sequenceId); - creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - - if (!result) - player->stopCrafting(false); -} - -// ---------------------------------------------------------------------- - -static void commandFuncCreateManfSchematic(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncCreateManfSchematic: PB null actor")); - return; - } - - PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncCreateManfSchematic: no player object for actor %s", actor.getValueString().c_str())); - return; - } - - const uint8 sequenceId = static_cast(atoi(Unicode::wideToNarrow(params).c_str())); - - const bool result = player->createManufacturingSchematic(); - - MessageQueueGenericIntResponse * const response = new MessageQueueGenericIntResponse (CM_createManfSchematic, result, sequenceId); - creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - - if (!result) - player->stopCrafting(false); -} - -// ---------------------------------------------------------------------- - -static void commandFuncCancelCraftingSession(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncCancelCraftingSession: PB null actor")); - return; - } - - PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncCancelCraftingSession: no player object for actor " - "%s", actor.getValueString().c_str())); - return; - } - - player->stopCrafting(true); -} - -// ---------------------------------------------------------------------- - -static void commandFuncStopCraftingSession(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncStopCraftingSession: PB null actor")); - return; - } - - PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncStopCraftingSession: no player object for actor " - "%s", actor.getValueString().c_str())); - return; - } - - player->stopCrafting(true); -} - -// ---------------------------------------------------------------------- - -static void commandFuncRestartCraftingSession(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncRestartCraftingSession: PB null actor")); - return; - } - - PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); - if (player == NULL) - { - WARNING (true, ("commandFuncRestartCraftingSession: no player object for actor " - "%s", actor.getValueString().c_str())); - return; - } - - uint8 sequenceId = static_cast(atoi(Unicode::wideToNarrow(params).c_str())); - - const bool success = player->restartCrafting(); - - MessageQueueGenericIntResponse * response = new MessageQueueGenericIntResponse ( - CM_restartCraftingSession, success, sequenceId); - creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetMatchMakingPersonalId(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingPersonalId() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), Unicode::wideToNarrow(params).c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - MatchMakingId matchMakingId; - matchMakingId.unPackIntString(Unicode::wideToNarrow(params)); - - playerObject->setMatchMakingPersonalProfileId(matchMakingId); - - //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingPersonalId() %s %s\n", actor.getValueString().c_str(), matchMakingId.isBitSet(MatchMakingId::B_anonymous) ? "anonymous" : "searchable")); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetMatchMakingCharacterId(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingCharacterId() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), Unicode::wideToNarrow(params).c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - MatchMakingId matchMakingId; - matchMakingId.unPackIntString(Unicode::wideToNarrow(params)); - - playerObject->setMatchMakingCharacterProfileId(matchMakingId); - - //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingCharacterId() %s %s\n", actor.getValueString().c_str(), matchMakingId.isBitSet(MatchMakingId::B_anonymous) ? "anonymous" : "searchable")); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAddFriend(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - ServerObject * const serverObject = ServerObject::getServerObject(actor); - - if (serverObject != NULL) - { - size_t pos = 0; - std::string name(nextStringParm(params, pos)); - - if (!name.empty()) - { - std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); - - //DEBUG_REPORT_LOG(true, ("commandFuncAddFriend() %s %s %s\n", actor.getValueString().c_str(), player.c_str(), name.c_str())); - - Chat::addFriend(player, name); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRemoveFriend(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - ServerObject * const serverObject = ServerObject::getServerObject(actor); - - if (serverObject != NULL) - { - size_t pos = 0; - std::string name(nextStringParm(params, pos)); - - if (!name.empty()) - { - std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); - - //DEBUG_REPORT_LOG(true, ("commandFuncRemoveFriend() %s %s %s\n", actor.getValueString().c_str(), player.c_str(), name.c_str())); - - Chat::removeFriend(player, name); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncGetFriendList(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - ServerObject * const serverObject = ServerObject::getServerObject(actor); - - if (serverObject != NULL) - { - std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); - - //DEBUG_REPORT_LOG(true, ("commandFuncGetFriendList() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str())); - - Chat::getFriendsList(player); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncAddIgnore(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - ServerObject * const serverObject = ServerObject::getServerObject(actor); - - if (serverObject != NULL) - { - size_t pos = 0; - std::string name(nextStringParm(params, pos)); - - if (!name.empty()) - { - std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); - - //DEBUG_REPORT_LOG(true, ("commandFuncAddIgnore() %s %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str(), name.c_str())); - - Chat::addIgnore(player, name); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRemoveIgnore(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - ServerObject * const serverObject = ServerObject::getServerObject(actor); - - if (serverObject != NULL) - { - size_t pos = 0; - std::string name(nextStringParm(params, pos)); - - if (!name.empty()) - { - std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); - - //DEBUG_REPORT_LOG(true, ("commandFuncRemoveIgnore() %s %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str(), name.c_str())); - - Chat::removeIgnore(player, name); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncGetIgnoreList(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - ServerObject * const serverObject = ServerObject::getServerObject(actor); - - if (serverObject != NULL) - { - std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); - - //DEBUG_REPORT_LOG(true, ("commandFuncGetIgnoreList() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str())); - - Chat::getIgnoreList(player); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestBiography(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) -{ - CreatureObject * const creatureObject = CreatureObject::getCreatureObject(actor); - - if (creatureObject != NULL) - { - BiographyManager::requestBiography(target, creatureObject); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetBiography(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) -{ - if (target != NetworkId::cms_invalid) - { - // get the actor - CreatureObject * const creatureActor = CreatureObject::getCreatureObject(actor); - if (!creatureActor) - { - WARNING (true, ("commandFuncSetBiography: bad actor")); - return; - } - - Client * const clientActor = creatureActor->getClient(); - if(!clientActor) - { - WARNING(true, ("no Client in commandFuncSetBiography")); - return; - } - - if(!clientActor->isGod()) - { - LOG("CustomerService", ("CheatChannel:%s attempted to set biography data on %s, but is not a God", PlayerObject::getAccountDescription(actor).c_str(), PlayerObject::getAccountDescription(target).c_str())); - } - else - { - BiographyManager::setBiography(target, params); - } - } - else - { - BiographyManager::setBiography(actor, params); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestCharacterSheetInfo(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - const CreatureObject* const creatureActor = CreatureObject::getCreatureObject(actor); - if (creatureActor == NULL) - { - WARNING (true, ("commandFuncRequestCharacterSheetInfo: null actor")); - return; - } - - //TODO get the born and played times (once they're in the DB) - int born = 0; - int played = 0; - - //get the bind location - Vector bindLoc; - std::string bindPlanet; - NetworkId bindId; - if (creatureActor->getObjVars().hasItem("bind.facility")) - { - creatureActor->getObjVars().getItem("bind.facility", bindId); - } - if(bindId != NetworkId::cms_invalid) - { - const ServerObject* const bindObject = ServerObject::getServerObject(bindId); - if (bindObject != NULL) - { - bindLoc = bindObject->getPosition_w(); - bindPlanet = bindObject->getSceneId(); - } - } - - //get the bankId - Vector bankLoc(0, 0, 0); - std::string bankPlanet; - if (creatureActor->getObjVars().hasItem("banking_bankid")) - { - creatureActor->getObjVars().getItem("banking_bankid", bankPlanet); - } - - // get the city(ies) this character is a citizen of - NetworkId cityHallOfMayorCity; - std::string citizensOf; - std::vector const & cityId = CityInterface::getCitizenOfCityId(creatureActor->getNetworkId()); - if (!cityId.empty()) - { - std::string cityName; - for (std::vector::const_iterator iterCity = cityId.begin(); iterCity != cityId.end(); ++iterCity) - { - CityInfo const & cityInfo = CityInterface::getCityInfo(*iterCity); - cityName = cityInfo.getCityName(); - if (cityName.empty()) - continue; - - if (!citizensOf.empty()) - citizensOf += ","; - - if (creatureActor->getNetworkId() == cityInfo.getLeaderId()) - { - citizensOf += "*"; - cityHallOfMayorCity = cityInfo.getCityHallId(); - } - - citizensOf += cityName; - } - } - - // get the residence location - Vector resLoc; - std::string resPlanet; - NetworkId houseNetworkId = creatureActor->getHouse(); - - // mayor has city hall as his residence - if (!houseNetworkId.isValid() && cityHallOfMayorCity.isValid()) - houseNetworkId = cityHallOfMayorCity; - - const ServerObject* const resObject = ServerObject::getServerObject(houseNetworkId); - if (resObject != NULL) - { - resLoc = resObject->getPosition_w(); - resPlanet = ServerWorld::getSceneId(); - } - else if (houseNetworkId.isValid() && MessageToQueue::isInstalled()) - { - // the residence may not be on this game server, try to find it - MessageToQueue::getInstance().sendMessageToC(houseNetworkId, - "C++CharacterSheetInfoResidenceLocationReq", - creatureActor->getNetworkId().getValueString(), - 0, - false); - } - - //get the spouse's name - Unicode::String spouseName = Unicode::emptyString; - if (creatureActor->getObjVars().hasItem("marriage.spouseName")) - { - creatureActor->getObjVars().getItem("marriage.spouseName", spouseName); - } - - //get the number of used lots - int lots = creatureActor->getMaxNumberOfLots(); - - PlayerObject const * const player = PlayerCreatureController::getPlayerObject(creatureActor); - if(player) - { - int lotsUsed = player->getAccountNumLots(); - lots -= lotsUsed; - } - - //build, send the message back to the client - CharacterSheetResponseMessage const chrm(born, played, bindLoc, bindPlanet, bankLoc, bankPlanet, resLoc, resPlanet, citizensOf, spouseName, lots); - Client * const client = creatureActor->getClient(); - if (client) - client->send(chrm, true); -} - -// ---------------------------------------------------------------------- - -static void commandFuncRequestCharacterMatch(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncRequestCharacterMatch() - networkId: %s params: %s\n", actor.getValueString().c_str(), Unicode::wideToNarrow(params).c_str())); - - // Build the new id - - MatchMakingCharacterPreferenceId matchMakingCharacterPreferenceId; - - matchMakingCharacterPreferenceId.unPackString(Unicode::wideToNarrow(params)); - - CharacterMatchManager::requestMatch(actor, matchMakingCharacterPreferenceId); -} - -// ---------------------------------------------------------------------- - -static void commandFuncExtractObject(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - CreatureObject* const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncExtractObject: PB null actor")); - return; - } - - if (creature->getInventory() == NULL) - { - WARNING (true, ("commandFuncExtractObject: actor %s has no inventory", - actor.getValueString().c_str())); - return; - } - - FactoryObject* const factory = dynamic_cast(NetworkIdManager::getObjectById (target)); - if (factory == NULL) - { - WARNING (true, ("commandFuncExtractObject: PB null target")); - return; - } - - Container::ContainerErrorCode error; - if (creature->canManipulateObject(*factory, false, true, true, 10.0f, error)) - factory->removeObject(*creature->getInventory()); - else - ContainerInterface::sendContainerMessageToClient(*creature, error, factory); -} - -// ---------------------------------------------------------------------- - -static void commandFuncRevokeSkill(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - CreatureObject * const creature = CreatureObject::getCreatureObject(actor); - if (creature == NULL) - { - WARNING (true, ("commandFuncRevokeSkill: PB null actor")); - return; - } - - size_t pos = 0; - std::string skillName = nextStringParm(params, pos); - const SkillObject * skill = SkillManager::getInstance ().getSkill (skillName); - if (skill == NULL) - { - WARNING (true, ("commandFuncRevokeSkill: can't revoke bad skill")); - } - else - { - LOG("CustomerService", ("Skill: God (via cmdfunc) has requested the revocation of skill %s from character %s.", - skillName.c_str(), creature->getNetworkId().getValueString().c_str())); - creature->revokeSkill (*skill); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetCurrentSkillTitle(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - CreatureObject * const creatureObject = CreatureObject::getCreatureObject(actor); - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - - if (playerObject != NULL) - { - size_t pos = 0; - std::string const &title = nextStringParm(params, pos); - - if (title.empty()) - { - playerObject->setTitle(title); - } - else - { - bool validTitle = false; - - // citizenship title is always valid - if (title == "citizenship") - { - playerObject->setTitle(title); - validTitle = true; - } - - // see if it's a collection slot title and the character actually has the collection slot - if (!validTitle) - { - CollectionsDataTable::CollectionInfoSlot const * const slot = CollectionsDataTable::isASlotTitle(title); - - if (slot && playerObject->hasCompletedCollectionSlot(*slot)) - { - playerObject->setTitle(title); - validTitle = true; - } - } - - // see if it's a collection title and the character actually has the collection - if (!validTitle) - { - CollectionsDataTable::CollectionInfoCollection const * const collection = CollectionsDataTable::isACollectionTitle(title); - - if (collection && playerObject->hasCompletedCollection(collection->name)) - { - playerObject->setTitle(title); - validTitle = true; - } - } - - // see if it's a collection page title and the character actually has the collection page - if (!validTitle) - { - CollectionsDataTable::CollectionInfoPage const * const page = CollectionsDataTable::isAPageTitle(title); - - if (page && playerObject->hasCompletedCollectionPage(page->name)) - { - playerObject->setTitle(title); - validTitle = true; - } - } - - // see if it's a guild member rank title and the character actually has the guild member rank - if (!validTitle) - { - GuildRankDataTable::GuildRank const * const guildRankInfo = GuildRankDataTable::isARankTitle(title); - - if (guildRankInfo && playerObject->getGuildRank().testBit(guildRankInfo->slotId)) - { - playerObject->setTitle(title); - validTitle = true; - } - } - - // see if it's a citizen rank title and the character actually has the citizen rank - if (!validTitle) - { - CitizenRankDataTable::CitizenRank const * const citizenRankInfo = CitizenRankDataTable::isARankTitle(title); - - if (citizenRankInfo && playerObject->getCitizenRank().testBit(citizenRankInfo->slotId)) - { - playerObject->setTitle(title); - validTitle = true; - } - } - - // see if it's a guild GCW Region Defender title - if (!validTitle) - { - if (title == "guild_gcw_region_defender") - { - std::pair > const & guildGcwDefenderRegionInfo = playerObject->getGuildGcwDefenderRegionInfo(); - if (!guildGcwDefenderRegionInfo.first.empty() && guildGcwDefenderRegionInfo.second.second) - { - playerObject->setTitle(title); - validTitle = true; - } - } - } - - // see if it's a city GCW Region Defender title - if (!validTitle) - { - if (title == "city_gcw_region_defender") - { - std::pair > const & cityGcwDefenderRegionInfo = playerObject->getCityGcwDefenderRegionInfo(); - if (!cityGcwDefenderRegionInfo.first.empty() && cityGcwDefenderRegionInfo.second.second) - { - playerObject->setTitle(title); - validTitle = true; - } - } - } - - // Run through all the skills for this player and make sure - // this is a valid skill title for them - if (!validTitle) - { - CreatureObject::SkillList::const_iterator iterSkillList = creatureObject->getSkillList().begin(); - for (; iterSkillList != creatureObject->getSkillList().end(); ++iterSkillList) - { - SkillObject const *skillObject = (*iterSkillList); - - if ( (skillObject != NULL) - && skillObject->isTitle() - && (skillObject->getSkillName() == title)) - { - playerObject->setTitle(title); - validTitle = true; - break; - } - } - } - - if (!validTitle) - { - playerObject->setTitle(std::string()); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncRepair(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - CreatureObject* const creature = dynamic_cast(NetworkIdManager::getObjectById (actor)); - if (creature == NULL) - { - WARNING (true, ("commandFuncRepair: PB null actor")); - return; - } - - TangibleObject* const object = dynamic_cast(NetworkIdManager::getObjectById (target)); - if (object == NULL) - { - WARNING (true, ("commandFuncRepair: PB null target")); - return; - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleSearchableByCtsSourceGalaxy(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncToggleSearchableByCtsSourceGalaxy() - networkId: %s\n", actor.getValueString().c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleSearchableByCtsSourceGalaxy(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleDisplayLocationInSearchResults(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncToggleDisplayLocationInSearchResults() - networkId: %s\n", actor.getValueString().c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleDisplayLocationInSearchResults(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleAnonymous(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncToggleAnonymous() - networkId: %s\n", actor.getValueString().c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleAnonymous(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleHelper(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncToggleHelper() - networkId: %s\n", actor.getValueString().c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleHelper(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleRolePlay(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncToggleRolePlay() - networkId: %s\n", actor.getValueString().c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleRolePlay(); - } -} - - -// ---------------------------------------------------------------------- - -static void commandFuncToggleOutOfCharacter(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleOutOfCharacter(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleLookingForWork(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleLookingForWork(); - } -} - - -// ---------------------------------------------------------------------- - -static void commandFuncToggleLookingForGroup(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncToggleLookingForGroup() - networkId: %s\n", actor.getValueString().c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleLookingForGroup(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleAwayFromKeyBoard(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - //DEBUG_REPORT_LOG(true, ("commandFuncToggleAwayFromKeyBoard() - networkId: %s\n", actor.getValueString().c_str())); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleAwayFromKeyBoard(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncToggleDisplayingFactionRank(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); - - if (playerObject != NULL) - { - playerObject->toggleDisplayingFactionRank(); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncReport(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject const * const reportingCreatureObject = CreatureObject::getCreatureObject(actor); - - if (reportingCreatureObject != NULL) - { - if (ReportManager::isThrottled(actor)) - { - // Player is trying to report too quickly after a previous report - - ProsePackage prosePackage; - prosePackage.stringId = StringId("system_msg", "report_wait"); - prosePackage.digitInteger = ReportManager::getThrottleTimeRemaining(actor); - - Chat::sendSystemMessage(*reportingCreatureObject, prosePackage); - } - else - { - Unicode::String harassingPlayerName; - //size_t curpos = 0; - //size_t endpos = 0; - - // If this player is on this galaxy, we can get the network id - - //Vivox phase 1 temporary solution: the client is appending - //its connection information to the report command, this should - //come from VChat really - Unicode::String const delimiter = Unicode::narrowToWide("|"); - - Unicode::UnicodeStringVector tokens; - if(Unicode::tokenize(params, tokens, &delimiter) && tokens.size() > 1) - { - harassingPlayerName = tokens[0]; - Unicode::String rest; - uint32 numTokens = tokens.size(); - for(uint32 i = 1; i < numTokens; ++i) - { - if(i != 1) - { - rest.append(delimiter); - } - rest.append(tokens[i]); - } - - NetworkId const harassingPlayerNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(harassingPlayerName))); - - ReportManager::addReport(reportingCreatureObject->getAssignedObjectFirstName(), actor, harassingPlayerName, harassingPlayerNetworkId, std::string("Report"), rest); - } - else - { - // No harassing player specified - - Chat::sendSystemMessage(*reportingCreatureObject, StringId("system_msg", "report_no_name"), Unicode::emptyString); - } - - - //if (Unicode::getFirstToken(name, curpos, endpos, harassingPlayerName)) - //{ - // NetworkId const harassingPlayerNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(harassingPlayerName))); - - // ReportManager::addReport(reportingCreatureObject->getAssignedObjectFirstName(), actor, harassingPlayerName, harassingPlayerNetworkId, std::string("Report")); - //} - //else - //{ - // // No harassing player specified - - // Chat::sendSystemMessage(*reportingCreatureObject, StringId("system_msg", "report_no_name"), Unicode::emptyString); - //} - } - } - else - { - DEBUG_WARNING(true, ("A non-player is trying to report a harassment. oid: %s", actor.getValueString().c_str())); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncNpcConversationStart(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - ServerObject * const actorObject = safe_cast(NetworkIdManager::getObjectById(actor)); - CreatureObject * const player = actorObject != NULL ? actorObject->asCreatureObject() : NULL; - if (player == NULL) - { - DEBUG_WARNING(true, ("commandFuncNpcConversationStart: couldn't find actor")); - return; - } - - ServerObject * const npcObject = safe_cast(NetworkIdManager::getObjectById(target)); - TangibleObject * const npc = npcObject != NULL ? npcObject->asTangibleObject() : NULL; - if (npc == NULL) - { - DEBUG_WARNING(true, ("commandFuncNpcConversationStart: Couldn't find npc to converse with")); - return; - } - - if (!ServerWorld::isSpaceScene()) - { - Container::ContainerErrorCode error = Container::CEC_Success; - if (!player->canManipulateObject(*npc, false, false, false, 30.0f, error)) - { - DEBUG_WARNING(true, ("commandFuncNpcConversationStart (ground): failed canManipulateObject check")); - return; - } - } - - std::string const & realParams = Unicode::wideToNarrow(params); - if (realParams.size() < 2) - { - DEBUG_WARNING(true, ("commandFuncNpcConversationStart: bad params %s", realParams.c_str())); - return; - } - - const char * const conversationName = &realParams[2]; - NpcConversationData::ConversationStarter const starter = static_cast(atoi(realParams.c_str())); - - player->startNpcConversation (*npc, conversationName, starter, 0); -} - -//---------------------------------------------------------------------- - -static void commandFuncNpcConversationStop(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - ServerObject * const actorObject = safe_cast(NetworkIdManager::getObjectById(actor)); - TangibleObject * const player = actorObject != NULL ? actorObject->asTangibleObject(): NULL; - if (player == NULL) - { - DEBUG_WARNING(true, ("commandFuncNpcConversationStop: couldn't find actor")); - return; - } - player->endNpcConversation(); -} - -//---------------------------------------------------------------------- - -static void commandFuncNpcConversationSelect(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - Object * const actorObject = NetworkIdManager::getObjectById(actor); - CreatureObject * const player = dynamic_cast(actorObject); - if (player == NULL) - { - DEBUG_WARNING(true, ("commandFuncNpcConversationStop: couldn't find actor")); - return; - } - - std::string realParams(Unicode::wideToNarrow(params)); - int selection = atoi(realParams.c_str()); - player->respondToNpc(selection); -} - -//---------------------------------------------------------------------- - -static void commandFuncServerDestroyObject (Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - CreatureObject * const player = dynamic_cast (NetworkIdManager::getObjectById (actor)); - if (player == NULL) - { - DEBUG_WARNING (true, ("commandFuncServerDestroyObject: couldn't find actor")); - return; - } - - ServerObject * const targetObject = safe_cast(NetworkIdManager::getObjectById (target)); - if (!targetObject) - { - PlayerObject * p = PlayerCreatureController::getPlayerObject(player); - if(p) - { - p->destroyWaypoint(target); - return; - } - else - { - DEBUG_WARNING (true, ("commandFuncServerDestroyObject: couldn't find target")); - return; - } - } - - ServerObject const * const topMost = getFirstParentInWorldOrPlayer(targetObject); - if (!topMost || topMost->getNetworkId() != actor) - { - DEBUG_WARNING (true, ("player tried to delete something not in their inventory")); - return; - } - - ProsePackage pp; - const bool sendResponse = !params.empty (); - - int const got = targetObject->getGameObjectType (); - if (sendResponse) - { - ProsePackageManagerServer::createSimpleProsePackage (*targetObject, SharedStringIds::rsp_object_deleted_prose, pp); - pp.other.stringId = GameObjectTypes::getStringId (got); - } - - // Cannot destroy an empty ship pcd while contained by a ship you own - if (got == SharedObjectTemplate::GOT_data_ship_control_device) - { - ShipObject const * const containingShip = ShipObject::getContainingShipObject(player); - if (containingShip && containingShip->getOwnerId() == actor && containingShip->getControlDevice() == targetObject) - { - if (sendResponse) - Chat::sendSystemMessage(*player, SharedStringIds::no_destroy_in_flight, Unicode::emptyString); - return; - } - } - - // Cannot destroy a tcg card that is in the middle of the redemption process - if (!VeteranRewardManager::checkForTcgRedemptionInProgress(*targetObject)) - return; - - // Cannot destroy a reward item that is in the middle of the trade in process - if (!VeteranRewardManager::checkForTradeInInProgress(*targetObject)) - return; - - Object const * const currentContainer = ContainerInterface::getContainedByObject(*targetObject); - if(currentContainer && currentContainer->asServerObject() && ( currentContainer->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron || currentContainer->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron_recipe ) ) - { - // Give the player a warning here? - return; - } - - if (targetObject->permanentlyDestroy(DeleteReasons::Player)) - { - LOG("CustomerService", ("Deletion:%s is deleting object %s", PlayerObject::getAccountDescription(actor).c_str(), ServerObject::getLogDescription(targetObject).c_str())); - if (sendResponse) - Chat::sendSystemMessage (*player, pp); - } - else - WARNING (true, ("commandFuncServerDestroyObject: Error encountered while deleting object %s", target.getValueString ().c_str ())); -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetSpokenLanguage(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - Object * const object = NetworkIdManager::getObjectById(actor); - CreatureObject * const creatureObject = dynamic_cast(object); - - if (creatureObject != NULL) - { - PlayerObject *playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - - if (playerObject != NULL) - { - size_t pos = 0; - int const languageId = nextIntParm(params, pos); - std::string skillModName; - GameLanguageManager::getLanguageSpeakSkillModName(languageId, skillModName); - - // Make sure the player is setting a valid game language - - std::map >::const_iterator iterModMap = creatureObject->getModMap().find(skillModName); - - if (iterModMap != creatureObject->getModMap().end()) - { - int const baseValue = iterModMap->second.first; - int const modValue = iterModMap->second.second; - - if ((baseValue + modValue) > 0) - { - playerObject->setSpokenLanguage(languageId); - } - } - else - { - DEBUG_WARNING(true, ("Invalid game language specified: %d", languageId)); - } - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncUnstick(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - Object * const object = NetworkIdManager::getObjectById(actor); - CreatureObject * const creatureObject = dynamic_cast(object); - if (creatureObject != NULL) - { - if (!ShipObject::getContainingShipObject(creatureObject)) // no unsticking in ships - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if (playerObject) - { - Chat::sendSystemMessageSimple(*creatureObject, SharedStringIds::unstick_in_progress, NULL); - if (!playerObject->getIsUnsticking()) - { - Vector position = creatureObject->getPosition_p(); - //Send positional information with this unstick along with the message. If you change - //the format of this positional information, you must also change it in the handler in ServerObject.cpp - char buf[255]; - snprintf(buf, sizeof(buf), "%f:%f", position.x, position.z); - buf[sizeof(buf) - 1] = '\0'; - - int wait = 30; - if (creatureObject->getClient() && creatureObject->getClient()->isGodValidated()) - { - if (creatureObject->getObjVars().getItem("debugUnstickWait", wait)) - { - if (wait <= 0) - wait = 1; - } - else - { - wait = 30; - } - } - - MessageToQueue::getInstance().sendMessageToC(actor, "C++Unstick", buf, wait, false); - playerObject->setIsUnsticking(true); - } - } - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncGetAccountInfo(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if(gm) - { - const Client * gmClient = gm->getClient(); - if(gmClient) - { - bool foundAsPilot = false; - const CreatureObject * player = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!player) - { - ShipObject const * const ship = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (ship) - { - foundAsPilot = true; - player = ship->getPilot(); - } - } - std::string result; - if(player) - { - const Client * client = player->getClient(); - if(client) - { - if (foundAsPilot) - result = "Pilot Character Name : "; - else - result = "Character Name : "; - - result += Unicode::wideToNarrow(player->getAssignedObjectName()); - result += "\nAccount Name : "; - result += client->getAccountName(); - result += "\nStation Id : "; - char buf[32]; - IGNORE_RETURN(snprintf(buf, sizeof(buf)-1, "%d", client->getStationId())); - buf[sizeof(buf)-1] = '\0'; - result += buf; - result += "\nGame Features : "; - result += ClientGameFeature::getDescription(client->getGameFeatures()); - result += "\nSubscription Features : "; - uint32 const subscriptionFeatures = client->getSubscriptionFeatures(); - result += ClientSubscriptionFeature::getDescription(subscriptionFeatures); - - result += "\nAccount SWG Feature Ids: "; - std::string accountFeatureIdsString; - Client::AccountFeatureIdList const & accountFeatureIds = client->getAccountFeatureIds(); - for (Client::AccountFeatureIdList::const_iterator iterAccountFeatureIds = accountFeatureIds.begin(); iterAccountFeatureIds != accountFeatureIds.end(); ++iterAccountFeatureIds) - { - if (!accountFeatureIdsString.empty()) - accountFeatureIdsString += ", "; - - accountFeatureIdsString += FormattedString<1024>().sprintf("%lu:%d", iterAccountFeatureIds->first, iterAccountFeatureIds->second); - - if (VeteranRewardManager::isFeatureIdBlockedBySubscriptionBit(*player, iterAccountFeatureIds->first)) - accountFeatureIdsString += "*"; - } - - if (!accountFeatureIdsString.empty()) - result += accountFeatureIdsString; - - result += "\nIP Address : "; - result += client->getIpAddress(); - result += "\nGod Mode : "; - if(client->isGod()) - result += "true"; - else - result += "false"; - } - else - { - result = "Object " + target.getValueString() + " is not controlled by a player."; - } - } - else - { - result = "Object " + target.getValueString() + " is not a creature or a ship."; - } - ConGenericMessage const msg(result, 0); - gmClient->send(msg, true); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncApplyPowerup (Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const NetworkId & powerupId = target; - const NetworkId targetOfApplyId (Unicode::wideToNarrow (params)); - ServerObject * const powerup = safe_cast(NetworkIdManager::getObjectById (powerupId)); - if (powerup) - { - const ServerObject * const targetOfApply = safe_cast(NetworkIdManager::getObjectById (targetOfApplyId)); - - if (targetOfApply) - { - const int got_targetOfApply = targetOfApply->getGameObjectType (); - const int got_powerup = powerup->getGameObjectType (); - - if (GameObjectTypes::doesPowerupApply (got_powerup, got_targetOfApply)) - { - GameScriptObject * const gso = powerup->getScriptObject(); - if (gso) - { - ScriptParams scriptParams; - scriptParams.addParam (actor); - scriptParams.addParam (targetOfApplyId); - gso->trigAllScripts(Scripting::TRIG_APPLY_POWERUP, scriptParams); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncLag (Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ -#if 0 - ServerObject * a = safe_cast(NetworkIdManager::getObjectById(actor)); - ServerObject * t = safe_cast(NetworkIdManager::getObjectById(target)); - if(! t) - { - t = a; - } - if(t != 0) - { - if(t->getClient()) - { - if(a && a->getClient()) - { - GameNetworkMessage const request("LagRequest"); - t->getClient()->send(request, true); - int connectionServerLag = t->getClient()->getConnectionServerLag(); - int gameServerLag = t->getClient()->getGameServerLag(); - char lagMsg[1024]; - snprintf(lagMsg, sizeof(lagMsg), "Lag update request sent to client.\nCurrent Lag: ConnectionServer=%d, GameServer=%d\n", connectionServerLag, gameServerLag); - std::string msg(lagMsg); - ConGenericMessage const result(msg, 0); - a->getClient()->send(result, true); - } - } - } -#endif -} - -// ---------------------------------------------------------------------- - -static void commandExecuteKnowledgeBaseMessage (Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const ¶ms) -{ - UNREF(actor); - UNREF(params); -} - -// ---------------------------------------------------------------------- - -static void commandFuncEmptyMailTarget(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - size_t pos = 0; - std::string networkId(nextStringParm(params, pos)); - - NetworkId targetNetworkId(networkId); - - DEBUG_REPORT_LOG(true, ("commandFuncEmptyMailTarget() - Player(%s) is emptying the mailbox of player(%s).\n", actor.getValueString().c_str(), targetNetworkId.getValueString().c_str())); - - Chat::emptyMail(actor, targetNetworkId); -} - -// ---------------------------------------------------------------------- - -static void commandFuncSetPlayerAppearance(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - //-- Collect parameters. - std::string token; - std::string objectTemplateName; - - bool useTarget = false; - size_t pos = 0; - - do - { - token = Unicode::toLower(nextStringParm(params, pos)); - if (token == "-target") - useTarget = true; - else if (!token.empty()) - objectTemplateName = token; - } while (!token.empty()); - - //-- Log attempt. - NetworkId subjectNetworkId = useTarget ? target: actor; - - LOG("setPlayerAppearance", - ("commandFuncSetPlayerAppearance(): command called by actor id=[%s]: attempting to change appearance for player id=[%s], using appearance info from object template=[%s], subject=[%s]", - actor.getValueString().c_str(), - subjectNetworkId.getValueString().c_str(), - objectTemplateName.c_str(), - useTarget ? "target" : "self" - )); - - //-- Validate parameters. - if (subjectNetworkId == NetworkId::cms_invalid) - { - WARNING(true, ("commandFuncSetPlayerAppearance(): subjectNetworkId is invalid, useTarget=[%s]", useTarget ? "true" : "false")); - return; - } - - CreatureObject *const creatureObject = dynamic_cast(NetworkIdManager::getObjectById(subjectNetworkId)); - if (!creatureObject) - { - WARNING(true, ("commandFuncSetPlayerAppearance(): subject network id=[%s] is not a CreatureObject-derived class.", subjectNetworkId.getValueString().c_str())); - return; - } - - if (objectTemplateName.empty()) - { - // Use the Creature's natural object template name. - objectTemplateName = creatureObject->getObjectTemplateName(); - } - else - { - // Ensure non-default object template name refers to an existing file. - if (!TreeFile::exists(objectTemplateName.c_str())) - { - WARNING(true, - ("commandFuncSetPlayerAppearance(): could not change id=[%s] to non-default object template name=[%s]: object template does not exist", - subjectNetworkId.getValueString().c_str(), - objectTemplateName.c_str() - )); - return; - } - } - - //-- Get the controller, instruct it to change the appearance. - CreatureController *const controller = dynamic_cast(creatureObject->getController()); - if (!controller) - { - WARNING(true, ("commandFuncSetPlayerAppearance(): subject network id=[%s] does not have a CreatureController.", subjectNetworkId.getValueString().c_str())); - return; - } - - //-- Set the new appearance. - controller->setAppearanceFromObjectTemplate(objectTemplateName); -} - -static void commandFuncRevertPlayerAppearance(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - //-- Collect parameters. - std::string token; - std::string objectTemplateName; - - bool useTarget = false; - size_t pos = 0; - - do - { - token = Unicode::toLower(nextStringParm(params, pos)); - if (token == "-target") - useTarget = true; - else if (!token.empty()) - objectTemplateName = token; - } while (!token.empty()); - - //-- Log attempt. - NetworkId subjectNetworkId = useTarget ? target: actor; - - LOG("setPlayerAppearance", - ("commandFuncRevertPlayerAppearance(): command called by actor id=[%s]: attempting to change appearance for player id=[%s], using appearance info from object template=[%s], subject=[%s]", - actor.getValueString().c_str(), - subjectNetworkId.getValueString().c_str(), - objectTemplateName.c_str(), - useTarget ? "target" : "self" - )); - - //-- Validate parameters. - if (subjectNetworkId == NetworkId::cms_invalid) - { - WARNING(true, ("commandFuncRevertPlayerAppearance(): subjectNetworkId is invalid, useTarget=[%s]", useTarget ? "true" : "false")); - return; - } - - CreatureObject *const creatureObject = dynamic_cast(NetworkIdManager::getObjectById(subjectNetworkId)); - if (!creatureObject) - { - WARNING(true, ("commandFuncRevertPlayerAppearance(): subject network id=[%s] is not a CreatureObject-derived class.", subjectNetworkId.getValueString().c_str())); - return; - } - - //-- Get the controller, instruct it to change the appearance. - CreatureController *const controller = dynamic_cast(creatureObject->getController()); - if (!controller) - { - WARNING(true, ("commandFuncRevertPlayerAppearance(): subject network id=[%s] does not have a CreatureController.", subjectNetworkId.getValueString().c_str())); - return; - } - - //-- Set the new appearance. - std::string const none("none"); - controller->setAppearanceFromObjectTemplate(none); -} - -//----------------------------------------------------------------------- - -static void commandFuncReconnectToTransferServer(Command const &, NetworkId const &, NetworkId const & , Unicode::String const &) -{ - GameNetworkMessage const msg("ReconnectToTransferServer"); - GameServer::getInstance().sendToCentralServer(msg); -} - -//----------------------------------------------------------------------- - -static void commandFuncFindFriend(Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const ¶ms) -{ - ServerObject * a = safe_cast(NetworkIdManager::getObjectById(actor)); - if(a && a->getClient()) - { - size_t pos = 0; - const std::string playerName = nextStringParm (params, pos); - CreatureObject * creatureObject = a->asCreatureObject(); - if(creatureObject) - { - if(! playerName.empty()) - { - // break the name down into its subcomponents - ChatAvatarId const cav(NameManager::normalizeName(playerName)); - - // can only find friend on the same cluster - bool const sameGame = (cav.gameCode.empty() || !_stricmp(cav.gameCode.c_str(), Chat::getGameCode().c_str())); - bool const sameCluster = (sameGame && (cav.cluster.empty() || !_stricmp(cav.cluster.c_str(), GameServer::getInstance().getClusterName().c_str()))); - - if (!sameGame || !sameCluster) - { - StringId stringId = StringId("ui_cmnty", "friend_location_failed_remote_name"); - Chat::sendSystemMessage(*creatureObject, stringId, Unicode::emptyString); - } - else - { - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if(playerObject) - { - playerObject->findFriend(cav.name); - } - } - } - else - { - // playerName is empty, send an error to requesting client - StringId stringId = StringId("ui_cmnty", "friend_location_failed_usage"); - Chat::sendSystemMessage(*creatureObject, stringId, Unicode::emptyString); - } - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncFormCommand(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - UNREF(target); - - Unicode::UnicodeStringVector tokens; - IGNORE_RETURN(Unicode::tokenize (params, tokens)); - - if(tokens.size() == 0) - return; - - std::string const commandStr = Unicode::wideToNarrow(tokens[0]); - FormManager::Command const command = static_cast(atoi(commandStr.c_str())); - - switch(command) - { - case FormManager::CREATE_OBJECT: - { - if(tokens.size() < 5) - return; - - std::string const templateName = Unicode::wideToNarrow(tokens[1]); - - std::string const & xStr = Unicode::wideToNarrow(tokens[2]); - std::string const & yStr = Unicode::wideToNarrow(tokens[3]); - std::string const & zStr = Unicode::wideToNarrow(tokens[4]); - std::string const & cellStr = Unicode::wideToNarrow(tokens[5]); - NetworkId const cellId(cellStr); - - float const x = static_cast(atof(xStr.c_str())); - float const y = static_cast(atof(yStr.c_str())); - float const z = static_cast(atof(zStr.c_str())); - - //we must have an odd number of tokens left (so that the datamap has a full key->value mapping) - if(tokens.size() % 2 != 0) - return; - - //TODO centralize pack/unpack - FormManager::UnpackedFormData dataMap; - std::vector values; - for(int i = 6; i < static_cast(tokens.size()) - 1; i += 2) - { - std::string const & key = Unicode::wideToNarrow(tokens[static_cast(i)]); - std::string const & value = Unicode::wideToNarrow(tokens[static_cast(i + 1)]); - values.clear(); - values.push_back(value); - dataMap[key] = values; - } - - FormManagerServer::handleCreateObjectData(actor, templateName, Vector(x, y, z), cellId, dataMap); - break; - } - - case FormManager::EDIT_OBJECT: - { - if(tokens.size() < 1) - return; - - //we must have an even number of tokens left (so that the datamap has a full key->value mapping) - if(tokens.size() % 2 != 1) - return; - - //TODO centralize pack/unpack - FormManager::UnpackedFormData dataMap; - std::vector values; - for(int i = 1; i < static_cast(tokens.size()) - 1; i += 2) - { - std::string const & key = Unicode::wideToNarrow(tokens[static_cast(i)]); - std::string const & value = Unicode::wideToNarrow(tokens[static_cast(i + 1)]); - values.clear(); - values.push_back(value); - dataMap[key] = values; - } - - FormManagerServer::handleEditObjectData(actor, target, dataMap); - break; - } - - case FormManager::REQUEST_EDIT_OBJECT: - { - FormManagerServer::requestEditObjectDataForClient(actor, target); - break; - } - - default: - DEBUG_FATAL(true, ("Unknown command in commandFuncFormCommand")); - break; - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncInstallShipComponents(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - //params for installShipComponent are " " - - Object const * const actorObj = NetworkIdManager::getObjectById(actor); - ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; - CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - { - return; - } - - //they must be near a space terminal (if not a god) - Client const * const client = actorCreature->getClient(); - if(!client) - return; - if(!client->isGod()) - { - Object * const targetObj = NetworkIdManager::getObjectById(target); - ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; - if( !targetServerObj || ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) && - (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) - return; - } - else - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); - } - - size_t pos = 0; - NetworkId const & shipId = nextOidParm(params, pos); - Object * const shipObj = NetworkIdManager::getObjectById(shipId); - ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; - ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; - if(!ship) - return; - - ShipChassisSlotType::Type const slotType = static_cast(nextIntParm(params, pos)); - NetworkId const & componentId = nextOidParm(params, pos); - Object * const componentObj = NetworkIdManager::getObjectById(componentId); - ServerObject * const componentServerObj = componentObj ? componentObj->asServerObject() : NULL; - TangibleObject * const component = componentServerObj ? componentServerObj->asTangibleObject() : NULL; - if(!component) - { - return; - } - - //make sure the player can manipulate the object - Container::ContainerErrorCode error = Container::CEC_Success; - if (!actorCreature->canManipulateObject(*component, true, true, true, 16.0f, error)) - { - StringId cantManipulateId("player_utility", "cannot_manipulate"); - Chat::sendSystemMessage(*actorCreature, cantManipulateId, Unicode::emptyString); - return; - } - - //make sure the object is not in a non-player modifiable slot - ContainedByProperty const * const containedByProperty = component->getContainedByProperty(); - if (containedByProperty) - { - Object const * const containedByObject = containedByProperty->getContainedBy(); - if (containedByObject) - { - SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*containedByObject); - if(slottedContainer) - { - SlotId const & slotId = slottedContainer->findFirstSlotIdForObject(component->getNetworkId()); - if(slotId != SlotId::invalid) - { - if(!ContainerInterface::canPlayerManipulateSlot(slotId)) - { - StringId cantManipulateId("player_utility", "cannot_manipulate_slot"); - Chat::sendSystemMessage(*actorCreature, cantManipulateId, Unicode::emptyString); - return; - } - } - } - } - } - - IGNORE_RETURN(ship->installComponent(actor, slotType, *component)); -} - -// ---------------------------------------------------------------------- - -static void commandFuncUninstallShipComponents(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - //params for uninstallShipComponent are " " - - Object * const actorObj = NetworkIdManager::getObjectById(actor); - ServerObject * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; - CreatureObject * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - return; - ServerObject * const actorInv = actorCreature->getInventory(); - if(!actorInv) - return; - - //they must be near a space terminal (if not a god) - Client const * const client = actorCreature->getClient(); - if(!client) - return; - if(!client->isGod()) - { - Object * const targetObj = NetworkIdManager::getObjectById(target); - ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; - if(!targetServerObj || - ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) - && (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) - return; - } - else - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); - } - - ServerObject const * const actorInventoryObject = actorCreature->getInventory(); - if(!actorInventoryObject) - { - Chat::sendSystemMessage(*actorCreature, SharedStringIds::shipcomponentinstall_noinventory, Unicode::emptyString); - return; - } - VolumeContainer const * const inventoryContainer = ContainerInterface::getVolumeContainer(*actorInventoryObject); - if(!inventoryContainer) - { - Chat::sendSystemMessage(*actorCreature, SharedStringIds::shipcomponentinstall_noinventorycontainer, Unicode::emptyString); - return; - } - if (inventoryContainer->getCurrentVolume() >= inventoryContainer->getTotalVolume()) - { - Chat::sendSystemMessage(*actorCreature, SharedStringIds::shipcomponentinstall_inventoryfull, Unicode::emptyString); - return; - } - - size_t pos = 0; - NetworkId const & shipId = nextOidParm(params, pos); - Object * const shipObj = NetworkIdManager::getObjectById(shipId); - ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; - ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; - if(!ship) - return; - - ShipChassisSlotType::Type const slotType = static_cast(nextIntParm(params, pos)); - - IGNORE_RETURN(ship->uninstallComponent(actor, slotType, *actorInv)); -} - - -// ---------------------------------------------------------------------- - -static void commandFuncInsertItemIntoShipComponentSlot(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - //params for insertItemIntoShipComponentSlot are " " - - Object * const actorObj = NetworkIdManager::getObjectById(actor); - ServerObject * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; - CreatureObject * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - return; - - //they must be near a space terminal (if not a god) - Client const * const client = actorCreature->getClient(); - if(!client) - return; - if(!client->isGod()) - { - Object * const targetObj = NetworkIdManager::getObjectById(target); - ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; - if(!targetServerObj || ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) && - (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) - return; - } - else - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); - } - - size_t pos = 0; - NetworkId const & shipId = nextOidParm(params, pos); - Object * const shipObj = NetworkIdManager::getObjectById(shipId); - ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; - ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; - if(!ship) - return; - - ShipChassisSlotType::Type const slotType = static_cast(nextIntParm(params, pos)); - - if(!ship->isSlotInstalled(slotType)) - return; - - NetworkId const componentId = nextOidParm(params, pos); - - ScriptParams trigParams; - trigParams.addParam(slotType); - trigParams.addParam(componentId); - trigParams.addParam(actor); - - //now trigger the ship - IGNORE_RETURN(ship->getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_ITEM_DROPPED_ON_SLOT, trigParams)); -} - -// ---------------------------------------------------------------------- - -static void commandFuncAssociateDroidControlDeviceWithShip(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - //params for associateDroidControlDeviceWithShip are " " - - Object const * const actorObj = NetworkIdManager::getObjectById(actor); - ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; - CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; - if (!actorCreature) - return; - - //they must be near a space terminal (if not a god) - Client const * const client = actorCreature->getClient(); - if(!client) - return; - if(!client->isGod()) - { - Object * const targetObj = NetworkIdManager::getObjectById(target); - ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; - if(!targetServerObj || ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) && - (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) - return; - } - else - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); - } - - size_t pos = 0; - NetworkId const & shipId = nextOidParm(params, pos); - Object * const shipObj = NetworkIdManager::getObjectById(shipId); - ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; - ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; - if(!ship) - return; - - NetworkId const droidControlDeviceId = nextOidParm(params, pos); - - if (!droidControlDeviceId.isValid()) - { - // removing from ship - ship->setInstalledDroidControlDevice(NetworkId::cms_invalid); - } - else - { - // putting in ship - ScriptParams trigParams; - trigParams.addParam(actorCreature->getNetworkId()); - trigParams.addParam(droidControlDeviceId); - - //now trigger the ship - IGNORE_RETURN(ship->getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_TRY_TO_EQUIP_DROID_CONTROL_DEVICE_IN_SHIP, trigParams)); - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncServerAsteroidDataListen(Command const &, NetworkId const & actor, NetworkId const & , Unicode::String const & ) -{ - Object const * const actorObj = NetworkIdManager::getObjectById(actor); - ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; - CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - return; - - ServerAsteroidManager::listenforServerAsteroidDebugData(actor); -} - -// ---------------------------------------------------------------------- - -static void commandFuncServerAsteroidDataStopListening(Command const &, NetworkId const & actor, NetworkId const & , Unicode::String const & ) -{ - Object const * const actorObj = NetworkIdManager::getObjectById(actor); - ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; - CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - return; - - ServerAsteroidManager::endListenforServerAsteroidDebugData(actor); -} - -//---------------------------------------------------------------------- - -static void commandFuncBoosterOn(Command const &, NetworkId const & actor, NetworkId const &, Unicode::String const &) -{ - internalSetBoosterOnOff(actor, true); -} - -//---------------------------------------------------------------------- - -static void commandFuncBoosterOff(Command const &, NetworkId const & actor, NetworkId const &, Unicode::String const &) -{ - internalSetBoosterOnOff(actor, false); -} - -//---------------------------------------------------------------------- - -static void commandFuncSetFormation(Command const &, NetworkId const & actor, NetworkId const &, Unicode::String const & params) -{ - Object * const o = NetworkIdManager::getObjectById(actor); - ServerObject * const so = o ? o->asServerObject() : NULL; - CreatureObject * const actorCreature = so ? so->asCreatureObject() : NULL; - if(actorCreature) - { - GroupObject * const group = actorCreature->getGroup(); - if(group) - { - if(group->getGroupLeaderId() == actor) - { - std::string paramsNarrow = Unicode::wideToNarrow(params); - if(paramsNarrow == "none") - { - group->setFormationNameCrc(Crc::crcNull); - } - else - { - if(PlayerFormationManager::isValidFormationName(paramsNarrow)) - group->setFormationNameCrc(Crc::normalizeAndCalculate(paramsNarrow.c_str())); - } - } - } - } -} - -//---------------------------------------------------------------------- - -static void commandFuncSetFormationSlot(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - Object * const actorObject = NetworkIdManager::getObjectById(actor); - ServerObject * const actorServerObject = (actorObject != 0) ? actorObject->asServerObject() : 0; - CreatureObject * const actorCreatureObject = (actorServerObject != 0) ? actorServerObject->asCreatureObject() : 0; - if ((actorCreatureObject != 0) && (actor != NetworkId::cms_invalid)) - { - GroupObject * const group = actorCreatureObject->getGroup(); - if (group) - { - if (group->getGroupLeaderId() == actor) - { - size_t pos = 0; - int const formationSlot = nextIntParm(params, pos); - if (formationSlot > -1) - { - group->setShipFormationSlotForMember(target, formationSlot); - } - } - } - } -} - -//---------------------------------------------------------------------- - -static void commandFuncUnDock(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - Object * const object = NetworkIdManager::getObjectById(actor); - - if (object != NULL) - { - ShipObject * const shipObject = ShipObject::getContainingShipObject(object->asServerObject()); - - if (shipObject != NULL) - { - ShipController * const shipController = dynamic_cast(shipObject->getController()); - - if (shipController != NULL) - { - shipController->unDock(); - } - else - { - WARNING(true, ("commandFuncUnDock() Undock requested on an object(%s) without a ShipController.", object->getDebugInformation().c_str())); - } - } - else - { - WARNING(true, ("commandFuncUnDock() Undock requested on an object(%s) contained by a NULL ShipObject.", object->getDebugInformation().c_str())); - } - } - else - { - WARNING(true, ("commandFuncUnDock() Undock requested on a NULL object(%s).", actor.getValueString().c_str())); - } -} - -//---------------------------------------------------------------------- - -static void commandFuncLaunchIntoSpace(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); - CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - { - WARNING(true, ("No actorCreature in commandFuncLaunchIntoSpace")); - return; - } - - if(!target.isValid()) - { - StringId invalidTargetId("player_utility", "invalid_target"); - Chat::sendSystemMessage(*actorCreature, invalidTargetId, Unicode::emptyString); - return; - } - - //target must be a space terminal - Object const * const o = NetworkIdManager::getObjectById(target); - ServerObject const * const so = o ? o->asServerObject() : NULL; - if(!so) - { - StringId invalidTargetId("player_utility", "target_not_server_object"); - Chat::sendSystemMessage(*actorCreature, invalidTargetId, Unicode::emptyString); - return; - } - if(so->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) - { - ProsePackage p; - p.stringId = StringId("player_utility", "not_space_terminal"); - p.target.id = target; - Unicode::String oob; - OutOfBandPackager::pack(p, -1, oob); - Chat::sendSystemMessage(*actorCreature, Unicode::emptyString, oob);; - return; - } - - Unicode::UnicodeStringVector tokens; - Unicode::tokenize (params, tokens); - - if(tokens.empty()) - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("(unlocalized) No parameters."), Unicode::emptyString); - return; - } - - NetworkId const shipPCDId(Unicode::wideToNarrow(tokens[0]).c_str()); - if(!shipPCDId.isValid()) - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("(unlocalized) Invalid ship."), Unicode::emptyString); - return; - } - Object * const terminalO = NetworkIdManager::getObjectById(target); - ServerObject * const terminalSO = terminalO ? terminalO->asServerObject() : NULL; - if(terminalSO) - { - std::vector networkIds; - - unsigned int tokenIndex = 1; - - if(tokens.size() > tokenIndex) - { - int const numberOfNetworkIds = atoi(Unicode::wideToNarrow(tokens[tokenIndex]).c_str()); - for (int i = 0; i < numberOfNetworkIds; ++i) - { - ++tokenIndex; - if(tokens.size() > tokenIndex) - { - NetworkId const Id(Unicode::wideToNarrow(tokens[tokenIndex])); - if (Id.isValid()) - { - networkIds.push_back(Id); - } - } - } - } - - ++tokenIndex; - - //adding an empty string is fine (it means they aren't traveling to another ground starport) - std::string strPointPlanetResult; - if(tokens.size() > tokenIndex) - { - strPointPlanetResult = Unicode::wideToNarrow(tokens[tokenIndex]); - } - - ++tokenIndex; - - //adding an empty string is fine (it means they aren't traveling to another ground starport) - std::string strPointLocationResult; - if(tokens.size() > tokenIndex) - { - strPointLocationResult = Unicode::wideToNarrow(tokens[tokenIndex]); - std::replace (strPointLocationResult.begin (), strPointLocationResult.end (), '_', ' '); - } - - ScriptParams params; - params.addParam(actor); - params.addParam(shipPCDId); - params.addParam(networkIds); - //adding an empty string is fine (it means they aren't traveling to another ground starport) - params.addParam(strPointPlanetResult.c_str()); - //adding an empty string is fine (it means they aren't traveling to another ground starport) - params.addParam(strPointLocationResult.c_str()); - - IGNORE_RETURN(terminalSO->getScriptObject()->trigAllScripts(Scripting::TRIG_ABOUT_TO_LAUNCH_TO_SPACE, params)); - } - else - { - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("(unlocalized) Invalid terminal"), Unicode::emptyString); - } -} - -//---------------------------------------------------------------------- - -static void commandFuncAcceptQuest(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); - CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - { - WARNING(true, ("No actorCreature in commandFuncAcceptQuest")); - return; - } - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); - if(!playerObject) - { - WARNING(true, ("No playerObject in commandFuncAcceptQuest")); - return; - } - - uint32 const questCrc = atoi(Unicode::wideToNarrow(params).c_str()); - if(playerObject->getPendingRequestQuestCrc() == questCrc) - { - NetworkId const & questGiver = playerObject->getPendingRequestQuestGiver(); - playerObject->questActivateQuest(questCrc, questGiver); - playerObject->setPendingRequestQuestInformation(0, NetworkId::cms_invalid); - } -} - -//---------------------------------------------------------------------- - -static void commandFuncReceiveReward(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) -{ - ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); - CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - { - WARNING(true, ("No actorCreature in commandFuncReceiveReward")); - return; - } - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); - if(!playerObject) - { - WARNING(true, ("No playerObject in commandFuncReceiveReward")); - return; - } - - Unicode::UnicodeStringVector sv; - Unicode::tokenize (params, sv); - - if(sv.empty()) - return; - uint32 const questCrc = atoi(Unicode::wideToNarrow(sv[0]).c_str()); - std::string selectedReward; - if(sv.size() > 1) - selectedReward = Unicode::wideToNarrow(sv[1]); - - if((playerObject->getPendingRequestQuestCrc() == questCrc) || playerObject->questPlayerCanClaimRewardFor(questCrc)) - { - playerObject->questGrantQuestReward(questCrc, selectedReward); - playerObject->setPendingRequestQuestInformation(0, NetworkId::cms_invalid); - } -} - -//---------------------------------------------------------------------- - -static void commandFuncAbandonQuest(Command const &, NetworkId const & actor, NetworkId const & , Unicode::String const & params) -{ - size_t pos = 0; - - //not currently used, but can distinguish between different quest types - int const questSystemType = nextIntParm(params, pos); - UNREF(questSystemType); - std::string const & questName = nextStringParm(params, pos); - - if(QuestManager::isQuestAbandonable(questName)) - { - ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); - CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; - if(actorCreature) - { - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); - if(playerObject) - { - Quest const * const q = QuestManager::getQuest(questName); - if(q && playerObject->questHasActiveQuest(q->getId()) && !playerObject->questHasCompletedQuest(q->getId())) - { - LOG("Quest", ("Abandon:%s abandoned quest [%s] with status [0x%08X].\n", - PlayerObject::getAccountDescription(actorServerObj->getClient()->getCharacterObjectId()).c_str(), - questName.c_str(), playerObject->questGetQuestStatus(q->getId()))); - - playerObject->questClearQuest(q->getId()); - } - } - } - } -} - - - -// ---------------------------------------------------------------------- - -static void commandFuncExchangeListCredits(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) -{ - ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); - CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; - if(!actorCreature) - { - WARNING(true, ("No actorCreature in commandFuncReceiveReward")); - return; - } - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); - if(!playerObject) - { - WARNING(true, ("No playerObject in commandFuncReceiveReward")); - return; - } - - Unicode::UnicodeStringVector sv; - Unicode::tokenize (params, sv); - - if(sv.empty()) - return; - uint32 const credits = (uint32)atoi(Unicode::wideToNarrow(sv[0]).c_str()); - if ( credits <= 0 ) - return; - - - char message[512]; - sprintf(message,"Listing %ld credits on station exchange.", credits); - Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide(message), Unicode::emptyString); - - - ExchangeListCreditsMessage const msg(actor, credits, GameServer::getInstance().getProcessId()); - GameServer::getInstance().sendToCentralServer(msg); -} - -//----------------------------------------------------------------------- - -static void commandFuncSquelch(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - char buffer[2048]; - if (!target.isValid()) - { - ConGenericMessage const msg("Error! No target specified for /squelch command.", 0); - gmClient->send(msg, true); - } - else - { - ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!so) - { - snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - CreatureObject * c = so->asCreatureObject(); - if (!c) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - PlayerObject * p = PlayerCreatureController::getPlayerObject(c); - if (!p) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else if (p->getSecondsUntilUnsquelched() < 0) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is already squelched", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - snprintf(buffer, sizeof(buffer)-1, "Squelching %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - - p->squelch(gm->getNetworkId(), Unicode::wideToNarrow(gm->getAssignedObjectName()), -1); - } - } - } - } - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncUnsquelch(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - char buffer[2048]; - if (!target.isValid()) - { - ConGenericMessage const msg("Error! No target specified for /unsquelch command.", 0); - gmClient->send(msg, true); - } - else - { - ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!so) - { - snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - CreatureObject * c = so->asCreatureObject(); - if (!c) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - PlayerObject * p = PlayerCreatureController::getPlayerObject(c); - if (!p) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else if (p->getSecondsUntilUnsquelched() == 0) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not currently squelched", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - snprintf(buffer, sizeof(buffer)-1, "Unsquelching %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - - p->unsquelch(); - } - } - } - } - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncGrantWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - char buffer[2048]; - if (!target.isValid()) - { - ConGenericMessage const msg("Error! No target specified for /grantWarden command.", 0); - gmClient->send(msg, true); - } - else - { - ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!so) - { - snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - CreatureObject * c = so->asCreatureObject(); - if (!c) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - PlayerObject * p = PlayerCreatureController::getPlayerObject(c); - if (!p) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else if (p->isWarden()) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is already a warden", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - snprintf(buffer, sizeof(buffer)-1, "Granting warden to %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - - p->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::Warden)); - - LOG("CustomerService", ("Warden:%s grantWarden to %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); - } - } - } - } - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncRevokeWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - char buffer[2048]; - if (!target.isValid()) - { - ConGenericMessage const msg("Error! No target specified for /revokeWarden command.", 0); - gmClient->send(msg, true); - } - else - { - ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!so) - { - snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - CreatureObject * c = so->asCreatureObject(); - if (!c) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - PlayerObject * p = PlayerCreatureController::getPlayerObject(c); - if (!p) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else if (!p->isWarden()) - { - snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a warden", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - } - else - { - snprintf(buffer, sizeof(buffer)-1, "Revoking warden from %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - ConGenericMessage const msg(buffer, 0); - gmClient->send(msg, true); - - p->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)); - - LOG("CustomerService", ("Warden:%s revokeWarden from %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); - } - } - } - } - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncSpammer(Command const &, NetworkId const &actor, NetworkId const & targetForCommand, Unicode::String const ¶ms) -{ - NetworkId target = targetForCommand; - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - // check warden permission first - const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); - if (!gmPlayerObject || !gmPlayerObject->isWarden()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); - return; - } - - // check to see if warden functionality is enabled - if (!ConfigServerGame::getEnableWarden()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "warden_functionality_disabled"), Unicode::emptyString); - return; - } - - // check for valid target - NetworkId parsedNetworkId; - if (!target.isValid()) - { - // check to see if a target name was specified, and see - // if that resolves into a player character in the galaxy - if (params.empty()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "no_target"), Unicode::emptyString); - return; - } - else - { - parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); - if (!parsedNetworkId.isValid()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - return; - } - else - { - target = parsedNetworkId; - } - } - } - - ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!so) - { - if (parsedNetworkId.isValid()) - { - // send a messageTo to the target to do apply the /spammer operation - char buffer[1024]; - snprintf(buffer, sizeof(buffer)-1, "%s %s", actor.getValueString().c_str(), Unicode::wideToNarrow(gm->getAssignedObjectName()).c_str()); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, - "C++SpammerReq", - buffer, - 0, - false, - actor, - "C++SpammerRspTargetNotFound"); - } - else - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - } - - return; - } - - CreatureObject * c = so->asCreatureObject(); - if (!c) - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - return; - } - - PlayerObject * p = PlayerCreatureController::getPlayerObject(c); - if (!p) - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - return; - } - - // on a session-authenticated cluster, cannot /spammer a secured login character - if (so->getClient() && so->getClient()->isGodValidated()) - { - if (!ConfigServerGame::getAdminGodToAll() && !ConfigServerGame::getEnableWardenCanSquelchSecuredLogin()) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "cannot_spammer_target"); - prosePackage.target.str = so->getAssignedObjectName(); - Chat::sendSystemMessage(*gm, prosePackage); - return; - } - } - - // cannot /spammer self - if (target == actor) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "cannot_spammer_target"); - prosePackage.target.str = so->getAssignedObjectName(); - Chat::sendSystemMessage(*gm, prosePackage); - return; - } - - // cannot /spammer a target that is already squelched - if (p->getSecondsUntilUnsquelched() != 0) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "cannot_spammer_target"); - prosePackage.target.str = so->getAssignedObjectName(); - Chat::sendSystemMessage(*gm, prosePackage); - return; - } - - // do it - p->squelch(actor, Unicode::wideToNarrow(gm->getAssignedObjectName()), ConfigServerGame::getWardenSquelchDurationSeconds()); - ReportManager::addReport(gm->getAssignedObjectFirstName(), actor, so->getAssignedObjectFirstName(), target, std::string("Warden")); - - // log it - LOG("CustomerService", ("Warden:%s has spammer %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); - - // display confirmation message - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "confirm_spammer"); - prosePackage.target.str = so->getAssignedObjectName(); - Chat::sendSystemMessage(*gm, prosePackage); - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncUnspammer(Command const &, NetworkId const &actor, NetworkId const & targetForCommand, Unicode::String const ¶ms) -{ - NetworkId target = targetForCommand; - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - // check warden permission first - const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); - if (!gmPlayerObject || !gmPlayerObject->isWarden()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); - return; - } - - // check for valid target - NetworkId parsedNetworkId; - if (!target.isValid()) - { - // check to see if a target name was specified, and see - // if that resolves into a player character in the galaxy - if (params.empty()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "no_target"), Unicode::emptyString); - return; - } - else - { - parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); - if (!parsedNetworkId.isValid()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - return; - } - else - { - target = parsedNetworkId; - } - } - } - - ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); - if (!so) - { - if (parsedNetworkId.isValid()) - { - // send a messageTo to the target to do apply the /unspammer operation - MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, - "C++UnspammerReq", - actor.getValueString(), - 0, - false, - actor, - "C++UnspammerRspTargetNotFound"); - } - else - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - } - - return; - } - - CreatureObject * c = so->asCreatureObject(); - if (!c) - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - return; - } - - PlayerObject * p = PlayerCreatureController::getPlayerObject(c); - if (!p) - { - Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); - return; - } - - // cannot /unspammer a target that is not currently /spammer(ed) - if (p->getSecondsUntilUnsquelched() <= 0) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "cannot_unspammer_target"); - prosePackage.target.str = so->getAssignedObjectName(); - Chat::sendSystemMessage(*gm, prosePackage); - return; - } - - // can only /unspammer target that I /spammer(ed) - if (p->getSquelchedById() != actor) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "cannot_unspammer_target"); - prosePackage.target.str = so->getAssignedObjectName(); - Chat::sendSystemMessage(*gm, prosePackage); - return; - } - - // do it - p->unsquelch(); - - // log it - LOG("CustomerService", ("Warden:%s has unspammer %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); - - // display confirmation message - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "confirm_unspammer"); - prosePackage.target.str = so->getAssignedObjectName(); - Chat::sendSystemMessage(*gm, prosePackage); - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncDeputizeWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - // check warden permission first - const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); - if (!gmPlayerObject || !gmPlayerObject->isWarden()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); - return; - } - - // check to see if warden functionality is enabled - if (!ConfigServerGame::getEnableWarden()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "warden_functionality_disabled"), Unicode::emptyString); - return; - } - - // check to see if wardens are allowed to deputize other wardens - if (!ConfigServerGame::getEnableWardenToDeputizeWarden()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); - return; - } - - // check for valid target - NetworkId parsedNetworkId = target; - if (!parsedNetworkId.isValid()) - { - // check to see if a target name was specified, and see - // if that resolves into a player character in the galaxy - if (params.empty()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "cannot_deputize"), Unicode::emptyString); - return; - } - else - { - parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); - if (!parsedNetworkId.isValid()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "cannot_deputize"), Unicode::emptyString); - return; - } - } - } - - // cannot deputize self - if (parsedNetworkId == gm->getNetworkId()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "cannot_deputize"), Unicode::emptyString); - return; - } - - // send a messageTo to the target to complete the deputize process - char buffer[1024]; - snprintf(buffer, sizeof(buffer)-1, "%s|%lu", gm->getNetworkId().getValueString().c_str(), gmPlayerObject->getStationId()); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, - "C++DeputizeWardenReq", - buffer, - 0, - false, - actor, - "C++DeputizeWardenRspCannotDeputize"); - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncUndeputizeWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) -{ - const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (gm) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - // check warden permission first - const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); - if (!gmPlayerObject || !gmPlayerObject->isWarden()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); - return; - } - - // check for valid target - NetworkId parsedNetworkId = target; - if (!parsedNetworkId.isValid()) - { - // check to see if a target name was specified, and see - // if that resolves into a player character in the galaxy - if (params.empty()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "cannot_undeputize"), Unicode::emptyString); - return; - } - else - { - parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); - if (!parsedNetworkId.isValid()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "cannot_undeputize"), Unicode::emptyString); - return; - } - } - } - - // cannot undeputize self - if (parsedNetworkId == gm->getNetworkId()) - { - Chat::sendSystemMessage(*gm, StringId("warden", "cannot_undeputize"), Unicode::emptyString); - return; - } - - // send a messageTo to the target to complete the undeputize process - char buffer[1024]; - snprintf(buffer, sizeof(buffer)-1, "%s|%lu", gm->getNetworkId().getValueString().c_str(), gmPlayerObject->getStationId()); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, - "C++UndeputizeWardenReq", - buffer, - 0, - false, - actor, - "C++UndeputizeWardenRspCannotUndeputize"); - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncRemoveBuff(Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const ¶ms) -{ - CreatureObject * player = dynamic_cast(NetworkIdManager::getObjectById(actor)); - if (player) - { - size_t pos = 0; - int32 const buffCrc = nextIntParm(params, pos); - if (buffCrc && BuffManager::getIsBuffPlayerRemovable(buffCrc)) - { - player->removeBuff(buffCrc); - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncOccupyUnlockedSlot(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - PlayerObject const * const gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); - if (gm && gmPlayerObject) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - // check to see if /occupyUnlockedSlot is enabled - if (!ConfigServerGame::getEnableOccupyUnlockedSlotCommand()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "occupy_unlocked_slot_command_disabled"), Unicode::emptyString); - return; - } - - // check to see if the account currently has an unoccupied unlocked slot - if (!gmClient->getHasUnoccupiedJediSlot()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "occupy_unlocked_slot_command_account_has_no_unoccupied_unlocked_slot"), Unicode::emptyString); - return; - } - - // already unlocked slot character - if (gmClient->getIsJediSlotCharacter()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "occupy_unlocked_slot_command_already_unlocked_character"), Unicode::emptyString); - return; - } - - // check to see if there is a cooldown is in effect for the command - int const timeNow = static_cast(::time(NULL)); - if (!gmClient->isGod() && gm->getObjVars().hasItem("timeNextOccupyVacateUnlockedSlotCommandAllowed") && (gm->getObjVars().getType("timeNextOccupyVacateUnlockedSlotCommandAllowed") == DynamicVariable::INT)) - { - int timeNextOccupyVacateUnlockedSlotCommandAllowed = 0; - if (gm->getObjVars().getItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", timeNextOccupyVacateUnlockedSlotCommandAllowed)) - { - if (timeNextOccupyVacateUnlockedSlotCommandAllowed > timeNow) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("unlocked_slot", "occupy_unlocked_slot_command_too_fast"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextOccupyVacateUnlockedSlotCommandAllowed - timeNow))); - Chat::sendSystemMessage(*gm, prosePackage); - - return; - } - } - } - - // CS log the request - LOG("CustomerService",("JediUnlockedSlot:%s requesting OccupyUnlockedSlot", PlayerObject::getAccountDescription(gm).c_str())); - - // send off request to LoginServer to make this character occupy the unlocked slot - GenericValueTypeMessage, uint32> > const occupyUnlockedSlotReq("OccupyUnlockedSlotReq", std::make_pair(std::make_pair(static_cast(gmPlayerObject->getStationId()), actor), GameServer::getInstance().getProcessId())); - GameServer::getInstance().sendToCentralServer(occupyUnlockedSlotReq); - - // set cooldown - if (!gmClient->isGod()) - { - IGNORE_RETURN(gm->setObjVarItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", (timeNow + ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); - } - - // display "wait for reply" message - ProsePackage prosePackage; - prosePackage.stringId = StringId("unlocked_slot", "occupy_unlocked_slot_wait_for_reply"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); - Chat::sendSystemMessage(*gm, prosePackage); - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncVacateUnlockedSlot(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - PlayerObject const * const gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); - if (gm && gmPlayerObject) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - // check to see if /vacateUnlockedSlot is enabled - if (!ConfigServerGame::getEnableVacateUnlockedSlotCommand()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "vacate_unlocked_slot_command_disabled"), Unicode::emptyString); - return; - } - - // check to see if this character is an unlocked slot character - if (!gmClient->getIsJediSlotCharacter()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "vacate_unlocked_slot_command_not_unlocked_character"), Unicode::emptyString); - return; - } - - // check to see if there is a cooldown is in effect for the command - int const timeNow = static_cast(::time(NULL)); - if (!gmClient->isGod() && gm->getObjVars().hasItem("timeNextOccupyVacateUnlockedSlotCommandAllowed") && (gm->getObjVars().getType("timeNextOccupyVacateUnlockedSlotCommandAllowed") == DynamicVariable::INT)) - { - int timeNextOccupyVacateUnlockedSlotCommandAllowed = 0; - if (gm->getObjVars().getItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", timeNextOccupyVacateUnlockedSlotCommandAllowed)) - { - if (timeNextOccupyVacateUnlockedSlotCommandAllowed > timeNow) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("unlocked_slot", "vacate_unlocked_slot_command_too_fast"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextOccupyVacateUnlockedSlotCommandAllowed - timeNow))); - Chat::sendSystemMessage(*gm, prosePackage); - - return; - } - } - } - - // CS log the request - LOG("CustomerService",("JediUnlockedSlot:%s requesting VacateUnlockedSlot", PlayerObject::getAccountDescription(gm).c_str())); - - // send off request to LoginServer to make this character vacate the unlocked slot - GenericValueTypeMessage, uint32> > const vacateUnlockedSlotReq("VacateUnlockedSlotReq", std::make_pair(std::make_pair(static_cast(gmPlayerObject->getStationId()), actor), GameServer::getInstance().getProcessId())); - GameServer::getInstance().sendToCentralServer(vacateUnlockedSlotReq); - - // set cooldown - if (!gmClient->isGod()) - { - IGNORE_RETURN(gm->setObjVarItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", (timeNow + ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); - } - - // display "wait for reply" message - ProsePackage prosePackage; - prosePackage.stringId = StringId("unlocked_slot", "vacate_unlocked_slot_wait_for_reply"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); - Chat::sendSystemMessage(*gm, prosePackage); - } - } -} - -//----------------------------------------------------------------------- - -static void commandFuncSwapUnlockedSlot(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); - PlayerObject const * const gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); - if (gm && gmPlayerObject) - { - const Client * gmClient = gm->getClient(); - if (gmClient) - { - // check to see if /swapUnlockedSlot is enabled - if (!ConfigServerGame::getEnableSwapUnlockedSlotCommand()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_disabled"), Unicode::emptyString); - return; - } - - // check to see if this character is an unlocked slot character - if (!gmClient->getIsJediSlotCharacter()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_not_unlocked_character"), Unicode::emptyString); - return; - } - - // check to see if a target character name is specified - if (params.empty()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_no_params"), Unicode::emptyString); - return; - } - - // check to see if a valid target character name is specified - NetworkId const parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); - if (!parsedNetworkId.isValid()) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_invalid_target"), Unicode::emptyString); - return; - } - - // cannot swap with yourself - if (parsedNetworkId == actor) - { - Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_target_is_already_unlocked_character"), Unicode::emptyString); - return; - } - - // check to see if there is a cooldown is in effect for the command - int const timeNow = static_cast(::time(NULL)); - if (!gmClient->isGod() && gm->getObjVars().hasItem("timeNextOccupyVacateUnlockedSlotCommandAllowed") && (gm->getObjVars().getType("timeNextOccupyVacateUnlockedSlotCommandAllowed") == DynamicVariable::INT)) - { - int timeNextOccupyVacateUnlockedSlotCommandAllowed = 0; - if (gm->getObjVars().getItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", timeNextOccupyVacateUnlockedSlotCommandAllowed)) - { - if (timeNextOccupyVacateUnlockedSlotCommandAllowed > timeNow) - { - ProsePackage prosePackage; - prosePackage.stringId = StringId("unlocked_slot", "swap_unlocked_slot_command_too_fast"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextOccupyVacateUnlockedSlotCommandAllowed - timeNow))); - Chat::sendSystemMessage(*gm, prosePackage); - - return; - } - } - } - - // CS log the request - LOG("CustomerService",("JediUnlockedSlot:%s requesting SwapUnlockedSlot with %s (%s)", PlayerObject::getAccountDescription(gm).c_str(), parsedNetworkId.getValueString().c_str(), NameManager::getInstance().getPlayerFullName(parsedNetworkId).c_str())); - - // send off request to LoginServer to make this character normal and the target characer unlocked - GenericValueTypeMessage, std::pair > > const swapUnlockedSlotReq("SwapUnlockedSlotReq", std::make_pair(std::make_pair(static_cast(gmPlayerObject->getStationId()), actor), std::make_pair(GameServer::getInstance().getProcessId(), parsedNetworkId))); - GameServer::getInstance().sendToCentralServer(swapUnlockedSlotReq); - - // set cooldown - if (!gmClient->isGod()) - { - IGNORE_RETURN(gm->setObjVarItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", (timeNow + ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); - } - - // display "wait for reply" message - ProsePackage prosePackage; - prosePackage.stringId = StringId("unlocked_slot", "swap_unlocked_slot_wait_for_reply"); - prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); - Chat::sendSystemMessage(*gm, prosePackage); - } - } -} - -// ---------------------------------------------------------------------- - -static void commandFuncPickupAllRoomItemsIntoInventory(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - // don't allow this in god mode because it could be used accidentally and pick up a bunch of stuff, - // and god mode allows stuff to be picked up, which wouldn't normally be allowed to be picked up - if (!targetObj->getClient()) - return; - - if (targetObj->getClient()->isGod()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You cannot do this while in GOD mode."), Unicode::emptyString); - return; - } - - // don't do this if the character is not "active", meaning he's probably doing it with a macro - if (targetPlayerObj->getSessionLastActiveTime() == 0) - return; - - // don't allow multiple /pickupAllRoomItemsIntoInventory and/or /dropAllInventoryItemsIntoRoom - int const timeNow = static_cast(::time(NULL)); - int pickupDropAllItemsOperationTimeout = 0; - if (targetObj->getObjVars().getItem("pickupDropAllItemsOperation.timeout", pickupDropAllItemsOperationTimeout) && (pickupDropAllItemsOperationTimeout > timeNow)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing the /pickupAllRoomItemsIntoInventory or /dropAllInventoryItemsIntoRoom command. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(pickupDropAllItemsOperationTimeout - timeNow)).c_str())), Unicode::emptyString); - return; - } - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); - return; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - if (!containingPOB->isOnAdminList(*targetObj)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const targetInventoryObj = targetObj->getInventory(); - if (!targetInventoryObj) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - VolumeContainer const * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); - if (!targetInventoryContainer) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - // see if the player specified to overload the inventory - Unicode::String const lowercaseParams = Unicode::toLower(params); - static Unicode::String const paramsOverload1 = Unicode::narrowToWide("-overload"); - static Unicode::String const paramsOverload2 = Unicode::narrowToWide("overload"); - bool const allowInventoryOverload = ((lowercaseParams == paramsOverload1) || (lowercaseParams == paramsOverload2)); - - int const inventoryBaseLimit = targetInventoryContainer->getTotalVolume(); - int const inventoryOverLimit = std::max(inventoryBaseLimit, (inventoryBaseLimit + ConfigServerGame::getMoveValidationMaxInventoryOverload() - 11)); - int const inventoryLimit = (allowInventoryOverload ? inventoryOverLimit : inventoryBaseLimit); - - if (targetInventoryContainer->getCurrentVolume() >= inventoryLimit) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Your inventory is full."), Unicode::emptyString); - - // if they didn't run the command with the -overload - // option, remind them about the -overload option - if (!allowInventoryOverload && (targetInventoryContainer->getCurrentVolume() < inventoryOverLimit)) - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("If you wish to pick up more items than available inventory space, you can specify the \"overload\" option with the command by typing \"/pickupAllRoomItemsIntoInventory -overload\" which will pick up additional items and overload your inventory, but not so overloaded as to prevent you from moving."), Unicode::emptyString); - - return; - } - - Container const * const cellContainer = ContainerInterface::getContainer(*containingCell); - if (!cellContainer) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - // the player counts as 1 item in the room - if (cellContainer->getNumberOfItems() <= 1) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("This room is empty."), Unicode::emptyString); - return; - } - - // start messageTo loop to pick up the items in the room, spread - // out over a period of time so it doesn't lag out the server - int pickupDropAllItemsOperationId = ::rand(); - while (pickupDropAllItemsOperationId == 0) - pickupDropAllItemsOperationId = ::rand(); - - targetPlayerObj->setPickupDropAllItemsOperationId(pickupDropAllItemsOperationId); - targetPlayerObj->setPickupDropAllItemsCellId(containingCell->getNetworkId()); - targetPlayerObj->setPickupAllItemsAllowInventoryOverload(allowInventoryOverload); - targetPlayerObj->setPickupDropAllItemsNumItemsSoFar(0); - targetPlayerObj->getPickupDropAllItemsProcessedItemsSoFar().clear(); - - IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.timeout", timeNow + (5 * 60))); - IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.operationId", pickupDropAllItemsOperationId)); - - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please remain in the room while the operation is being performed. You will be notified when the operation is complete."), Unicode::emptyString); - - MessageToQueue::getInstance().sendMessageToC(targetObj->getNetworkId(), - "C++PickupAllRoomItemsIntoInventory", - "", - 0, - false); -} - -// ---------------------------------------------------------------------- - -static void commandFuncDropAllInventoryItemsIntoRoom(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - // don't allow this in god mode because it could be used accidentally and drop a bunch of stuff, - // and god mode allows stuff to be dropped, which wouldn't normally be allowed to be dropped - if (!targetObj->getClient()) - return; - - if (targetObj->getClient()->isGod()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You cannot do this while in GOD mode."), Unicode::emptyString); - return; - } - - // don't do this if the character is not "active", meaning he's probably doing it with a macro - if (targetPlayerObj->getSessionLastActiveTime() == 0) - return; - - // don't allow multiple /pickupAllRoomItemsIntoInventory and/or /dropAllInventoryItemsIntoRoom - int const timeNow = static_cast(::time(NULL)); - int pickupDropAllItemsOperationTimeout = 0; - if (targetObj->getObjVars().getItem("pickupDropAllItemsOperation.timeout", pickupDropAllItemsOperationTimeout) && (pickupDropAllItemsOperationTimeout > timeNow)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing the /pickupAllRoomItemsIntoInventory or /dropAllInventoryItemsIntoRoom command. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(pickupDropAllItemsOperationTimeout - timeNow)).c_str())), Unicode::emptyString); - return; - } - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); - return; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - // check for lot overlimit drop restriction - if ((targetPlayerObj->getAccountNumLots() > targetObj->getMaxNumberOfLots()) && targetObj->getObjVars().hasItem("lotOverlimit.structure_id")) - { - NetworkId lotOverlimitStructure; - if (targetObj->getObjVars().getItem("lotOverlimit.structure_id", lotOverlimitStructure) && lotOverlimitStructure.isValid()) - { - if (GameObjectTypes::isTypeOf(containingPOB->getGameObjectType(), SharedObjectTemplate::GOT_building) && (containingPOB->getNetworkId() != lotOverlimitStructure)) - { - std::string lotOverlimitStructureName; - std::string lotOverlimitStructureLocation; - - IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); - IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); - - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are currently over the lot limit, and cannot drop any item into (or move around items within) any factory or structure, other than the %s structure located at %s that caused you to exceed the lot limit.", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); - return; - } - } - } - - if (!containingPOB->isOnAdminList(*targetObj)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const targetInventoryObj = targetObj->getInventory(); - if (!targetInventoryObj) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - VolumeContainer const * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); - if (!targetInventoryContainer) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - int pobBaseItemLimit = 0; - int pobAdditionalItems = 0; - const int pobItemLimit = containingPOB->getPobTotalItemLimit(pobBaseItemLimit, pobAdditionalItems); - - if (containingPOB->getPobItemCount() >= pobItemLimit) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("The structure or POB ship is full."), Unicode::emptyString); - return; - } - - if (targetInventoryContainer->getCurrentVolume() <= 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Your inventory is empty."), Unicode::emptyString); - return; - } - - // start messageTo loop to drop the inventory items into the room, - // spread out over a period of time so it doesn't lag out the server - int pickupDropAllItemsOperationId = ::rand(); - while (pickupDropAllItemsOperationId == 0) - pickupDropAllItemsOperationId = ::rand(); - - targetPlayerObj->setPickupDropAllItemsOperationId(pickupDropAllItemsOperationId); - targetPlayerObj->setPickupDropAllItemsCellId(containingCell->getNetworkId()); - targetPlayerObj->setPickupDropAllItemsNumItemsSoFar(0); - targetPlayerObj->getPickupDropAllItemsProcessedItemsSoFar().clear(); - - IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.timeout", timeNow + (5 * 60))); - IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.operationId", pickupDropAllItemsOperationId)); - - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please remain in the room while the operation is being performed. You will be notified when the operation is complete."), Unicode::emptyString); - - MessageToQueue::getInstance().sendMessageToC(targetObj->getNetworkId(), - "C++DropAllInventoryItemsIntoRoom", - "", - 0, - false); -} - -// ---------------------------------------------------------------------- - -static void commandFuncSaveDecorationLayout(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject const * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); - return; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - if (!containingPOB->isOnAdminList(*targetObj)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - // poke script to pop up some SUI windows to let the user pick which save slot to use - MessageToQueue::getInstance().sendMessageToJava(targetObj->getNetworkId(), "handleSaveDecorationLayout", std::vector(), 0, false); -} - -// ---------------------------------------------------------------------- - -static void commandFuncRestoreDecorationLayout(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) -{ - CreatureObject const * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - // don't allow another restore on the pob while one is still in progress - int const timeNow = static_cast(::time(NULL)); - int restoreDecorationOperationTimeout = 0; - if (targetObj->getObjVars().getItem("restoreDecorationOperation.timeout", restoreDecorationOperationTimeout) && (restoreDecorationOperationTimeout > timeNow)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing a restore decoration layout operation. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(restoreDecorationOperationTimeout - timeNow)).c_str())), Unicode::emptyString); - return; - } - - if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); - return; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - // check for lot overlimit drop restriction - if ((targetPlayerObj->getAccountNumLots() > targetObj->getMaxNumberOfLots()) && targetObj->getObjVars().hasItem("lotOverlimit.structure_id")) - { - NetworkId lotOverlimitStructure; - if (targetObj->getObjVars().getItem("lotOverlimit.structure_id", lotOverlimitStructure) && lotOverlimitStructure.isValid()) - { - if (GameObjectTypes::isTypeOf(containingPOB->getGameObjectType(), SharedObjectTemplate::GOT_building) && (containingPOB->getNetworkId() != lotOverlimitStructure)) - { - std::string lotOverlimitStructureName; - std::string lotOverlimitStructureLocation; - - IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); - IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); - - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are currently over the lot limit, and cannot drop any item into (or move around items within) any factory or structure, other than the %s structure located at %s that caused you to exceed the lot limit.", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); - return; - } - } - } - - if (!containingPOB->isOnAdminList(*targetObj)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - // see if there's any saved decoration layout to restore - if (!targetPlayerObj->getObjVars().hasItem("savedDecoration1.saveTime") && !targetPlayerObj->getObjVars().hasItem("savedDecoration2.saveTime") && !targetPlayerObj->getObjVars().hasItem("savedDecoration3.saveTime")) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You do not have any saved decoration layout."), Unicode::emptyString); - return; - } - - // poke script to pop up some SUI windows to let the user pick which save slot to use - MessageToQueue::getInstance().sendMessageToJava(targetObj->getNetworkId(), "handleRestoreDecorationLayout", std::vector(), 0, false); -} - -// ---------------------------------------------------------------------- - -static void commandFuncAreaPickRandomPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextAreaPickRandomPlayerCommandAllowed") && (targetObj->getObjVars().getType("timeNextAreaPickRandomPlayerCommandAllowed") == DynamicVariable::INT)) - { - int timeNextAreaPickRandomPlayerCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextAreaPickRandomPlayerCommandAllowed", timeNextAreaPickRandomPlayerCommandAllowed)) - { - if (timeNextAreaPickRandomPlayerCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextAreaPickRandomPlayerCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - // handle options - static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); - uint32 socialType = 0; - int range = 16; // default is 16m - - if (!params.empty()) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) - { - static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); - static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); - static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); - static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); - std::string emote; - - for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) - { - if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) - { - socialType = pointatSocialType; - } - else if (iter->find(paramsEmote1) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(7); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - else if (iter->find(paramsEmote2) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(6); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - else - { - range = ::atoi(Unicode::wideToNarrow(*iter).c_str()); - if ((range < 1) || (range > 256)) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Range must be 1-256."), Unicode::emptyString); - return; - } - } - } - } - } - - std::vector playersInRange; - ServerWorld::findPlayerCreaturesInRange(targetObj->getPosition_w(), static_cast(range), playersInRange); - if (playersInRange.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("No eligible players found within %dm.", range)), Unicode::emptyString); - } - else - { - std::vector validPlayers; - CreatureObject const * co; - for (std::vector::const_iterator iter = playersInRange.begin(); iter != playersInRange.end(); ++iter) - { - co = (*iter)->asCreatureObject(); - if (!co || !PlayerCreatureController::getPlayerObject(co)) - continue; - - // always include self, even if I am invisible - if (co->getNetworkId() == targetObj->getNetworkId()) - { - validPlayers.push_back(*iter); - continue; - } - - // don't include invisible players - if (co->isHidden() || !co->isVisible() || !co->getCoverVisibility()) - continue; - - validPlayers.push_back(*iter); - } - - if (validPlayers.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("No eligible players found within %dm.", range)), Unicode::emptyString); - } - else - { - int const random = ::rand() % validPlayers.size(); - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Player \"%s\" within %dm was randomly chosen.", Unicode::wideToNarrow(validPlayers[random]->getAssignedObjectName()).c_str(), range)), Unicode::emptyString); - - // do emote at the selected player, if requested - if (socialType > 0) - { - // if I'm the one selected, use the /pointat social to point at myself - // since other socials may not make sense when I am the target - doSocial(*targetObj, validPlayers[random]->getNetworkId(), ((validPlayers[random]->getNetworkId() == targetObj->getNetworkId()) ? pointatSocialType : socialType)); - } - } - } - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextAreaPickRandomPlayerCommandAllowed", (timeNow + 30))); -} - -// ---------------------------------------------------------------------- - -static void commandFuncRoomPickRandomPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) -{ - CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); - if (!targetObj) - return; - - PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); - if (!targetPlayerObj) - return; - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); - return; - } - - // prevent spamming of the command - Client const * const client = targetObj->getClient(); - if (!client) - return; - - int const timeNow = static_cast(::time(NULL)); - if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextRoomPickRandomPlayerCommandAllowed") && (targetObj->getObjVars().getType("timeNextRoomPickRandomPlayerCommandAllowed") == DynamicVariable::INT)) - { - int timeNextRoomPickRandomPlayerCommandAllowed = 0; - if (targetObj->getObjVars().getItem("timeNextRoomPickRandomPlayerCommandAllowed", timeNextRoomPickRandomPlayerCommandAllowed)) - { - if (timeNextRoomPickRandomPlayerCommandAllowed > timeNow) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextRoomPickRandomPlayerCommandAllowed - timeNow))), Unicode::emptyString); - return; - } - } - } - - // handle options - static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); - uint32 socialType = 0; - - if (!params.empty()) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) - { - static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); - static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); - static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); - static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); - std::string emote; - - for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) - { - if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) - { - socialType = pointatSocialType; - } - else if (iter->find(paramsEmote1) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(7); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - else if (iter->find(paramsEmote2) == 0) - { - emote = Unicode::wideToNarrow(*iter).substr(6); - socialType = SocialsManager::getSocialTypeByName(emote); - if (socialType == 0) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); - return; - } - } - } - } - } - - std::vector validPlayers; - Container const * const cellContainer = ContainerInterface::getContainer(*containingCell); - if (cellContainer) - { - Object const * object; - ServerObject const * serverObject; - CreatureObject const * creatureObject; - for (ContainerConstIterator iter = cellContainer->begin(); iter != cellContainer->end(); ++iter) - { - object = (*iter).getObject(); - if (!object) - continue; - - serverObject = object->asServerObject(); - if (!serverObject) - continue; - - creatureObject = serverObject->asCreatureObject(); - if (!creatureObject || !PlayerCreatureController::getPlayerObject(creatureObject)) - continue; - - // always include self, even if I am invisible - if (creatureObject->getNetworkId() == targetObj->getNetworkId()) - { - validPlayers.push_back(serverObject); - continue; - } - - // don't include invisible players - if (creatureObject->isHidden() || !creatureObject->isVisible() || !creatureObject->getCoverVisibility()) - continue; - - validPlayers.push_back(serverObject); - } - } - - if (validPlayers.empty()) - { - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No eligible players found in this room."), Unicode::emptyString); - } - else - { - int const random = ::rand() % validPlayers.size(); - Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Player \"%s\" was randomly chosen out of %d players in this room.", Unicode::wideToNarrow(validPlayers[random]->getAssignedObjectName()).c_str(), validPlayers.size())), Unicode::emptyString); - - // do emote at the selected player, if requested - if (socialType > 0) - { - // if I'm the one selected, use the /pointat social to point at myself - // since other socials may not make sense when I am the target - doSocial(*targetObj, validPlayers[random]->getNetworkId(), ((validPlayers[random]->getNetworkId() == targetObj->getNetworkId()) ? pointatSocialType : socialType)); - } - } - - // set cooldown - if (!client->isGod()) - IGNORE_RETURN(targetObj->setObjVarItem("timeNextRoomPickRandomPlayerCommandAllowed", (timeNow + 30))); -} - -// ====================================================================== - -void CommandCppFuncs::install() -{ - // console style commands - CommandTable::addCppFunction("console_all", commandFuncConsoleAll); - CommandTable::addCppFunction("console_combat", commandFuncConsoleCombat); - CommandTable::addCppFunction("console_craft", commandFuncConsoleCraft); - CommandTable::addCppFunction("console_database", commandFuncConsoleDatabase); - CommandTable::addCppFunction("console_manufacture", commandFuncConsoleManufacture); - CommandTable::addCppFunction("console_money", commandFuncConsoleMoney); - CommandTable::addCppFunction("console_npc", commandFuncConsoleNpc); - CommandTable::addCppFunction("console_object", commandFuncConsoleObject); - CommandTable::addCppFunction("console_objvar", commandFuncConsoleObjvar); - CommandTable::addCppFunction("console_resource", commandFuncConsoleResource); - CommandTable::addCppFunction("console_script", commandFuncConsoleScript); - CommandTable::addCppFunction("console_server", commandFuncConsoleServer); - CommandTable::addCppFunction("console_skill", commandFuncConsoleSkill); - - // communication commands - CommandTable::addCppFunction("social", commandFuncSocial); - CommandTable::addCppFunction("socialInternal", commandFuncSocialInternal); - CommandTable::addCppFunction("spatialChat", commandFuncSpatialChat); - CommandTable::addCppFunction("spatialChatInternal", commandFuncSpatialChatInternal); - CommandTable::addCppFunction("setMood", commandFuncSetMood); - CommandTable::addCppFunction("setMoodInternal", commandFuncSetMoodInternal); - CommandTable::addCppFunction("systemMessage", commandFuncSystemMessage); -// CommandTable::addCppFunction("combatSpam", commandFuncCombatSpam); - - // admin commands - CommandTable::addCppFunction("admin_setGodMode", commandFuncAdminSetGodMode); - CommandTable::addCppFunction("admin_kick", commandFuncAdminKick); - CommandTable::addCppFunction("admin_planetwarp", commandFuncAdminPlanetwarp); - CommandTable::addCppFunction("admin_teleport", commandFuncAdminTeleport); - CommandTable::addCppFunction("admin_teleportTo", commandFuncAdminTeleportTo); - CommandTable::addCppFunction("admin_listGuilds", commandFuncAdminListGuilds); - CommandTable::addCppFunction("editBank", commandFuncAdminEditBank); - CommandTable::addCppFunction("editStats", commandFuncAdminEditStats); - CommandTable::addCppFunction("editAppearance", commandFuncAdminEditAppearance); - CommandTable::addCppFunction("grantTitle", commandFuncAdminGrantTitle); - CommandTable::addCppFunction("credits", commandFuncAdminCredits); - CommandTable::addCppFunction("getStationName", commandFuncAdminGetStationName); - CommandTable::addCppFunction("emptyMailTarget", commandFuncEmptyMailTarget); - CommandTable::addCppFunction("setPlayerAppearance", commandFuncSetPlayerAppearance); - CommandTable::addCppFunction("revertPlayerAppearance", commandFuncRevertPlayerAppearance); - - // auction commands - CommandTable::addCppFunction("auction_create", commandFuncAuctionCreate); - CommandTable::addCppFunction("auction_create_immediate", commandFuncAuctionCreateImmediate); - CommandTable::addCppFunction("auction_bid", commandFuncAuctionBid); - CommandTable::addCppFunction("auction_cancel", commandFuncAuctionCancel); - CommandTable::addCppFunction("auction_accept", commandFuncAuctionAccept); - CommandTable::addCppFunction("auction_query", commandFuncAuctionQuery); - CommandTable::addCppFunction("auction_retrieve", commandFuncAuctionRetrieve); - - // cell/building permissions commands - CommandTable::addCppFunction("addBannedPlayer", commandFuncAddBannedPlayer); - CommandTable::addCppFunction("removeBannedPlayer", commandFuncRemoveBannedPlayer); - CommandTable::addCppFunction("addAllowedPlayer", commandFuncAddAllowedPlayer); - CommandTable::addCppFunction("removeAllowedPlayer", commandFuncRemoveAllowedPlayer); - CommandTable::addCppFunction("setPublicState", commandFuncSetPublicState); - CommandTable::addCppFunction("setOwner", commandFuncSetOwner); - - CommandTable::addCppFunction("setPosture", commandSetPosture); - CommandTable::addCppFunction("duel", commandFuncDuel); - CommandTable::addCppFunction("endDuel", commandFuncEndDuel); - - // ui - CommandTable::addCppFunction("setWaypointActiveStatus", commandFuncSetWaypointActiveStatus); - CommandTable::addCppFunction("setWaypointName", commandFuncSetWaypointName); - - // harvester - CommandTable::addCppFunction("harvesterActivate", commandFuncHarvesterActivate); - CommandTable::addCppFunction("harvesterDeactivate", commandFuncHarvesterDeactivate); - CommandTable::addCppFunction("harvesterHarvest", commandFuncHarvesterHarvest); - CommandTable::addCppFunction("harvesterSelectResource", commandFuncHarvesterSelectResource); - CommandTable::addCppFunction("harvesterDiscardHopper", commandFuncHarvesterDiscardHopper); - CommandTable::addCppFunction("harvesterMakeCrate", commandFuncHarvesterMakeCrate); - CommandTable::addCppFunction("harvesterGetResourceData", commandFuncHarvesterGetResourceData); - - // syncronized ui - CommandTable::addCppFunction("synchronizedUiListen" , commandFuncSynchronizedUiListen); - CommandTable::addCppFunction("synchronizedUiStopListening", commandFuncSynchronizedUiStopListening); - - // resource - CommandTable::addCppFunction("resourceSetName", commandFuncResourceSetName); - - // resource container - CommandTable::addCppFunction("resourceContainerTransfer", commandFuncResourceContainerTransfer); - CommandTable::addCppFunction("resourceContainerSplit", commandFuncResourceContainerSplit); - - // survey - CommandTable::addCppFunction("makeSurvey", commandFuncMakeSurvey); - CommandTable::addCppFunction("requestSurvey", commandFuncRequestSurvey); - CommandTable::addCppFunction("requestCoreSample", commandFuncRequestCoreSample); - - CommandTable::addCppFunction("transferItemWeapon", commandFuncTransferWeapon); - CommandTable::addCppFunction("transferItemArmor", commandFuncTransferArmor); - CommandTable::addCppFunction("transferItemMisc", commandFuncTransferMisc); - CommandTable::addCppFunction("openContainer", commandFuncOpenContainer); - CommandTable::addCppFunction("closeContainer", commandFuncCloseContainer); - CommandTable::addCppFunction("openLotteryContainer", commandFuncOpenLotteryContainer); - CommandTable::addCppFunction("closeLotteryContainer", commandFuncCloseLotteryContainer); - CommandTable::addCppFunction("giveItem", commandFuncGiveItem); - - // grouping - CommandTable::addCppFunction("groupInvite", commandFuncGroupInvite); - CommandTable::addCppFunction("groupUninvite", commandFuncGroupUninvite); - CommandTable::addCppFunction("groupJoin", commandFuncGroupJoin); - CommandTable::addCppFunction("groupDecline", commandFuncGroupDecline); - CommandTable::addCppFunction("groupDisband", commandFuncGroupDisband); - CommandTable::addCppFunction("kickFromShip", commandFuncKickFromShip); - CommandTable::addCppFunction("groupChat", commandFuncGroupChat); - CommandTable::addCppFunction("groupMakeLeader", commandFuncGroupMakeLeader); - CommandTable::addCppFunction("groupMakeMasterLooter", commandFuncGroupMakeMasterLooter); - CommandTable::addCppFunction("createGroupPickup", commandFuncCreateGroupPickup); - CommandTable::addCppFunction("useGroupPickup", commandFuncUseGroupPickup); - CommandTable::addCppFunction("groupTextChatRoomRejoin", commandFuncGroupTextChatRoomRejoin); - CommandTable::addCppFunction("groupPickRandomGroupMember", commandFuncGroupPickRandomGroupMember); - - // guilds - CommandTable::addCppFunction("guildChat", commandFuncGuildChat); - CommandTable::addCppFunction("guildTextChatRoomRejoin", commandFuncGuildTextChatRoomRejoin); - CommandTable::addCppFunction("guildPickRandomGuildMember", commandFuncGuildPickRandomGuildMember); - - // city - CommandTable::addCppFunction("cityChat", commandFuncCityChat); - CommandTable::addCppFunction("cityTextChatRoomRejoin", commandFuncCityTextChatRoomRejoin); - CommandTable::addCppFunction("cityPickRandomCitizen", commandFuncCityPickRandomCitizen); - - //chat - CommandTable::addCppFunction("auctionChat", commandFuncAuctionChat); - CommandTable::addCppFunction("planetChat", commandFuncPlanetChat); - - // crafting - CommandTable::addCppFunction("requestResourceWeights", commandFuncRequestResourceWeights); - CommandTable::addCppFunction("requestResourceWeightsBatch", commandFuncRequestResourceWeightsBatch); - CommandTable::addCppFunction("requestDraftSlots", commandFuncRequestDraftSlots); - CommandTable::addCppFunction("requestDraftSlotsBatch", commandFuncRequestDraftSlotsBatch); - CommandTable::addCppFunction("requestManfSchematicSlots", commandFuncRequestManfSchematicSlots); - CommandTable::addCppFunction("requestCraftingSession", commandFuncRequestCraftingSession); - CommandTable::addCppFunction("requestCraftingSessionFail",commandFuncRequestCraftingSessionFail); - CommandTable::addCppFunction("selectDraftSchematic", commandFuncSelectDraftSchematic); - CommandTable::addCppFunction("nextCraftingStage", commandFuncNextCraftingStage); - CommandTable::addCppFunction("createPrototype", commandFuncCreatePrototype); - CommandTable::addCppFunction("createManfSchematic", commandFuncCreateManfSchematic); - CommandTable::addCppFunction("cancelCraftingSession", commandFuncCancelCraftingSession); - CommandTable::addCppFunction("stopCraftingSession", commandFuncStopCraftingSession); - CommandTable::addCppFunction("restartCraftingSession", commandFuncRestartCraftingSession); - CommandTable::addCppFunction("extractObject", commandFuncExtractObject); - CommandTable::addCppFunction("repair", commandFuncRepair); - CommandTable::addCppFunction("factoryCrateSplit", commandFuncFactoryCrateSplit); - - // misc - CommandTable::addCppFunction("showDanceVisuals", commandFuncShowDanceVisuals); - CommandTable::addCppFunction("showMusicianVisuals", commandFuncShowMusicianVisuals); - CommandTable::addCppFunction("placeStructure", commandFuncPlaceStructure); - CommandTable::addCppFunction("getAttributes", commandFuncGetAttributes); - CommandTable::addCppFunction("getAttributesBatch", commandFuncGetAttributesBatch); - CommandTable::addCppFunction("sitServer", commandFuncSitServer); - CommandTable::addCppFunction("jumpServer", commandFuncJumpServer); - CommandTable::addCppFunction("purchaseTicket", commandFuncPurchaseTicket); - CommandTable::addCppFunction("addFriend", commandFuncAddFriend); - CommandTable::addCppFunction("removeFriend", commandFuncRemoveFriend); - CommandTable::addCppFunction("getFriendList", commandFuncGetFriendList); - CommandTable::addCppFunction("addIgnore", commandFuncAddIgnore); - CommandTable::addCppFunction("removeIgnore", commandFuncRemoveIgnore); - CommandTable::addCppFunction("getIgnoreList", commandFuncGetIgnoreList); - CommandTable::addCppFunction("requestBiography", commandFuncRequestBiography); - CommandTable::addCppFunction("setBiography", commandFuncSetBiography); - CommandTable::addCppFunction("requestWaypointAtPosition", commandFuncRequestWaypointAtPosition); - CommandTable::addCppFunction("serverDestroyObject", commandFuncServerDestroyObject); - CommandTable::addCppFunction("setSpokenLanguage", commandFuncSetSpokenLanguage); - CommandTable::addCppFunction("applyPowerup", commandFuncApplyPowerup); - CommandTable::addCppFunction("report", commandFuncReport); - CommandTable::addCppFunction("resetCooldowns", commandFuncResetCooldowns); - CommandTable::addCppFunction("spewCommandQueue", commandFuncSpewCommandQueue); - CommandTable::addCppFunction("locateStructure", commandFuncLocateStructure); - CommandTable::addCppFunction("locateVendor", commandFuncLocateVendor); - CommandTable::addCppFunction("showCtsHistory", commandFuncShowCtsHistory); - CommandTable::addCppFunction("pickupAllRoomItemsIntoInventory", commandFuncPickupAllRoomItemsIntoInventory); - CommandTable::addCppFunction("dropAllInventoryItemsIntoRoom", commandFuncDropAllInventoryItemsIntoRoom); - CommandTable::addCppFunction("saveDecorationLayout", commandFuncSaveDecorationLayout); - CommandTable::addCppFunction("restoreDecorationLayout", commandFuncRestoreDecorationLayout); - CommandTable::addCppFunction("areaPickRandomPlayer", commandFuncAreaPickRandomPlayer); - CommandTable::addCppFunction("roomPickRandomPlayer", commandFuncRoomPickRandomPlayer); - - // match making - CommandTable::addCppFunction("setMatchMakingPersonalId", commandFuncSetMatchMakingPersonalId); - CommandTable::addCppFunction("setMatchMakingCharacterId", commandFuncSetMatchMakingCharacterId); - CommandTable::addCppFunction("requestCharacterMatch", commandFuncRequestCharacterMatch); - CommandTable::addCppFunction("toggleSearchableByCtsSourceGalaxy", commandFuncToggleSearchableByCtsSourceGalaxy); - CommandTable::addCppFunction("toggleDisplayLocationInSearchResults", commandFuncToggleDisplayLocationInSearchResults); - CommandTable::addCppFunction("toggleAnonymous", commandFuncToggleAnonymous); - CommandTable::addCppFunction("toggleHelper", commandFuncToggleHelper); - CommandTable::addCppFunction("toggleRolePlay", commandFuncToggleRolePlay); - CommandTable::addCppFunction("toggleLookingForGroup", commandFuncToggleLookingForGroup); - CommandTable::addCppFunction("toggleAwayFromKeyBoard", commandFuncToggleAwayFromKeyBoard); - CommandTable::addCppFunction("toggleDisplayingFactionRank", commandFuncToggleDisplayingFactionRank); - CommandTable::addCppFunction("toggleOutOfCharacter", commandFuncToggleOutOfCharacter); - CommandTable::addCppFunction("toggleLookingForWork", commandFuncToggleLookingForWork); - - //skill - CommandTable::addCppFunction("revokeSkill", commandFuncRevokeSkill); - CommandTable::addCppFunction("setCurrentSkillTitle", commandFuncSetCurrentSkillTitle); - - //misc ui - CommandTable::addCppFunction("permissionListModify", commandFuncPermissionListModify); - CommandTable::addCppFunction("requestCharacterSheetInfo", commandFuncRequestCharacterSheetInfo); - CommandTable::addCppFunction("removeBuff", commandFuncRemoveBuff); - - // npc conversation - CommandTable::addCppFunction("npcConversationStart", commandFuncNpcConversationStart); - CommandTable::addCppFunction("npcConversationStop", commandFuncNpcConversationStop); - CommandTable::addCppFunction("npcConversationSelect", commandFuncNpcConversationSelect); - CommandTable::addCppFunction("handleUnstick", commandFuncUnstick); - CommandTable::addCppFunction("getAccountInfo", commandFuncGetAccountInfo); - CommandTable::addCppFunction("lag", commandFuncLag); - - //knowledgebase (i.e. holocron) - CommandTable::addCppFunction("executeKnowledgeBaseMessage", commandExecuteKnowledgeBaseMessage); - CommandTable::addCppFunction("reconnectToTransferServer", commandFuncReconnectToTransferServer); - CommandTable::addCppFunction("findFriend", commandFuncFindFriend); - - // godclient-specific functions - CommandTable::addCppFunction(FormManager::getFormCommandName(), commandFuncFormCommand); - - // space - CommandTable::addCppFunction("installShipComponent", commandFuncInstallShipComponents); - CommandTable::addCppFunction("uninstallShipComponent", commandFuncUninstallShipComponents); - CommandTable::addCppFunction("insertItemIntoShipComponentSlot", commandFuncInsertItemIntoShipComponentSlot); - CommandTable::addCppFunction("associateDroidControlDeviceWithShip", commandFuncAssociateDroidControlDeviceWithShip); - CommandTable::addCppFunction("unassociateDroidControlDeviceWithShip", commandFuncAssociateDroidControlDeviceWithShip); - - CommandTable::addCppFunction("serverAsteroidDataListen" , commandFuncServerAsteroidDataListen); - CommandTable::addCppFunction("serverAsteroidDataStopListening", commandFuncServerAsteroidDataStopListening); - - CommandTable::addCppFunction("boosterOn", commandFuncBoosterOn); - CommandTable::addCppFunction("boosterOff", commandFuncBoosterOff); - - CommandTable::addCppFunction("setFormation", commandFuncSetFormation); - CommandTable::addCppFunction("setFormationSlot", commandFuncSetFormationSlot); - CommandTable::addCppFunction("undock", commandFuncUnDock); - CommandTable::addCppFunction("launchIntoSpace", commandFuncLaunchIntoSpace); - CommandTable::addCppFunction("acceptQuest", commandFuncAcceptQuest); - CommandTable::addCppFunction("completeQuest", commandFuncReceiveReward); - CommandTable::addCppFunction("abandonQuest", commandFuncAbandonQuest); - - // exchange - CommandTable::addCppFunction("exchangeListCredits", commandFuncExchangeListCredits); - - // squelch - CommandTable::addCppFunction("squelch", commandFuncSquelch); - CommandTable::addCppFunction("unsquelch", commandFuncUnsquelch); - - // warden - CommandTable::addCppFunction("grantWarden", commandFuncGrantWarden); - CommandTable::addCppFunction("revokeWarden", commandFuncRevokeWarden); - CommandTable::addCppFunction("spammer", commandFuncSpammer); - CommandTable::addCppFunction("unspammer", commandFuncUnspammer); - CommandTable::addCppFunction("deputizeWarden", commandFuncDeputizeWarden); - CommandTable::addCppFunction("undeputizeWarden", commandFuncUndeputizeWarden); - - // unlocked slot management commands - CommandTable::addCppFunction("occupyUnlockedSlot", commandFuncOccupyUnlockedSlot); - CommandTable::addCppFunction("vacateUnlockedSlot", commandFuncVacateUnlockedSlot); - CommandTable::addCppFunction("swapUnlockedSlot", commandFuncSwapUnlockedSlot); -} - -// ---------------------------------------------------------------------- - -void CommandCppFuncs::remove() -{ -} - -// ====================================================================== +// ====================================================================== +// +// CommandCppFuncs.cpp +// Copyright 2002-2004, Sony Online Entertainment, Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/CommandCppFuncs.h" + +#include "UnicodeUtils.h" +#include "serverGame/BiographyManager.h" +#include "serverGame/BuildingObject.h" +#include "serverGame/BuffManager.h" +#include "serverGame/CellObject.h" +#include "serverGame/CharacterMatchManager.h" +#include "serverGame/Chat.h" +#include "serverGame/CitizenInfo.h" +#include "serverGame/CityInfo.h" +#include "serverGame/CityInterface.h" +#include "serverGame/Client.h" +#include "serverGame/CommandStringId.h" +#include "serverGame/CommandQueue.h" +#include "serverGame/CommoditiesMarket.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ConsoleManager.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureController.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/DraftSchematicObject.h" +#include "serverGame/FactoryObject.h" +#include "serverGame/FormManagerServer.h" +#include "serverGame/GameServer.h" +#include "serverGame/GroupObject.h" +#include "serverGame/GroupStringId.h" +#include "serverGame/GuildInterface.h" +#include "serverGame/GuildMemberInfo.h" +#include "serverGame/HarvesterInstallationObject.h" +#include "serverGame/ServerImageDesignerManager.h" +#include "serverGame/ManufactureSchematicObject.h" +#include "serverGame/MessageToQueue.h" +#include "serverGame/NameManager.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/ProsePackageManagerServer.h" +#include "serverGame/ReportManager.h" +#include "serverGame/ResourceContainerObject.h" +#include "serverGame/ResourceTypeObject.h" +#include "serverGame/ServerAsteroidManager.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/ShipController.h" +#include "serverGame/ShipObject.h" +#include "serverGame/TaskGetAttributes.h" +#include "serverGame/VeteranRewardManager.h" +#include "serverNetworkMessages/DownloadCharacterMessage.h" +#include "serverNetworkMessages/ExchangeListCreditsMessage.h" +#include "serverNetworkMessages/GameConnectionServerMessages.h" +#include "serverNetworkMessages/GroupMemberParam.h" +#include "serverNetworkMessages/UploadCharacterMessage.h" +#include "serverNetworkMessages/TeleportToMessage.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptDictionary.h" +#include "serverScript/ScriptFunctionTable.h" +#include "serverScript/ScriptParameters.h" +#include "sharedCollision/CollisionProperty.h" +#include "sharedCollision/CollisionWorld.h" +#include "sharedCollision/Footprint.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/DynamicVariableLocationData.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedFoundation/NetworkId.h" +#include "sharedGame/CitizenRankDataTable.h" +#include "sharedGame/Command.h" +#include "sharedGame/CommandTable.h" +#include "sharedGame/CustomizationManager.h" +#include "sharedGame/GroupPickupPoint.h" +#include "sharedGame/GuildRankDataTable.h" +#include "sharedGame/PlayerFormationManager.h" +#include "sharedGame/GameLanguageManager.h" +#include "sharedGame/GameObjectTypes.h" +#include "sharedGame/TravelPoint.h" +#include "sharedUtility/Location.h" +#include "sharedGame/MatchMakingCharacterPreferenceId.h" +#include "sharedGame/MatchMakingCharacterProfileId.h" +#include "sharedGame/MatchMakingId.h" +#include "sharedGame/MoodManager.h" +#include "sharedGame/OutOfBandPackager.h" +#include "sharedGame/PlatformFeatureBits.h" +#include "sharedGame/ProsePackage.h" +#include "sharedGame/Quest.h" +#include "sharedGame/QuestManager.h" +#include "sharedGame/SharedStringIds.h" +#include "sharedGame/ShipChassisSlotType.h" +#include "sharedGame/SocialsManager.h" +#include "sharedGame/SpatialChatManager.h" +#include "sharedGame/TextIterator.h" +#include "sharedGame/Waypoint.h" +#include "sharedLog/Log.h" +#include "sharedMath/MultiShape.h" +#include "sharedNetworkMessages/CharacterSheetResponseMessage.h" +#include "sharedNetworkMessages/ChatAvatarId.h" +#include "sharedNetworkMessages/ChatRequestLog.h" +#include "sharedNetworkMessages/ClientEffectMessages.h" +#include "sharedNetworkMessages/ConsoleChannelMessages.h" +#include "sharedNetworkMessages/EditAppearanceMessage.h" +#include "sharedNetworkMessages/EditStatsMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/MessageQueueCombatSpam.h" +#include "sharedNetworkMessages/MessageQueueDraftSlotsQueryResponse.h" +#include "sharedNetworkMessages/MessageQueueGenericIntResponse.h" +#include "sharedNetworkMessages/MessageQueueGenericResponse.h" +#include "sharedNetworkMessages/MessageQueueGenericValueType.h" +#include "sharedNetworkMessages/MessageQueueNetworkId.h" +#include "sharedNetworkMessages/MessageQueuePosture.h" +#include "sharedNetworkMessages/MessageQueueSitOnObject.h" +#include "sharedNetworkMessages/MessageQueueSpatialChat.h" +#include "sharedObject/CachedNetworkId.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/CustomizationData.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/PaletteColorCustomizationVariable.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedObject/SlottedContainmentProperty.h" +#include "sharedObject/VolumeContainer.h" +#include "sharedSkillSystem/SkillManager.h" +#include "sharedSkillSystem/SkillObject.h" +#include "sharedTerrain/TerrainObject.h" + +#include + +namespace CommandCppFuncsNamespace +{ + const std::string BEAST_SCRIPT = "ai.beast"; + + void internalSetBoosterOnOff(NetworkId const & actor, bool onOff) + { + ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); + CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; + + if (actorCreature == NULL) + return; + + ShipObject * const shipObject = actorCreature->getPilotedShip(); + if (shipObject == NULL) + return; + + if (!shipObject->isSlotInstalled(ShipChassisSlotType::SCST_booster)) + { + Chat::sendSystemMessage(*actorCreature, SharedStringIds::no_booster, Unicode::emptyString); + return; + } + + if (!shipObject->isComponentFunctional(ShipChassisSlotType::SCST_booster)) + { + Chat::sendSystemMessage(*actorCreature, SharedStringIds::booster_disabled, Unicode::emptyString); + return; + } + + if (onOff && shipObject->getBoosterEnergyCurrent() < shipObject->getBoosterEnergyRechargeRate()) + { + Chat::sendSystemMessage(*actorCreature, SharedStringIds::booster_low_energy, Unicode::emptyString); + return; + } + + if (onOff && !shipObject->isBoosterReady()) + { + Chat::sendSystemMessage(*actorCreature, SharedStringIds::booster_not_ready, Unicode::emptyString); + return; + } + + shipObject->setComponentActive(ShipChassisSlotType::SCST_booster, onOff); + shipObject->restartBoosterTimer(); + } + + ServerObject const *getFirstParentInWorldOrPlayer(ServerObject const *o) + { + while (o && !o->isInWorld() && !o->isPlayerControlled()) + o = safe_cast(ContainerInterface::getContainedByObject(*o)); + return o; + } + + ServerObject const *getFirstCreatureContainer(ServerObject const *o) + { + while (o && !o->isInWorld() && !o->asCreatureObject()) + o = safe_cast(ContainerInterface::getContainedByObject(*o)); + return o; + } + + + ShipObject *getAttachedShip(CreatureObject *creature) + { + // The "attached" ship is the ship which must move along with the creature. + // This means if the creature is piloting, the ship is is piloting, + // or the containing ship if the creature is the ship's owner. + ShipObject * const ship = ShipObject::getContainingShipObject(creature); + if ( ship + && ( ship->getOwnerId() == creature->getNetworkId() + || creature->getPilotedShip() == ship)) + return ship; + return 0; + } + + CreatureObject * findAndResolveCreatureByNetworkId(NetworkId const & targetId) + { + CreatureObject * targetCreatureObject = NULL; + + { + // find the target. the target could be either a creature or ship + ServerObject * const serverObject = ServerWorld::findObjectByNetworkId(targetId); + targetCreatureObject = (serverObject != NULL) ? serverObject->asCreatureObject() : NULL; + + if (targetCreatureObject == NULL) + { + ShipObject * const shipObject = (serverObject != NULL) ? serverObject->asShipObject() : NULL; + + if (shipObject != NULL) + { + targetCreatureObject = shipObject->getPilot(); + + if (targetCreatureObject == NULL) + { + // this means that it is a POB ship that doesn't have a pilot + // in this case we find the owner + std::vector passengers; + shipObject->findAllPassengers(passengers, true); + + std::vector::const_iterator ii = passengers.begin(); + std::vector::const_iterator iiEnd = passengers.end(); + + for (; ii != iiEnd && targetCreatureObject == NULL; ++ii) + { + if ((*ii)->getNetworkId() == shipObject->getOwnerId()) + { + targetCreatureObject = *ii; + break; + } + } + } + } + } + } + return targetCreatureObject; + } + + ShipObject const *getFirstPackedShipForCreature(CreatureObject const &creature) + { + ServerObject const * const datapad = creature.getDatapad(); + if (datapad) + { + Container const * const container = ContainerInterface::getContainer(*datapad); + if (container) + { + for (ContainerConstIterator i = container->begin(); i != container->end(); ++i) + { + ServerObject const * const content = safe_cast((*i).getObject()); + if ( content + && content->getGameObjectType() == SharedObjectTemplate::GOT_data_ship_control_device + && !content->isBeingDestroyed()) + { + Container const * const scdContainer = ContainerInterface::getContainer(*content); + if (scdContainer) + { + for (ContainerConstIterator j = scdContainer->begin(); j != scdContainer->end(); ++j) + { + ServerObject const * const scdContent = safe_cast((*j).getObject()); + if (scdContent && !scdContent->isBeingDestroyed() && scdContent->asShipObject()) + return scdContent->asShipObject(); + } + } + } + } + } + } + return 0; + } + + // Move a list of items back into their slots. We assume the items were just in their slots and can be moved back with no problems. + void reequipItems(ServerObject & destination, const std::vector > & oldItems) + { + Container::ContainerErrorCode errorCode = Container::CEC_Success; + for (std::vector >::const_iterator i = oldItems.begin(); i != oldItems.end(); ++i) + { + IGNORE_RETURN(ContainerInterface::transferItemToSlottedContainer(destination, *((*i).first), (*i).second, NULL, errorCode)); + } + } + + void doSocial(ServerObject & actor, NetworkId const & targetId, uint32 socialType) + { + if (actor.getClient()) + { + ServerObject const * const target = ServerWorld::findObjectByNetworkId(targetId); + if (target && ObserveTracker::isObserving(*(actor.getClient()), *target)) + { + actor.performSocial(targetId, socialType, true, true); + } + } + } + + namespace GroupHelpers + { + bool creatureIsContainedInPOBShip(CreatureObject const * creatureObject); + void removeFromGroupAndCreatePOBGroup(GroupObject * groupToRemoveFrom, + GroupMemberParam const & leader, + GroupObject::GroupMemberParamVector & membersInsidePOB); + // The owner of the POB ship is not included in the inside POB member lists + void separateGroupBasedOffofPOBShip(GroupObject * groupObj, + NetworkId const & ownerOfThePOBShipId, + NetworkId const & POBShipId, + GroupObject::GroupMemberParamVector & membersInsidePOB, + GroupObject::GroupMemberParamVector & membersOutsidePOB); + + TravelPoint const * getNearestTravelPoint(std::string const & planetName, Vector const & location, std::vector const & cityBanList, uint32 faction, bool starPortAndShuttleportOnly); + } + + void triggerSpaceEjectPlayerFromShip(CreatureObject * creatureObject); + + int const cs_spaceSpeechMultiple = 10; +} + +// ====================================================================== + +bool CommandCppFuncsNamespace::GroupHelpers::creatureIsContainedInPOBShip(CreatureObject const * const creatureObject) +{ + NOT_NULL(creatureObject); + + ShipObject const * const shipObject = ShipObject::getContainingShipObject(creatureObject); + return shipObject && shipObject->getPortalProperty(); +} + +// ---------------------------------------------------------------------- + +void CommandCppFuncsNamespace::GroupHelpers::removeFromGroupAndCreatePOBGroup(GroupObject * const groupToRemoveFrom, + GroupMemberParam const & leader, + GroupObject::GroupMemberParamVector & membersInsidePOB) +{ + if (groupToRemoveFrom != 0) + { + GroupObject::GroupMemberParamVector::const_iterator ii = membersInsidePOB.begin(); + GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersInsidePOB.end(); + + for (; ii != iiEnd; ++ii) + { + NetworkId const & memberId = (*ii).m_memberId; + groupToRemoveFrom->removeGroupMember(memberId); + + CreatureObject * const memberCreatureObject = dynamic_cast(ServerWorld::findObjectByNetworkId(memberId)); + if (memberCreatureObject != 0) + { + if (memberCreatureObject->getGroup() == groupToRemoveFrom) + memberCreatureObject->getGroup()->onGroupMemberRemoved(memberCreatureObject->getNetworkId(), false); + } + } + } + + if (!membersInsidePOB.empty()) + { + ServerUniverse::getInstance().createGroup(leader, membersInsidePOB); + } +} + +// ---------------------------------------------------------------------- + +// The owner of the POB ship is not included in the inside POB member lists +void CommandCppFuncsNamespace::GroupHelpers::separateGroupBasedOffofPOBShip(GroupObject * const groupObj, + NetworkId const & ownerOfThePOBShipId, + NetworkId const & POBShipId, + GroupObject::GroupMemberParamVector & membersInsidePOB, + GroupObject::GroupMemberParamVector & membersOutsidePOB) +{ + NOT_NULL(groupObj); + + GroupObject::GroupMemberVector const & groupMembers = groupObj->getGroupMembers(); + GroupObject::GroupMemberVector::const_iterator ii = groupMembers.begin(); + GroupObject::GroupMemberVector::const_iterator iiEnd = groupMembers.end(); + + for (; ii != iiEnd; ++ii) + { + NetworkId const & memberId = ii->first; + NetworkId const & POBShipMemberIsContainedInId = groupObj->getPOBShipMemberIsContainedIn(memberId); + GroupMemberParam const & groupMemberParam = groupObj->createGroupMemberParamForMember(memberId); + + if (POBShipMemberIsContainedInId == POBShipId) + { + // this member is contained in the same POB + if (memberId != ownerOfThePOBShipId) + { + // and is not the owner of the POB + membersInsidePOB.push_back(groupMemberParam); + } + } + else + { + membersOutsidePOB.push_back(groupMemberParam); + } + } +} + +// ---------------------------------------------------------------------- + +void CommandCppFuncsNamespace::triggerSpaceEjectPlayerFromShip(CreatureObject * const creatureObject) +{ + if (creatureObject == 0) + { + WARNING(true, ("CommandCppFuncsNamespace::triggerSpaceEjectPlayerFromShip: NULL CreatureObject.")); + return; + } + + GameScriptObject * gameScriptObject = creatureObject->getScriptObject(); + + if(gameScriptObject != 0) + { + ScriptParams scriptParams; + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SPACE_EJECT_PLAYER_FROM_SHIP, scriptParams)); + } + else + { + WARNING(true, ("CommandCppFuncsNamespace::triggerSpaceEjectPlayerFromShip: NULL ScriptObject.")); + } +} + +// ---------------------------------------------------------------------- + +TravelPoint const * CommandCppFuncsNamespace::GroupHelpers::getNearestTravelPoint(std::string const & planetName, Vector const & location, std::vector const & cityBanList, uint32 faction, bool starPortAndShuttleportOnly) +{ + TravelPoint const * nearestTravelPoint = NULL; + PlanetObject const * const planetObject = ServerUniverse::getInstance().getPlanetByName(planetName); + if (planetObject) + { + int const numberOfTravelPoints = planetObject->getNumberOfTravelPoints(); + for (int i = 0; i < numberOfTravelPoints; ++i) + { + TravelPoint const * tp = planetObject->getTravelPoint(i); + if (!tp) + continue; + + if (starPortAndShuttleportOnly && ((tp->getType() & TravelPoint::TPT_PC_CampShuttleBeacon) || (tp->getType() & TravelPoint::TPT_NPC_StaticBaseBeacon))) + continue; + + // need to check factional alignment in order to use the gcw static base travel point + std::string const & tpName = tp->getName(); + if (tpName.find("gcwstaticbase") != std::string::npos) + { + if ((tpName.find("rebel") != std::string::npos) && !PvpData::isRebelFactionId(faction)) + continue; + else if ((tpName.find("imperial") != std::string::npos) && !PvpData::isImperialFactionId(faction)) + continue; + } + + // if the travel point is inside a player city, make sure player is not banned in that city + if (!cityBanList.empty()) + { + int const cityAtTp = CityInterface::getCityAtLocation(planetName, static_cast(tp->getPosition_w().x), static_cast(tp->getPosition_w().z), 0); + if ((cityAtTp > 0) && (std::find(cityBanList.begin(), cityBanList.end(), cityAtTp) != cityBanList.end())) + continue; + } + + if (!nearestTravelPoint || (location.magnitudeBetweenSquared(tp->getPosition_w()) < location.magnitudeBetweenSquared(nearestTravelPoint->getPosition_w()))) + nearestTravelPoint = tp; + } + } + + return nearestTravelPoint; +} + +// ====================================================================== + +using namespace CommandCppFuncsNamespace; + +// ====================================================================== + +static const std::string OBJVAR_PLAYERS_CAN_ACCESS_CONTAINER("players_can_access_container"); + +// ====================================================================== + +static void sendProseMessage(const CreatureObject &actor, const ServerObject * const target, StringId const &stringId) +{ + Chat::sendSystemMessageSimple (actor, stringId, target); +} + +// ====================================================================== + +static Client *getClientFromCharacterId(NetworkId const &charId) +{ + ServerObject *obj = safe_cast(NetworkIdManager::getObjectById(charId)); + if (obj) + return obj->getClient(); + return 0; +} + +// ---------------------------------------------------------------------- + +static std::string nextStringParm(Unicode::String const &str, size_t &curpos) +{ + size_t endpos = 0; + Unicode::String token; + if (!Unicode::getFirstToken(str, curpos, endpos, token)) + return std::string (); + curpos = endpos; + return Unicode::wideToNarrow(token); +} + +// ---------------------------------------------------------------------- + +static int nextIntParm(Unicode::String const &str, size_t &curpos) +{ + std::string strParm = nextStringParm(str, curpos); + if (strParm.empty()) + return -1; + return atoi(strParm.c_str()); +} + +// ---------------------------------------------------------------------- + +static NetworkId nextOidParm(Unicode::String const &str, size_t &curpos) +{ + std::string const &s = nextStringParm(str, curpos); + if (!s.empty()) + { + if ((!isdigit(s.c_str()[0])) && ((s.c_str()[0]) != '-')) + return NameManager::getInstance().getPlayerId(NameManager::normalizeName(s)); + return NetworkId(s); + } + return NetworkId::cms_invalid; +} + +// ---------------------------------------------------------------------- + +static float nextFloatParm(Unicode::String const &str, size_t &curpos) +{ + return static_cast(strtod(nextStringParm(str, curpos).c_str(), NULL)); +} + + +// ---------------------------------------------------------------------- + +static bool nextBoolParm(Unicode::String const &str, size_t &curpos) +{ + return (nextIntParm(str, curpos) != 0); +} + +// ---------------------------------------------------------------------- + +static Vector nextVectorParm(Unicode::String const &str, size_t &curpos) +{ + float x=nextFloatParm(str,curpos); + float y=nextFloatParm(str,curpos); + float z=nextFloatParm(str,curpos); + + return Vector(x,y,z); +} + +// ====================================================================== + +static void commandFuncConsoleAll(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + if (actor != NetworkId::cms_invalid) + { + ServerObject *obj = safe_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + Client *client = obj->getClient(); + if (client && client->isGod()) + { + LOG("CustomerService",("Avatar:%s executing command: %s", PlayerObject::getAccountDescription(client->getCharacterObjectId()).c_str(), Unicode::wideToNarrow(params).c_str())); + ConsoleMgr::processString(Unicode::wideToNarrow(params), client, 0); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleCategory(NetworkId const &actor, + std::string const &category, Unicode::String const ¶ms) +{ + if (actor != NetworkId::cms_invalid) + { + ServerObject *obj = safe_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + Client *client = obj->getClient(); + if (client) + { + ConsoleMgr::processString(category + " " + Unicode::wideToNarrow(params), client, 0); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleCombat(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "combat", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleCraft(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "craft", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleDatabase(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "database", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleManufacture(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "manufacture", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleMoney(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "money", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleNpc(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "npc", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleObject(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "object", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleObjvar(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "objvar", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleResource(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "resource", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleScript(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "script", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleServer(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "server", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncConsoleSkill(Command const &command, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + UNREF(target); + commandFuncConsoleCategory(actor, "skill", params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminSetGodMode(Command const &, NetworkId const &actor, + NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + bool enable = nextBoolParm(params, pos); + + Client *client = getClientFromCharacterId(actor); + if (client) + IGNORE_RETURN(client->setGodMode(enable)); +} + +// ---------------------------------------------------------------------- + +static void commandFuncResetCooldowns(Command const &, NetworkId const &actor, + NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (actorObj) + { + actorObj->getCommandQueue()->resetCooldowns(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSpewCommandQueue(Command const &, NetworkId const &actor, + NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (actorObj) + { + actorObj->getCommandQueue()->spew(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminKick(Command const &, NetworkId const &actor, + NetworkId const &target, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (actorObj) + { + NetworkId who(target); + if (who == NetworkId::cms_invalid) + { + size_t curpos = 0; + who = nextOidParm(params, curpos); + if (who == NetworkId::cms_invalid) + return; + } + + ShipObject * const shipObject = dynamic_cast(NetworkIdManager::getObjectById(who)); + if (shipObject) + { + // If the target is a ship, kick all the people in the ship + std::vector passengers; + shipObject->findAllPassengers(passengers, true); + for (std::vector::const_iterator i=passengers.begin(); i!=passengers.end(); ++i) + { + KickPlayer const kickMessage((*i)->getNetworkId(), "Admin Kick"); + GameServer::getInstance().sendToConnectionServers(kickMessage); + } + } + else + { + KickPlayer const kickMessage(who, "Admin Kick"); + GameServer::getInstance().sendToConnectionServers(kickMessage); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncLocateStructure(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); + if (!playerObj) + return; + + Client * const clientObj = actorObj->getClient(); + if (!clientObj) + return; + + bool const isGod = clientObj->isGod(); + NetworkId ownerId = actor; + + // god mode can specify a different player to search for + if (isGod && !params.empty()) + { + ownerId = NetworkId(Unicode::wideToNarrow(params)); + if (!ownerId.isValid()) + ownerId = actor; + } + + int const timeNow = static_cast(::time(NULL)); + if (!isGod && actorObj->getObjVars().hasItem("timeNextLocateStructureCommandAllowed") && (actorObj->getObjVars().getType("timeNextLocateStructureCommandAllowed") == DynamicVariable::INT)) + { + int timeNextLocateStructureCommandAllowed = 0; + if (actorObj->getObjVars().getItem("timeNextLocateStructureCommandAllowed", timeNextLocateStructureCommandAllowed)) + { + if (timeNextLocateStructureCommandAllowed > timeNow) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("player_structure", "locate_structure_command_too_fast"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextLocateStructureCommandAllowed - timeNow))); + Chat::sendSystemMessage(*actorObj, prosePackage); + + return; + } + } + } + + NetworkId ownerResidenceId; + if (ownerId == actor) + { + ownerResidenceId = actorObj->getHouse(); + + StringId::LocUnicodeString response; + if (StringId("player_structure", "locate_structure_command_executing").localize(response)) + ConsoleMgr::broadcastString(Unicode::wideToNarrow(response), clientObj); + } + else + { + // should only be here for god mode + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Searching galaxy for all unpacked structures and installations owned by %s.", ownerId.getValueString().c_str()), + clientObj); + } + + GenericValueTypeMessage, std::pair, NetworkId> > > locateStructureByOwnerIdReq("LSBOIReq", std::make_pair(std::make_pair(GameServer::getInstance().getProcessId(), isGod), std::make_pair(std::make_pair(ownerId, ownerResidenceId), actor))); + GameServer::getInstance().sendToCentralServer(locateStructureByOwnerIdReq); + + if (!isGod) + IGNORE_RETURN(actorObj->setObjVarItem("timeNextLocateStructureCommandAllowed", (timeNow + ConfigServerGame::getLocateStructureCommandIntervalSeconds()))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncLocateVendor(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); + if (!playerObj) + return; + + Client * const clientObj = actorObj->getClient(); + if (!clientObj) + return; + + bool const isGod = clientObj->isGod(); + NetworkId ownerId = actor; + + // god mode can specify a different player to search for + if (isGod && !params.empty()) + { + ownerId = NetworkId(Unicode::wideToNarrow(params)); + if (!ownerId.isValid()) + ownerId = actor; + } + + int const timeNow = static_cast(::time(NULL)); + if (!isGod && actorObj->getObjVars().hasItem("timeNextLocateVendorCommandAllowed") && (actorObj->getObjVars().getType("timeNextLocateVendorCommandAllowed") == DynamicVariable::INT)) + { + int timeNextLocateVendorCommandAllowed = 0; + if (actorObj->getObjVars().getItem("timeNextLocateVendorCommandAllowed", timeNextLocateVendorCommandAllowed)) + { + if (timeNextLocateVendorCommandAllowed > timeNow) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("player_vendor", "locate_vendor_command_too_fast"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToMS(static_cast(timeNextLocateVendorCommandAllowed - timeNow))); + Chat::sendSystemMessage(*actorObj, prosePackage); + + return; + } + } + } + + if (ownerId == actor) + { + StringId::LocUnicodeString response; + if (StringId("player_vendor", "locate_vendor_command_executing").localize(response)) + ConsoleMgr::broadcastString(Unicode::wideToNarrow(response), clientObj); + } + else + { + // should only be here for god mode + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Searching the commodities system for all initialized vendors owned by %s.", ownerId.getValueString().c_str()), + clientObj); + } + + GenericValueTypeMessage, bool> > const msg("GetVendorInfoForPlayer", std::make_pair(std::make_pair(actor, ownerId), isGod)); + CommoditiesMarket::sendToCommoditiesServer(msg); + + if (!isGod) + IGNORE_RETURN(actorObj->setObjVarItem("timeNextLocateVendorCommandAllowed", (timeNow + ConfigServerGame::getLocateVendorCommandIntervalSeconds()))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncShowCtsHistory(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject const * targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + Client * const clientObj = targetObj->getClient(); + if (!clientObj) + return; + + NetworkId target = actor; + + // god mode can specify a different player to show CTS history for + if (clientObj->isGod() && !params.empty()) + { + target = NetworkId(Unicode::wideToNarrow(params)); + if (!target.isValid()) + target = actor; + } + + if (target != actor) + { + targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(target)); + targetPlayerObj = (targetObj ? PlayerCreatureController::getPlayerObject(targetObj) : NULL); + if (!targetPlayerObj) + { + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%s is not a valid or nearby player character.", target.getValueString().c_str()), clientObj); + return; + } + + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Retrieving CTS history for %s.", target.getValueString().c_str()), clientObj); + } + else + { + ConsoleMgr::broadcastString("Retrieving CTS history for this character.", clientObj); + } + + // we need to return the CTS history ordered by transfer time + std::multimap > orderedCtsHistory; + + DynamicVariableList::NestedList const ctsTransactions(targetObj->getObjVars(), "ctsHistory"); + for (DynamicVariableList::NestedList::const_iterator i = ctsTransactions.begin(); i != ctsTransactions.end(); ++i) + { + Unicode::String ctsTransactionDetail; + if (i.getValue(ctsTransactionDetail)) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(ctsTransactionDetail, tokens, NULL, NULL) && (tokens.size() >= 4)) + { + Unicode::String characterName; + for (size_t i = 3, j = tokens.size(); i < j; ++i) + { + if (!characterName.empty()) + characterName += Unicode::narrowToWide(" "); + + characterName += tokens[i]; + } + + IGNORE_RETURN(orderedCtsHistory.insert(std::make_pair(atoi(Unicode::wideToNarrow(tokens[0]).c_str()), std::make_pair(Unicode::wideToNarrow(characterName), Unicode::wideToNarrow(tokens[1]))))); + } + } + } + + if (orderedCtsHistory.empty()) + { + ConsoleMgr::broadcastString("No CTS history found.", clientObj); + } + else + { + int count = 0; + for (std::multimap >::const_iterator iter = orderedCtsHistory.begin(); iter != orderedCtsHistory.end(); ++iter) + { + ++count; + + if (orderedCtsHistory.size() == 1) + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("Transferred from %s, %s on %s.", iter->second.first.c_str(), iter->second.second.c_str(), CalendarTime::convertEpochToTimeStringLocal(iter->first).c_str()), clientObj); + else + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%d) Transferred from %s, %s on %s.", count, iter->second.first.c_str(), iter->second.second.c_str(), CalendarTime::convertEpochToTimeStringLocal(iter->first).c_str()), clientObj); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminPlanetwarp(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + size_t pos = 0; + std::string const planetName = nextStringParm(params, pos); + Vector const newPosition_w = nextVectorParm(params, pos); + NetworkId const newContainer = nextOidParm(params, pos); + Vector const newPosition_p = nextVectorParm(params, pos); + + CreatureObject * const actorCreature = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorCreature) + { + TangibleObject *targetTangible = actorCreature; + if (target != NetworkId::cms_invalid) + targetTangible = dynamic_cast(ServerWorld::findObjectByNetworkId(target)); + + if (targetTangible) + { + if (!ServerWorld::isSpaceScene() && !strncmp(planetName.c_str(), "space_", 5) && targetTangible->asCreatureObject()) + { + // going to space from the ground, so require a ship and set launch information + ShipObject const * const ship = getFirstPackedShipForCreature(*targetTangible->asCreatureObject()); + if (!ship) + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("No valid ship, cannot warp to space scene."), Unicode::emptyString); + return; + } + + DynamicVariableLocationData const loc(targetTangible->getPosition_w(), ServerWorld::getSceneId(), NetworkId::cms_invalid); + targetTangible->setObjVarItem("space.launch.worldLoc", loc); + targetTangible->setObjVarItem("space.launch.ship", ship->getNetworkId()); + targetTangible->setObjVarItem("space.launch.startIndex", static_cast(0)); + } + + GameServer::getInstance().requestSceneWarp(CachedNetworkId(*targetTangible), planetName, newPosition_w, newContainer, newPosition_p); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminTeleport(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + size_t pos = 0; + Vector position_w = nextVectorParm(params, pos); + NetworkId targetCell = nextOidParm(params, pos); + Vector position_p = nextVectorParm(params, pos); + + // make sure coordinates are sane + float const maxSaneCoordinate = 100000; + if ((position_w.x < -maxSaneCoordinate) || + (position_w.x > maxSaneCoordinate) || + (position_w.y < -maxSaneCoordinate) || + (position_w.y > maxSaneCoordinate) || + (position_w.z < -maxSaneCoordinate) || + (position_w.z > maxSaneCoordinate) || + (position_p.x < -maxSaneCoordinate) || + (position_p.x > maxSaneCoordinate) || + (position_p.y < -maxSaneCoordinate) || + (position_p.y > maxSaneCoordinate) || + (position_p.z < -maxSaneCoordinate) || + (position_p.z > maxSaneCoordinate)) + { + const Object * const actorObj = NetworkIdManager::getObjectById(actor); + if (actorObj && actorObj->asServerObject()) + { + Client * const actorClient = actorObj->asServerObject()->getClient(); + if (actorClient) + { + char buffer[512]; + snprintf(buffer, sizeof(buffer)-1, "specified coordinate (%.2f,%.2f,%.2f) (%.2f,%.2f,%.2f) is out of range", + position_w.x, position_w.y, position_w.z, + position_p.x, position_p.y, position_p.z); + buffer[sizeof(buffer)-1] = '\0'; + + ConsoleMgr::broadcastString(buffer, actorClient); + } + } + + return; + } + + ServerObject *teleportObj = 0; + if (target != NetworkId::cms_invalid) + teleportObj = ServerWorld::findObjectByNetworkId(target); + else + teleportObj = ServerWorld::findObjectByNetworkId(actor); + + if (teleportObj) + { + // if the person teleporting is the owner of the containing ship, move the ship instead + ShipObject * const ship = getAttachedShip(teleportObj->asCreatureObject()); + if (ship) + ship->teleportObject(position_w, NetworkId::cms_invalid, "", position_w, ""); + else + teleportObj->teleportObject(position_w, targetCell, "", position_p, ""); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminTeleportTo(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + CreatureObject * const actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (actorObj) + { + CachedNetworkId who(target); + if (who == NetworkId::cms_invalid) + { + size_t curpos = 0; + who = nextOidParm(params, curpos); + } + // if the object exists locally, just teleport to it, otherwise send to db server for scatter/gather + Object * const destObj = who.getObject(); + if (destObj) + { + // if the person teleporting has a ship that must go with it, move the ship instead + ShipObject * const ship = getAttachedShip(actorObj->asCreatureObject()); + if (ship) + ship->teleportObject(destObj->findPosition_w(), NetworkId::cms_invalid, "", destObj->findPosition_w(), ""); + else + { + Object const * const firstParent = ContainerInterface::getFirstParentInWorld(*destObj); + if (firstParent) + { + actorObj->teleportObject( + firstParent->getPosition_w(), + firstParent->getAttachedTo() ? firstParent->getAttachedTo()->getNetworkId() : NetworkId::cms_invalid, + "", + firstParent->getPosition_p(), + ""); + } + } + } + else + { + TeleportToMessage const teleportToMessage(actor, who, GameServer::getInstance().getProcessId()); + GameServer::getInstance().sendToCentralServer(teleportToMessage); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminListGuilds(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + Object *actorObj = NetworkIdManager::getObjectById(actor); + if (actorObj && actorObj->asServerObject()) + { + Client *client = actorObj->asServerObject()->getClient(); + if (client) + { + char buf[512]; + std::vector guildIds; + + GuildInterface::getAllGuildIds(guildIds); + for (std::vector::const_iterator i = guildIds.begin(); i != guildIds.end(); ++i) + { + snprintf(buf, 511, "id:%-8d name:%s abbrev:%s leaderId:%s", + *i, + GuildInterface::getGuildName(*i).c_str(), + GuildInterface::getGuildAbbrev(*i).c_str(), + GuildInterface::getGuildLeaderId(*i).getValueString().c_str()); + buf[511] = '\0'; + ConsoleMgr::broadcastString(buf, client); + } + snprintf(buf, 511, "%d guilds total.", guildIds.size()); + ConsoleMgr::broadcastString(buf, client); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminEditBank(Command const &cmd, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + CreatureObject * actorCreature = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + CreatureObject * targetCreature = safe_cast(ServerWorld::findObjectByNetworkId(target)); + if (!targetCreature || !actorCreature) + { + DEBUG_REPORT_LOG(true, ("Received open command for null player or target.\n")); + return; + } + + ServerObject * targetBank = targetCreature->getBankContainer(); + if(!targetBank) + { + DEBUG_REPORT_LOG(true, ("Couldn't get bank for player %s.\n", target.getValueString().c_str())); + return; + } + + if (targetBank->isAuthoritative()) + { + ScriptParams params; + params.addParam(actor); + if (targetBank->getScriptObject()->trigAllScripts(Scripting::TRIG_ABOUT_TO_OPEN_CONTAINER, params) == SCRIPT_CONTINUE) + { + Client *client = actorCreature->getClient(); + if (client) + client->openContainer(*targetBank, 0, std::string()); + } + } + else + { + GenericValueTypeMessage > const rssMessage( + "RequestSameServer", + std::make_pair( + ContainerInterface::getTopmostContainer(*actorCreature)->getNetworkId(), + ContainerInterface::getTopmostContainer(*targetBank)->getNetworkId())); + GameServer::getInstance().sendToPlanetServer(rssMessage); + ContainerInterface::sendContainerMessageToClient(*actorCreature, Container::CEC_TryAgain, targetBank); + + //actorCreature->transferAuthority(targetBank->getAuthServerProcessId(), true, false); + //actorCreature->commandQueueEnqueue(cmd, target, params, 0, false, Command::CP_Normal, false); + //LOG("container", ("Received open editBank. Player not on same server as the target's bank. Migrating player")); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminEditStats(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject* const creatureActor = dynamic_cast(NetworkIdManager::getObjectById (actor)); + if (!creatureActor) + { + WARNING (true, ("commandFuncAdminEditStats: null actor")); + return; + } + + CreatureObject* const creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (target)); + if (!creatureTarget) + { + WARNING (true, ("commandFuncAdminEditStats: null target")); + return; + } + + EditStatsMessage const esm(target); + Client * const client = creatureActor->getClient(); + if (client) + client->send(esm, true); +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminEditAppearance(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject* const creatureActor = dynamic_cast(NetworkIdManager::getObjectById (actor)); + if (!creatureActor) + { + WARNING (true, ("commandFuncAdminEditAppearance: null actor")); + return; + } + + CreatureObject* const creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (target)); + if (!creatureTarget) + { + WARNING (true, ("commandFuncAdminEditAppearance: null target")); + return; + } + + EditAppearanceMessage const eam(target); + Client * const client = creatureActor->getClient(); + if (client) + client->send(eam, true); +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminGrantTitle(Command const &, NetworkId const &, NetworkId const &, Unicode::String const &) +{ +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminCredits(Command const &, NetworkId const &, NetworkId const &, Unicode::String const &) +{ +} + +// ---------------------------------------------------------------------- + +static void commandFuncAdminGetStationName(Command const &, NetworkId const & actor, NetworkId const & target , Unicode::String const & params) +{ + const Object * const actorObj = NetworkIdManager::getObjectById(actor); + if (actorObj && actorObj->asServerObject()) + { + Client * const actorClient = actorObj->asServerObject()->getClient(); + if (actorClient) + { + const CreatureObject* creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (target)); + if (!creatureTarget) + { + size_t pos = 0; + NetworkId targetId(nextOidParm(params, pos)); + creatureTarget = dynamic_cast(NetworkIdManager::getObjectById (targetId)); + } + + if(!creatureTarget) + { + ConsoleMgr::broadcastString("Could not resolve target passed to getStationName", actorClient); + return; + } + + const Client * const clientTarget = creatureTarget->getClient(); + if(clientTarget) + { + const std::string & stationName = clientTarget->getAccountName(); + char buf [512]; + snprintf(buf, 511, "Station name is: %s.", stationName.c_str()); + ConsoleMgr::broadcastString(buf, actorClient); + } + else + DEBUG_WARNING(true, ("Could not get the target Client in commandFuncAdminGetStationName")); + } + else + DEBUG_WARNING(true, ("Could not get the actor Client in commandFuncAdminGetStationName")); + } + else + DEBUG_WARNING(true, ("Could not get the actor object in commandFuncAdminGetStationName")); +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionCreate(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + + /*printf("!!!!AUCTION: process = %i\n", (int)GameServer::getInstance().getProcessId()); + printf("!!!!PID = %i\n", (int)getpid()); + + Chat::getFriendsList("SWG.msivertson.Orami"); + + return;*/ + + size_t pos = 0; + NetworkId itemId(nextOidParm(params, pos)); + NetworkId auctionContainerId(nextOidParm(params, pos)); + int minBid = nextIntParm(params, pos); + int timer = nextIntParm(params, pos); + Unicode::String userDescription = Unicode::narrowToWide(nextStringParm(params, pos)); + + UNREF(timer); + + CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + TangibleObject *itemTangible = dynamic_cast(NetworkIdManager::getObjectById(itemId)); + ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); + + if (actorCreature && itemTangible && auctionContainer) + { + CommoditiesMarket::auctionCreatePermanent( + "Test Name", + *itemTangible, + *auctionContainer, + minBid, + userDescription); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionCreateImmediate(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + NetworkId itemId(nextOidParm(params, pos)); + NetworkId auctionContainerId(nextOidParm(params, pos)); + int price = nextIntParm(params, pos); + int timer = nextIntParm(params, pos); + Unicode::String userDescription = Unicode::narrowToWide(nextStringParm(params, pos)); + + CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + + + + TangibleObject *itemTangible = dynamic_cast(NetworkIdManager::getObjectById(itemId)); + ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); + + if (actorCreature && itemTangible && auctionContainer) + { + CommoditiesMarket::auctionCreateImmediate( + *actorCreature, + *itemTangible, + Unicode::String(), + *auctionContainer, + price, + timer, + userDescription); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionBid(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + NetworkId auctionId(nextOidParm(params, pos)); + int bidAmount = nextIntParm(params, pos); + int maxProxyBid = nextIntParm(params, pos); + CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + + CommoditiesMarket::getAuctionDetails(*actorCreature, auctionId); + + if (actorCreature) + { + CommoditiesMarket::auctionBid( + *actorCreature, + auctionId.getValue(), + bidAmount, + maxProxyBid); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionCancel(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + NetworkId auctionId(nextOidParm(params, pos)); + + CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + + if (actorCreature) + { + CommoditiesMarket::auctionCancel( + *actorCreature, + auctionId.getValue()); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionAccept(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + NetworkId auctionId(nextOidParm(params, pos)); + + CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + + if (actorCreature) + { + CommoditiesMarket::auctionAccept( + *actorCreature, + auctionId.getValue()); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionQuery(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ +#if 0 + size_t pos = 0; + NetworkId auctionContainerId(nextOidParm(params, pos)); + int requestId = nextIntParm(params, pos); + int type = nextIntParm(params, pos); + int category = nextIntParm(params, pos); + + CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); + + if (actorCreature && auctionContainer) + { + CommoditiesMarket::auctionQuery( + *actorCreature, + requestId, + type, + category, + *auctionContainer); + } +#endif +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionRetrieve(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + NetworkId itemId(nextOidParm(params, pos)); + NetworkId auctionId(nextOidParm(params, pos)); + NetworkId auctionContainerId(nextOidParm(params, pos)); + + CreatureObject *actorCreature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(auctionContainerId)); + + if (actorCreature && auctionContainer && actorCreature->isAuthoritative() && auctionContainer->isAuthoritative()) + { + CommoditiesMarket::auctionRetrieve( + *actorCreature, + auctionId.getValue(), + itemId, + *auctionContainer); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSocial(Command const &command, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + UNREF(command); + if (actor != NetworkId::cms_invalid) + { + ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + Unicode::UnicodeStringVector sv; + Unicode::tokenize (params, sv); + + if (sv.empty ()) + { + WARNING (true, ("commandFuncSocial no params")); + return; + } + + const std::string & socialName = Unicode::wideToNarrow (sv [0]); + const uint32 socialType = SocialsManager::getSocialTypeByName (socialName); + + if (!socialType) + WARNING (true, ("commandFuncSocial Bad social type specified: [%s]", socialName.c_str ())); + else + { + bool animationOk = true; + bool textOk = true; + if (sv.size () > 1) + animationOk = !sv [1].empty () && sv [1][0] == '1'; + if (sv.size () > 2) + textOk = !sv [2].empty () && sv [2][0] == '1'; + + obj->performSocial (target, socialType, animationOk, textOk); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSocialInternal (Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + UNREF(command); + if (actor != NetworkId::cms_invalid) + { + ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + Unicode::UnicodeStringVector sv; + Unicode::tokenize (params, sv); + + if (sv.size () < 2) + { + WARNING (true, ("commandFuncSocial not enough params")); + return; + } + + const NetworkId targetId (Unicode::wideToNarrow (sv [0])); + const uint32 socialType = atoi (Unicode::wideToNarrow (sv [1]).c_str()); + + if (!socialType) + WARNING (true, ("commandFuncSocialInternal Bad social type specified: '%d'", socialType)); + else + { + bool animationOk = true; + bool textOk = true; + if (sv.size () > 3) + { + animationOk = !sv [2].empty () && sv [2][0] == '1'; + textOk = !sv [3].empty () && sv [3][0] == '1'; + } + obj->performSocial (targetId, socialType, animationOk, textOk); + } + } + } +} + +//---------------------------------------------------------------------- + +static void commandFuncSetMood (Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + UNREF(command); + if (actor != NetworkId::cms_invalid) + { + CreatureObject * const obj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + const std::string moodName = Unicode::wideToNarrow (params); + + if (moodName == "none") + { + obj->setMood (0); + } + else + { + const uint32 moodType = MoodManager::getMoodByCanonicalName (moodName); + if (moodType) + obj->setMood (moodType); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetMoodInternal (Command const &command, NetworkId const &actor, + NetworkId const &, Unicode::String const ¶ms) +{ + UNREF(command); + if (actor != NetworkId::cms_invalid) + { + CreatureObject * const obj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + const uint32 moodType = atoi(Unicode::wideToNarrow(params).c_str()); + obj->setMood (moodType); + } + } +} + +//---------------------------------------------------------------------- + +static void commandFuncRequestWaypointAtPosition (Command const &command, NetworkId const &actor, + NetworkId const &, Unicode::String const ¶ms) +{ + UNREF(command); + if (actor != NetworkId::cms_invalid) + { + CreatureObject * const obj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + if(obj->isPlayerControlled()) + { + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(obj); + if(playerObject) + { + size_t curpos = 0; + + uint8 color = static_cast(Waypoint::Blue); + std::string planet = nextStringParm (params, curpos); + + // the first parameter may be the name of the planet or an unsigned + // int specifying the color of the waypoint, in which case the + // second parameter is the name of the planet + + // obfuscation to prevent player from manually entering the + // requestWaypointAtPosition command and specifying the waypoint color + char buffer[256]; + snprintf(buffer, sizeof(buffer)-1, "(^-,=+_)color_%s(,+-=_^)=", actor.getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + if (planet.find(buffer) == 0) + { + size_t const bufferLength = strlen(buffer); + if (planet.size() > bufferLength) + { + std::string const colorStr = planet.substr(bufferLength); + color = static_cast(atoi(colorStr.c_str())); + + if ((color >= static_cast(Waypoint::NumColors)) || (color == static_cast(Waypoint::Invisible))) + color = static_cast(Waypoint::Blue); + } + + planet = nextStringParm(params, curpos); + } + + const float x = nextFloatParm (params, curpos); + const float y = nextFloatParm (params, curpos); + const float z = nextFloatParm (params, curpos); + curpos = Unicode::skipWhitespace (params, curpos); + + const std::string& sceneId = ServerWorld::getSceneId(); + StringId s("planet_n", sceneId); + + const Unicode::String & name = ((curpos != Unicode::String::npos) ? (params.substr (curpos)) : (Unicode::narrowToWide("@" + s.getCanonicalRepresentation()))); + + // get player object + Waypoint waypoint(playerObject->createWaypoint(Location(Vector(x, y, z), NetworkId::cms_invalid, Location::getCrcBySceneName(planet)),false)); + if (waypoint.isValid()) + { + waypoint.setName(name); // Waypoints are a bit like smart pointers, so this is changing the data on the PlayerObject, not just on a local variable + waypoint.setColor(color); + } + else + { + Chat::sendSystemMessage(*obj, SharedStringIds::too_many_waypoints, Unicode::emptyString); + } + } + } + } + } +} + +// ---------------------------------------------------------------------- + +/** +* Parameters: +* All parameters except text are integers +*/ + +static void commandFuncSpatialChatInternal(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + if (actor != NetworkId::cms_invalid) + { + ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + + size_t curpos = 0; + + const NetworkId targetId (nextStringParm (params, curpos)); + const int chatType = nextIntParm (params, curpos); + const int mood = nextIntParm (params, curpos); + int flags = nextIntParm (params, curpos); + int language = nextIntParm (params, curpos); + + // Verify the language parameter + + if (!GameLanguageManager::isLanguageValid(language)) + { + language = GameLanguageManager::getBasicLanguageId(); + } + + curpos = Unicode::skipWhitespace (params, curpos); + + if (curpos == Unicode::String::npos) + { + DEBUG_WARNING (true, ("empty string in spatial chat")); + return; + } + + const size_t nullpos = params.find (static_cast(0), curpos); + + Unicode::String text; + Unicode::String oob; + + if (nullpos != Unicode::String::npos) + { + text = params.substr (curpos, nullpos - curpos); + oob = params.substr (nullpos + 1); + } + else + { + // Strip any color codes the user may have entered + + text = TextIterator(params.substr (curpos)).getPrintableText(); + } + + if (text.empty()) + { + return; + } + + const bool isPrivate = SpatialChatManager::isPrivate (chatType); + + if (isPrivate) + flags |= MessageQueueSpatialChat::F_isPrivate; + + if (chatType != -1 && mood != -1 && flags != -1 && curpos != Unicode::String::npos) + { + uint16 volume = SpatialChatManager::getVolume (chatType); + + CreatureObject * const creatureActor = obj->asCreatureObject(); + + //speak cs_spaceSpeechMultiple times when piloting a ship + if(creatureActor && creatureActor->getPilotedShip()) + volume *= cs_spaceSpeechMultiple; + + // track amount of spatial chat for the character + bool allowToSpeak = true; + bool squelched = false; + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureActor); + if (playerObject) + { + // update chat character count + playerObject->updateChatSpamSpatialNumCharacters(actor, text.size()); + + // see if player has exceeded chat limit + if (ConfigServerGame::getChatSpamLimiterEnabledForFreeTrial() && + obj->getClient() && + ((obj->getClient()->getSubscriptionFeatures() & ClientSubscriptionFeature::Base) == 0) && + ((playerObject->getChatSpamSpatialNumCharacters() + playerObject->getChatSpamNonSpatialNumCharacters()) > ConfigServerGame::getChatSpamLimiterNumCharacters())) + { + allowToSpeak = false; + } + // see if the player is squelched + else if (0 != playerObject->getSecondsUntilUnsquelched()) + { + allowToSpeak = false; + squelched = true; + } + } + + if (allowToSpeak) + { + // character allowed to talk + obj->speakText( + MessageQueueSpatialChat( + CachedNetworkId(actor), + CachedNetworkId(targetId), + text, + volume, + static_cast(chatType), + static_cast(mood), + flags, + language, + oob)); + } + else if (!squelched && (ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds() > 0) && obj->getClient()) + { + // send message telling character he can no longer talk + const int timeNow = static_cast(::time(NULL)); + const int chatSpamTimeEndInterval = playerObject->getChatSpamTimeEndInterval(); + if ((chatSpamTimeEndInterval > timeNow) && (timeNow >= playerObject->getChatSpamNextTimeToNotifyPlayerWhenLimited())) + { + GenericValueTypeMessage csl("ChatSpamLimited", (chatSpamTimeEndInterval - timeNow)); + obj->getClient()->send(csl, true); + + playerObject->setChatSpamNextTimeToNotifyPlayerWhenLimited((timeNow + ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds())); + } + } + } + } + } +} + +// ---------------------------------------------------------------------- + +/** +* Parameters: [null terminator + oob] +* All parameters are strings +*/ + +static void commandFuncSpatialChat(Command const &, NetworkId const &actor, NetworkId const & targetId, Unicode::String const ¶ms) +{ + if (actor != NetworkId::cms_invalid) + { + ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(actor)); + if (obj) + { + size_t curpos = 0; + + Unicode::String chatTypeName; + Unicode::String moodTypeName; + Unicode::String flagsString; + + if (!Unicode::getFirstToken (params, curpos, curpos, chatTypeName) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncSpatialChat (no chat type)")); + return; + } + + if (!Unicode::getFirstToken (params, ++curpos, curpos, moodTypeName) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncSpatialChat (no mood type)")); + return; + } + + if (!Unicode::getFirstToken (params, ++curpos, curpos, flagsString) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncSpatialChat (no flags)")); + return; + } + + curpos = Unicode::skipWhitespace(params, ++curpos); + + const std::string & narrow_chatTypeName = Unicode::wideToNarrow (chatTypeName); + const std::string & narrow_moodTypeName = Unicode::wideToNarrow (moodTypeName); + + const uint32 chatType = SpatialChatManager::getChatTypeByName (narrow_chatTypeName); + + curpos = Unicode::skipWhitespace (params, curpos); + + if (curpos == Unicode::String::npos) + { + DEBUG_WARNING (true, ("empty string in spatial chat")); + return; + } + + size_t nullpos = params.find (static_cast(0), curpos); + + Unicode::String text; + Unicode::String oob; + + if (nullpos != Unicode::String::npos) + { + text = params.substr (curpos, nullpos - curpos); + oob = params.substr (nullpos + 1); + } + else + { + text = params.substr (curpos); + + } + + if (curpos != Unicode::String::npos) + { + const uint32 moodType = MoodManager::getMoodByCanonicalName (narrow_moodTypeName); + const bool isPrivate = SpatialChatManager::isPrivate (chatType); + + uint32 flags = atoi (Unicode::wideToNarrow (flagsString).c_str ()); + if (isPrivate) + flags |= MessageQueueSpatialChat::F_isPrivate; + + const uint16 volume = SpatialChatManager::getVolume (chatType); + + // track amount of spatial chat for the character + bool allowToSpeak = true; + bool squelched = false; + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(obj->asCreatureObject()); + if (playerObject) + { + // update chat character count + playerObject->updateChatSpamSpatialNumCharacters(actor, text.size()); + + // see if player has exceeded chat limit + if (ConfigServerGame::getChatSpamLimiterEnabledForFreeTrial() && + obj->getClient() && + ((obj->getClient()->getSubscriptionFeatures() & ClientSubscriptionFeature::Base) == 0) && + ((playerObject->getChatSpamSpatialNumCharacters() + playerObject->getChatSpamNonSpatialNumCharacters()) > ConfigServerGame::getChatSpamLimiterNumCharacters())) + { + allowToSpeak = false; + } + // see if the player is squelched + else if (0 != playerObject->getSecondsUntilUnsquelched()) + { + allowToSpeak = false; + squelched = true; + } + } + + if (allowToSpeak) + { + // character allowed to talk + obj->speakText( + MessageQueueSpatialChat( + CachedNetworkId(actor), + CachedNetworkId(targetId), + text, + volume, + static_cast(chatType), + static_cast(moodType), + flags, + 0, + oob)); + } + else if (!squelched && (ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds() > 0) && obj->getClient()) + { + // send message telling character he can no longer talk + const int timeNow = static_cast(::time(NULL)); + const int chatSpamTimeEndInterval = playerObject->getChatSpamTimeEndInterval(); + if ((chatSpamTimeEndInterval > timeNow) && (timeNow >= playerObject->getChatSpamNextTimeToNotifyPlayerWhenLimited())) + { + GenericValueTypeMessage csl("ChatSpamLimited", (chatSpamTimeEndInterval - timeNow)); + obj->getClient()->send(csl, true); + + playerObject->setChatSpamNextTimeToNotifyPlayerWhenLimited((timeNow + ConfigServerGame::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds())); + } + } + } + else + WARNING (true, ("Invalid empty output string in commandFuncSpatialChat")); + } + } +} + +//---------------------------------------------------------------------- + +/** +* +* string Params: +* - string networkId of 'other' participant +* - integer numeric value +* - integer bitflags for transmission (0x01 == sendToActor, 0x02 == sendToTarget, 0x04 == sendToBystanders) +* - string or stringID. StringId is preceded with a '@' +* +static void commandFuncCombatSpam (Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + const CachedNetworkId actorId (actor); + const CachedNetworkId targetId (target); + + ServerObject * const obj = safe_cast(actorId.getObject ()); + if (!obj) + { + WARNING (true, ("null actor in commandFuncCombatSpam")); + return; + } + + size_t curpos = 0; + + Unicode::String otherIdStr; + Unicode::String intValueStr; + Unicode::String bitflagsStr; + Unicode::String stringId; + Unicode::String combatSpamType; + + if (!Unicode::getFirstToken (params, curpos, curpos, otherIdStr) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing networkId value)")); + return; + } + + if (!Unicode::getFirstToken (params, ++curpos, curpos, intValueStr) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing int value)")); + return; + } + + if (!Unicode::getFirstToken (params, ++curpos, curpos, bitflagsStr) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing bitflags)")); + return; + } + + if (!Unicode::getFirstToken (params, ++curpos, curpos, stringId) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing stringId)")); + return; + } + + if (!Unicode::getFirstToken (params, ++curpos, curpos, combatSpamType)) + { + WARNING (true, ("Not enough arguments to commandFuncCombatSpam (missing combatSpamType)")); + return; + } + + //DEBUG_REPORT_LOG(true, ("Combat spam type: %d\n", Unicode::toInt(combatSpamType))); + + const CachedNetworkId otherId (Unicode::wideToNarrow (otherIdStr)); + + MessageQueueCombatSpam msg (actorId, (actor.getObject() ? actor.getObject()->getPosition_w() : Vector::zero), targetId, (target.getObject() ? target.getObject()->getPosition_w() : Vector::zero), otherId, 0, Unicode::String (), static_cast(Unicode::toInt(combatSpamType))); + + curpos = Unicode::skipWhitespace(params, ++curpos); + + const int intValue = atoi (Unicode::wideToNarrow (intValueStr).c_str ()); + const int bitflags = atoi (Unicode::wideToNarrow (bitflagsStr).c_str ()); + + if (bitflags == 0) + { + WARNING_STRICT_FATAL (true, ("Got a commandFuncCombatSpam with no recepients specified.")); + } + + msg.m_intValue = intValue; + + if (stringId [0] == '@') + { + stringId.erase (static_cast(0), 1); + msg.m_msgId = StringId (Unicode::wideToNarrow (stringId)); + } + else + msg.m_msg = stringId; + + enum Bitflags + { + B_sendToActor = 0x01, + B_sendToTarget = 0x02, + B_sendToBystanders = 0x04 + }; + + const bool sendToSelf = (bitflags & B_sendToActor) != 0; + const bool sendToTarget = (bitflags & B_sendToTarget) != 0; + const bool sendToBystanders = (bitflags & B_sendToBystanders) != 0; + + obj->performCombatSpam (msg, sendToSelf, sendToTarget, sendToBystanders); +} +*/ +//---------------------------------------------------------------------- + +/** +* +* string Params: +* - string target type (Player or ChatChannel) +* - string target id (Player name or chat channel name, e.g. SWG.betaGalaxy.Justin or SWG.betaGalaxy.system) +* - string message +*/ + +static void commandFuncSystemMessage(Command const &, NetworkId const &, NetworkId const &, Unicode::String const ¶ms) +{ + size_t curpos = 0; + + Unicode::String targetTypeStr; + Unicode::String targetIdStr; + + if (!Unicode::getFirstToken (params, curpos, curpos, targetTypeStr) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing int value)")); + return; + } + + if (!Unicode::getFirstToken (params, ++curpos, curpos, targetIdStr) || curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing bitflags)")); + return; + } + + if (curpos == Unicode::String::npos) + { + WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing msg)")); + return; + } + + curpos = Unicode::skipWhitespace(params, ++curpos); + + Unicode::String output = params.substr (curpos); + + if (output.empty ()) + { + WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing msg)")); + return; + } + + std::string targetType = Unicode::wideToNarrow(targetTypeStr); + std::string targetId = Unicode::wideToNarrow(targetIdStr); + static const Unicode::String oob; + + if(targetType == "Player") + { + Chat::sendInstantMessage("SYSTEM", targetId, output, oob); + } + else if(targetType == "ChatChannel") + { + Chat::sendToRoom("SYSTEM", targetId, output, oob); + } +} + +//----------------------------------------------------------------------- + +static void commandFuncSetWaypointActiveStatus(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) +{ + CachedNetworkId actorId(actor); + WARNING(! actorId.getObject(), ("commandSetWaypointActiveStatus: Could not get an object for actor id %s\n", actor.getValueString().c_str())); + if(actorId.getObject()) + { + CreatureObject * creature = dynamic_cast(actorId.getObject()); + if(creature) + { + if(creature->isPlayerControlled()) + { + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creature); + if(playerObject) + { + Waypoint w = playerObject->getWaypoint(target); + if (w.isValid()) + { + Unicode::String status; + size_t curpos = 0; + if (!Unicode::getFirstToken (params, curpos, curpos, status)) + { + WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing int value)")); + return; + } + if(status == Unicode::narrowToWide("on")) + { + w.setActive(true); + } + else if(status == Unicode::narrowToWide("off")) + { + w.setActive(false); + } + } + } + } + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncSetWaypointName(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) +{ + CachedNetworkId actorId(actor); + WARNING(! actorId.getObject(), ("commandFuncSetWaypointName: Could not get an object for actor id %s\n", actor.getValueString().c_str())); + if(actorId.getObject()) + { + CreatureObject * creature = dynamic_cast(actorId.getObject()); + if(creature) + { + if(creature->isPlayerControlled()) + { + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creature); + if(playerObject) + { + Waypoint w = playerObject->getWaypoint(target); + if (w.isValid()) + { + Unicode::String name; + size_t curpos = 0; + if (!Unicode::getFirstToken (params, curpos, curpos, name)) + { + WARNING (true, ("Not enough arguments to commandFuncSystemMessage (missing text value)")); + return; + } + w.setName(params); + } + } + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandSetPosture(Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CachedNetworkId actorId(actor); + if (actorId.getObject() != NULL) + { + CreatureController * const controller = dynamic_cast(actorId.getObject()->getController()); + if (controller != NULL) + { + CreatureObject * const creature = safe_cast(actorId.getObject()); + NOT_NULL (creature); + Postures::Enumerator const posture = creature->getPosture(); + + // send the creature's posture to it + MessageQueuePosture * message = new MessageQueuePosture(posture, true); + controller->appendMessage( + CM_setPosture, + 0.0f, + message, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_ALL_CLIENT + ); + + // Ensure the chair sitting state is off if the player is not sitting. + if (posture != Postures::Sitting) + { + creature->setState(States::SittingOnChair, false); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncJumpServer(Command const &command, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CachedNetworkId actorId(actor); + if (actorId.getObject() != NULL) + { + CreatureController * const controller = dynamic_cast(actorId.getObject()->getController()); + if (controller != NULL) + { + controller->appendMessage( + CM_jump, + 0.0f, + NULL, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_ALL_CLIENT + ); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAddBannedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t curpos = 0; + NetworkId objId(nextOidParm(params, curpos)); + curpos = Unicode::skipWhitespace(params, curpos); + + Object *obj = NetworkIdManager::getObjectById(objId); + Client *client = getClientFromCharacterId(actor); + if (obj) + { + CellObject *cell = dynamic_cast(obj); + if (cell) + { + BuildingObject *building = cell->getOwnerBuilding(); + if (building && building->isOwner(actor, client)) + cell->addBanned(Unicode::wideToNarrow(params.substr(curpos))); + } + else + { + BuildingObject *building = dynamic_cast(obj); + if (building && building->isOwner(actor, client)) + building->addBanned(Unicode::wideToNarrow(params.substr(curpos))); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRemoveBannedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t curpos = 0; + NetworkId objId(nextOidParm(params, curpos)); + curpos = Unicode::skipWhitespace(params, curpos); + + Object *obj = NetworkIdManager::getObjectById(objId); + Client *client = getClientFromCharacterId(actor); + if (obj) + { + CellObject *cell = dynamic_cast(obj); + if (cell) + { + BuildingObject *building = cell->getOwnerBuilding(); + if (building && building->isOwner(actor, client)) + cell->removeBanned(Unicode::wideToNarrow(params.substr(curpos))); + } + else + { + BuildingObject *building = dynamic_cast(obj); + if (building && building->isOwner(actor, client)) + building->removeBanned(Unicode::wideToNarrow(params.substr(curpos))); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAddAllowedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t curpos = 0; + NetworkId objId(nextOidParm(params, curpos)); + curpos = Unicode::skipWhitespace(params, curpos); + + Object *obj = NetworkIdManager::getObjectById(objId); + Client *client = getClientFromCharacterId(actor); + if (obj) + { + CellObject *cell = dynamic_cast(obj); + if (cell) + { + BuildingObject *building = cell->getOwnerBuilding(); + if (building && building->isOwner(actor, client)) + cell->addAllowed(Unicode::wideToNarrow(params.substr(curpos))); + } + else + { + BuildingObject *building = dynamic_cast(obj); + if (building && building->isOwner(actor, client)) + building->addAllowed(Unicode::wideToNarrow(params.substr(curpos))); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRemoveAllowedPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t curpos = 0; + NetworkId objId(nextOidParm(params, curpos)); + curpos = Unicode::skipWhitespace(params, curpos); + + Object *obj = NetworkIdManager::getObjectById(objId); + Client *client = getClientFromCharacterId(actor); + if (obj) + { + CellObject *cell = dynamic_cast(obj); + if (cell) + { + BuildingObject *building = cell->getOwnerBuilding(); + if (building && building->isOwner(actor, client)) + cell->removeAllowed(Unicode::wideToNarrow(params.substr(curpos))); + } + else + { + BuildingObject *building = dynamic_cast(obj); + if (building && building->isOwner(actor, client)) + building->removeAllowed(Unicode::wideToNarrow(params.substr(curpos))); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetPublicState(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t curpos = 0; + NetworkId objId(nextOidParm(params, curpos)); + int publicState = nextIntParm(params, curpos); + + Object *obj = NetworkIdManager::getObjectById(objId); + Client *client = getClientFromCharacterId(actor); + if (obj) + { + CellObject *cell = dynamic_cast(obj); + if (cell) + { + BuildingObject *building = cell->getOwnerBuilding(); + if (building && building->isOwner(actor, client)) + cell->setIsPublic(publicState ? true : false); + } + else + { + BuildingObject *building = dynamic_cast(obj); + if (building && building->isOwner(actor, client)) + building->setIsPublic(publicState ? true : false); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetOwner(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t curpos = 0; + NetworkId objId(nextOidParm(params, curpos)); + NetworkId ownerId(nextOidParm(params, curpos)); + + Object *obj = NetworkIdManager::getObjectById(objId); + Client *client = getClientFromCharacterId(actor); + if (obj) + { + ServerObject *tangibleObj = safe_cast(obj); + if (tangibleObj && tangibleObj->isOwner(actor, client)) + { + tangibleObj->setOwnerId(ownerId); + } + } +} + +// ---------------------------------------------------------------------- + +static void resolveDuelParticipants(CreatureObject &actor, TangibleObject &target, TangibleObject *&actorFlagObj, CreatureObject *&targetMessageObj) +{ + ShipObject * const targetShip = target.asShipObject(); + if (targetShip) + { + // Dueling a ship + // actorFlagObj is the containing ship of the actor if he owns it + ShipObject * const actorShip = ShipObject::getContainingShipObject(&actor); + if ( actorShip + && actorShip->isPlayerShip() + && actor.getNetworkId() == actorShip->getOwnerId()) + actorFlagObj = actorShip; + // targetMessageObj is the owner of the target ship + if (targetShip->isPlayerShip()) + { + Object * const o = NetworkIdManager::getObjectById(targetShip->getOwnerId()); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so) + targetMessageObj = so->asCreatureObject(); + } + } + } + else + { + actorFlagObj = &actor; + targetMessageObj = target.asCreatureObject(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncDuel(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + if (target != NetworkId::cms_invalid && target != actor) + { + CreatureObject * const actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + TangibleObject * const targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (actorObj && targetObj) + { + TangibleObject *actorFlagObj = 0; + CreatureObject *targetMessageObj = 0; + resolveDuelParticipants(*actorObj, *targetObj, actorFlagObj, targetMessageObj); + + if (actorFlagObj && targetMessageObj && actorObj != targetMessageObj) + { + if (PlayerObject::isIgnoring(actor, targetMessageObj->getNetworkId())) + return; + + if (actorObj->hasAutoDeclineDuel()) + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_CANNOT_DUEL_AUTO_DECLINE); + return; + } + + if (Pvp::canAttack(*actorObj, *targetObj)) + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ALREADY_CAN_ATTACK); + return; + } + + if (Pvp::canAttack(*targetObj, *actorObj)) + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_AVAILABLE_TO_DUEL); + return; + } + + if (targetObj->hasAutoDeclineDuel()) + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_AVAILABLE_TO_DUEL); + sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_AUTO_DECLINED_DUEL); + return; + } + + if(targetObj->getObjVars().hasItem("hologram_performer")) + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_HOLOGRAM); + } + else if (!Pvp::isDuelingAllowed(*actorFlagObj, *targetObj)) + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_HERE); + } + else if (Pvp::hasDuelEnemyFlag(*actorFlagObj, targetObj->getNetworkId())) + { + if (Pvp::hasDuelEnemyFlag(*targetObj, actorFlagObj->getNetworkId())) + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ALREADY_DUELING); + else + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ALREADY_CHALLENGED); + } + else if (Pvp::hasDuelEnemyFlag(*targetObj, actorFlagObj->getNetworkId())) + { + // Duel Accepted and Starting. + Pvp::setDuelEnemyFlag(*actorFlagObj, *targetObj); + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_ACCEPT_SELF); + sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_ACCEPT_TARGET); + + // Call their Script Triggers + ServerObject* serverActor = actorObj->asServerObject(); + if(serverActor) + { + ScriptParams params; + params.addParam(actor); + params.addParam(target); + if(serverActor->getScriptObject()) + { + IGNORE_RETURN(serverActor->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_START, params)); + + } + } + + ServerObject* serverTarget = targetObj->asServerObject(); + if(serverTarget) + { + ScriptParams params; + params.addParam(actor); + params.addParam(target); + if(serverTarget->getScriptObject()) + { + IGNORE_RETURN( serverTarget->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_START, params)); + } + } + /// End script triggers. + + } + else + { + // Duel Request + // Call their Script Triggers + ServerObject* serverActor = actorObj->asServerObject(); + if(serverActor) + { + ScriptParams params; + params.addParam(actor); + params.addParam(target); + if(serverActor->getScriptObject()) + { + if( serverActor->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_REQUEST, params) == SCRIPT_OVERRIDE ) + return; + } + } + + ServerObject* serverTarget = targetObj->asServerObject(); + if(serverTarget) + { + ScriptParams params; + params.addParam(actor); + params.addParam(target); + if(serverTarget->getScriptObject()) + { + if( serverTarget->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DUEL_REQUEST, params) == SCRIPT_OVERRIDE ) + return; + } + } + /// End script triggers. + Pvp::setDuelEnemyFlag(*actorFlagObj, *targetObj); + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_CHALLENGE_SELF); + sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_CHALLENGE_TARGET); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncEndDuel(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + if (target != NetworkId::cms_invalid) + { + CreatureObject * const actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + TangibleObject * const targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (actorObj && targetObj) + { + TangibleObject *actorFlagObj = 0; + CreatureObject *targetMessageObj = 0; + resolveDuelParticipants(*actorObj, *targetObj, actorFlagObj, targetMessageObj); + + if (actorFlagObj && targetMessageObj) + { + if (Pvp::hasDuelEnemyFlag(*targetObj, actorFlagObj->getNetworkId())) + { + Pvp::removeDuelEnemyFlags(*targetObj, actorFlagObj->getNetworkId()); + if (Pvp::hasDuelEnemyFlag(*actorFlagObj, targetObj->getNetworkId())) + { + Pvp::removeDuelEnemyFlags(*actorFlagObj, targetObj->getNetworkId()); + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_END_SELF); + sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_END_TARGET); + + // notify script that the duel has ended because of the EndDuel command + { + ScriptParams params; + params.addParam(targetObj->getNetworkId(), "target"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(actorFlagObj->getNetworkId(), + "endDuelCommandNotification", dictionary->getSerializedData(), 0, false); + } + } + + { + ScriptParams params; + params.addParam(actorFlagObj->getNetworkId(), "target"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(targetObj->getNetworkId(), + "endDuelCommandNotification", dictionary->getSerializedData(), 0, false); + } + } + } + else + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_REJECT_SELF); + sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_REJECT_TARGET); + } + } + else if (Pvp::hasDuelEnemyFlag(*actorFlagObj, targetObj->getNetworkId())) + { + Pvp::removeDuelEnemyFlags(*actorFlagObj, targetObj->getNetworkId()); + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_CANCEL_SELF); + sendProseMessage(*targetMessageObj, actorObj, CommandStringId::SID_DUEL_CANCEL_TARGET); + } + else + { + sendProseMessage(*actorObj, targetMessageObj, CommandStringId::SID_DUEL_NOT_DUELING); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncHarvesterActivate(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) + targetObj->activate(actor); +} + +// ---------------------------------------------------------------------- + +static void commandFuncHarvesterDeactivate(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (targetObj && actorObj &&targetObj->isOnAdminList(*actorObj)) + targetObj->deactivate(); + +} + +// ---------------------------------------------------------------------- + +static void commandFuncHarvesterHarvest(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) + targetObj->harvest(); +} + +// ---------------------------------------------------------------------- + +static void commandFuncHarvesterSelectResource(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶meter) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + NetworkId poolId(Unicode::wideToNarrow(parameter)); + if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) + targetObj->selectResource(poolId, actor); +} + +// ---------------------------------------------------------------------- + +static void commandFuncHarvesterDiscardHopper(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (targetObj && actorObj &&targetObj->isOnAdminList(*actorObj)) + targetObj->discardAllHopperContents(); +} + +// ---------------------------------------------------------------------- + +static void commandFuncHarvesterMakeCrate(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + size_t pos=0; + const NetworkId resourceId = nextOidParm(params,pos); + const int amount = nextIntParm(params,pos); + const bool discard = nextBoolParm(params,pos); + const uint8 sequenceId = static_cast(nextIntParm(params,pos)); + + if (targetObj && actorObj && targetObj->isOnAdminList(*actorObj)) + targetObj->emptyHopper(actor,resourceId,amount,discard,sequenceId); +} + +// ---------------------------------------------------------------------- + +static void commandFuncResourceSetName(Command const &, NetworkId const &, NetworkId const &target, Unicode::String const ¶ms) +{ + ResourceTypeObject * const targetObj = ServerUniverse::getInstance().getResourceTypeById(target); + if (targetObj) + targetObj->setName(Unicode::wideToNarrow(params)); +} + +// ---------------------------------------------------------------------- + +static void commandFuncResourceContainerTransfer(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!player) + return; + + ResourceContainerObject *sourceObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + size_t pos = 0; + NetworkId destId = nextOidParm(params,pos); + ResourceContainerObject *destObj = dynamic_cast(NetworkIdManager::getObjectById(destId)); + int amount = nextIntParm(params,pos); + + + if (!sourceObj || !destObj || amount <= 0) + return; + + Container::ContainerErrorCode error = Container::CEC_Success; + if (!player->canManipulateObject(*sourceObj, true, true, true, 10.0f, error)) + { + ContainerInterface::sendContainerMessageToClient(*player, error, sourceObj); + return; + } + if (!player->canManipulateObject(*destObj, true, true, true, 10.0f, error)) + { + ContainerInterface::sendContainerMessageToClient(*player, error, destObj); + return; + } + + sourceObj->transferTo(*destObj, amount); +} + +// ---------------------------------------------------------------------- + +static void commandFuncMakeSurvey(Command const &, NetworkId const &, NetworkId const &, Unicode::String const &) +{ + //TODO: Do something here someday +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestSurvey(Command const &, NetworkId const &actor, NetworkId const &tool, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (actorObj && actorObj->getClient()) + { + size_t curpos = 0; + Unicode::String resourceName = Unicode::narrowToWide(nextStringParm (params, curpos)); + + ScriptParams params; + params.addParam(actor); + params.addParam(resourceName); + + //now trigger the script, the actor should have exactly one on himself + ServerObject *toolObj = safe_cast(NetworkIdManager::getObjectById(tool)); + if (toolObj) + toolObj->getScriptObject()->trigAllScripts(Scripting::TRIG_REQUEST_SURVEY, params); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestCoreSample(Command const &, NetworkId const &actor, NetworkId const &tool, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (actorObj && actorObj->getClient()) + { + size_t curpos = 0; + Unicode::String resourceName = Unicode::narrowToWide(nextStringParm (params, curpos)); + + ScriptParams params; + params.addParam(actor); + params.addParam(resourceName); + + //now trigger the script, the actor should have exactly one on himself + ServerObject *toolObj = safe_cast(NetworkIdManager::getObjectById(tool)); + if (toolObj) + toolObj->getScriptObject()->trigAllScripts(Scripting::TRIG_REQUEST_CORESAMPLE, params); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncResourceContainerSplit(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + ResourceContainerObject * const sourceObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!sourceObj) + return; + + CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!player) + return; + + size_t pos = 0; + const int amount = nextIntParm(params,pos); + const CachedNetworkId destContainer (nextOidParm(params,pos)); + const int arrangementId = nextIntParm(params,pos); + const Vector & newLocation = nextVectorParm(params,pos); + + Container::ContainerErrorCode error = Container::CEC_Success; + if (!player->canManipulateObject(*sourceObj, true, true, true, 10.0f, error)) + { + ContainerInterface::sendContainerMessageToClient(*player, error, sourceObj); + } + else if (!sourceObj->splitContainer(amount,destContainer,arrangementId,newLocation, safe_cast(NetworkIdManager::getObjectById(actor)))) + { + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_Full, safe_cast(destContainer.getObject ())); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncFactoryCrateSplit(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + FactoryObject * const sourceObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!sourceObj) + return; + + CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!player) + return; + + size_t pos = 0; + const int amount = nextIntParm(params,pos); + const CachedNetworkId destContainerId (nextOidParm(params,pos)); + ServerObject * destContainer = safe_cast(destContainerId.getObject()); + if (destContainer == NULL || ContainerInterface::getVolumeContainer(*destContainer) == NULL) + { + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_NotFound); + return; + } + + Container::ContainerErrorCode error = Container::CEC_Success; + if (!player->canManipulateObject(*sourceObj, true, true, true, 10.0f, error)) + { + ContainerInterface::sendContainerMessageToClient(*player, error, sourceObj); + } + else if (sourceObj->makeCopy(*destContainer, amount) == NULL) + { + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_Full, + destContainer); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncPermissionListModify(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (actorObj && actorObj->getClient()) + { + size_t curpos = 0; + const Unicode::String & playerName = Unicode::narrowToWide(nextStringParm (params, curpos)); + const Unicode::String & listName = Unicode::narrowToWide(nextStringParm (params, curpos)); + const Unicode::String & action = Unicode::narrowToWide(nextStringParm (params, curpos)); + + ScriptParams params; + params.addParam(actor); + params.addParam(playerName); + params.addParam(listName); + params.addParam(action); + + //now trigger the script, the actor should have exactly one on himself + actorObj->getScriptObject()->trigAllScripts(Scripting::TRIG_PERMISSION_LIST_MODIFY, params); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSynchronizedUiListen(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + ServerObject *targetObj = safe_cast(NetworkIdManager::getObjectById(target)); + CreatureObject * const actorObject = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (targetObj && actorObject) + targetObj->addSynchronizedUiClient(*actorObject); +} + +// ---------------------------------------------------------------------- + +static void commandFuncSynchronizedUiStopListening(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + ServerObject *targetObj = safe_cast(NetworkIdManager::getObjectById(target)); + if (targetObj) + targetObj->removeSynchronizedUiClient(actor); +} + +// ---------------------------------------------------------------------- + +static void commandFuncHarvesterGetResourceData(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + HarvesterInstallationObject *targetObj = dynamic_cast(NetworkIdManager::getObjectById(target)); + CreatureObject *actorObject = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (targetObj && actorObject && targetObj->isOnAdminList(*actorObject)) + { + targetObj->sendResourceDataToClient(*actorObject); + } +} + +// ---------------------------------------------------------------------- +/** +* @param params the destination container, and an optional arrangement +*/ + +//------------------------------------------------------------------------------------------ +static void commandFuncTransferItem(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) +{ + ServerObject * const item = ServerWorld::findObjectByNetworkId(target); + ServerObject * const playerSo = ServerWorld::findObjectByNetworkId(actor); + + if (!playerSo || !item) + { + DEBUG_REPORT_LOG(true, ("Received transfer item command for null player or target.\n")); + return; + } + + if (item->isPlayerControlled()) + return; + + CreatureObject* const player = playerSo->asCreatureObject(); + if (!player) + return; + + size_t curpos = 0; + const NetworkId & destId = nextOidParm(params, curpos); + const int arrangement = nextIntParm(params, curpos); + const Vector & pos = nextVectorParm(params, curpos); + Transform t; + t.setPosition_p(pos); + + ServerObject * const destination = safe_cast(NetworkIdManager::getObjectById(destId)); + + //@todo this value (6) came from a data table that cannot be referenced. It's the distance you can be from an object for pick up. When we get command table range validation in, we can remove it. + Container::ContainerErrorCode errorCode = Container::CEC_Success; + + // call canManipulateObject telling it to skip the no trade check; + // we'll do the no trade check separately if canManipulateObject passes + bool allowedByGodMode = false; + bool canManipulateTarget = player->canManipulateObject(*item, true, true, true, 6, errorCode, true, &allowedByGodMode); + if (canManipulateTarget && !allowedByGodMode && item->markedNoTrade()) + { + // the item must be owned by this creature + NetworkId ownerId; + if (item->asIntangibleObject()) + { + ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*item)); + ownerId = containedBy ? containedBy->getOwnerId() : NetworkId::cms_invalid; + } + else + { + ownerId = item->getOwnerId(); + } + + if (ownerId != player->getNetworkId()) + { + canManipulateTarget = false; + + if (item->markedNoTradeShared(true)) + { + // if the no trade item is a "shared" no trade item and is immediately + // contained in a structure cell, and is being transferred to the + // transferer's inventory (i.e. picked up), also allow the transfer + // if the transferer is on the same account as the current owner of the item + ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*item)); + if (containedBy && containedBy->asCellObject()) + { + if (destination && (player->getInventory() == destination)) + { + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(player); + if (playerObject && (playerObject->getStationId() == NameManager::getInstance().getPlayerStationId(ownerId))) + canManipulateTarget = true; + } + } + } + } + } + + if (!canManipulateTarget) + { + if(errorCode == Container::CEC_NoPermission) + { + Object * parentObject = ContainerInterface::getContainedByObject(*item); + if(parentObject && parentObject->asServerObject() && parentObject->asServerObject()->asTangibleObject() + && parentObject->asServerObject()->asTangibleObject()->isLocked()) + { + ContainerInterface::sendContainerMessageToClient(*player, errorCode, parentObject->asServerObject()); + return; + } + } + ContainerInterface::sendContainerMessageToClient(*player, errorCode, item); + return; + } + + //-- don't transfer from/to factory crates + { + if (destination && destination->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) + return; + + const ServerObject * const containedBy = safe_cast(ContainerInterface::getContainedByObject (*item)); + + if (containedBy && containedBy->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) + return; + } + + // If our destination is a locked container, make sure we can access it. + bool lockedDestContainer = false; + { + if(destination && destination->asTangibleObject() && destination->asTangibleObject()->isLocked()) + { + lockedDestContainer = true; + TangibleObject * destTangible = destination->asTangibleObject(); + if(!destTangible->isUserOnAccessList(player->getNetworkId()) && !destTangible->isGuildOnAccessList(player->getGuildId()) + && player->getClient() && !player->getClient()->isGod()) + { + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_NoPermission, destination); + return; + } + } + + } + + { + // No Drag and Drop while using Loot rules (especially random). + const ServerObject * source = getFirstCreatureContainer(item); + + if(source && source->asCreatureObject() && source->asCreatureObject()->isDead() && destination) + { + const ServerObject* dest = getFirstCreatureContainer(destination); + if(dest && dest->asCreatureObject() && dest->asCreatureObject()->getGroup()) + { + int lootRule = dest->asCreatureObject()->getGroup()->getLootRule(); + // Random/Lotto Loot Rule, no drag and drop allowed! + if(lootRule == 3 || lootRule == 2) + { + return; + } + } + } + + } + + if (!item->isAuthoritative()) + { + GenericValueTypeMessage > const rssMessage( + "RequestSameServer", + std::make_pair( + ContainerInterface::getTopmostContainer(*player)->getNetworkId(), + ContainerInterface::getTopmostContainer(*item)->getNetworkId())); + GameServer::getInstance().sendToPlanetServer(rssMessage); + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, item); + return; + } + + bool retval = true; + if (destId == NetworkId::cms_invalid) + { + //to world + retval = ContainerInterface::transferItemToWorld(*item, t, player, errorCode); + } + else + { + if (!destination) + { + DEBUG_REPORT_LOG(true, ("Cannot transfer item to unknown destination container\n")); + return; + } + if (!destination->isAuthoritative()) + { + GenericValueTypeMessage > const rssMessage( + "RequestSameServer", + std::make_pair( + ContainerInterface::getTopmostContainer(*player)->getNetworkId(), + ContainerInterface::getTopmostContainer(*destination)->getNetworkId())); + GameServer::getInstance().sendToPlanetServer(rssMessage); + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, destination); + return; + } + + //@todo quick check to make sure people aren't exploiting unlimited volume containers. Really there shouldn't be any of these, but there have been bugs in the past... + VolumeContainer * vol = ContainerInterface::getVolumeContainer(*destination); + if (vol && vol->getTotalVolume() == static_cast(VolumeContainer::VL_NoVolumeLimit)) + { + WARNING(true, ("Player accessing infinite volume container %s", destination->getNetworkId().getValueString().c_str())); + //send error message and return + } + + //Don't allow people to put things in unowned containers. Locked containers are allowed since they enforce their own list. + if (!destination->getObjVars().hasItem(OBJVAR_PLAYERS_CAN_ACCESS_CONTAINER) && !lockedDestContainer && + player->getClient() && !player->getClient()->isGod() && + destination->getOwnerId() == NetworkId::cms_invalid) + { + errorCode = Container::CEC_NoPermission; + ContainerInterface::sendContainerMessageToClient(*player, errorCode, destination); + return; + } + + //Check to make sure you can manipulate the destination + if (!player->canManipulateObject(*destination, false, true, true, 6, errorCode)) + { + ContainerInterface::sendContainerMessageToClient(*player, errorCode, destination); + return; + } + + //special case. If this is our inventory we are unequipping to, allow it to be somewhat overloaded. + const Object * itemParent = ContainerInterface::getContainedByObject(*item); + if (itemParent && itemParent == player && player->getInventory() == destination && item->getVolume() < 2) + { + VolumeContainer * volContainer = ContainerInterface::getVolumeContainer(*destination); + if (!volContainer) + { + errorCode = Container::CEC_Unknown; + } + else + { + const int allowedOverload = volContainer->getTotalVolume() + 2; + if (volContainer->getCurrentVolume() >= allowedOverload) + { + errorCode = Container::CEC_Full; + } + else + { + int oldCap = volContainer->debugDoNotUseSetCapacity(allowedOverload); + retval = ContainerInterface::transferItemToVolumeContainer(*destination, *item, player, errorCode, true); + IGNORE_RETURN( volContainer->debugDoNotUseSetCapacity(oldCap) ); + } + } + } + else + { + const Object * destParent = ContainerInterface::getContainedByObject(*destination); + if(destParent && destParent == player->getAppearanceInventory()) + { + // Trying to transfer to a container currently in our Appearance inventory. Not allowed. + StringId const code("container_error_message", "container34_prose"); + + ProsePackage pp; + pp.stringId = code; + pp.actor.id = player->getNetworkId (); + + // Send to the player. + Chat::sendSystemMessage (*player, pp); + + retval = false; + + } + else if (destination == player->getAppearanceInventory() && ContainerInterface::getContainer(*item) != NULL) + { + const Container * itemContainer = ContainerInterface::getContainer(*item); + if(itemContainer && itemContainer->getNumberOfItems() == 0) + { + retval = ContainerInterface::transferItemToUnknownContainer(*destination, *item, arrangement, t, player, errorCode); + } + else + { + StringId const code("container_error_message", "container33_prose"); + + ProsePackage pp; + pp.stringId = code; + pp.actor.id = player->getNetworkId (); + + // Send to the player. + Chat::sendSystemMessage (*player, pp); + } + } + else + { + retval = ContainerInterface::transferItemToUnknownContainer(*destination, *item, arrangement, t, player, errorCode); + + // if we are equipping an object to a filled slot, move the equipped item(s) to our inventory + if (!retval && errorCode == Container::CEC_SlotOccupied && destination->getNetworkId() == player->getNetworkId()) + { + ServerObject * inventory = player->getInventory(); + const SlottedContainer * equipment = ContainerInterface::getSlottedContainer(*player); + const SlottedContainmentProperty * itemContainmentProperty = ContainerInterface::getSlottedContainmentProperty(*item); + + if (inventory != NULL && equipment != NULL && itemContainmentProperty != NULL) + { + std::vector > oldItems; + retval = true; + int slotCount = itemContainmentProperty->getNumberOfSlots(arrangement); + for (int i = 0; i < slotCount && retval; ++i) + { + SlotId slot = itemContainmentProperty->getSlotId(arrangement, i); + const Container::ContainedItem & currentWeaponId = equipment->getObjectInSlot(slot, errorCode); + ServerObject * oldItem = safe_cast(currentWeaponId.getObject()); + if (oldItem != NULL) + { + if (ContainerInterface::transferItemToVolumeContainer(*inventory, *oldItem, player, errorCode, true)) + { + oldItems.push_back(std::make_pair(oldItem, slot)); + } + else + retval = false; + } + } + if (retval) + { + if (!ContainerInterface::transferItemToUnknownContainer(*destination, *item, arrangement, t, player, errorCode)) + { + // move the old items back into their slots + reequipItems(*destination, oldItems); + retval = false; + } + + } + else + { + // move the old items back into their slots + reequipItems(*destination, oldItems); + errorCode = Container::CEC_SlotOccupied; + } + } + } + } + } + } + + if (!retval && player) + { + if(errorCode == Container::CEC_SlotOccupied && destination == player->getAppearanceInventory()) + { + // Failed to place an object in our appearance inventory. Let's flush out some more information. + ServerObject * appearanceInv = player->getAppearanceInventory(); + const SlottedContainer * equipment = ContainerInterface::getSlottedContainer(*appearanceInv); + const SlottedContainmentProperty * itemContainmentProperty = ContainerInterface::getSlottedContainmentProperty(*item); + + if(!itemContainmentProperty || !equipment || arrangement < 0) + { + // This should never happen, but if it does - just send our normal bland error message. + ContainerInterface::sendContainerMessageToClient(*player, errorCode); + return; + } + + int slotCount = itemContainmentProperty->getNumberOfSlots(arrangement); + std::vector objectsToSend; + for (int i = 0; i < slotCount; ++i) + { + SlotId slot = itemContainmentProperty->getSlotId(arrangement, i); + const Container::ContainedItem & currentWeaponId = equipment->getObjectInSlot(slot, errorCode); + ServerObject * oldItem = safe_cast(currentWeaponId.getObject()); + if (oldItem != NULL) + { + if( std::find(objectsToSend.begin(), objectsToSend.end(), oldItem) == objectsToSend.end() ) + objectsToSend.push_back(oldItem); + } + } + + std::vector::iterator iter = objectsToSend.begin(); + for(; iter != objectsToSend.end(); ++iter) + { + // No idea how this could happen, but just incase. + if((*iter) == NULL) + continue; + + StringId const code("container_error_message", "container32_prose"); + + // Setup the prose package with all the %TT and %TO information. + ProsePackage pp; + pp.stringId = code; + + pp.target.id = (*iter)->getNetworkId (); + pp.target.str = (*iter)->getAssignedObjectName (); + if (pp.target.str.empty ()) + pp.target.stringId = (*iter)->getObjectNameStringId (); + + pp.other.id = item->getNetworkId(); + pp.other.str = item->getAssignedObjectName(); + if (pp.other.str.empty()) + pp.other.stringId = item->getObjectNameStringId(); + + pp.actor.id = player->getNetworkId (); + + // Send to the player. + Chat::sendSystemMessage (*player, pp); + } + + return; + } + + ContainerInterface::sendContainerMessageToClient(*player, errorCode); + } +} +// ---------------------------------------------------------------------- + +static bool isGoingInWeaponSlot(const ServerObject& target, int arrangement) +{ + if (arrangement <= 0) + return false; + + const SlottedContainmentProperty * slotted = ContainerInterface::getSlottedContainmentProperty(target); + bool useWeapon = false; + if (slotted) + { + //In this case, the player is transferring something from their equipment, which may be armor or a weapon + static const SlotId right_hand = SlotIdManager::findSlotId(CrcLowerString("hold_r")); + static const SlotId left_hand = SlotIdManager::findSlotId(CrcLowerString("hold_l")); + + const int numSlots = slotted->getNumberOfSlots(arrangement); + for (int i = 0; i < numSlots; ++i) + { + SlotId currentSlot = slotted->getSlotId(arrangement, i); + if (currentSlot == right_hand || currentSlot == left_hand) + { + useWeapon = true; + break; + } + } + } + return useWeapon; +} + +//------------------------------------------------------------------------------------------ + +static void commandFuncTransferWeapon(Command const & c, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) +{ + ServerObject * item = ServerWorld::findObjectByNetworkId(target); + CreatureObject * actorObject = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + + size_t curpos = 0; + const NetworkId & destId = nextOidParm(params, curpos); + const int arrangement = nextIntParm(params, curpos); + UNREF(destId); + + if (item && actorObject && isGoingInWeaponSlot(*item, arrangement)) + { + commandFuncTransferItem(c, actor, target, params); + } + +} + +//------------------------------------------------------------------------------------------ + +static void commandFuncTransferArmor(Command const & c, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) +{ + CreatureObject * actorObject = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObject) + { + commandFuncTransferItem(c, actor, target, params); + } +} + +//------------------------------------------------------------------------------------------ + +void CommandCppFuncs::commandFuncTransferMisc(Command const & c, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) +{ + ServerObject * item = ServerWorld::findObjectByNetworkId(target); + CreatureObject * actorObject = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + + size_t curpos = 0; + const NetworkId & destId = nextOidParm(params, curpos); + const int arrangement = nextIntParm(params, curpos); + + //This command can only be used to transfer non-weapon objects not contained directly by the player unless it is not armor + if (item && actorObject && !isGoingInWeaponSlot(*item, arrangement) && + ( destId != actor || !GameObjectTypes::isTypeOf(item->getGameObjectType(), SharedObjectTemplate::GOT_armor)) ) + { + commandFuncTransferItem(c, actor, target, params); + } +} + +//------------------------------------------------------------------------------------------ +/** +* @param params the slotname, if any, to be echo'd back to the client or passed to the script +*/ + +static void commandFuncOpenContainer(Command const & cmd, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) +{ + ServerObject * container = ServerWorld::findObjectByNetworkId(target); + CreatureObject * player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!container || !player) + { + DEBUG_REPORT_LOG(true, ("Received open command for null player or target.\n")); + return; + } + //@todo check permissions + if (!ContainerInterface::getContainer(*container)) + { + DEBUG_REPORT_LOG(true, ("Received open command on non container object.\n")); + return; + } + + //-- don't open factory crates + if (container->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) + return; + + //-- if they are opening a crafting station, what they really want is the hopper + //-- but only if the object is not a volume container + if (container->getGameObjectType () == SharedObjectTemplate::GOT_misc_crafting_station + && (NULL == ContainerInterface::getVolumeContainer (*container))) + { + static const SlotId inputHopperId(SlotIdManager::findSlotId(CrcLowerString("ingredient_hopper"))); + + ServerObject const * const station = container; + ServerObject * hopper = NULL; + const SlottedContainer * stationContainer = ContainerInterface::getSlottedContainer (*station); + if (stationContainer != NULL) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + Object* tmpHopperObj = (stationContainer->getObjectInSlot (inputHopperId, tmp)).getObject(); + if (tmp == Container::CEC_Success && tmpHopperObj) + { + hopper = tmpHopperObj->asServerObject(); + } + } + + if (hopper) + { + container = hopper; + } + else + { + // report the failure as it indicates a change to some other system + WARNING(true, ("Received open command on a crafting station and failed to open the hopper.\n")); + } + } + + size_t curpos = 0; + + std::string slotName; + int sequence = nextIntParm (params, curpos); + if (curpos != std::string::npos) + { + ++curpos; + slotName = nextStringParm (params, curpos); + } + + if (container->isAuthoritative()) + { + Container::ContainerErrorCode code = Container::CEC_Success; + + bool const isPublicContainer = container->getGameObjectType () == SharedObjectTemplate::GOT_misc_container_public; + + if (isPublicContainer && player->getClient()) + ObserveTracker::onClientAboutToOpenPublicContainer(*player->getClient(), *container); + + bool const doPermissionCheckOnItem = !isPublicContainer; + bool const doPermissionCheckOnParents = !isPublicContainer; + + if (player->canManipulateObject(*container, false, doPermissionCheckOnItem, doPermissionCheckOnParents, 6.0f, code)) + { + // Additional check for Locked containers. + if(container->asTangibleObject() && container->asTangibleObject()->isLocked()) + { + TangibleObject * tangibleTarget = container->asTangibleObject(); + if(!tangibleTarget->isUserOnAccessList(player->getNetworkId()) && !tangibleTarget->isGuildOnAccessList(player->getGuildId())) + { + // Player is NOT on the admin list or guild list, they cannot open the container. + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_NoPermission, container); + return; + } + } + + ScriptParams params; + params.addParam(actor); + if (container->getScriptObject()->trigAllScripts(Scripting::TRIG_ABOUT_TO_OPEN_CONTAINER, params) == SCRIPT_CONTINUE) + { + Client *client = player->getClient(); + if (client) + client->openContainer(*container, sequence, slotName); + } + } + else + { + ContainerInterface::sendContainerMessageToClient(*player, code, container); + } + } + else + { + GenericValueTypeMessage > const rssMessage( + "RequestSameServer", + std::make_pair( + ContainerInterface::getTopmostContainer(*player)->getNetworkId(), + ContainerInterface::getTopmostContainer(*container)->getNetworkId())); + GameServer::getInstance().sendToPlanetServer(rssMessage); + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, container); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncCloseContainer(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + ServerObject * const container = ServerWorld::findObjectByNetworkId(target); + ServerObject * const player = ServerWorld::findObjectByNetworkId(actor); + if (!container || !player) + { + DEBUG_REPORT_LOG(true, ("Received close command for null player or target.\n")); + return; + } + + //-- can't close ourself + if (player == container) + return; + + if (!ContainerInterface::getContainer(*container)) + { + DEBUG_REPORT_LOG(true, ("Received close command on non container object.\n")); + return; + } + + if (container->isAuthoritative()) + { + Client * const client = player->getClient(); + if (client) + client->closeContainer(*container); + } + else + { + DEBUG_REPORT_LOG(true, ("Multi-Server not supported for containers yet")); + //@todo the player is trying to access a container not on this server. Somehow get it here + //Then do the check + } + +} + +//------------------------------------------------------------------------------------------ + +static void commandFuncOpenLotteryContainer(Command const & /*command*/, NetworkId const & /*actor*/, NetworkId const & /*target*/, Unicode::String const & /*params*/) +{ + // moved from a command to a script hook. + // This needs to be removed for the next + // official non-hotfix patch +} + +// ---------------------------------------------------------------------- + +static void commandFuncCloseLotteryContainer(Command const & cmd, NetworkId const & actor, NetworkId const &target, Unicode::String const & params) +{ + ServerObject * const container = ServerWorld::findObjectByNetworkId(target); + if (container == 0) + { + DEBUG_REPORT_LOG(true, ("commandFuncOpenLotteryContainer: container == 0.\n")); + return; + } + + CreatureObject * const player = safe_cast(ServerWorld::findObjectByNetworkId(actor)); + if (player == 0) + { + DEBUG_REPORT_LOG(true, ("commandFuncOpenLotteryContainer: player == 0.\n")); + return; + } + + if (ContainerInterface::getContainer(*container) == 0) + { + DEBUG_REPORT_LOG(true, ("commandFuncOpenLotteryContainer: ContainerInterface::getContainer == 0.\n")); + return; + } + + Controller * const controller = player->getController(); + + if (controller != 0) + { + typedef MessageQueueGenericValueType Message; + Message * const message = new Message(target); + + controller->appendMessage( + CM_groupCloseLotteryWindowOnClient, + 0.0f, + message, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } +} + +// ---------------------------------------------------------------------- +/** +* @param params the destination container, and an optional arrangement +*/ +static void commandFuncGiveItem(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) +{ + ServerObject * const item = ServerWorld::findObjectByNetworkId(target); + ServerObject * const player = ServerWorld::findObjectByNetworkId(actor); + if (!player || !item) + { + DEBUG_REPORT_LOG(true, ("Received give item command for null player or target.\n")); + return; + } + size_t curpos = 0; + NetworkId destId = nextOidParm(params, curpos); + + //@todo this value (6) came from a data table that cannot be referenced. It's the distance you can be from an object for pick up. When we get command table range validation in, we can remove it. + Container::ContainerErrorCode errorCode = Container::CEC_Success; + if (!player->canManipulateObject(*item, true, true, true, 6, errorCode)) + { + ContainerInterface::sendContainerMessageToClient(*player, errorCode, item); + return; + } + + if (!item->isAuthoritative()) + { + GenericValueTypeMessage > const rssMessage( + "RequestSameServer", + std::make_pair( + ContainerInterface::getTopmostContainer(*player)->getNetworkId(), + ContainerInterface::getTopmostContainer(*item)->getNetworkId())); + GameServer::getInstance().sendToPlanetServer(rssMessage); + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, item); + return; + } + + ServerObject* const destination = safe_cast(NetworkIdManager::getObjectById(destId)); + + if (!destination) + { + DEBUG_REPORT_LOG(true, ("Cannot transfer item to unknown destination container\n")); + return; + } + + if (!destination->isAuthoritative()) + { + GenericValueTypeMessage > const rssMessage( + "RequestSameServer", + std::make_pair( + ContainerInterface::getTopmostContainer(*player)->getNetworkId(), + ContainerInterface::getTopmostContainer(*destination)->getNetworkId())); + GameServer::getInstance().sendToPlanetServer(rssMessage); + ContainerInterface::sendContainerMessageToClient(*player, Container::CEC_TryAgain, destination); + return; + } + + if (!player->canManipulateObject(*destination, false, false, false, 6, errorCode)) + { + ContainerInterface::sendContainerMessageToClient(*player, errorCode, destination); + return; + } + + // check and see if this is a gem->socket operation, which is handled by our code + TangibleObject * const socket = dynamic_cast(destination); + if (socket != NULL) + { + TangibleObject * const gem = dynamic_cast(item); + if (gem != NULL) + { + const int destGot = socket->getGameObjectType(); + const SharedTangibleObjectTemplate * const gemTemplate = safe_cast(gem->getSharedTemplate()); + const int count = gemTemplate->getSocketDestinationsCount(); + + for (int i = 0; i < count; ++i) + { + const int gemSocketGot = gemTemplate->getSocketDestinations(i); + if (destGot == gemSocketGot || GameObjectTypes::isTypeOf (destGot, gemSocketGot)) + { + // make sure the gem and socket are both in the player's inventory + if (!socket->isContainedBy(*player, true) || + !gem->isContainedBy(*player, true)) + { + Chat::sendSystemMessage(*player, SharedStringIds::gem_not_in_inventory, Unicode::emptyString); + return; + } + + // if the socketed item is equipped, unequip it temporarily + CreatureObject * owner = NULL; + Object * container = ContainerInterface::getContainedByObject(*socket); + if (container != NULL && container->asServerObject()->asCreatureObject() != NULL) + { + owner = container->asServerObject()->asCreatureObject(); + // fake unequipping the item + owner->onContainerLostItem(NULL, *socket, NULL); + } + + std::vector > skillModBonuses; + gem->getSkillModBonuses(skillModBonuses, false); + if (socket->addSkillModSocketBonuses(skillModBonuses)) + { + gem->permanentlyDestroy(DeleteReasons::Consumed); + Chat::sendSystemMessage(*player, SharedStringIds::gem_inserted, Unicode::emptyString); + } + else + { + // tell the player they can't use the gem + Chat::sendSystemMessage(*player, SharedStringIds::gem_not_inserted, Unicode::emptyString); + } + if (owner != NULL) + { + // "re-equip" the item + owner->onContainerGainItem(*socket, NULL, NULL); + } + return; + } + } + } + } + + // nope, pass it on to scripts + ScriptParams scriptParameters; + scriptParameters.addParam (target); + scriptParameters.addParam (actor); + + if (destination->getScriptObject()->trigAllScripts(Scripting::TRIG_GIVE_ITEM, scriptParameters) == SCRIPT_OVERRIDE) + { + item->permanentlyDestroy(DeleteReasons::BadContainerTransfer); + } + +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupInvite(Command const & command, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + if (actor == target) + return; + + CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + ShipObject const * const actorShipObject = ShipObject::getContainingShipObject(actorObj); + + GroupObject * const groupObj = actorObj->getGroup(); + if (groupObj) + { + if (groupObj->getGroupLeaderId() != actor) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_LEADER); + return; + } + } + + NetworkId parsedNetworkId = NetworkId::cms_invalid; + if (target.isValid()) + { + CreatureObject * const targetObj = findAndResolveCreatureByNetworkId(target); + if (targetObj) + { + // pointer check is done for space + if (actorObj == targetObj) + { + return; + } + + parsedNetworkId = targetObj->getNetworkId(); + } + } + else if (!params.empty()) + { + // check to see if a target name was specified, and see + // if that resolves into a player character in the galaxy + parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); + } + + if (!parsedNetworkId.isValid()) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_INVITE_NO_TARGET_SELF); + return; + } + + // cannot invite while in combat + if (actorObj->getState(States::Combat) && ConfigServerGame::getGroupInviteInviterCombatRestriction()) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_INVITE_IN_COMBAT); + return; + } + + // send a messageTo to the target to invite to group + char buffer[1024]; + snprintf(buffer, sizeof(buffer)-1, "%s|%s|%s|%s", actor.getValueString().c_str(), (actorShipObject ? actorShipObject->getNetworkId().getValueString().c_str() : "0"), (groupObj ? groupObj->getNetworkId().getValueString().c_str() : "0"), Unicode::wideToNarrow(actorObj->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, + "C++InviteToGroupReq", + buffer, + 0, + false, + actor, + "C++InviteToGroupRspTargetNotFound"); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupUninvite(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + if (actor == target) + return; + + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + NetworkId parsedNetworkId = NetworkId::cms_invalid; + if (target.isValid()) + { + CreatureObject * const targetObj = findAndResolveCreatureByNetworkId(target); + if (targetObj) + { + parsedNetworkId = targetObj->getNetworkId(); + } + } + else if (!params.empty()) + { + // check to see if a target name was specified, and see + // if that resolves into a player character in the galaxy + parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); + } + + if (!parsedNetworkId.isValid()) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_UNINVITE_NO_TARGET_SELF); + return; + } + + // send a messageTo to the target to uninvite + char buffer[1024]; + snprintf(buffer, sizeof(buffer)-1, "%s|%s", actor.getValueString().c_str(), Unicode::wideToNarrow(actorObj->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, + "C++UninviteFromGroupReq", + buffer, + 0, + false, + actor, + "C++UninviteFromGroupRspTargetNotFound"); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupJoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + if ((actorObj->getGroup()) && (!GroupHelpers::creatureIsContainedInPOBShip(actorObj))) + return; + + NetworkId const & inviterId = actorObj->getGroupInviterId(); + if (!inviterId.isValid()) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_INVITED); + return; + } + + // cannot join while in combat + if (actorObj->getState(States::Combat) && ConfigServerGame::getGroupJoinInviteeCombatRestriction()) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_JOIN_IN_COMBAT); + return; + } + + // send a messageTo to the inviter requesting the inviter's + // group/group member information so we can join the group + // or create a new group with the inviter as the group leader + MessageToQueue::getInstance().sendMessageToC(inviterId, + "C++GroupJoinInviterInfoReq", + actorObj->getNetworkId().getValueString(), + 0, + false, + actor, + "C++GroupJoinInviterInfoReqInviterNotFound"); + + actorObj->setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupDecline(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObj) + { + NetworkId inviterId = actorObj->getGroupInviterId(); + if (inviterId.isValid()) + { + // notify invitee + ProsePackage pp; + pp.stringId = GroupStringId::SID_GROUP_DECLINE_SELF; + pp.target.str = Unicode::narrowToWide(actorObj->getGroupInviterName()); + pp.actor.id = actorObj->getNetworkId(); + Chat::sendSystemMessage(*actorObj, pp); + + // notify inviter + StringId responseSid = GroupStringId::SID_GROUP_DECLINE_LEADER; + std::string const inviteeName(Unicode::wideToNarrow(actorObj->getAssignedObjectName())); + std::string response = responseSid.getCanonicalRepresentation(); + response += "|"; + + if (!inviteeName.empty()) + { + response += "nameString|"; + response += inviteeName; + } + else + { + StringId inviteeNameSid = actorObj->getObjectNameStringId(); + response += "nameStringId|"; + response += inviteeNameSid.getCanonicalRepresentation(); + } + + MessageToQueue::getInstance().sendMessageToC(inviterId, + "C++GroupOperationGenericRsp", + response, + 0, + false); + } + + actorObj->setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupDisband(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObj) + { + GroupObject * const groupObj = actorObj->getGroup(); + if (groupObj) + { + if (groupObj->getGroupLeaderId() != actor) + { + // we are not the leader. we are tring to leave the group + NetworkId const & POBShipId = groupObj->getPOBShipMemberIsContainedIn(actor); + + if ((POBShipId.isValid()) && (groupObj->getPOBShipOwnedByMember(actor) == POBShipId)) + { + // we own this POB so we can remove everyone inside it from the group + GroupMemberParam const & leader = groupObj->createGroupMemberParamForMember(actor); + + GroupObject::GroupMemberParamVector membersInsidePOB; + GroupObject::GroupMemberParamVector membersOutsidePOB; + + GroupHelpers::separateGroupBasedOffofPOBShip(groupObj, + actor, + POBShipId, + membersInsidePOB, + membersOutsidePOB); + + // if there are no members outside, then the group only consisted of + // the people in the POB. If that's the case, then don't destroy the + // old group and create a new one + if (!membersOutsidePOB.empty()) + { + groupObj->removeGroupMember(actor); + + if (actorObj->getGroup() == groupObj) + actorObj->getGroup()->onGroupMemberRemoved(actorObj->getNetworkId(), false); + + // remove everyone inside the target POB from the group + GroupHelpers::removeFromGroupAndCreatePOBGroup(groupObj, leader, membersInsidePOB); + } + } + else + { + // we don't own the POB or we are not in a POB ship so just remove us + groupObj->removeGroupMember(actor); + + if (actorObj->getGroup() == groupObj) + actorObj->getGroup()->onGroupMemberRemoved(actorObj->getNetworkId(), false); + } + } + else + { + // we are the group leader, no target is specified, so we disband the group + if (!target.isValid()) + { + // find everyone in a POB and remove them from the group + // and create new POB based groups for them + + // this is done in 2 steps because the second half will actually remove + // members from the group. we don't want to iterate over the members as + // they are being removed + + GroupObject::GroupMemberParamVector membersOwningPOBs; + std::vector membersNotInPOBs; + + { + GroupObject::GroupMemberVector const & groupMembers = groupObj->getGroupMembers(); + GroupObject::GroupMemberVector::const_iterator ii = groupMembers.begin(); + GroupObject::GroupMemberVector::const_iterator iiEnd = groupMembers.end(); + + for (; ii != iiEnd; ++ii) + { + // get the member + NetworkId const & memberId = ii->first; + NetworkId const & POBShipId = groupObj->getPOBShipOwnedByMember(memberId); + + if ((POBShipId.isValid()) && (groupObj->getPOBShipMemberIsContainedIn(memberId).isValid())) + { + GroupMemberParam const & memberWithPOBShip = groupObj->createGroupMemberParamForMember(memberId); + membersOwningPOBs.push_back(memberWithPOBShip); + } + else + { + membersNotInPOBs.push_back(memberId); + } + } + } + + // we build and cache this data for after the GroupObject has been destroyed + std::map membersInsidePOB; + std::map membersOutsidePOB; + + { + // create the new POB ship group data collections for those that need it + GroupObject::GroupMemberParamVector::const_iterator ii = membersOwningPOBs.begin(); + GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersOwningPOBs.end(); + + for (; ii != iiEnd; ++ii) + { + NetworkId const & memberId = (*ii).m_memberId; + NetworkId const & POBShipId = (*ii).m_memberShipId; + + GroupHelpers::separateGroupBasedOffofPOBShip(groupObj, + memberId, + POBShipId, + membersInsidePOB[memberId], + membersOutsidePOB[memberId]); + } + } + + if (membersOwningPOBs.empty()) + { + groupObj->disbandGroup(); + + if (actorObj->getGroup() == groupObj) + actorObj->getGroup()->onGroupMemberRemoved(actorObj->getNetworkId(), true); + } + else + { + // manually remove everyone from the actors group. this helps us avoid + // calling disband and then creteGroup with the actor being set up as + // the leader. Calling disband and create with each group would cause + // the actions to be executed out of order on multiserver due to creates + // message being processed before the controller's remove and disband + // messages were processed + { + std::set membersNotInActorsGroup; + + { + // gather all of the members that are not inside the current + // group leader's ship + + GroupObject::GroupMemberParamVector::const_iterator ii = membersOwningPOBs.begin(); + GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersOwningPOBs.end(); + + for (; ii != iiEnd; ++ii) + { + GroupMemberParam const & owner = *ii; + + if (owner.m_memberId != actor) + { + GroupObject::GroupMemberParamVector const & membersOutsideActorPOB = membersOutsidePOB[owner.m_memberId]; + + GroupObject::GroupMemberParamVector::const_iterator jj = membersOutsideActorPOB.begin(); + GroupObject::GroupMemberParamVector::const_iterator jjEnd = membersOutsideActorPOB.end(); + + for (; jj != jjEnd; ++jj) + { + membersNotInActorsGroup.insert((*jj).m_memberId); + } + } + } + + std::vector::const_iterator jj = membersNotInPOBs.begin(); + std::vector::const_iterator jjEnd = membersNotInPOBs.end(); + + // we need to make sure that we also add in other non POB ships to be removed + + for (; jj != jjEnd; ++jj) + { + if (*jj != actor) + { + membersNotInActorsGroup.insert(*jj); + } + } + } + + // remove everyone that is is not in the original leader's POB from the + // current group + std::set::const_iterator ii = membersNotInActorsGroup.begin(); + std::set::const_iterator iiEnd = membersNotInActorsGroup.end(); + + for (; ii != iiEnd; ++ii) + { + NetworkId const & memberId = *ii; + groupObj->removeGroupMember(memberId); + + CreatureObject * const memberCreatureObject = dynamic_cast(ServerWorld::findObjectByNetworkId(memberId)); + if (memberCreatureObject != 0) + { + if (memberCreatureObject->getGroup() == groupObj) + memberCreatureObject->getGroup()->onGroupMemberRemoved(memberCreatureObject->getNetworkId(), false); + } + } + } + + // now create the POB groups that we just built the data sets for + { + // create the new POB ship groups for those that need it + GroupObject::GroupMemberParamVector::const_iterator ii = membersOwningPOBs.begin(); + GroupObject::GroupMemberParamVector::const_iterator iiEnd = membersOwningPOBs.end(); + + for (; ii != iiEnd; ++ii) + { + GroupMemberParam const & leader = *ii; + + // create the new POB groups. notice NULL is passed in for the + // groupToRemoveFrom because the original group has already had + // all of the members removed + + if (leader.m_memberId != actor) + { + GroupHelpers::removeFromGroupAndCreatePOBGroup(0, leader, membersInsidePOB[leader.m_memberId]); + } + } + } + } + } + + // we are the group leader. a target is specified, so we remove them + else if (groupObj->isGroupMember(target)) + { + // send message to target to leave the group + MessageToQueue::getInstance().sendMessageToC(target, + "C++LeaveGroupReq", + groupObj->getNetworkId().getValueString(), + 0, + false); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncKickFromShip(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) +{ + CreatureObject const * const actorObject = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObject != 0) + { + CreatureObject * const targetObject = dynamic_cast(ServerWorld::findObjectByNetworkId(target)); + if ((targetObject != 0) && (actorObject != targetObject)) + { + ShipObject const * const actorShipObject = ShipObject::getContainingShipObject(actorObject); + + if ((actorShipObject != 0) && (actorShipObject->getOwnerId() == actorObject->getNetworkId())) + { + // check that both are in the same ship + if (ShipObject::getContainingShipObject(targetObject) == actorShipObject) + { + triggerSpaceEjectPlayerFromShip(targetObject); + } + } + else + { + sendProseMessage(*actorObject, 0, GroupStringId::SID_GROUP_NO_KICK_FROM_SHIP_OWNER); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObj) + { + GroupObject *groupObj = actorObj->getGroup(); + if (groupObj) + { + // don't allow if the actor is squelched + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); + if (!playerObj || (playerObj->getSecondsUntilUnsquelched() != 0)) + { + return; + } + + groupObj->sendGroupChat(actor, params); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAuctionChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObj) + { + std::string firstName; + size_t pos = 0; + Unicode::getFirstToken(Unicode::wideToNarrow(actorObj->getObjectName()), 0, pos, firstName); + + const std::string channelName = "SWG." + GameServer::getInstance().getClusterName() + "." + ServerWorld::getSceneId() + ".named.Auction"; + Chat::sendToRoom(firstName, channelName, params, Unicode::String()); + + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncPlanetChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObj) + { + std::string firstName; + size_t pos = 0; + Unicode::getFirstToken(Unicode::wideToNarrow(actorObj->getObjectName()), 0, pos, firstName); + + const std::string channelName = "SWG." + GameServer::getInstance().getClusterName() + "." + ServerWorld::getSceneId() + ".named.Planet"; + Chat::sendToRoom(firstName, channelName, params, Unicode::String()); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupMakeLeader(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + if (actor == target) + return; + + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + if (!target.isValid()) + return; + + GroupObject * const groupObj = actorObj->getGroup(); + if (groupObj) + { + if (groupObj->getGroupLeaderId() != actor) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_LEADER); + return; + } + + groupObj->makeLeader(target); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupMakeMasterLooter(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + GroupObject * const groupObj = actorObj->getGroup(); + if (groupObj != 0) + { + if (groupObj->getGroupLeaderId() != actor) + { + sendProseMessage(*actorObj, 0, GroupStringId::SID_GROUP_MUST_BE_LEADER); + return; + } + + groupObj->makeLootMaster(target.isValid() ? target : actor); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncCreateGroupPickup(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); + if (!playerObj) + return; + + Client * const clientObj = actorObj->getClient(); + if (!clientObj) + return; + + GroupObject * const groupObj = actorObj->getGroup(); + if (!groupObj || ((groupObj->getGroupLeaderId() != actor) && (playerObj->getSkillTemplate().find("officer_") != 0))) + { + sendProseMessage(*actorObj, 0, StringId("group", "create_group_pickup_not_group_leader")); + return; + } + + Vector const currentWorldLocation = actorObj->findPosition_w(); + std::string const currentScene = ServerWorld::getSceneId(); + if (!GroupPickupPoint::isGroupPickupAllowedAtLocation(currentScene, static_cast(currentWorldLocation.x), static_cast(currentWorldLocation.z))) + { + sendProseMessage(*actorObj, 0, StringId("group", "create_group_pickup_unsupported_location")); + return; + } + + if (groupObj->getSecondsLeftOnGroupPickup()) + { + sendProseMessage(*actorObj, 0, StringId("group", "create_group_pickup_existing")); + return; + } + + // see if there are any connected player group members within 20m to assist/approve creating the group pickup point + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + GroupObject::GroupMemberVector const & groupMembers = groupObj->getGroupMembers(); + bool anyConnectedGroupMemberInRange = false; + + GroupObject::GroupMemberVector::const_iterator iterGroupMember; + for (iterGroupMember = groupMembers.begin(); iterGroupMember != groupMembers.end(); ++iterGroupMember) + { + if ((iterGroupMember->first != actor) && groupObj->isMemberPC(iterGroupMember->first) && (connectedCharacterLfgData.count(iterGroupMember->first) > 0)) + { + CreatureObject const * memberObj = dynamic_cast(ServerWorld::findObjectByNetworkId(iterGroupMember->first)); + if (memberObj) + { + Vector const memberWorldLocation = memberObj->findPosition_w(); + if (static_cast(currentWorldLocation.magnitudeBetweenSquared(memberWorldLocation)) <= ConfigServerGame::getGroupPickupPointApprovalRangeSquared()) + { + anyConnectedGroupMemberInRange = true; + break; + } + } + } + } + + // if there are no connected group members within 20m, bail + if (!anyConnectedGroupMemberInRange) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("group", "create_group_pickup_no_assistant"); + prosePackage.digitInteger = static_cast(sqrt(static_cast(ConfigServerGame::getGroupPickupPointApprovalRangeSquared()))); + + Chat::sendSystemMessage(*actorObj, prosePackage); + return; + } + + // tell other group members that the group leader has created the group pickup point; + // we need to contact all other group members, even if they are not currently connected, + // so that we can create the group pickup point waypoint for them when they reconnect + std::string const actorName = Unicode::wideToNarrow(actorObj->getAssignedObjectName()); + for (iterGroupMember = groupMembers.begin(); iterGroupMember != groupMembers.end(); ++iterGroupMember) + { + if ((iterGroupMember->first != actor) && groupObj->isMemberPC(iterGroupMember->first)) + { + char buffer[1024]; + snprintf(buffer, sizeof(buffer)-1, "%s|%d|%d|%d|%s", currentScene.c_str(), static_cast(currentWorldLocation.x), static_cast(currentWorldLocation.y), static_cast(currentWorldLocation.z), actorName.c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(iterGroupMember->first, + "C++GroupPickupPointCreated", + buffer, + 0, + false); + } + } + + // create the group pickup point + time_t const timeNow = ::time(NULL); + groupObj->setGroupPickupTimer(timeNow, timeNow + static_cast(ConfigServerGame::getGroupPickupPointTimeLimitSeconds())); + groupObj->setGroupPickupLocation(currentScene, currentWorldLocation); + + // tell group leader that the group pickup point has been created + StringId::LocUnicodeString response; + if (StringId("group", "create_group_pickup_success_leader").localize(response)) + { + ConsoleMgr::broadcastString(FormattedString<2048>().sprintf(Unicode::wideToNarrow(response).c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigServerGame::getGroupPickupPointTimeLimitSeconds())).c_str()), + clientObj); + } + + // create/update the group leader's group pickup point waypoint + Location const location(currentWorldLocation, NetworkId::cms_invalid, Location::getCrcBySceneName(currentScene)); + playerObj->createOrUpdateReusableWaypoint(location, "groupPickupWp", Unicode::narrowToWide("Group Pickup Point"), Waypoint::White); +} + +// ---------------------------------------------------------------------- + +static void commandFuncUseGroupPickup(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject * const actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!actorObj) + return; + + PlayerObject const * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); + if (!playerObj) + return; + + Client const * const clientObj = actorObj->getClient(); + if (!clientObj) + return; + + GameScriptObject * const gameScriptObject = actorObj->getScriptObject(); + if (!gameScriptObject) + return; + + bool starPortAndShuttleportOnly = false; + static Unicode::String const noCampParam = Unicode::narrowToWide("nocamp"); + if (Unicode::caseInsensitiveCompare(params, noCampParam)) + starPortAndShuttleportOnly = true; + + GroupObject * const groupObj = actorObj->getGroup(); + if (!groupObj || (groupObj->getSecondsLeftOnGroupPickup() == 0)) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_none_active")); + return; + } + + Vector const currentWorldLocation = actorObj->findPosition_w(); + std::string const currentScene = ServerWorld::getSceneId(); + if (!GroupPickupPoint::isGroupPickupAllowedAtLocation(currentScene, static_cast(currentWorldLocation.x), static_cast(currentWorldLocation.z))) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_unsupported_location")); + return; + } + + if (actorObj->getState(States::Combat)) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_in_combat")); + return; + } + + if (actorObj->isIncapacitated() || actorObj->isDead()) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_dead_or_incap")); + return; + } + + if (actorObj->getMountedCreature()) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_on_mount")); + return; + } + + // trigger script to make sure script is ok with the player traveling to the group pickup point + ScriptParams sp1; + if (gameScriptObject->trigAllScripts(Scripting::TRIG_ABOUT_TO_TRAVEL_TO_GROUP_PICKUP_POINT, sp1) != SCRIPT_CONTINUE) + return; + + // if group pickup point is in mustafar or any of the kashyyyk zones, + // check to make sure player has the required feature bits to go there + std::pair const & groupPickupLocation = groupObj->getGroupPickupLocation(); + uint32 const gameFeatureBits = clientObj->getGameFeatures(); + + if (groupPickupLocation.first.find("kashyyyk") == 0) + { + if (!((gameFeatureBits & ClientGameFeature::Episode3PreorderDownload) || (gameFeatureBits & ClientGameFeature::Episode3ExpansionRetail))) + { + sendProseMessage(*actorObj, 0, StringId("travel", "kashyyyk_unauthorized")); + return; + } + } + else if (groupPickupLocation.first == "mustafar") + { + if (!((gameFeatureBits & ClientGameFeature::TrialsOfObiwanPreorder) || (gameFeatureBits & ClientGameFeature::TrialsOfObiwanRetail))) + { + sendProseMessage(*actorObj, 0, StringId("travel", "mustafar_unauthorized")); + return; + } + } + + // determine cost, and make sure player has enough credits + int totalCost; + if (!GroupPickupPoint::getGroupPickupTravelCost(currentScene, groupPickupLocation.first, totalCost) || (totalCost <= 0)) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_determine_cost")); + return; + } + + int const bankBalance = actorObj->getBankBalance(); + int const cashBalance = actorObj->getCashBalance(); + + if ((bankBalance + cashBalance) < totalCost) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("group", "use_group_pickup_not_enough_credits"); + prosePackage.digitInteger = totalCost; + + Chat::sendSystemMessage(*actorObj, prosePackage); + return; + } + + // find the travel point (starport, shuttleport, camp with shuttle beacon) + // nearest to the group pickup point + + // get the list of cities the player is currently banned from + std::vector cityBanList; + DynamicVariableList const & objvars = actorObj->getObjVars(); + if (objvars.hasItem("city.banlist") && (objvars.getType("city.banlist") == DynamicVariable::INT_ARRAY)) + IGNORE_RETURN(objvars.getItem("city.banlist", cityBanList)); + + std::string sceneIdOfNearestTravelPoint = groupPickupLocation.first; + TravelPoint const * nearestTravelPoint = GroupHelpers::getNearestTravelPoint(groupPickupLocation.first, groupPickupLocation.second, cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); + + // if no nearest travel point found, and the pickup point is inside one + // of the kashyyyk zones that do not have a starport, use kashyyyk_main + // as the pickup point planet and find the nearest travel point there, + // and that should return at least the kachirho starport + // *****OR***** + // if nearest travel point is found inside any kashyyyk zone other than kashyyyk_main + // and the player is not already in that respective zone, don't allow them to travel + // there as entrance to those zones requires going through kashyyyk_main first, so + // find the nearest travel point in kashyyyk_main and use that as the travel point + bool findNearestTravelPointOnKashyyykMain = false; + if (!nearestTravelPoint && (groupPickupLocation.first.find("kashyyyk") == 0) && (groupPickupLocation.first != "kashyyyk_main")) + { + // if already on the kashyyyk zone where the group pickup point is, player is + // already closest to the group pickup point than any travel point on kashyyyk_main + if (currentScene == groupPickupLocation.first) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_closest_to_group_pickup_point")); + return; + } + + findNearestTravelPointOnKashyyykMain = true; + } + else if (nearestTravelPoint && (groupPickupLocation.first.find("kashyyyk") == 0) && (groupPickupLocation.first != "kashyyyk_main") && (currentScene != groupPickupLocation.first)) + { + findNearestTravelPointOnKashyyykMain = true; + } + + if (findNearestTravelPointOnKashyyykMain) + { + sceneIdOfNearestTravelPoint = "kashyyyk_main"; + + if (groupPickupLocation.first == "kashyyyk_hunting") + { + // we want to find the travel point on kashyyyk_main nearest to the entrance to kashyyyk_hunting which is at (190.0f, 20.0f, -430.0f) + nearestTravelPoint = GroupHelpers::getNearestTravelPoint(sceneIdOfNearestTravelPoint, Vector(190.0f, 20.0f, -430.0f), cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); + } + else if (groupPickupLocation.first == "kashyyyk_dead_forest") + { + // we want to find the travel point on kashyyyk_main nearest to the entrance to kashyyyk_dead_forest which is at (-745.0f, 18.0f, 256.0f) + nearestTravelPoint = GroupHelpers::getNearestTravelPoint(sceneIdOfNearestTravelPoint, Vector(-745.0f, 18.0f, 256.0f), cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); + } + else + { + // (-672.0f, 19.0f, -157.0f) is the kachirho starport + nearestTravelPoint = GroupHelpers::getNearestTravelPoint(sceneIdOfNearestTravelPoint, Vector(-672.0f, 19.0f, -157.0f), cityBanList, actorObj->getPvpFaction(), starPortAndShuttleportOnly); + } + } + + if (!nearestTravelPoint) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_find_travelpoint")); + return; + } + + // if nearest travel point and current planet is the same, and the nearest travel point to the + // group pickup point is farther away than the current location to the group pickup point, then + // fail, as there is no need to travel as the player is currently closer to the group pickup point + if ((sceneIdOfNearestTravelPoint == currentScene) && (sceneIdOfNearestTravelPoint == groupPickupLocation.first) && (groupPickupLocation.second.magnitudeBetweenSquared(nearestTravelPoint->getPosition_w()) > groupPickupLocation.second.magnitudeBetweenSquared(currentWorldLocation))) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_closest_to_group_pickup_point")); + return; + } + + // if the nearest travel point is a shuttleport in a player city, the city gets a share of the travel cost + int cityShareOfCost = 0; + int systemShareOfCost = totalCost; + int const cityIdAtNearestTravelPoint = CityInterface::getCityAtLocation(sceneIdOfNearestTravelPoint, static_cast(nearestTravelPoint->getPosition_w().x), static_cast(nearestTravelPoint->getPosition_w().z), 0); + NetworkId cityHallAtNearestTravelPoint; + std::string cityNameAtNearestTravelPoint; + if (cityIdAtNearestTravelPoint > 0) + { + CityInfo const & ci = CityInterface::getCityInfo(cityIdAtNearestTravelPoint); + cityHallAtNearestTravelPoint = ci.getCityHallId(); + if (cityHallAtNearestTravelPoint.isValid()) + { + cityNameAtNearestTravelPoint = ci.getCityName(); + cityShareOfCost = (totalCost * ConfigServerGame::getGroupPickupTravelPlayerCityPercent()) / 100; + systemShareOfCost = totalCost - cityShareOfCost; + } + } + + // if player doesn't have enough money in bank, transfer from cash into back to make up the difference + if (bankBalance < totalCost) + { + if (!actorObj->depositCashToBank(totalCost - bankBalance)) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_move_cash_to_bank")); + return; + } + } + + // transfer the total travel cost from the player + if (!actorObj->transferBankCreditsTo("GroupPickupPointTravel", totalCost)) + { + sendProseMessage(*actorObj, 0, StringId("group", "use_group_pickup_internal_error_cannot_transfer_payment_from_bank")); + return; + } + + // tell player his credits have been deducted + ProsePackage prosePackage; + prosePackage.stringId = StringId("group", "use_group_pickup_credits_deducted"); + prosePackage.digitInteger = totalCost; + + Chat::sendSystemMessage(*actorObj, prosePackage); + + // if the city gets a share of the travel cost, send message to the city hall to transfer the city's share + if (cityHallAtNearestTravelPoint.isValid() && (cityShareOfCost > 0)) + { + char buffer[64]; + snprintf(buffer, sizeof(buffer)-1, "%d", cityShareOfCost); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(cityHallAtNearestTravelPoint, + "C++CityShareGroupPickupPointTravelCost", + buffer, + 0, + false); + } + + // log the transaction + if (cityHallAtNearestTravelPoint.isValid()) + LOG("CustomerService", ("GroupPickupPointTravel:%s in group %s traveled from %s to %s for a cost of %d (%d to system, %d to %s)", playerObj->getAccountDescription().c_str(), groupObj->getNetworkId().getValueString().c_str(), currentScene.c_str(), groupPickupLocation.first.c_str(), totalCost, systemShareOfCost, cityShareOfCost, cityNameAtNearestTravelPoint.c_str())); + else + LOG("CustomerService", ("GroupPickupPointTravel:%s in group %s traveled from %s to %s for a cost of %d", playerObj->getAccountDescription().c_str(), groupObj->getNetworkId().getValueString().c_str(), currentScene.c_str(), groupPickupLocation.first.c_str(), totalCost)); + + // trigger script to teleport player to the destination travel location; + // script has various "cleanup/setup" it needs to be when the player travels + ScriptParams sp2; + sp2.addParam(sceneIdOfNearestTravelPoint.c_str()); + sp2.addParam(nearestTravelPoint->getName().c_str()); + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_TRAVEL_TO_GROUP_PICKUP_POINT, sp2)); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupPickRandomGroupMember(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + GroupObject const * const group = targetObj->getGroup(); + if (!group) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a group."), Unicode::emptyString); + return; + } + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGroupPickRandomGroupMemberCommandAllowed") && (targetObj->getObjVars().getType("timeNextGroupPickRandomGroupMemberCommandAllowed") == DynamicVariable::INT)) + { + int timeNextGroupPickRandomGroupMemberCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextGroupPickRandomGroupMemberCommandAllowed", timeNextGroupPickRandomGroupMemberCommandAllowed)) + { + if (timeNextGroupPickRandomGroupMemberCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGroupPickRandomGroupMemberCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + // handle options + static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); + uint32 socialType = 0; + + if (!params.empty()) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) + { + static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); + static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); + static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); + static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); + std::string emote; + + for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) + { + if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) + { + socialType = pointatSocialType; + } + else if (iter->find(paramsEmote1) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(7); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + else if (iter->find(paramsEmote2) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(6); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + } + } + } + + GroupObject::GroupMemberVector const & results = group->getGroupMembers(); + if (results.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No group member could be found."), Unicode::emptyString); + } + else + { + GroupObject::GroupMemberVector pcMembers; + for (GroupObject::GroupMemberVector::const_iterator iter = results.begin(); iter != results.end(); ++iter) + { + if (group->isMemberPC(iter->first)) + { + pcMembers.push_back(*iter); + } + } + + if (pcMembers.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No group member could be found."), Unicode::emptyString); + } + else + { + int const random = ::rand() % pcMembers.size(); + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Group member \"%s\" was randomly chosen.", pcMembers[random].second.c_str())), Unicode::emptyString); + + // do emote at the selected player, if requested + if (socialType > 0) + { + // if I'm the one selected, use the /pointat social to point at myself + // since other socials may not make sense when I am the target + doSocial(*targetObj, pcMembers[random].first, ((pcMembers[random].first == targetObj->getNetworkId()) ? pointatSocialType : socialType)); + } + } + } + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextGroupPickRandomGroupMemberCommandAllowed", (timeNow + 30))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGroupTextChatRoomRejoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + GroupObject const * const group = targetObj->getGroup(); + if (!group) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a group."), Unicode::emptyString); + return; + } + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGroupTextChatRoomRejoinCommandAllowed") && (targetObj->getObjVars().getType("timeNextGroupTextChatRoomRejoinCommandAllowed") == DynamicVariable::INT)) + { + int timeNextGroupTextChatRoomRejoinCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextGroupTextChatRoomRejoinCommandAllowed", timeNextGroupTextChatRoomRejoinCommandAllowed)) + { + if (timeNextGroupTextChatRoomRejoinCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGroupTextChatRoomRejoinCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Attempting to leave and rejoin the group text chat room."), Unicode::emptyString); + group->reenterGroupChatRoom(*targetObj); + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextGroupTextChatRoomRejoinCommandAllowed", (timeNow + 60))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGuildChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObj) + { + // don't allow if the actor is squelched + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); + if (!playerObj || (playerObj->getSecondsUntilUnsquelched() != 0)) + { + return; + } + + GuildInterface::sendGuildChat(*actorObj, params); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncGuildTextChatRoomRejoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + if (targetObj->getGuildId() == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a guild."), Unicode::emptyString); + return; + } + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGuildTextChatRoomRejoinCommandAllowed") && (targetObj->getObjVars().getType("timeNextGuildTextChatRoomRejoinCommandAllowed") == DynamicVariable::INT)) + { + int timeNextGuildTextChatRoomRejoinCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextGuildTextChatRoomRejoinCommandAllowed", timeNextGuildTextChatRoomRejoinCommandAllowed)) + { + if (timeNextGuildTextChatRoomRejoinCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGuildTextChatRoomRejoinCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Attempting to leave and rejoin the guild text chat room."), Unicode::emptyString); + GuildInterface::reenterGuildChatRoom(*targetObj); + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextGuildTextChatRoomRejoinCommandAllowed", (timeNow + 60))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGuildPickRandomGuildMember(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + if (targetObj->getGuildId() == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently in a guild."), Unicode::emptyString); + return; + } + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextGuildPickRandomGuildMemberCommandAllowed") && (targetObj->getObjVars().getType("timeNextGuildPickRandomGuildMemberCommandAllowed") == DynamicVariable::INT)) + { + int timeNextGuildPickRandomGuildMemberCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextGuildPickRandomGuildMemberCommandAllowed", timeNextGuildPickRandomGuildMemberCommandAllowed)) + { + if (timeNextGuildPickRandomGuildMemberCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextGuildPickRandomGuildMemberCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + // handle options + static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); + uint32 socialType = 0; + bool onlineOption = false; + + if (!params.empty()) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) + { + static Unicode::String const paramsOnline1 = Unicode::narrowToWide("-online"); + static Unicode::String const paramsOnline2 = Unicode::narrowToWide("online"); + static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); + static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); + static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); + static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); + std::string emote; + + for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) + { + if ((*iter == paramsOnline1) || (*iter == paramsOnline2)) + { + onlineOption = true; + } + else if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) + { + socialType = pointatSocialType; + } + else if (iter->find(paramsEmote1) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(7); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + else if (iter->find(paramsEmote2) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(6); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + } + } + } + + std::vector results; + GuildInterface::getGuildMemberIdsWithPermissions(targetObj->getGuildId(), GuildInterface::Member, results); + if (results.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No guild member could be found."), Unicode::emptyString); + } + else + { + std::vector resultsOnline; + if (onlineOption) + { + std::map const & connectedPlayers = ServerUniverse::getConnectedCharacterLfgData(); + for (std::vector::const_iterator iter = results.begin(); iter != results.end(); ++iter) + { + if ((*iter == targetObj->getNetworkId()) || (connectedPlayers.count(*iter) > 0)) + resultsOnline.push_back(*iter); + } + + if (resultsOnline.empty()) + resultsOnline.push_back(targetObj->getNetworkId()); + } + + NetworkId const randomMember = (onlineOption ? resultsOnline[::rand() % resultsOnline.size()] : results[::rand() % results.size()]); + GuildMemberInfo const * const gmi = GuildInterface::getGuildMemberInfo(targetObj->getGuildId(), randomMember); + if (!gmi) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No guild member could be found."), Unicode::emptyString); + } + else + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Guild member \"%s\" was randomly chosen out of %d guild members in guild %s [%s].", gmi->m_name.c_str(), results.size(), GuildInterface::getGuildName(targetObj->getGuildId()).c_str(), GuildInterface::getGuildAbbrev(targetObj->getGuildId()).c_str())), Unicode::emptyString); + + // reminder of the -online option + if (!onlineOption && (randomMember != targetObj->getNetworkId()) && (ServerUniverse::getConnectedCharacterLfgData().count(randomMember) <= 0)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Use \"/guildPickRandomGuildMember -online\" to only select online guild members."), Unicode::emptyString); + } + + // do emote at the selected player, if requested + if (socialType > 0) + { + // if I'm the one selected, use the /pointat social to point at myself + // since other socials may not make sense when I am the target + doSocial(*targetObj, randomMember, ((randomMember == targetObj->getNetworkId()) ? pointatSocialType : socialType)); + } + } + } + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextGuildPickRandomGuildMemberCommandAllowed", (timeNow + 30))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncCityChat(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject *actorObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (actorObj) + { + // don't allow if the actor is squelched + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(actorObj); + if (!playerObj || (playerObj->getSecondsUntilUnsquelched() != 0)) + { + return; + } + + CityInterface::sendCityChat(*actorObj, params); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncCityTextChatRoomRejoin(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + std::vector const & cityIds = CityInterface::getCitizenOfCityId(targetObj->getNetworkId()); + if (cityIds.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently a citizen of a player city."), Unicode::emptyString); + return; + } + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextCityTextChatRoomRejoinCommandAllowed") && (targetObj->getObjVars().getType("timeNextCityTextChatRoomRejoinCommandAllowed") == DynamicVariable::INT)) + { + int timeNextCityTextChatRoomRejoinCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextCityTextChatRoomRejoinCommandAllowed", timeNextCityTextChatRoomRejoinCommandAllowed)) + { + if (timeNextCityTextChatRoomRejoinCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextCityTextChatRoomRejoinCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Attempting to leave and rejoin the city text chat room."), Unicode::emptyString); + CityInterface::reenterCityChatRoom(*targetObj); + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextCityTextChatRoomRejoinCommandAllowed", (timeNow + 60))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncCityPickRandomCitizen(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + std::vector const & cityIds = CityInterface::getCitizenOfCityId(targetObj->getNetworkId()); + if (cityIds.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You are not currently a citizen of any city."), Unicode::emptyString); + return; + } + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextCityPickRandomCitizenCommandAllowed") && (targetObj->getObjVars().getType("timeNextCityPickRandomCitizenCommandAllowed") == DynamicVariable::INT)) + { + int timeNextCityPickRandomCitizenCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextCityPickRandomCitizenCommandAllowed", timeNextCityPickRandomCitizenCommandAllowed)) + { + if (timeNextCityPickRandomCitizenCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextCityPickRandomCitizenCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + // handle options + static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); + uint32 socialType = 0; + bool onlineOption = false; + + if (!params.empty()) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) + { + static Unicode::String const paramsOnline1 = Unicode::narrowToWide("-online"); + static Unicode::String const paramsOnline2 = Unicode::narrowToWide("online"); + static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); + static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); + static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); + static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); + std::string emote; + + for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) + { + if ((*iter == paramsOnline1) || (*iter == paramsOnline2)) + { + onlineOption = true; + } + else if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) + { + socialType = pointatSocialType; + } + else if (iter->find(paramsEmote1) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(7); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + else if (iter->find(paramsEmote2) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(6); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + } + } + } + + std::vector results; + CityInterface::getCitizenIds(cityIds[0], results); + if (results.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No citizen could be found."), Unicode::emptyString); + } + else + { + std::vector resultsOnline; + if (onlineOption) + { + std::map const & connectedPlayers = ServerUniverse::getConnectedCharacterLfgData(); + for (std::vector::const_iterator iter = results.begin(); iter != results.end(); ++iter) + { + if ((*iter == targetObj->getNetworkId()) || (connectedPlayers.count(*iter) > 0)) + resultsOnline.push_back(*iter); + } + + if (resultsOnline.empty()) + resultsOnline.push_back(targetObj->getNetworkId()); + } + + NetworkId const randomMember = (onlineOption ? resultsOnline[::rand() % resultsOnline.size()] : results[::rand() % results.size()]); + CitizenInfo const * const ci = CityInterface::getCitizenInfo(cityIds[0], randomMember); + if (!ci) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No citizen could be found."), Unicode::emptyString); + } + else + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Citizen \"%s\" was randomly chosen out of %d citizens in city %s.", ci->m_citizenName.c_str(), results.size(), CityInterface::getCityInfo(cityIds[0]).getCityName().c_str())), Unicode::emptyString); + + // reminder of the -online option + if (!onlineOption && (randomMember != targetObj->getNetworkId()) && (ServerUniverse::getConnectedCharacterLfgData().count(randomMember) <= 0)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Use \"/cityPickRandomCitizen -online\" to only select online citizens."), Unicode::emptyString); + } + + // do emote at the selected player, if requested + if (socialType > 0) + { + // if I'm the one selected, use the /pointat social to point at myself + // since other socials may not make sense when I am the target + doSocial(*targetObj, randomMember, ((randomMember == targetObj->getNetworkId()) ? pointatSocialType : socialType)); + } + } + } + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextCityPickRandomCitizenCommandAllowed", (timeNow + 30))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncShowDanceVisuals(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + bool enable = nextBoolParm(params, pos); + CreatureObject *creature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (creature) + { + IGNORE_RETURN(creature->showDanceVisuals(enable)); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncShowMusicianVisuals(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + bool enable = nextBoolParm(params, pos); + CreatureObject *creature = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (creature) + { + IGNORE_RETURN(creature->showMusicianVisuals(enable)); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncPlaceStructure (const Command& /*command*/, const NetworkId& actor, const NetworkId& /*target*/, const Unicode::String& parameters) +{ + Object* const object = NetworkIdManager::getObjectById (actor); + if (!object) + { + DEBUG_WARNING (true, ("commandFuncPlaceStructure: PB null actor\n")); + return; + } + + ServerObject* const serverObject = dynamic_cast (object); + if (!serverObject) + { + DEBUG_WARNING (true, ("commandFuncPlaceStructure: object is not a server object\n")); + return; + } + + size_t pos = 0; + const NetworkId deedNetworkId = nextOidParm (parameters, pos); + const float x = nextFloatParm (parameters, pos); + const float z = nextFloatParm (parameters, pos); + const Vector position (x, 0.f, z); + const int rotation = nextIntParm (parameters, pos); + + ScriptParams scriptParameters; + scriptParameters.addParam (actor); + scriptParameters.addParam (deedNetworkId); + scriptParameters.addParam (position); + scriptParameters.addParam (rotation); + + if (serverObject->getScriptObject ()->trigAllScripts (Scripting::TRIG_PLACE_STRUCTURE, scriptParameters) != SCRIPT_CONTINUE) + DEBUG_REPORT_LOG (true, ("commandFuncPlaceStructure: did not return SCRIPT_CONTINUE\n")); +} + +// ---------------------------------------------------------------------- +/** + * Change the posture of the player to sitting. + * + * Broadcast the request to sit on a chair. + */ + +static void commandFuncSitServer(const Command& /*command*/, const NetworkId& actorId, const NetworkId& /* targetId */, const Unicode::String& parameters) +{ + // The command handler only runs on the authoratative server for the actor, + // so it should be fine to directly grab the CreatureController from the actor. + + //-- Get the actor object. + Object *const actorObject = NetworkIdManager::getObjectById(actorId); + if (!actorObject) + { + DEBUG_WARNING(true, ("commandFuncPostureSit: failed to lookup Object from actorId network id [%s], aborting sit request.\n", actorId.getValueString().c_str())); + return; + } + + CreatureObject *const creatureActorObject = CreatureObject::asCreatureObject(actorObject); + if (!creatureActorObject) + { + DEBUG_WARNING(true, ("commandFuncPostureSit: Object [%s] is not a creature, aborting sit request.\n", actorId.getValueString().c_str())); + return; + } + + //-- Do not let a player sit on the ground in water. (Sitting on a chair in water is okay, but that implies a designer stuck a chair in water). + bool const sittingOnChair = !parameters.empty(); + NetworkId chairCellId; + Vector chairPosition_p; + + if (sittingOnChair) + { + //-- Pull the chair cell id and position out of the parameters string. + std::string const narrowParameters = Unicode::wideToNarrow(parameters); + + std::string::size_type const lastCommaIndex = narrowParameters.find_last_of(','); + + std::string const chairCellIdString(narrowParameters, lastCommaIndex + 1); + std::string const chairPosition_pString(narrowParameters, 0, lastCommaIndex); + + //-- Get chair position. Abort command if cannot scan vector position from string. + int const scanCount = sscanf(chairPosition_pString.c_str(), "%g,%g,%g", &chairPosition_p.x, &chairPosition_p.y, &chairPosition_p.z); + if (scanCount != 3) + { + DEBUG_WARNING(true, ("commandFuncPostureSit: sitting on chair but chair parameter [%s] was malformed: couldn't be converted to parent x,y,z.", Unicode::wideToNarrow(parameters).c_str())); + return; + } + + chairCellId = NetworkId(chairCellIdString); + } + + if (!sittingOnChair) + { + // Trying to sit on the ground. + const TerrainObject* const terrainObject = TerrainObject::getConstInstance(); + const CollisionProperty* const collisionProperty = actorObject->getCollisionProperty (); + const bool isOnSolidFloor = collisionProperty && collisionProperty->getFootprint() && collisionProperty->getFootprint()->isOnSolidFloor(); + + Vector normal = Vector::unitY; + if (terrainObject && actorObject->isInWorldCell() && !isOnSolidFloor) + { + const Vector position = actorObject->getPosition_w (); + + float terrainHeight; + if (terrainObject->getHeight(position, terrainHeight, normal)) + { + //-- see if the object is swimming + float waterHeight; + if (terrainObject->getWaterHeight(position, waterHeight)) + { + if (waterHeight >terrainHeight) + { + // Client is in the water, abort the command. + Chat::sendSystemMessage (*creatureActorObject, SharedStringIds::no_sitting_in_water, Unicode::emptyString); + return; + } + } + } + } + } + + //-- Get the controller. + Controller *const controller = actorObject->getController(); + if (!controller) + { + DEBUG_WARNING(true, ("commandFuncPostureSit: object [%s] has no controller, aborting sit request.\n", actorId.getValueString().c_str())); + return; + } + + //-- Send the SitOnObject controller message to all clients. + if (!sittingOnChair) + { + //-- Just tell the client to change to the sitting posture immediately. + const_cast(creatureActorObject)->setPosture(Postures::Sitting, true); + } + else + { + //-- Send a SitOnObject message with the chair coordinates. + const_cast(creatureActorObject)->sitOnObject(chairCellId, chairPosition_p); + } + +} + +// ---------------------------------------------------------------------- + +static void commandFuncGetAttributes(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const & params) +{ + size_t curpos = 0; + int const clientRevision = nextIntParm(params, curpos); + TaskGetAttributes * const task = new TaskGetAttributes(actor, target, clientRevision); + NonCriticalTaskQueue::getInstance().addTask(task); +} + +// ---------------------------------------------------------------------- + +static void commandFuncGetAttributesBatch(Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const & params) +{ + size_t curpos = 0; + NetworkId obj = nextOidParm(params, curpos); + while(obj != NetworkId::cms_invalid) + { + int const clientRevision = nextIntParm(params, curpos); + TaskGetAttributes * const task = new TaskGetAttributes(actor, obj, clientRevision); + NonCriticalTaskQueue::getInstance().addTask(task); + obj = nextOidParm(params, curpos); + } +} + +// ---------------------------------------------------------------------- + +static std::string underscoreToSpace (const std::string& source) +{ + std::string result = source; + std::replace (result.begin (), result.end (), '_', ' '); + + return result; +} + +// ---------------------------------------------------------------------- + +static void commandFuncPurchaseTicket (const Command& /*command*/, const NetworkId& actor, const NetworkId& /*target*/, const Unicode::String& parameters) +{ + ServerObject* const serverObject = ServerObject::getServerObject(actor); + if (!serverObject) + { + DEBUG_WARNING (true, ("commandFuncPurchaseTicket: object is not a server object")); + return; + } + + size_t pos = 0; + const Unicode::String planetName1 = Unicode::narrowToWide (nextStringParm (parameters, pos)); + const Unicode::String travelPoint1 = Unicode::narrowToWide (underscoreToSpace (nextStringParm (parameters, pos))); + const Unicode::String planetName2 = Unicode::narrowToWide (nextStringParm (parameters, pos)); + const Unicode::String travelPoint2 = Unicode::narrowToWide (underscoreToSpace (nextStringParm (parameters, pos))); + const bool roundTrip = nextBoolParm (parameters, pos); + const bool instantTravel = nextBoolParm (parameters, pos); + + ScriptParams scriptParameters; + scriptParameters.addParam (actor); + scriptParameters.addParam (planetName1); + scriptParameters.addParam (travelPoint1); + scriptParameters.addParam (planetName2); + scriptParameters.addParam (travelPoint2); + scriptParameters.addParam (roundTrip); + + Scripting::TrigId id = instantTravel ? Scripting::TRIG_PURCHASE_TICKET_INSTANT_TRAVEL : Scripting::TRIG_PURCHASE_TICKET; + + if (serverObject->getScriptObject ()->trigAllScripts (id, scriptParameters) != SCRIPT_CONTINUE) + DEBUG_REPORT_LOG (true, ("commandFuncPurchaseTicket: did not return SCRIPT_CONTINUE\n")); +} + +//---------------------------------------------------------------------- + +static void commandFuncRequestResourceWeights(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncRequestResourceWeights: PB null actor")); + return; + } + + uint32 schematicCrc; + sscanf(Unicode::wideToNarrow(params).c_str(), "%lu", &schematicCrc); + DraftSchematicObject::requestResourceWeights(*creature, schematicCrc); +} + +//---------------------------------------------------------------------- + +static void commandFuncRequestResourceWeightsBatch(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = dynamic_cast(NetworkIdManager::getObjectById (actor)); + if (creature == NULL) + { + WARNING (true, ("commandFuncRequestResourceWeightsBatch: PB null actor")); + return; + } + + int schematicCrc; + + size_t curpos = 0; + schematicCrc = nextIntParm(params, curpos); + while(schematicCrc != -1) + { + DraftSchematicObject::requestResourceWeights(*creature, static_cast(schematicCrc)); + schematicCrc = nextIntParm(params, curpos); + } +} + +//---------------------------------------------------------------------- + +static void commandFuncRequestDraftSlots (const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncRequestDraftSlots: PB null actor")); + return; + } + + PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncRequestDraftSlots: no player object for actor ""%s", actor.getValueString().c_str())); + return; + } + + uint32 serverCrc, sharedCrc; + sscanf(Unicode::wideToNarrow(params).c_str(), "%lu %lu", &serverCrc, &sharedCrc); + + MessageQueueDraftSlotsQueryResponse * const message = new MessageQueueDraftSlotsQueryResponse(std::make_pair(serverCrc, sharedCrc)); + if (!player->requestDraftSlots(serverCrc, NULL, message)) + { + WARNING (true, ("commandFuncRequestDraftSlots failed to request draft slots for %u", serverCrc)); + delete message; + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestDraftSlotsBatch (const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncRequestDraftSlotsBatch: PB null actor")); + return; + } + + PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncRequestDraftSlotsBatch: no player object for actor ""%s", actor.getValueString().c_str())); + return; + } + + uint32 uServerCrc = 0; + uint32 uSharedCrc = 0; + size_t curpos = 0; + + std::string serverCrcString = nextStringParm(params, curpos); + if(serverCrcString.empty()) + return; + sscanf(serverCrcString.c_str(), "%lu", &uServerCrc); + std::string sharedCrcString = nextStringParm(params, curpos); + if(sharedCrcString.empty()) + return; + sscanf(sharedCrcString.c_str(), "%lu", &uSharedCrc); + + bool done = false; + while(uServerCrc != 0 && uSharedCrc != 0 && !done) + { + MessageQueueDraftSlotsQueryResponse * const message = new MessageQueueDraftSlotsQueryResponse(std::make_pair(uServerCrc, uSharedCrc)); + if (!player->requestDraftSlots(uServerCrc, NULL, message)) + { + WARNING (true, ("commandFuncRequestDraftSlotsBatch failed to request draft slots for %lu", uServerCrc)); + delete message; + } + serverCrcString = nextStringParm(params, curpos); + if(serverCrcString.empty()) + done = true; + sscanf(serverCrcString.c_str(), "%lu", &uServerCrc); + sharedCrcString = nextStringParm(params, curpos); + if(sharedCrcString.empty()) + done = true; + sscanf(sharedCrcString.c_str(), "%lu", &uSharedCrc); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestManfSchematicSlots (const Command& , const NetworkId& actor, const NetworkId& target, const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncRequestDraftSlots: PB null actor")); + return; + } + + const ManufactureSchematicObject * schematic = dynamic_cast< + const ManufactureSchematicObject *>(NetworkIdManager::getObjectById(target)); + if (schematic != NULL) + { + schematic->requestSlots(*creature); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestCraftingSession (const Command& , const NetworkId& actor, const NetworkId& target, const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncRequestCraftingSession: PB null actor")); + return; + } + + PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncRequestCraftingSession: no player object for actor " + "%s", actor.getValueString().c_str())); + return; + } + + if (!player->requestCraftingSession(target)) + { + // get the station we are attempting to use. + TangibleObject const * const craftingObject = TangibleObject::getTangibleObject(target); + + // 1 means this request was made on a crafting station versus a crafting tool. + uint8 const sequenceId = static_cast(craftingObject && craftingObject->isCraftingStation() ? 1 : 0); + + MessageQueueGenericIntResponse * response = new MessageQueueGenericIntResponse ( + CM_requestCraftingSession, false, sequenceId); + creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestCraftingSessionFail(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject* const creatureActor = CreatureObject::getCreatureObject(actor); + if (creatureActor) + { + creatureActor->getController()->appendMessage( + CM_craftingResult, + 0.0f, + new MessageQueueGenericIntResponse(CM_requestCraftingSession, false, 0), + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSelectDraftSchematic (const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncSelectDraftSchematic: PB null actor")); + return; + } + + PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncSelectDraftSchematic: no player object for actor " + "%s", actor.getValueString().c_str())); + return; + } + + int schematicIndex = atoi(Unicode::wideToNarrow(params).c_str()); + + player->selectDraftSchematic(schematicIndex); +} + +// ---------------------------------------------------------------------- + +static void commandFuncNextCraftingStage(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncNextCraftingStage: PB null actor")); + return; + } + + PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncNextCraftingStage: no player object for actor " + "%s", actor.getValueString().c_str())); + return; + } + + uint8 sequenceId = static_cast(atoi(Unicode::wideToNarrow(params).c_str())); + int result = player->goToNextCraftingStage(); + + MessageQueueGenericIntResponse * response = new MessageQueueGenericIntResponse ( + CM_nextCraftingStage, result, sequenceId); + creature->getController()->appendMessage(CM_nextCraftingStageResult, 0.0f, response, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); +} + +// ---------------------------------------------------------------------- + +static void commandFuncCreatePrototype(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncCreatePrototype: PB null actor")); + return; + } + + PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncCreatePrototype: no player object for actor %s", actor.getValueString().c_str())); + return; + } + + size_t pos = 0; + const uint8 sequenceId = static_cast(nextIntParm(params, pos)); + bool realPrototype = nextBoolParm(params, pos); + + const bool result = player->createPrototype(realPrototype); + + MessageQueueGenericIntResponse * const response = new MessageQueueGenericIntResponse (CM_createPrototype, result, sequenceId); + creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + + if (!result) + player->stopCrafting(false); +} + +// ---------------------------------------------------------------------- + +static void commandFuncCreateManfSchematic(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncCreateManfSchematic: PB null actor")); + return; + } + + PlayerObject * const player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncCreateManfSchematic: no player object for actor %s", actor.getValueString().c_str())); + return; + } + + const uint8 sequenceId = static_cast(atoi(Unicode::wideToNarrow(params).c_str())); + + const bool result = player->createManufacturingSchematic(); + + MessageQueueGenericIntResponse * const response = new MessageQueueGenericIntResponse (CM_createManfSchematic, result, sequenceId); + creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + + if (!result) + player->stopCrafting(false); +} + +// ---------------------------------------------------------------------- + +static void commandFuncCancelCraftingSession(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncCancelCraftingSession: PB null actor")); + return; + } + + PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncCancelCraftingSession: no player object for actor " + "%s", actor.getValueString().c_str())); + return; + } + + player->stopCrafting(true); +} + +// ---------------------------------------------------------------------- + +static void commandFuncStopCraftingSession(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncStopCraftingSession: PB null actor")); + return; + } + + PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncStopCraftingSession: no player object for actor " + "%s", actor.getValueString().c_str())); + return; + } + + player->stopCrafting(true); +} + +// ---------------------------------------------------------------------- + +static void commandFuncRestartCraftingSession(const Command& , const NetworkId& actor, const NetworkId& , const Unicode::String& params) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncRestartCraftingSession: PB null actor")); + return; + } + + PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); + if (player == NULL) + { + WARNING (true, ("commandFuncRestartCraftingSession: no player object for actor " + "%s", actor.getValueString().c_str())); + return; + } + + uint8 sequenceId = static_cast(atoi(Unicode::wideToNarrow(params).c_str())); + + const bool success = player->restartCrafting(); + + MessageQueueGenericIntResponse * response = new MessageQueueGenericIntResponse ( + CM_restartCraftingSession, success, sequenceId); + creature->getController()->appendMessage(CM_craftingResult, 0.0f, response, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetMatchMakingPersonalId(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingPersonalId() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), Unicode::wideToNarrow(params).c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + MatchMakingId matchMakingId; + matchMakingId.unPackIntString(Unicode::wideToNarrow(params)); + + playerObject->setMatchMakingPersonalProfileId(matchMakingId); + + //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingPersonalId() %s %s\n", actor.getValueString().c_str(), matchMakingId.isBitSet(MatchMakingId::B_anonymous) ? "anonymous" : "searchable")); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetMatchMakingCharacterId(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingCharacterId() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), Unicode::wideToNarrow(params).c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + MatchMakingId matchMakingId; + matchMakingId.unPackIntString(Unicode::wideToNarrow(params)); + + playerObject->setMatchMakingCharacterProfileId(matchMakingId); + + //DEBUG_REPORT_LOG(true, ("commandFuncSetMatchMakingCharacterId() %s %s\n", actor.getValueString().c_str(), matchMakingId.isBitSet(MatchMakingId::B_anonymous) ? "anonymous" : "searchable")); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAddFriend(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + ServerObject * const serverObject = ServerObject::getServerObject(actor); + + if (serverObject != NULL) + { + size_t pos = 0; + std::string name(nextStringParm(params, pos)); + + if (!name.empty()) + { + std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); + + //DEBUG_REPORT_LOG(true, ("commandFuncAddFriend() %s %s %s\n", actor.getValueString().c_str(), player.c_str(), name.c_str())); + + Chat::addFriend(player, name); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRemoveFriend(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + ServerObject * const serverObject = ServerObject::getServerObject(actor); + + if (serverObject != NULL) + { + size_t pos = 0; + std::string name(nextStringParm(params, pos)); + + if (!name.empty()) + { + std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); + + //DEBUG_REPORT_LOG(true, ("commandFuncRemoveFriend() %s %s %s\n", actor.getValueString().c_str(), player.c_str(), name.c_str())); + + Chat::removeFriend(player, name); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncGetFriendList(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + ServerObject * const serverObject = ServerObject::getServerObject(actor); + + if (serverObject != NULL) + { + std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); + + //DEBUG_REPORT_LOG(true, ("commandFuncGetFriendList() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str())); + + Chat::getFriendsList(player); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncAddIgnore(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + ServerObject * const serverObject = ServerObject::getServerObject(actor); + + if (serverObject != NULL) + { + size_t pos = 0; + std::string name(nextStringParm(params, pos)); + + if (!name.empty()) + { + std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); + + //DEBUG_REPORT_LOG(true, ("commandFuncAddIgnore() %s %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str(), name.c_str())); + + Chat::addIgnore(player, name); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRemoveIgnore(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + ServerObject * const serverObject = ServerObject::getServerObject(actor); + + if (serverObject != NULL) + { + size_t pos = 0; + std::string name(nextStringParm(params, pos)); + + if (!name.empty()) + { + std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); + + //DEBUG_REPORT_LOG(true, ("commandFuncRemoveIgnore() %s %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str(), name.c_str())); + + Chat::removeIgnore(player, name); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncGetIgnoreList(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + ServerObject * const serverObject = ServerObject::getServerObject(actor); + + if (serverObject != NULL) + { + std::string player(Chat::constructChatAvatarId(*serverObject).getFullName()); + + //DEBUG_REPORT_LOG(true, ("commandFuncGetIgnoreList() %s %s\n", actor.getValueString().empty() ? "noId" : actor.getValueString().c_str(), player.c_str())); + + Chat::getIgnoreList(player); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestBiography(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const &) +{ + CreatureObject * const creatureObject = CreatureObject::getCreatureObject(actor); + + if (creatureObject != NULL) + { + BiographyManager::requestBiography(target, creatureObject); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetBiography(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const ¶ms) +{ + if (target != NetworkId::cms_invalid) + { + // get the actor + CreatureObject * const creatureActor = CreatureObject::getCreatureObject(actor); + if (!creatureActor) + { + WARNING (true, ("commandFuncSetBiography: bad actor")); + return; + } + + Client * const clientActor = creatureActor->getClient(); + if(!clientActor) + { + WARNING(true, ("no Client in commandFuncSetBiography")); + return; + } + + if(!clientActor->isGod()) + { + LOG("CustomerService", ("CheatChannel:%s attempted to set biography data on %s, but is not a God", PlayerObject::getAccountDescription(actor).c_str(), PlayerObject::getAccountDescription(target).c_str())); + } + else + { + BiographyManager::setBiography(target, params); + } + } + else + { + BiographyManager::setBiography(actor, params); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestCharacterSheetInfo(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + const CreatureObject* const creatureActor = CreatureObject::getCreatureObject(actor); + if (creatureActor == NULL) + { + WARNING (true, ("commandFuncRequestCharacterSheetInfo: null actor")); + return; + } + + //TODO get the born and played times (once they're in the DB) + int born = 0; + int played = 0; + + //get the bind location + Vector bindLoc; + std::string bindPlanet; + NetworkId bindId; + if (creatureActor->getObjVars().hasItem("bind.facility")) + { + creatureActor->getObjVars().getItem("bind.facility", bindId); + } + if(bindId != NetworkId::cms_invalid) + { + const ServerObject* const bindObject = ServerObject::getServerObject(bindId); + if (bindObject != NULL) + { + bindLoc = bindObject->getPosition_w(); + bindPlanet = bindObject->getSceneId(); + } + } + + //get the bankId + Vector bankLoc(0, 0, 0); + std::string bankPlanet; + if (creatureActor->getObjVars().hasItem("banking_bankid")) + { + creatureActor->getObjVars().getItem("banking_bankid", bankPlanet); + } + + // get the city(ies) this character is a citizen of + NetworkId cityHallOfMayorCity; + std::string citizensOf; + std::vector const & cityId = CityInterface::getCitizenOfCityId(creatureActor->getNetworkId()); + if (!cityId.empty()) + { + std::string cityName; + for (std::vector::const_iterator iterCity = cityId.begin(); iterCity != cityId.end(); ++iterCity) + { + CityInfo const & cityInfo = CityInterface::getCityInfo(*iterCity); + cityName = cityInfo.getCityName(); + if (cityName.empty()) + continue; + + if (!citizensOf.empty()) + citizensOf += ","; + + if (creatureActor->getNetworkId() == cityInfo.getLeaderId()) + { + citizensOf += "*"; + cityHallOfMayorCity = cityInfo.getCityHallId(); + } + + citizensOf += cityName; + } + } + + // get the residence location + Vector resLoc; + std::string resPlanet; + NetworkId houseNetworkId = creatureActor->getHouse(); + + // mayor has city hall as his residence + if (!houseNetworkId.isValid() && cityHallOfMayorCity.isValid()) + houseNetworkId = cityHallOfMayorCity; + + const ServerObject* const resObject = ServerObject::getServerObject(houseNetworkId); + if (resObject != NULL) + { + resLoc = resObject->getPosition_w(); + resPlanet = ServerWorld::getSceneId(); + } + else if (houseNetworkId.isValid() && MessageToQueue::isInstalled()) + { + // the residence may not be on this game server, try to find it + MessageToQueue::getInstance().sendMessageToC(houseNetworkId, + "C++CharacterSheetInfoResidenceLocationReq", + creatureActor->getNetworkId().getValueString(), + 0, + false); + } + + //get the spouse's name + Unicode::String spouseName = Unicode::emptyString; + if (creatureActor->getObjVars().hasItem("marriage.spouseName")) + { + creatureActor->getObjVars().getItem("marriage.spouseName", spouseName); + } + + //get the number of used lots + int lots = creatureActor->getMaxNumberOfLots(); + + PlayerObject const * const player = PlayerCreatureController::getPlayerObject(creatureActor); + if(player) + { + int lotsUsed = player->getAccountNumLots(); + lots -= lotsUsed; + } + + //build, send the message back to the client + CharacterSheetResponseMessage const chrm(born, played, bindLoc, bindPlanet, bankLoc, bankPlanet, resLoc, resPlanet, citizensOf, spouseName, lots); + Client * const client = creatureActor->getClient(); + if (client) + client->send(chrm, true); +} + +// ---------------------------------------------------------------------- + +static void commandFuncRequestCharacterMatch(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncRequestCharacterMatch() - networkId: %s params: %s\n", actor.getValueString().c_str(), Unicode::wideToNarrow(params).c_str())); + + // Build the new id + + MatchMakingCharacterPreferenceId matchMakingCharacterPreferenceId; + + matchMakingCharacterPreferenceId.unPackString(Unicode::wideToNarrow(params)); + + CharacterMatchManager::requestMatch(actor, matchMakingCharacterPreferenceId); +} + +// ---------------------------------------------------------------------- + +static void commandFuncExtractObject(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + CreatureObject* const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncExtractObject: PB null actor")); + return; + } + + if (creature->getInventory() == NULL) + { + WARNING (true, ("commandFuncExtractObject: actor %s has no inventory", + actor.getValueString().c_str())); + return; + } + + FactoryObject* const factory = dynamic_cast(NetworkIdManager::getObjectById (target)); + if (factory == NULL) + { + WARNING (true, ("commandFuncExtractObject: PB null target")); + return; + } + + Container::ContainerErrorCode error; + if (creature->canManipulateObject(*factory, false, true, true, 10.0f, error)) + factory->removeObject(*creature->getInventory()); + else + ContainerInterface::sendContainerMessageToClient(*creature, error, factory); +} + +// ---------------------------------------------------------------------- + +static void commandFuncRevokeSkill(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + CreatureObject * const creature = CreatureObject::getCreatureObject(actor); + if (creature == NULL) + { + WARNING (true, ("commandFuncRevokeSkill: PB null actor")); + return; + } + + size_t pos = 0; + std::string skillName = nextStringParm(params, pos); + const SkillObject * skill = SkillManager::getInstance ().getSkill (skillName); + if (skill == NULL) + { + WARNING (true, ("commandFuncRevokeSkill: can't revoke bad skill")); + } + else + { + LOG("CustomerService", ("Skill: God (via cmdfunc) has requested the revocation of skill %s from character %s.", + skillName.c_str(), creature->getNetworkId().getValueString().c_str())); + creature->revokeSkill (*skill); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetCurrentSkillTitle(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + CreatureObject * const creatureObject = CreatureObject::getCreatureObject(actor); + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + + if (playerObject != NULL) + { + size_t pos = 0; + std::string const &title = nextStringParm(params, pos); + + if (title.empty()) + { + playerObject->setTitle(title); + } + else + { + bool validTitle = false; + + // citizenship title is always valid + if (title == "citizenship") + { + playerObject->setTitle(title); + validTitle = true; + } + + // see if it's a collection slot title and the character actually has the collection slot + if (!validTitle) + { + CollectionsDataTable::CollectionInfoSlot const * const slot = CollectionsDataTable::isASlotTitle(title); + + if (slot && playerObject->hasCompletedCollectionSlot(*slot)) + { + playerObject->setTitle(title); + validTitle = true; + } + } + + // see if it's a collection title and the character actually has the collection + if (!validTitle) + { + CollectionsDataTable::CollectionInfoCollection const * const collection = CollectionsDataTable::isACollectionTitle(title); + + if (collection && playerObject->hasCompletedCollection(collection->name)) + { + playerObject->setTitle(title); + validTitle = true; + } + } + + // see if it's a collection page title and the character actually has the collection page + if (!validTitle) + { + CollectionsDataTable::CollectionInfoPage const * const page = CollectionsDataTable::isAPageTitle(title); + + if (page && playerObject->hasCompletedCollectionPage(page->name)) + { + playerObject->setTitle(title); + validTitle = true; + } + } + + // see if it's a guild member rank title and the character actually has the guild member rank + if (!validTitle) + { + GuildRankDataTable::GuildRank const * const guildRankInfo = GuildRankDataTable::isARankTitle(title); + + if (guildRankInfo && playerObject->getGuildRank().testBit(guildRankInfo->slotId)) + { + playerObject->setTitle(title); + validTitle = true; + } + } + + // see if it's a citizen rank title and the character actually has the citizen rank + if (!validTitle) + { + CitizenRankDataTable::CitizenRank const * const citizenRankInfo = CitizenRankDataTable::isARankTitle(title); + + if (citizenRankInfo && playerObject->getCitizenRank().testBit(citizenRankInfo->slotId)) + { + playerObject->setTitle(title); + validTitle = true; + } + } + + // see if it's a guild GCW Region Defender title + if (!validTitle) + { + if (title == "guild_gcw_region_defender") + { + std::pair > const & guildGcwDefenderRegionInfo = playerObject->getGuildGcwDefenderRegionInfo(); + if (!guildGcwDefenderRegionInfo.first.empty() && guildGcwDefenderRegionInfo.second.second) + { + playerObject->setTitle(title); + validTitle = true; + } + } + } + + // see if it's a city GCW Region Defender title + if (!validTitle) + { + if (title == "city_gcw_region_defender") + { + std::pair > const & cityGcwDefenderRegionInfo = playerObject->getCityGcwDefenderRegionInfo(); + if (!cityGcwDefenderRegionInfo.first.empty() && cityGcwDefenderRegionInfo.second.second) + { + playerObject->setTitle(title); + validTitle = true; + } + } + } + + // Run through all the skills for this player and make sure + // this is a valid skill title for them + if (!validTitle) + { + CreatureObject::SkillList::const_iterator iterSkillList = creatureObject->getSkillList().begin(); + for (; iterSkillList != creatureObject->getSkillList().end(); ++iterSkillList) + { + SkillObject const *skillObject = (*iterSkillList); + + if ( (skillObject != NULL) + && skillObject->isTitle() + && (skillObject->getSkillName() == title)) + { + playerObject->setTitle(title); + validTitle = true; + break; + } + } + } + + if (!validTitle) + { + playerObject->setTitle(std::string()); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncRepair(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + CreatureObject* const creature = dynamic_cast(NetworkIdManager::getObjectById (actor)); + if (creature == NULL) + { + WARNING (true, ("commandFuncRepair: PB null actor")); + return; + } + + TangibleObject* const object = dynamic_cast(NetworkIdManager::getObjectById (target)); + if (object == NULL) + { + WARNING (true, ("commandFuncRepair: PB null target")); + return; + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleSearchableByCtsSourceGalaxy(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncToggleSearchableByCtsSourceGalaxy() - networkId: %s\n", actor.getValueString().c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleSearchableByCtsSourceGalaxy(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleDisplayLocationInSearchResults(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncToggleDisplayLocationInSearchResults() - networkId: %s\n", actor.getValueString().c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleDisplayLocationInSearchResults(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleAnonymous(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncToggleAnonymous() - networkId: %s\n", actor.getValueString().c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleAnonymous(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleHelper(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncToggleHelper() - networkId: %s\n", actor.getValueString().c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleHelper(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleRolePlay(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncToggleRolePlay() - networkId: %s\n", actor.getValueString().c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleRolePlay(); + } +} + + +// ---------------------------------------------------------------------- + +static void commandFuncToggleOutOfCharacter(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleOutOfCharacter(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleLookingForWork(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleLookingForWork(); + } +} + + +// ---------------------------------------------------------------------- + +static void commandFuncToggleLookingForGroup(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncToggleLookingForGroup() - networkId: %s\n", actor.getValueString().c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleLookingForGroup(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleAwayFromKeyBoard(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + //DEBUG_REPORT_LOG(true, ("commandFuncToggleAwayFromKeyBoard() - networkId: %s\n", actor.getValueString().c_str())); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleAwayFromKeyBoard(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncToggleDisplayingFactionRank(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(CreatureObject::getCreatureObject(actor)); + + if (playerObject != NULL) + { + playerObject->toggleDisplayingFactionRank(); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncReport(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject const * const reportingCreatureObject = CreatureObject::getCreatureObject(actor); + + if (reportingCreatureObject != NULL) + { + if (ReportManager::isThrottled(actor)) + { + // Player is trying to report too quickly after a previous report + + ProsePackage prosePackage; + prosePackage.stringId = StringId("system_msg", "report_wait"); + prosePackage.digitInteger = ReportManager::getThrottleTimeRemaining(actor); + + Chat::sendSystemMessage(*reportingCreatureObject, prosePackage); + } + else + { + Unicode::String harassingPlayerName; + //size_t curpos = 0; + //size_t endpos = 0; + + // If this player is on this galaxy, we can get the network id + + //Vivox phase 1 temporary solution: the client is appending + //its connection information to the report command, this should + //come from VChat really + Unicode::String const delimiter = Unicode::narrowToWide("|"); + + Unicode::UnicodeStringVector tokens; + if(Unicode::tokenize(params, tokens, &delimiter) && tokens.size() > 1) + { + harassingPlayerName = tokens[0]; + Unicode::String rest; + uint32 numTokens = tokens.size(); + for(uint32 i = 1; i < numTokens; ++i) + { + if(i != 1) + { + rest.append(delimiter); + } + rest.append(tokens[i]); + } + + NetworkId const harassingPlayerNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(harassingPlayerName))); + + ReportManager::addReport(reportingCreatureObject->getAssignedObjectFirstName(), actor, harassingPlayerName, harassingPlayerNetworkId, std::string("Report"), rest); + } + else + { + // No harassing player specified + + Chat::sendSystemMessage(*reportingCreatureObject, StringId("system_msg", "report_no_name"), Unicode::emptyString); + } + + + //if (Unicode::getFirstToken(name, curpos, endpos, harassingPlayerName)) + //{ + // NetworkId const harassingPlayerNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(harassingPlayerName))); + + // ReportManager::addReport(reportingCreatureObject->getAssignedObjectFirstName(), actor, harassingPlayerName, harassingPlayerNetworkId, std::string("Report")); + //} + //else + //{ + // // No harassing player specified + + // Chat::sendSystemMessage(*reportingCreatureObject, StringId("system_msg", "report_no_name"), Unicode::emptyString); + //} + } + } + else + { + DEBUG_WARNING(true, ("A non-player is trying to report a harassment. oid: %s", actor.getValueString().c_str())); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncNpcConversationStart(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + ServerObject * const actorObject = safe_cast(NetworkIdManager::getObjectById(actor)); + CreatureObject * const player = actorObject != NULL ? actorObject->asCreatureObject() : NULL; + if (player == NULL) + { + DEBUG_WARNING(true, ("commandFuncNpcConversationStart: couldn't find actor")); + return; + } + + ServerObject * const npcObject = safe_cast(NetworkIdManager::getObjectById(target)); + TangibleObject * const npc = npcObject != NULL ? npcObject->asTangibleObject() : NULL; + if (npc == NULL) + { + DEBUG_WARNING(true, ("commandFuncNpcConversationStart: Couldn't find npc to converse with")); + return; + } + + if (!ServerWorld::isSpaceScene()) + { + Container::ContainerErrorCode error = Container::CEC_Success; + if (!player->canManipulateObject(*npc, false, false, false, 30.0f, error)) + { + DEBUG_WARNING(true, ("commandFuncNpcConversationStart (ground): failed canManipulateObject check")); + return; + } + } + + std::string const & realParams = Unicode::wideToNarrow(params); + if (realParams.size() < 2) + { + DEBUG_WARNING(true, ("commandFuncNpcConversationStart: bad params %s", realParams.c_str())); + return; + } + + const char * const conversationName = &realParams[2]; + NpcConversationData::ConversationStarter const starter = static_cast(atoi(realParams.c_str())); + + player->startNpcConversation (*npc, conversationName, starter, 0); +} + +//---------------------------------------------------------------------- + +static void commandFuncNpcConversationStop(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + ServerObject * const actorObject = safe_cast(NetworkIdManager::getObjectById(actor)); + TangibleObject * const player = actorObject != NULL ? actorObject->asTangibleObject(): NULL; + if (player == NULL) + { + DEBUG_WARNING(true, ("commandFuncNpcConversationStop: couldn't find actor")); + return; + } + player->endNpcConversation(); +} + +//---------------------------------------------------------------------- + +static void commandFuncNpcConversationSelect(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + Object * const actorObject = NetworkIdManager::getObjectById(actor); + CreatureObject * const player = dynamic_cast(actorObject); + if (player == NULL) + { + DEBUG_WARNING(true, ("commandFuncNpcConversationStop: couldn't find actor")); + return; + } + + std::string realParams(Unicode::wideToNarrow(params)); + int selection = atoi(realParams.c_str()); + player->respondToNpc(selection); +} + +//---------------------------------------------------------------------- + +static void commandFuncServerDestroyObject (Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + CreatureObject * const player = dynamic_cast (NetworkIdManager::getObjectById (actor)); + if (player == NULL) + { + DEBUG_WARNING (true, ("commandFuncServerDestroyObject: couldn't find actor")); + return; + } + + ServerObject * const targetObject = safe_cast(NetworkIdManager::getObjectById (target)); + if (!targetObject) + { + PlayerObject * p = PlayerCreatureController::getPlayerObject(player); + if(p) + { + p->destroyWaypoint(target); + return; + } + else + { + DEBUG_WARNING (true, ("commandFuncServerDestroyObject: couldn't find target")); + return; + } + } + + ServerObject const * const topMost = getFirstParentInWorldOrPlayer(targetObject); + if (!topMost || topMost->getNetworkId() != actor) + { + DEBUG_WARNING (true, ("player tried to delete something not in their inventory")); + return; + } + + ProsePackage pp; + const bool sendResponse = !params.empty (); + + int const got = targetObject->getGameObjectType (); + if (sendResponse) + { + ProsePackageManagerServer::createSimpleProsePackage (*targetObject, SharedStringIds::rsp_object_deleted_prose, pp); + pp.other.stringId = GameObjectTypes::getStringId (got); + } + + // Cannot destroy an empty ship pcd while contained by a ship you own + if (got == SharedObjectTemplate::GOT_data_ship_control_device) + { + ShipObject const * const containingShip = ShipObject::getContainingShipObject(player); + if (containingShip && containingShip->getOwnerId() == actor && containingShip->getControlDevice() == targetObject) + { + if (sendResponse) + Chat::sendSystemMessage(*player, SharedStringIds::no_destroy_in_flight, Unicode::emptyString); + return; + } + } + + // Cannot destroy a tcg card that is in the middle of the redemption process + if (!VeteranRewardManager::checkForTcgRedemptionInProgress(*targetObject)) + return; + + // Cannot destroy a reward item that is in the middle of the trade in process + if (!VeteranRewardManager::checkForTradeInInProgress(*targetObject)) + return; + + Object const * const currentContainer = ContainerInterface::getContainedByObject(*targetObject); + if(currentContainer && currentContainer->asServerObject() && ( currentContainer->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron || currentContainer->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron_recipe ) ) + { + // Give the player a warning here? + return; + } + + if (targetObject->permanentlyDestroy(DeleteReasons::Player)) + { + LOG("CustomerService", ("Deletion:%s is deleting object %s", PlayerObject::getAccountDescription(actor).c_str(), ServerObject::getLogDescription(targetObject).c_str())); + if (sendResponse) + Chat::sendSystemMessage (*player, pp); + } + else + WARNING (true, ("commandFuncServerDestroyObject: Error encountered while deleting object %s", target.getValueString ().c_str ())); +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetSpokenLanguage(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + Object * const object = NetworkIdManager::getObjectById(actor); + CreatureObject * const creatureObject = dynamic_cast(object); + + if (creatureObject != NULL) + { + PlayerObject *playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + + if (playerObject != NULL) + { + size_t pos = 0; + int const languageId = nextIntParm(params, pos); + std::string skillModName; + GameLanguageManager::getLanguageSpeakSkillModName(languageId, skillModName); + + // Make sure the player is setting a valid game language + + std::map >::const_iterator iterModMap = creatureObject->getModMap().find(skillModName); + + if (iterModMap != creatureObject->getModMap().end()) + { + int const baseValue = iterModMap->second.first; + int const modValue = iterModMap->second.second; + + if ((baseValue + modValue) > 0) + { + playerObject->setSpokenLanguage(languageId); + } + } + else + { + DEBUG_WARNING(true, ("Invalid game language specified: %d", languageId)); + } + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncUnstick(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + Object * const object = NetworkIdManager::getObjectById(actor); + CreatureObject * const creatureObject = dynamic_cast(object); + if (creatureObject != NULL) + { + if (!ShipObject::getContainingShipObject(creatureObject)) // no unsticking in ships + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if (playerObject) + { + Chat::sendSystemMessageSimple(*creatureObject, SharedStringIds::unstick_in_progress, NULL); + if (!playerObject->getIsUnsticking()) + { + Vector position = creatureObject->getPosition_p(); + //Send positional information with this unstick along with the message. If you change + //the format of this positional information, you must also change it in the handler in ServerObject.cpp + char buf[255]; + snprintf(buf, sizeof(buf), "%f:%f", position.x, position.z); + buf[sizeof(buf) - 1] = '\0'; + + int wait = 30; + if (creatureObject->getClient() && creatureObject->getClient()->isGodValidated()) + { + if (creatureObject->getObjVars().getItem("debugUnstickWait", wait)) + { + if (wait <= 0) + wait = 1; + } + else + { + wait = 30; + } + } + + MessageToQueue::getInstance().sendMessageToC(actor, "C++Unstick", buf, wait, false); + playerObject->setIsUnsticking(true); + } + } + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncGetAccountInfo(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if(gm) + { + const Client * gmClient = gm->getClient(); + if(gmClient) + { + bool foundAsPilot = false; + const CreatureObject * player = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!player) + { + ShipObject const * const ship = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (ship) + { + foundAsPilot = true; + player = ship->getPilot(); + } + } + std::string result; + if(player) + { + const Client * client = player->getClient(); + if(client) + { + if (foundAsPilot) + result = "Pilot Character Name : "; + else + result = "Character Name : "; + + result += Unicode::wideToNarrow(player->getAssignedObjectName()); + result += "\nAccount Name : "; + result += client->getAccountName(); + result += "\nStation Id : "; + char buf[32]; + IGNORE_RETURN(snprintf(buf, sizeof(buf)-1, "%d", client->getStationId())); + buf[sizeof(buf)-1] = '\0'; + result += buf; + result += "\nGame Features : "; + result += ClientGameFeature::getDescription(client->getGameFeatures()); + result += "\nSubscription Features : "; + uint32 const subscriptionFeatures = client->getSubscriptionFeatures(); + result += ClientSubscriptionFeature::getDescription(subscriptionFeatures); + + result += "\nAccount SWG Feature Ids: "; + std::string accountFeatureIdsString; + Client::AccountFeatureIdList const & accountFeatureIds = client->getAccountFeatureIds(); + for (Client::AccountFeatureIdList::const_iterator iterAccountFeatureIds = accountFeatureIds.begin(); iterAccountFeatureIds != accountFeatureIds.end(); ++iterAccountFeatureIds) + { + if (!accountFeatureIdsString.empty()) + accountFeatureIdsString += ", "; + + accountFeatureIdsString += FormattedString<1024>().sprintf("%lu:%d", iterAccountFeatureIds->first, iterAccountFeatureIds->second); + + if (VeteranRewardManager::isFeatureIdBlockedBySubscriptionBit(*player, iterAccountFeatureIds->first)) + accountFeatureIdsString += "*"; + } + + if (!accountFeatureIdsString.empty()) + result += accountFeatureIdsString; + + result += "\nIP Address : "; + result += client->getIpAddress(); + result += "\nGod Mode : "; + if(client->isGod()) + result += "true"; + else + result += "false"; + } + else + { + result = "Object " + target.getValueString() + " is not controlled by a player."; + } + } + else + { + result = "Object " + target.getValueString() + " is not a creature or a ship."; + } + ConGenericMessage const msg(result, 0); + gmClient->send(msg, true); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncApplyPowerup (Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const NetworkId & powerupId = target; + const NetworkId targetOfApplyId (Unicode::wideToNarrow (params)); + ServerObject * const powerup = safe_cast(NetworkIdManager::getObjectById (powerupId)); + if (powerup) + { + const ServerObject * const targetOfApply = safe_cast(NetworkIdManager::getObjectById (targetOfApplyId)); + + if (targetOfApply) + { + const int got_targetOfApply = targetOfApply->getGameObjectType (); + const int got_powerup = powerup->getGameObjectType (); + + if (GameObjectTypes::doesPowerupApply (got_powerup, got_targetOfApply)) + { + GameScriptObject * const gso = powerup->getScriptObject(); + if (gso) + { + ScriptParams scriptParams; + scriptParams.addParam (actor); + scriptParams.addParam (targetOfApplyId); + gso->trigAllScripts(Scripting::TRIG_APPLY_POWERUP, scriptParams); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncLag (Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ +#if 0 + ServerObject * a = safe_cast(NetworkIdManager::getObjectById(actor)); + ServerObject * t = safe_cast(NetworkIdManager::getObjectById(target)); + if(! t) + { + t = a; + } + if(t != 0) + { + if(t->getClient()) + { + if(a && a->getClient()) + { + GameNetworkMessage const request("LagRequest"); + t->getClient()->send(request, true); + int connectionServerLag = t->getClient()->getConnectionServerLag(); + int gameServerLag = t->getClient()->getGameServerLag(); + char lagMsg[1024]; + snprintf(lagMsg, sizeof(lagMsg), "Lag update request sent to client.\nCurrent Lag: ConnectionServer=%d, GameServer=%d\n", connectionServerLag, gameServerLag); + std::string msg(lagMsg); + ConGenericMessage const result(msg, 0); + a->getClient()->send(result, true); + } + } + } +#endif +} + +// ---------------------------------------------------------------------- + +static void commandExecuteKnowledgeBaseMessage (Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const ¶ms) +{ + UNREF(actor); + UNREF(params); +} + +// ---------------------------------------------------------------------- + +static void commandFuncEmptyMailTarget(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + size_t pos = 0; + std::string networkId(nextStringParm(params, pos)); + + NetworkId targetNetworkId(networkId); + + DEBUG_REPORT_LOG(true, ("commandFuncEmptyMailTarget() - Player(%s) is emptying the mailbox of player(%s).\n", actor.getValueString().c_str(), targetNetworkId.getValueString().c_str())); + + Chat::emptyMail(actor, targetNetworkId); +} + +// ---------------------------------------------------------------------- + +static void commandFuncSetPlayerAppearance(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + //-- Collect parameters. + std::string token; + std::string objectTemplateName; + + bool useTarget = false; + size_t pos = 0; + + do + { + token = Unicode::toLower(nextStringParm(params, pos)); + if (token == "-target") + useTarget = true; + else if (!token.empty()) + objectTemplateName = token; + } while (!token.empty()); + + //-- Log attempt. + NetworkId subjectNetworkId = useTarget ? target: actor; + + LOG("setPlayerAppearance", + ("commandFuncSetPlayerAppearance(): command called by actor id=[%s]: attempting to change appearance for player id=[%s], using appearance info from object template=[%s], subject=[%s]", + actor.getValueString().c_str(), + subjectNetworkId.getValueString().c_str(), + objectTemplateName.c_str(), + useTarget ? "target" : "self" + )); + + //-- Validate parameters. + if (subjectNetworkId == NetworkId::cms_invalid) + { + WARNING(true, ("commandFuncSetPlayerAppearance(): subjectNetworkId is invalid, useTarget=[%s]", useTarget ? "true" : "false")); + return; + } + + CreatureObject *const creatureObject = dynamic_cast(NetworkIdManager::getObjectById(subjectNetworkId)); + if (!creatureObject) + { + WARNING(true, ("commandFuncSetPlayerAppearance(): subject network id=[%s] is not a CreatureObject-derived class.", subjectNetworkId.getValueString().c_str())); + return; + } + + if (objectTemplateName.empty()) + { + // Use the Creature's natural object template name. + objectTemplateName = creatureObject->getObjectTemplateName(); + } + else + { + // Ensure non-default object template name refers to an existing file. + if (!TreeFile::exists(objectTemplateName.c_str())) + { + WARNING(true, + ("commandFuncSetPlayerAppearance(): could not change id=[%s] to non-default object template name=[%s]: object template does not exist", + subjectNetworkId.getValueString().c_str(), + objectTemplateName.c_str() + )); + return; + } + } + + //-- Get the controller, instruct it to change the appearance. + CreatureController *const controller = dynamic_cast(creatureObject->getController()); + if (!controller) + { + WARNING(true, ("commandFuncSetPlayerAppearance(): subject network id=[%s] does not have a CreatureController.", subjectNetworkId.getValueString().c_str())); + return; + } + + //-- Set the new appearance. + controller->setAppearanceFromObjectTemplate(objectTemplateName); +} + +static void commandFuncRevertPlayerAppearance(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + //-- Collect parameters. + std::string token; + std::string objectTemplateName; + + bool useTarget = false; + size_t pos = 0; + + do + { + token = Unicode::toLower(nextStringParm(params, pos)); + if (token == "-target") + useTarget = true; + else if (!token.empty()) + objectTemplateName = token; + } while (!token.empty()); + + //-- Log attempt. + NetworkId subjectNetworkId = useTarget ? target: actor; + + LOG("setPlayerAppearance", + ("commandFuncRevertPlayerAppearance(): command called by actor id=[%s]: attempting to change appearance for player id=[%s], using appearance info from object template=[%s], subject=[%s]", + actor.getValueString().c_str(), + subjectNetworkId.getValueString().c_str(), + objectTemplateName.c_str(), + useTarget ? "target" : "self" + )); + + //-- Validate parameters. + if (subjectNetworkId == NetworkId::cms_invalid) + { + WARNING(true, ("commandFuncRevertPlayerAppearance(): subjectNetworkId is invalid, useTarget=[%s]", useTarget ? "true" : "false")); + return; + } + + CreatureObject *const creatureObject = dynamic_cast(NetworkIdManager::getObjectById(subjectNetworkId)); + if (!creatureObject) + { + WARNING(true, ("commandFuncRevertPlayerAppearance(): subject network id=[%s] is not a CreatureObject-derived class.", subjectNetworkId.getValueString().c_str())); + return; + } + + //-- Get the controller, instruct it to change the appearance. + CreatureController *const controller = dynamic_cast(creatureObject->getController()); + if (!controller) + { + WARNING(true, ("commandFuncRevertPlayerAppearance(): subject network id=[%s] does not have a CreatureController.", subjectNetworkId.getValueString().c_str())); + return; + } + + //-- Set the new appearance. + std::string const none("none"); + controller->setAppearanceFromObjectTemplate(none); +} + +//----------------------------------------------------------------------- + +static void commandFuncReconnectToTransferServer(Command const &, NetworkId const &, NetworkId const & , Unicode::String const &) +{ + GameNetworkMessage const msg("ReconnectToTransferServer"); + GameServer::getInstance().sendToCentralServer(msg); +} + +//----------------------------------------------------------------------- + +static void commandFuncFindFriend(Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const ¶ms) +{ + ServerObject * a = safe_cast(NetworkIdManager::getObjectById(actor)); + if(a && a->getClient()) + { + size_t pos = 0; + const std::string playerName = nextStringParm (params, pos); + CreatureObject * creatureObject = a->asCreatureObject(); + if(creatureObject) + { + if(! playerName.empty()) + { + // break the name down into its subcomponents + ChatAvatarId const cav(NameManager::normalizeName(playerName)); + + // can only find friend on the same cluster + bool const sameGame = (cav.gameCode.empty() || !_stricmp(cav.gameCode.c_str(), Chat::getGameCode().c_str())); + bool const sameCluster = (sameGame && (cav.cluster.empty() || !_stricmp(cav.cluster.c_str(), GameServer::getInstance().getClusterName().c_str()))); + + if (!sameGame || !sameCluster) + { + StringId stringId = StringId("ui_cmnty", "friend_location_failed_remote_name"); + Chat::sendSystemMessage(*creatureObject, stringId, Unicode::emptyString); + } + else + { + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if(playerObject) + { + playerObject->findFriend(cav.name); + } + } + } + else + { + // playerName is empty, send an error to requesting client + StringId stringId = StringId("ui_cmnty", "friend_location_failed_usage"); + Chat::sendSystemMessage(*creatureObject, stringId, Unicode::emptyString); + } + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncFormCommand(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + UNREF(target); + + Unicode::UnicodeStringVector tokens; + IGNORE_RETURN(Unicode::tokenize (params, tokens)); + + if(tokens.size() == 0) + return; + + std::string const commandStr = Unicode::wideToNarrow(tokens[0]); + FormManager::Command const command = static_cast(atoi(commandStr.c_str())); + + switch(command) + { + case FormManager::CREATE_OBJECT: + { + if(tokens.size() < 5) + return; + + std::string const templateName = Unicode::wideToNarrow(tokens[1]); + + std::string const & xStr = Unicode::wideToNarrow(tokens[2]); + std::string const & yStr = Unicode::wideToNarrow(tokens[3]); + std::string const & zStr = Unicode::wideToNarrow(tokens[4]); + std::string const & cellStr = Unicode::wideToNarrow(tokens[5]); + NetworkId const cellId(cellStr); + + float const x = static_cast(atof(xStr.c_str())); + float const y = static_cast(atof(yStr.c_str())); + float const z = static_cast(atof(zStr.c_str())); + + //we must have an odd number of tokens left (so that the datamap has a full key->value mapping) + if(tokens.size() % 2 != 0) + return; + + //TODO centralize pack/unpack + FormManager::UnpackedFormData dataMap; + std::vector values; + for(int i = 6; i < static_cast(tokens.size()) - 1; i += 2) + { + std::string const & key = Unicode::wideToNarrow(tokens[static_cast(i)]); + std::string const & value = Unicode::wideToNarrow(tokens[static_cast(i + 1)]); + values.clear(); + values.push_back(value); + dataMap[key] = values; + } + + FormManagerServer::handleCreateObjectData(actor, templateName, Vector(x, y, z), cellId, dataMap); + break; + } + + case FormManager::EDIT_OBJECT: + { + if(tokens.size() < 1) + return; + + //we must have an even number of tokens left (so that the datamap has a full key->value mapping) + if(tokens.size() % 2 != 1) + return; + + //TODO centralize pack/unpack + FormManager::UnpackedFormData dataMap; + std::vector values; + for(int i = 1; i < static_cast(tokens.size()) - 1; i += 2) + { + std::string const & key = Unicode::wideToNarrow(tokens[static_cast(i)]); + std::string const & value = Unicode::wideToNarrow(tokens[static_cast(i + 1)]); + values.clear(); + values.push_back(value); + dataMap[key] = values; + } + + FormManagerServer::handleEditObjectData(actor, target, dataMap); + break; + } + + case FormManager::REQUEST_EDIT_OBJECT: + { + FormManagerServer::requestEditObjectDataForClient(actor, target); + break; + } + + default: + DEBUG_FATAL(true, ("Unknown command in commandFuncFormCommand")); + break; + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncInstallShipComponents(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + //params for installShipComponent are " " + + Object const * const actorObj = NetworkIdManager::getObjectById(actor); + ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; + CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + { + return; + } + + //they must be near a space terminal (if not a god) + Client const * const client = actorCreature->getClient(); + if(!client) + return; + if(!client->isGod()) + { + Object * const targetObj = NetworkIdManager::getObjectById(target); + ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; + if( !targetServerObj || ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) && + (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) + return; + } + else + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); + } + + size_t pos = 0; + NetworkId const & shipId = nextOidParm(params, pos); + Object * const shipObj = NetworkIdManager::getObjectById(shipId); + ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; + ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; + if(!ship) + return; + + ShipChassisSlotType::Type const slotType = static_cast(nextIntParm(params, pos)); + NetworkId const & componentId = nextOidParm(params, pos); + Object * const componentObj = NetworkIdManager::getObjectById(componentId); + ServerObject * const componentServerObj = componentObj ? componentObj->asServerObject() : NULL; + TangibleObject * const component = componentServerObj ? componentServerObj->asTangibleObject() : NULL; + if(!component) + { + return; + } + + //make sure the player can manipulate the object + Container::ContainerErrorCode error = Container::CEC_Success; + if (!actorCreature->canManipulateObject(*component, true, true, true, 16.0f, error)) + { + StringId cantManipulateId("player_utility", "cannot_manipulate"); + Chat::sendSystemMessage(*actorCreature, cantManipulateId, Unicode::emptyString); + return; + } + + //make sure the object is not in a non-player modifiable slot + ContainedByProperty const * const containedByProperty = component->getContainedByProperty(); + if (containedByProperty) + { + Object const * const containedByObject = containedByProperty->getContainedBy(); + if (containedByObject) + { + SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*containedByObject); + if(slottedContainer) + { + SlotId const & slotId = slottedContainer->findFirstSlotIdForObject(component->getNetworkId()); + if(slotId != SlotId::invalid) + { + if(!ContainerInterface::canPlayerManipulateSlot(slotId)) + { + StringId cantManipulateId("player_utility", "cannot_manipulate_slot"); + Chat::sendSystemMessage(*actorCreature, cantManipulateId, Unicode::emptyString); + return; + } + } + } + } + } + + IGNORE_RETURN(ship->installComponent(actor, slotType, *component)); +} + +// ---------------------------------------------------------------------- + +static void commandFuncUninstallShipComponents(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + //params for uninstallShipComponent are " " + + Object * const actorObj = NetworkIdManager::getObjectById(actor); + ServerObject * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; + CreatureObject * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + return; + ServerObject * const actorInv = actorCreature->getInventory(); + if(!actorInv) + return; + + //they must be near a space terminal (if not a god) + Client const * const client = actorCreature->getClient(); + if(!client) + return; + if(!client->isGod()) + { + Object * const targetObj = NetworkIdManager::getObjectById(target); + ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; + if(!targetServerObj || + ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) + && (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) + return; + } + else + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); + } + + ServerObject const * const actorInventoryObject = actorCreature->getInventory(); + if(!actorInventoryObject) + { + Chat::sendSystemMessage(*actorCreature, SharedStringIds::shipcomponentinstall_noinventory, Unicode::emptyString); + return; + } + VolumeContainer const * const inventoryContainer = ContainerInterface::getVolumeContainer(*actorInventoryObject); + if(!inventoryContainer) + { + Chat::sendSystemMessage(*actorCreature, SharedStringIds::shipcomponentinstall_noinventorycontainer, Unicode::emptyString); + return; + } + if (inventoryContainer->getCurrentVolume() >= inventoryContainer->getTotalVolume()) + { + Chat::sendSystemMessage(*actorCreature, SharedStringIds::shipcomponentinstall_inventoryfull, Unicode::emptyString); + return; + } + + size_t pos = 0; + NetworkId const & shipId = nextOidParm(params, pos); + Object * const shipObj = NetworkIdManager::getObjectById(shipId); + ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; + ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; + if(!ship) + return; + + ShipChassisSlotType::Type const slotType = static_cast(nextIntParm(params, pos)); + + IGNORE_RETURN(ship->uninstallComponent(actor, slotType, *actorInv)); +} + + +// ---------------------------------------------------------------------- + +static void commandFuncInsertItemIntoShipComponentSlot(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + //params for insertItemIntoShipComponentSlot are " " + + Object * const actorObj = NetworkIdManager::getObjectById(actor); + ServerObject * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; + CreatureObject * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + return; + + //they must be near a space terminal (if not a god) + Client const * const client = actorCreature->getClient(); + if(!client) + return; + if(!client->isGod()) + { + Object * const targetObj = NetworkIdManager::getObjectById(target); + ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; + if(!targetServerObj || ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) && + (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) + return; + } + else + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); + } + + size_t pos = 0; + NetworkId const & shipId = nextOidParm(params, pos); + Object * const shipObj = NetworkIdManager::getObjectById(shipId); + ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; + ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; + if(!ship) + return; + + ShipChassisSlotType::Type const slotType = static_cast(nextIntParm(params, pos)); + + if(!ship->isSlotInstalled(slotType)) + return; + + NetworkId const componentId = nextOidParm(params, pos); + + ScriptParams trigParams; + trigParams.addParam(slotType); + trigParams.addParam(componentId); + trigParams.addParam(actor); + + //now trigger the ship + IGNORE_RETURN(ship->getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_ITEM_DROPPED_ON_SLOT, trigParams)); +} + +// ---------------------------------------------------------------------- + +static void commandFuncAssociateDroidControlDeviceWithShip(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + //params for associateDroidControlDeviceWithShip are " " + + Object const * const actorObj = NetworkIdManager::getObjectById(actor); + ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; + CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; + if (!actorCreature) + return; + + //they must be near a space terminal (if not a god) + Client const * const client = actorCreature->getClient(); + if(!client) + return; + if(!client->isGod()) + { + Object * const targetObj = NetworkIdManager::getObjectById(target); + ServerObject * const targetServerObj = targetObj ? targetObj->asServerObject() : NULL; + if(!targetServerObj || ((targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) && + (targetServerObj->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space_npe)) ) + return; + } + else + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("Bypassing terminal check due to GOD mode."), Unicode::emptyString); + } + + size_t pos = 0; + NetworkId const & shipId = nextOidParm(params, pos); + Object * const shipObj = NetworkIdManager::getObjectById(shipId); + ServerObject * const shipServerObj = shipObj ? shipObj->asServerObject() : NULL; + ShipObject * const ship = shipServerObj ? shipServerObj->asShipObject() : NULL; + if(!ship) + return; + + NetworkId const droidControlDeviceId = nextOidParm(params, pos); + + if (!droidControlDeviceId.isValid()) + { + // removing from ship + ship->setInstalledDroidControlDevice(NetworkId::cms_invalid); + } + else + { + // putting in ship + ScriptParams trigParams; + trigParams.addParam(actorCreature->getNetworkId()); + trigParams.addParam(droidControlDeviceId); + + //now trigger the ship + IGNORE_RETURN(ship->getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_TRY_TO_EQUIP_DROID_CONTROL_DEVICE_IN_SHIP, trigParams)); + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncServerAsteroidDataListen(Command const &, NetworkId const & actor, NetworkId const & , Unicode::String const & ) +{ + Object const * const actorObj = NetworkIdManager::getObjectById(actor); + ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; + CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + return; + + ServerAsteroidManager::listenforServerAsteroidDebugData(actor); +} + +// ---------------------------------------------------------------------- + +static void commandFuncServerAsteroidDataStopListening(Command const &, NetworkId const & actor, NetworkId const & , Unicode::String const & ) +{ + Object const * const actorObj = NetworkIdManager::getObjectById(actor); + ServerObject const * const actorServerObj = actorObj ? actorObj->asServerObject() : NULL; + CreatureObject const * const actorCreature = actorServerObj ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + return; + + ServerAsteroidManager::endListenforServerAsteroidDebugData(actor); +} + +//---------------------------------------------------------------------- + +static void commandFuncBoosterOn(Command const &, NetworkId const & actor, NetworkId const &, Unicode::String const &) +{ + internalSetBoosterOnOff(actor, true); +} + +//---------------------------------------------------------------------- + +static void commandFuncBoosterOff(Command const &, NetworkId const & actor, NetworkId const &, Unicode::String const &) +{ + internalSetBoosterOnOff(actor, false); +} + +//---------------------------------------------------------------------- + +static void commandFuncSetFormation(Command const &, NetworkId const & actor, NetworkId const &, Unicode::String const & params) +{ + Object * const o = NetworkIdManager::getObjectById(actor); + ServerObject * const so = o ? o->asServerObject() : NULL; + CreatureObject * const actorCreature = so ? so->asCreatureObject() : NULL; + if(actorCreature) + { + GroupObject * const group = actorCreature->getGroup(); + if(group) + { + if(group->getGroupLeaderId() == actor) + { + std::string paramsNarrow = Unicode::wideToNarrow(params); + if(paramsNarrow == "none") + { + group->setFormationNameCrc(Crc::crcNull); + } + else + { + if(PlayerFormationManager::isValidFormationName(paramsNarrow)) + group->setFormationNameCrc(Crc::normalizeAndCalculate(paramsNarrow.c_str())); + } + } + } + } +} + +//---------------------------------------------------------------------- + +static void commandFuncSetFormationSlot(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + Object * const actorObject = NetworkIdManager::getObjectById(actor); + ServerObject * const actorServerObject = (actorObject != 0) ? actorObject->asServerObject() : 0; + CreatureObject * const actorCreatureObject = (actorServerObject != 0) ? actorServerObject->asCreatureObject() : 0; + if ((actorCreatureObject != 0) && (actor != NetworkId::cms_invalid)) + { + GroupObject * const group = actorCreatureObject->getGroup(); + if (group) + { + if (group->getGroupLeaderId() == actor) + { + size_t pos = 0; + int const formationSlot = nextIntParm(params, pos); + if (formationSlot > -1) + { + group->setShipFormationSlotForMember(target, formationSlot); + } + } + } + } +} + +//---------------------------------------------------------------------- + +static void commandFuncUnDock(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + Object * const object = NetworkIdManager::getObjectById(actor); + + if (object != NULL) + { + ShipObject * const shipObject = ShipObject::getContainingShipObject(object->asServerObject()); + + if (shipObject != NULL) + { + ShipController * const shipController = dynamic_cast(shipObject->getController()); + + if (shipController != NULL) + { + shipController->unDock(); + } + else + { + WARNING(true, ("commandFuncUnDock() Undock requested on an object(%s) without a ShipController.", object->getDebugInformation().c_str())); + } + } + else + { + WARNING(true, ("commandFuncUnDock() Undock requested on an object(%s) contained by a NULL ShipObject.", object->getDebugInformation().c_str())); + } + } + else + { + WARNING(true, ("commandFuncUnDock() Undock requested on a NULL object(%s).", actor.getValueString().c_str())); + } +} + +//---------------------------------------------------------------------- + +static void commandFuncLaunchIntoSpace(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); + CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + { + WARNING(true, ("No actorCreature in commandFuncLaunchIntoSpace")); + return; + } + + if(!target.isValid()) + { + StringId invalidTargetId("player_utility", "invalid_target"); + Chat::sendSystemMessage(*actorCreature, invalidTargetId, Unicode::emptyString); + return; + } + + //target must be a space terminal + Object const * const o = NetworkIdManager::getObjectById(target); + ServerObject const * const so = o ? o->asServerObject() : NULL; + if(!so) + { + StringId invalidTargetId("player_utility", "target_not_server_object"); + Chat::sendSystemMessage(*actorCreature, invalidTargetId, Unicode::emptyString); + return; + } + if(so->getGameObjectType() != SharedObjectTemplate::GOT_terminal_space) + { + ProsePackage p; + p.stringId = StringId("player_utility", "not_space_terminal"); + p.target.id = target; + Unicode::String oob; + OutOfBandPackager::pack(p, -1, oob); + Chat::sendSystemMessage(*actorCreature, Unicode::emptyString, oob);; + return; + } + + Unicode::UnicodeStringVector tokens; + Unicode::tokenize (params, tokens); + + if(tokens.empty()) + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("(unlocalized) No parameters."), Unicode::emptyString); + return; + } + + NetworkId const shipPCDId(Unicode::wideToNarrow(tokens[0]).c_str()); + if(!shipPCDId.isValid()) + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("(unlocalized) Invalid ship."), Unicode::emptyString); + return; + } + Object * const terminalO = NetworkIdManager::getObjectById(target); + ServerObject * const terminalSO = terminalO ? terminalO->asServerObject() : NULL; + if(terminalSO) + { + std::vector networkIds; + + unsigned int tokenIndex = 1; + + if(tokens.size() > tokenIndex) + { + int const numberOfNetworkIds = atoi(Unicode::wideToNarrow(tokens[tokenIndex]).c_str()); + for (int i = 0; i < numberOfNetworkIds; ++i) + { + ++tokenIndex; + if(tokens.size() > tokenIndex) + { + NetworkId const Id(Unicode::wideToNarrow(tokens[tokenIndex])); + if (Id.isValid()) + { + networkIds.push_back(Id); + } + } + } + } + + ++tokenIndex; + + //adding an empty string is fine (it means they aren't traveling to another ground starport) + std::string strPointPlanetResult; + if(tokens.size() > tokenIndex) + { + strPointPlanetResult = Unicode::wideToNarrow(tokens[tokenIndex]); + } + + ++tokenIndex; + + //adding an empty string is fine (it means they aren't traveling to another ground starport) + std::string strPointLocationResult; + if(tokens.size() > tokenIndex) + { + strPointLocationResult = Unicode::wideToNarrow(tokens[tokenIndex]); + std::replace (strPointLocationResult.begin (), strPointLocationResult.end (), '_', ' '); + } + + ScriptParams params; + params.addParam(actor); + params.addParam(shipPCDId); + params.addParam(networkIds); + //adding an empty string is fine (it means they aren't traveling to another ground starport) + params.addParam(strPointPlanetResult.c_str()); + //adding an empty string is fine (it means they aren't traveling to another ground starport) + params.addParam(strPointLocationResult.c_str()); + + IGNORE_RETURN(terminalSO->getScriptObject()->trigAllScripts(Scripting::TRIG_ABOUT_TO_LAUNCH_TO_SPACE, params)); + } + else + { + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide("(unlocalized) Invalid terminal"), Unicode::emptyString); + } +} + +//---------------------------------------------------------------------- + +static void commandFuncAcceptQuest(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); + CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + { + WARNING(true, ("No actorCreature in commandFuncAcceptQuest")); + return; + } + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); + if(!playerObject) + { + WARNING(true, ("No playerObject in commandFuncAcceptQuest")); + return; + } + + uint32 const questCrc = atoi(Unicode::wideToNarrow(params).c_str()); + if(playerObject->getPendingRequestQuestCrc() == questCrc) + { + NetworkId const & questGiver = playerObject->getPendingRequestQuestGiver(); + playerObject->questActivateQuest(questCrc, questGiver); + playerObject->setPendingRequestQuestInformation(0, NetworkId::cms_invalid); + } +} + +//---------------------------------------------------------------------- + +static void commandFuncReceiveReward(Command const &, NetworkId const & actor, NetworkId const & target, Unicode::String const & params) +{ + ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); + CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + { + WARNING(true, ("No actorCreature in commandFuncReceiveReward")); + return; + } + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); + if(!playerObject) + { + WARNING(true, ("No playerObject in commandFuncReceiveReward")); + return; + } + + Unicode::UnicodeStringVector sv; + Unicode::tokenize (params, sv); + + if(sv.empty()) + return; + uint32 const questCrc = atoi(Unicode::wideToNarrow(sv[0]).c_str()); + std::string selectedReward; + if(sv.size() > 1) + selectedReward = Unicode::wideToNarrow(sv[1]); + + if((playerObject->getPendingRequestQuestCrc() == questCrc) || playerObject->questPlayerCanClaimRewardFor(questCrc)) + { + playerObject->questGrantQuestReward(questCrc, selectedReward); + playerObject->setPendingRequestQuestInformation(0, NetworkId::cms_invalid); + } +} + +//---------------------------------------------------------------------- + +static void commandFuncAbandonQuest(Command const &, NetworkId const & actor, NetworkId const & , Unicode::String const & params) +{ + size_t pos = 0; + + //not currently used, but can distinguish between different quest types + int const questSystemType = nextIntParm(params, pos); + UNREF(questSystemType); + std::string const & questName = nextStringParm(params, pos); + + if(QuestManager::isQuestAbandonable(questName)) + { + ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); + CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; + if(actorCreature) + { + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); + if(playerObject) + { + Quest const * const q = QuestManager::getQuest(questName); + if(q && playerObject->questHasActiveQuest(q->getId()) && !playerObject->questHasCompletedQuest(q->getId())) + { + LOG("Quest", ("Abandon:%s abandoned quest [%s] with status [0x%08X].\n", + PlayerObject::getAccountDescription(actorServerObj->getClient()->getCharacterObjectId()).c_str(), + questName.c_str(), playerObject->questGetQuestStatus(q->getId()))); + + playerObject->questClearQuest(q->getId()); + } + } + } + } +} + + + +// ---------------------------------------------------------------------- + +static void commandFuncExchangeListCredits(Command const &, NetworkId const &actor, NetworkId const &target, Unicode::String const ¶ms) +{ + ServerObject * const actorServerObj = safe_cast(NetworkIdManager::getObjectById(actor)); + CreatureObject * const actorCreature = actorServerObj != NULL ? actorServerObj->asCreatureObject() : NULL; + if(!actorCreature) + { + WARNING(true, ("No actorCreature in commandFuncReceiveReward")); + return; + } + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(actorCreature); + if(!playerObject) + { + WARNING(true, ("No playerObject in commandFuncReceiveReward")); + return; + } + + Unicode::UnicodeStringVector sv; + Unicode::tokenize (params, sv); + + if(sv.empty()) + return; + uint32 const credits = (uint32)atoi(Unicode::wideToNarrow(sv[0]).c_str()); + if ( credits <= 0 ) + return; + + + char message[512]; + sprintf(message,"Listing %ld credits on station exchange.", credits); + Chat::sendSystemMessage(*actorCreature, Unicode::narrowToWide(message), Unicode::emptyString); + + + ExchangeListCreditsMessage const msg(actor, credits, GameServer::getInstance().getProcessId()); + GameServer::getInstance().sendToCentralServer(msg); +} + +//----------------------------------------------------------------------- + +static void commandFuncSquelch(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + char buffer[2048]; + if (!target.isValid()) + { + ConGenericMessage const msg("Error! No target specified for /squelch command.", 0); + gmClient->send(msg, true); + } + else + { + ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!so) + { + snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + CreatureObject * c = so->asCreatureObject(); + if (!c) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + PlayerObject * p = PlayerCreatureController::getPlayerObject(c); + if (!p) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else if (p->getSecondsUntilUnsquelched() < 0) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is already squelched", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + snprintf(buffer, sizeof(buffer)-1, "Squelching %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + + p->squelch(gm->getNetworkId(), Unicode::wideToNarrow(gm->getAssignedObjectName()), -1); + } + } + } + } + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncUnsquelch(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + char buffer[2048]; + if (!target.isValid()) + { + ConGenericMessage const msg("Error! No target specified for /unsquelch command.", 0); + gmClient->send(msg, true); + } + else + { + ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!so) + { + snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + CreatureObject * c = so->asCreatureObject(); + if (!c) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + PlayerObject * p = PlayerCreatureController::getPlayerObject(c); + if (!p) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else if (p->getSecondsUntilUnsquelched() == 0) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not currently squelched", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + snprintf(buffer, sizeof(buffer)-1, "Unsquelching %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + + p->unsquelch(); + } + } + } + } + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncGrantWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + char buffer[2048]; + if (!target.isValid()) + { + ConGenericMessage const msg("Error! No target specified for /grantWarden command.", 0); + gmClient->send(msg, true); + } + else + { + ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!so) + { + snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + CreatureObject * c = so->asCreatureObject(); + if (!c) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + PlayerObject * p = PlayerCreatureController::getPlayerObject(c); + if (!p) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else if (p->isWarden()) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is already a warden", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + snprintf(buffer, sizeof(buffer)-1, "Granting warden to %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + + p->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::Warden)); + + LOG("CustomerService", ("Warden:%s grantWarden to %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); + } + } + } + } + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncRevokeWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + char buffer[2048]; + if (!target.isValid()) + { + ConGenericMessage const msg("Error! No target specified for /revokeWarden command.", 0); + gmClient->send(msg, true); + } + else + { + ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!so) + { + snprintf(buffer, sizeof(buffer)-1, "Error! Cannot find object for %s", target.getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + CreatureObject * c = so->asCreatureObject(); + if (!c) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a creature object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + PlayerObject * p = PlayerCreatureController::getPlayerObject(c); + if (!p) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a player object", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else if (!p->isWarden()) + { + snprintf(buffer, sizeof(buffer)-1, "Error! %s (%s) is not a warden", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + } + else + { + snprintf(buffer, sizeof(buffer)-1, "Revoking warden from %s (%s)", target.getValueString().c_str(), Unicode::wideToNarrow(so->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + ConGenericMessage const msg(buffer, 0); + gmClient->send(msg, true); + + p->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)); + + LOG("CustomerService", ("Warden:%s revokeWarden from %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); + } + } + } + } + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncSpammer(Command const &, NetworkId const &actor, NetworkId const & targetForCommand, Unicode::String const ¶ms) +{ + NetworkId target = targetForCommand; + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + // check warden permission first + const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); + if (!gmPlayerObject || !gmPlayerObject->isWarden()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); + return; + } + + // check to see if warden functionality is enabled + if (!ConfigServerGame::getEnableWarden()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "warden_functionality_disabled"), Unicode::emptyString); + return; + } + + // check for valid target + NetworkId parsedNetworkId; + if (!target.isValid()) + { + // check to see if a target name was specified, and see + // if that resolves into a player character in the galaxy + if (params.empty()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "no_target"), Unicode::emptyString); + return; + } + else + { + parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); + if (!parsedNetworkId.isValid()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + return; + } + else + { + target = parsedNetworkId; + } + } + } + + ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!so) + { + if (parsedNetworkId.isValid()) + { + // send a messageTo to the target to do apply the /spammer operation + char buffer[1024]; + snprintf(buffer, sizeof(buffer)-1, "%s %s", actor.getValueString().c_str(), Unicode::wideToNarrow(gm->getAssignedObjectName()).c_str()); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, + "C++SpammerReq", + buffer, + 0, + false, + actor, + "C++SpammerRspTargetNotFound"); + } + else + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + } + + return; + } + + CreatureObject * c = so->asCreatureObject(); + if (!c) + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + return; + } + + PlayerObject * p = PlayerCreatureController::getPlayerObject(c); + if (!p) + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + return; + } + + // on a session-authenticated cluster, cannot /spammer a secured login character + if (so->getClient() && so->getClient()->isGodValidated()) + { + if (!ConfigServerGame::getAdminGodToAll() && !ConfigServerGame::getEnableWardenCanSquelchSecuredLogin()) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "cannot_spammer_target"); + prosePackage.target.str = so->getAssignedObjectName(); + Chat::sendSystemMessage(*gm, prosePackage); + return; + } + } + + // cannot /spammer self + if (target == actor) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "cannot_spammer_target"); + prosePackage.target.str = so->getAssignedObjectName(); + Chat::sendSystemMessage(*gm, prosePackage); + return; + } + + // cannot /spammer a target that is already squelched + if (p->getSecondsUntilUnsquelched() != 0) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "cannot_spammer_target"); + prosePackage.target.str = so->getAssignedObjectName(); + Chat::sendSystemMessage(*gm, prosePackage); + return; + } + + // do it + p->squelch(actor, Unicode::wideToNarrow(gm->getAssignedObjectName()), ConfigServerGame::getWardenSquelchDurationSeconds()); + ReportManager::addReport(gm->getAssignedObjectFirstName(), actor, so->getAssignedObjectFirstName(), target, std::string("Warden")); + + // log it + LOG("CustomerService", ("Warden:%s has spammer %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); + + // display confirmation message + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "confirm_spammer"); + prosePackage.target.str = so->getAssignedObjectName(); + Chat::sendSystemMessage(*gm, prosePackage); + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncUnspammer(Command const &, NetworkId const &actor, NetworkId const & targetForCommand, Unicode::String const ¶ms) +{ + NetworkId target = targetForCommand; + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + // check warden permission first + const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); + if (!gmPlayerObject || !gmPlayerObject->isWarden()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); + return; + } + + // check for valid target + NetworkId parsedNetworkId; + if (!target.isValid()) + { + // check to see if a target name was specified, and see + // if that resolves into a player character in the galaxy + if (params.empty()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "no_target"), Unicode::emptyString); + return; + } + else + { + parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); + if (!parsedNetworkId.isValid()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + return; + } + else + { + target = parsedNetworkId; + } + } + } + + ServerObject * so = dynamic_cast(NetworkIdManager::getObjectById(target)); + if (!so) + { + if (parsedNetworkId.isValid()) + { + // send a messageTo to the target to do apply the /unspammer operation + MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, + "C++UnspammerReq", + actor.getValueString(), + 0, + false, + actor, + "C++UnspammerRspTargetNotFound"); + } + else + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + } + + return; + } + + CreatureObject * c = so->asCreatureObject(); + if (!c) + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + return; + } + + PlayerObject * p = PlayerCreatureController::getPlayerObject(c); + if (!p) + { + Chat::sendSystemMessage(*gm, StringId("warden", "invalid_target"), Unicode::emptyString); + return; + } + + // cannot /unspammer a target that is not currently /spammer(ed) + if (p->getSecondsUntilUnsquelched() <= 0) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "cannot_unspammer_target"); + prosePackage.target.str = so->getAssignedObjectName(); + Chat::sendSystemMessage(*gm, prosePackage); + return; + } + + // can only /unspammer target that I /spammer(ed) + if (p->getSquelchedById() != actor) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "cannot_unspammer_target"); + prosePackage.target.str = so->getAssignedObjectName(); + Chat::sendSystemMessage(*gm, prosePackage); + return; + } + + // do it + p->unsquelch(); + + // log it + LOG("CustomerService", ("Warden:%s has unspammer %s", PlayerObject::getAccountDescription(gm).c_str(), p->getAccountDescription().c_str())); + + // display confirmation message + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "confirm_unspammer"); + prosePackage.target.str = so->getAssignedObjectName(); + Chat::sendSystemMessage(*gm, prosePackage); + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncDeputizeWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + // check warden permission first + const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); + if (!gmPlayerObject || !gmPlayerObject->isWarden()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); + return; + } + + // check to see if warden functionality is enabled + if (!ConfigServerGame::getEnableWarden()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "warden_functionality_disabled"), Unicode::emptyString); + return; + } + + // check to see if wardens are allowed to deputize other wardens + if (!ConfigServerGame::getEnableWardenToDeputizeWarden()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); + return; + } + + // check for valid target + NetworkId parsedNetworkId = target; + if (!parsedNetworkId.isValid()) + { + // check to see if a target name was specified, and see + // if that resolves into a player character in the galaxy + if (params.empty()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "cannot_deputize"), Unicode::emptyString); + return; + } + else + { + parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); + if (!parsedNetworkId.isValid()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "cannot_deputize"), Unicode::emptyString); + return; + } + } + } + + // cannot deputize self + if (parsedNetworkId == gm->getNetworkId()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "cannot_deputize"), Unicode::emptyString); + return; + } + + // send a messageTo to the target to complete the deputize process + char buffer[1024]; + snprintf(buffer, sizeof(buffer)-1, "%s|%lu", gm->getNetworkId().getValueString().c_str(), gmPlayerObject->getStationId()); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, + "C++DeputizeWardenReq", + buffer, + 0, + false, + actor, + "C++DeputizeWardenRspCannotDeputize"); + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncUndeputizeWarden(Command const &, NetworkId const &actor, NetworkId const & target, Unicode::String const ¶ms) +{ + const CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (gm) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + // check warden permission first + const PlayerObject * gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); + if (!gmPlayerObject || !gmPlayerObject->isWarden()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "not_authorized"), Unicode::emptyString); + return; + } + + // check for valid target + NetworkId parsedNetworkId = target; + if (!parsedNetworkId.isValid()) + { + // check to see if a target name was specified, and see + // if that resolves into a player character in the galaxy + if (params.empty()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "cannot_undeputize"), Unicode::emptyString); + return; + } + else + { + parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); + if (!parsedNetworkId.isValid()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "cannot_undeputize"), Unicode::emptyString); + return; + } + } + } + + // cannot undeputize self + if (parsedNetworkId == gm->getNetworkId()) + { + Chat::sendSystemMessage(*gm, StringId("warden", "cannot_undeputize"), Unicode::emptyString); + return; + } + + // send a messageTo to the target to complete the undeputize process + char buffer[1024]; + snprintf(buffer, sizeof(buffer)-1, "%s|%lu", gm->getNetworkId().getValueString().c_str(), gmPlayerObject->getStationId()); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(parsedNetworkId, + "C++UndeputizeWardenReq", + buffer, + 0, + false, + actor, + "C++UndeputizeWardenRspCannotUndeputize"); + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncRemoveBuff(Command const &, NetworkId const &actor, NetworkId const & , Unicode::String const ¶ms) +{ + CreatureObject * player = dynamic_cast(NetworkIdManager::getObjectById(actor)); + if (player) + { + size_t pos = 0; + int32 const buffCrc = nextIntParm(params, pos); + if (buffCrc && BuffManager::getIsBuffPlayerRemovable(buffCrc)) + { + player->removeBuff(buffCrc); + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncOccupyUnlockedSlot(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + PlayerObject const * const gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); + if (gm && gmPlayerObject) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + // check to see if /occupyUnlockedSlot is enabled + if (!ConfigServerGame::getEnableOccupyUnlockedSlotCommand()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "occupy_unlocked_slot_command_disabled"), Unicode::emptyString); + return; + } + + // check to see if the account currently has an unoccupied unlocked slot + if (!gmClient->getHasUnoccupiedJediSlot()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "occupy_unlocked_slot_command_account_has_no_unoccupied_unlocked_slot"), Unicode::emptyString); + return; + } + + // already unlocked slot character + if (gmClient->getIsJediSlotCharacter()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "occupy_unlocked_slot_command_already_unlocked_character"), Unicode::emptyString); + return; + } + + // check to see if there is a cooldown is in effect for the command + int const timeNow = static_cast(::time(NULL)); + if (!gmClient->isGod() && gm->getObjVars().hasItem("timeNextOccupyVacateUnlockedSlotCommandAllowed") && (gm->getObjVars().getType("timeNextOccupyVacateUnlockedSlotCommandAllowed") == DynamicVariable::INT)) + { + int timeNextOccupyVacateUnlockedSlotCommandAllowed = 0; + if (gm->getObjVars().getItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", timeNextOccupyVacateUnlockedSlotCommandAllowed)) + { + if (timeNextOccupyVacateUnlockedSlotCommandAllowed > timeNow) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("unlocked_slot", "occupy_unlocked_slot_command_too_fast"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextOccupyVacateUnlockedSlotCommandAllowed - timeNow))); + Chat::sendSystemMessage(*gm, prosePackage); + + return; + } + } + } + + // CS log the request + LOG("CustomerService",("JediUnlockedSlot:%s requesting OccupyUnlockedSlot", PlayerObject::getAccountDescription(gm).c_str())); + + // send off request to LoginServer to make this character occupy the unlocked slot + GenericValueTypeMessage, uint32> > const occupyUnlockedSlotReq("OccupyUnlockedSlotReq", std::make_pair(std::make_pair(static_cast(gmPlayerObject->getStationId()), actor), GameServer::getInstance().getProcessId())); + GameServer::getInstance().sendToCentralServer(occupyUnlockedSlotReq); + + // set cooldown + if (!gmClient->isGod()) + { + IGNORE_RETURN(gm->setObjVarItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", (timeNow + ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); + } + + // display "wait for reply" message + ProsePackage prosePackage; + prosePackage.stringId = StringId("unlocked_slot", "occupy_unlocked_slot_wait_for_reply"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); + Chat::sendSystemMessage(*gm, prosePackage); + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncVacateUnlockedSlot(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + PlayerObject const * const gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); + if (gm && gmPlayerObject) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + // check to see if /vacateUnlockedSlot is enabled + if (!ConfigServerGame::getEnableVacateUnlockedSlotCommand()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "vacate_unlocked_slot_command_disabled"), Unicode::emptyString); + return; + } + + // check to see if this character is an unlocked slot character + if (!gmClient->getIsJediSlotCharacter()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "vacate_unlocked_slot_command_not_unlocked_character"), Unicode::emptyString); + return; + } + + // check to see if there is a cooldown is in effect for the command + int const timeNow = static_cast(::time(NULL)); + if (!gmClient->isGod() && gm->getObjVars().hasItem("timeNextOccupyVacateUnlockedSlotCommandAllowed") && (gm->getObjVars().getType("timeNextOccupyVacateUnlockedSlotCommandAllowed") == DynamicVariable::INT)) + { + int timeNextOccupyVacateUnlockedSlotCommandAllowed = 0; + if (gm->getObjVars().getItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", timeNextOccupyVacateUnlockedSlotCommandAllowed)) + { + if (timeNextOccupyVacateUnlockedSlotCommandAllowed > timeNow) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("unlocked_slot", "vacate_unlocked_slot_command_too_fast"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextOccupyVacateUnlockedSlotCommandAllowed - timeNow))); + Chat::sendSystemMessage(*gm, prosePackage); + + return; + } + } + } + + // CS log the request + LOG("CustomerService",("JediUnlockedSlot:%s requesting VacateUnlockedSlot", PlayerObject::getAccountDescription(gm).c_str())); + + // send off request to LoginServer to make this character vacate the unlocked slot + GenericValueTypeMessage, uint32> > const vacateUnlockedSlotReq("VacateUnlockedSlotReq", std::make_pair(std::make_pair(static_cast(gmPlayerObject->getStationId()), actor), GameServer::getInstance().getProcessId())); + GameServer::getInstance().sendToCentralServer(vacateUnlockedSlotReq); + + // set cooldown + if (!gmClient->isGod()) + { + IGNORE_RETURN(gm->setObjVarItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", (timeNow + ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); + } + + // display "wait for reply" message + ProsePackage prosePackage; + prosePackage.stringId = StringId("unlocked_slot", "vacate_unlocked_slot_wait_for_reply"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); + Chat::sendSystemMessage(*gm, prosePackage); + } + } +} + +//----------------------------------------------------------------------- + +static void commandFuncSwapUnlockedSlot(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject * gm = dynamic_cast(NetworkIdManager::getObjectById(actor)); + PlayerObject const * const gmPlayerObject = PlayerCreatureController::getPlayerObject(gm); + if (gm && gmPlayerObject) + { + const Client * gmClient = gm->getClient(); + if (gmClient) + { + // check to see if /swapUnlockedSlot is enabled + if (!ConfigServerGame::getEnableSwapUnlockedSlotCommand()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_disabled"), Unicode::emptyString); + return; + } + + // check to see if this character is an unlocked slot character + if (!gmClient->getIsJediSlotCharacter()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_not_unlocked_character"), Unicode::emptyString); + return; + } + + // check to see if a target character name is specified + if (params.empty()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_no_params"), Unicode::emptyString); + return; + } + + // check to see if a valid target character name is specified + NetworkId const parsedNetworkId = NameManager::getInstance().getPlayerId(Unicode::wideToNarrow(Unicode::toLower(params))); + if (!parsedNetworkId.isValid()) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_invalid_target"), Unicode::emptyString); + return; + } + + // cannot swap with yourself + if (parsedNetworkId == actor) + { + Chat::sendSystemMessage(*gm, StringId("unlocked_slot", "swap_unlocked_slot_command_target_is_already_unlocked_character"), Unicode::emptyString); + return; + } + + // check to see if there is a cooldown is in effect for the command + int const timeNow = static_cast(::time(NULL)); + if (!gmClient->isGod() && gm->getObjVars().hasItem("timeNextOccupyVacateUnlockedSlotCommandAllowed") && (gm->getObjVars().getType("timeNextOccupyVacateUnlockedSlotCommandAllowed") == DynamicVariable::INT)) + { + int timeNextOccupyVacateUnlockedSlotCommandAllowed = 0; + if (gm->getObjVars().getItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", timeNextOccupyVacateUnlockedSlotCommandAllowed)) + { + if (timeNextOccupyVacateUnlockedSlotCommandAllowed > timeNow) + { + ProsePackage prosePackage; + prosePackage.stringId = StringId("unlocked_slot", "swap_unlocked_slot_command_too_fast"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(timeNextOccupyVacateUnlockedSlotCommandAllowed - timeNow))); + Chat::sendSystemMessage(*gm, prosePackage); + + return; + } + } + } + + // CS log the request + LOG("CustomerService",("JediUnlockedSlot:%s requesting SwapUnlockedSlot with %s (%s)", PlayerObject::getAccountDescription(gm).c_str(), parsedNetworkId.getValueString().c_str(), NameManager::getInstance().getPlayerFullName(parsedNetworkId).c_str())); + + // send off request to LoginServer to make this character normal and the target characer unlocked + GenericValueTypeMessage, std::pair > > const swapUnlockedSlotReq("SwapUnlockedSlotReq", std::make_pair(std::make_pair(static_cast(gmPlayerObject->getStationId()), actor), std::make_pair(GameServer::getInstance().getProcessId(), parsedNetworkId))); + GameServer::getInstance().sendToCentralServer(swapUnlockedSlotReq); + + // set cooldown + if (!gmClient->isGod()) + { + IGNORE_RETURN(gm->setObjVarItem("timeNextOccupyVacateUnlockedSlotCommandAllowed", (timeNow + ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); + } + + // display "wait for reply" message + ProsePackage prosePackage; + prosePackage.stringId = StringId("unlocked_slot", "swap_unlocked_slot_wait_for_reply"); + prosePackage.target.str = Unicode::narrowToWide(CalendarTime::convertSecondsToHMS(static_cast(ConfigServerGame::getOccupyVacateUnlockedSlotCommandCooldownSeconds()))); + Chat::sendSystemMessage(*gm, prosePackage); + } + } +} + +// ---------------------------------------------------------------------- + +static void commandFuncPickupAllRoomItemsIntoInventory(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const ¶ms) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + // don't allow this in god mode because it could be used accidentally and pick up a bunch of stuff, + // and god mode allows stuff to be picked up, which wouldn't normally be allowed to be picked up + if (!targetObj->getClient()) + return; + + if (targetObj->getClient()->isGod()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You cannot do this while in GOD mode."), Unicode::emptyString); + return; + } + + // don't do this if the character is not "active", meaning he's probably doing it with a macro + if (targetPlayerObj->getSessionLastActiveTime() == 0) + return; + + // don't allow multiple /pickupAllRoomItemsIntoInventory and/or /dropAllInventoryItemsIntoRoom + int const timeNow = static_cast(::time(NULL)); + int pickupDropAllItemsOperationTimeout = 0; + if (targetObj->getObjVars().getItem("pickupDropAllItemsOperation.timeout", pickupDropAllItemsOperationTimeout) && (pickupDropAllItemsOperationTimeout > timeNow)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing the /pickupAllRoomItemsIntoInventory or /dropAllInventoryItemsIntoRoom command. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(pickupDropAllItemsOperationTimeout - timeNow)).c_str())), Unicode::emptyString); + return; + } + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); + return; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + if (!containingPOB->isOnAdminList(*targetObj)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const targetInventoryObj = targetObj->getInventory(); + if (!targetInventoryObj) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + VolumeContainer const * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); + if (!targetInventoryContainer) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + // see if the player specified to overload the inventory + Unicode::String const lowercaseParams = Unicode::toLower(params); + static Unicode::String const paramsOverload1 = Unicode::narrowToWide("-overload"); + static Unicode::String const paramsOverload2 = Unicode::narrowToWide("overload"); + bool const allowInventoryOverload = ((lowercaseParams == paramsOverload1) || (lowercaseParams == paramsOverload2)); + + int const inventoryBaseLimit = targetInventoryContainer->getTotalVolume(); + int const inventoryOverLimit = std::max(inventoryBaseLimit, (inventoryBaseLimit + ConfigServerGame::getMoveValidationMaxInventoryOverload() - 11)); + int const inventoryLimit = (allowInventoryOverload ? inventoryOverLimit : inventoryBaseLimit); + + if (targetInventoryContainer->getCurrentVolume() >= inventoryLimit) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Your inventory is full."), Unicode::emptyString); + + // if they didn't run the command with the -overload + // option, remind them about the -overload option + if (!allowInventoryOverload && (targetInventoryContainer->getCurrentVolume() < inventoryOverLimit)) + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("If you wish to pick up more items than available inventory space, you can specify the \"overload\" option with the command by typing \"/pickupAllRoomItemsIntoInventory -overload\" which will pick up additional items and overload your inventory, but not so overloaded as to prevent you from moving."), Unicode::emptyString); + + return; + } + + Container const * const cellContainer = ContainerInterface::getContainer(*containingCell); + if (!cellContainer) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + // the player counts as 1 item in the room + if (cellContainer->getNumberOfItems() <= 1) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("This room is empty."), Unicode::emptyString); + return; + } + + // start messageTo loop to pick up the items in the room, spread + // out over a period of time so it doesn't lag out the server + int pickupDropAllItemsOperationId = ::rand(); + while (pickupDropAllItemsOperationId == 0) + pickupDropAllItemsOperationId = ::rand(); + + targetPlayerObj->setPickupDropAllItemsOperationId(pickupDropAllItemsOperationId); + targetPlayerObj->setPickupDropAllItemsCellId(containingCell->getNetworkId()); + targetPlayerObj->setPickupAllItemsAllowInventoryOverload(allowInventoryOverload); + targetPlayerObj->setPickupDropAllItemsNumItemsSoFar(0); + targetPlayerObj->getPickupDropAllItemsProcessedItemsSoFar().clear(); + + IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.timeout", timeNow + (5 * 60))); + IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.operationId", pickupDropAllItemsOperationId)); + + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please remain in the room while the operation is being performed. You will be notified when the operation is complete."), Unicode::emptyString); + + MessageToQueue::getInstance().sendMessageToC(targetObj->getNetworkId(), + "C++PickupAllRoomItemsIntoInventory", + "", + 0, + false); +} + +// ---------------------------------------------------------------------- + +static void commandFuncDropAllInventoryItemsIntoRoom(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + // don't allow this in god mode because it could be used accidentally and drop a bunch of stuff, + // and god mode allows stuff to be dropped, which wouldn't normally be allowed to be dropped + if (!targetObj->getClient()) + return; + + if (targetObj->getClient()->isGod()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You cannot do this while in GOD mode."), Unicode::emptyString); + return; + } + + // don't do this if the character is not "active", meaning he's probably doing it with a macro + if (targetPlayerObj->getSessionLastActiveTime() == 0) + return; + + // don't allow multiple /pickupAllRoomItemsIntoInventory and/or /dropAllInventoryItemsIntoRoom + int const timeNow = static_cast(::time(NULL)); + int pickupDropAllItemsOperationTimeout = 0; + if (targetObj->getObjVars().getItem("pickupDropAllItemsOperation.timeout", pickupDropAllItemsOperationTimeout) && (pickupDropAllItemsOperationTimeout > timeNow)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing the /pickupAllRoomItemsIntoInventory or /dropAllInventoryItemsIntoRoom command. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(pickupDropAllItemsOperationTimeout - timeNow)).c_str())), Unicode::emptyString); + return; + } + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); + return; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + // check for lot overlimit drop restriction + if ((targetPlayerObj->getAccountNumLots() > targetObj->getMaxNumberOfLots()) && targetObj->getObjVars().hasItem("lotOverlimit.structure_id")) + { + NetworkId lotOverlimitStructure; + if (targetObj->getObjVars().getItem("lotOverlimit.structure_id", lotOverlimitStructure) && lotOverlimitStructure.isValid()) + { + if (GameObjectTypes::isTypeOf(containingPOB->getGameObjectType(), SharedObjectTemplate::GOT_building) && (containingPOB->getNetworkId() != lotOverlimitStructure)) + { + std::string lotOverlimitStructureName; + std::string lotOverlimitStructureLocation; + + IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); + IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); + + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are currently over the lot limit, and cannot drop any item into (or move around items within) any factory or structure, other than the %s structure located at %s that caused you to exceed the lot limit.", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); + return; + } + } + } + + if (!containingPOB->isOnAdminList(*targetObj)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const targetInventoryObj = targetObj->getInventory(); + if (!targetInventoryObj) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + VolumeContainer const * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); + if (!targetInventoryContainer) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + int pobBaseItemLimit = 0; + int pobAdditionalItems = 0; + const int pobItemLimit = containingPOB->getPobTotalItemLimit(pobBaseItemLimit, pobAdditionalItems); + + if (containingPOB->getPobItemCount() >= pobItemLimit) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("The structure or POB ship is full."), Unicode::emptyString); + return; + } + + if (targetInventoryContainer->getCurrentVolume() <= 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Your inventory is empty."), Unicode::emptyString); + return; + } + + // start messageTo loop to drop the inventory items into the room, + // spread out over a period of time so it doesn't lag out the server + int pickupDropAllItemsOperationId = ::rand(); + while (pickupDropAllItemsOperationId == 0) + pickupDropAllItemsOperationId = ::rand(); + + targetPlayerObj->setPickupDropAllItemsOperationId(pickupDropAllItemsOperationId); + targetPlayerObj->setPickupDropAllItemsCellId(containingCell->getNetworkId()); + targetPlayerObj->setPickupDropAllItemsNumItemsSoFar(0); + targetPlayerObj->getPickupDropAllItemsProcessedItemsSoFar().clear(); + + IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.timeout", timeNow + (5 * 60))); + IGNORE_RETURN(targetObj->setObjVarItem("pickupDropAllItemsOperation.operationId", pickupDropAllItemsOperationId)); + + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please remain in the room while the operation is being performed. You will be notified when the operation is complete."), Unicode::emptyString); + + MessageToQueue::getInstance().sendMessageToC(targetObj->getNetworkId(), + "C++DropAllInventoryItemsIntoRoom", + "", + 0, + false); +} + +// ---------------------------------------------------------------------- + +static void commandFuncSaveDecorationLayout(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject const * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); + return; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + if (!containingPOB->isOnAdminList(*targetObj)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + // poke script to pop up some SUI windows to let the user pick which save slot to use + MessageToQueue::getInstance().sendMessageToJava(targetObj->getNetworkId(), "handleSaveDecorationLayout", std::vector(), 0, false); +} + +// ---------------------------------------------------------------------- + +static void commandFuncRestoreDecorationLayout(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const &) +{ + CreatureObject const * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + // don't allow another restore on the pob while one is still in progress + int const timeNow = static_cast(::time(NULL)); + int restoreDecorationOperationTimeout = 0; + if (targetObj->getObjVars().getItem("restoreDecorationOperation.timeout", restoreDecorationOperationTimeout) && (restoreDecorationOperationTimeout > timeNow)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing a restore decoration layout operation. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(restoreDecorationOperationTimeout - timeNow)).c_str())), Unicode::emptyString); + return; + } + + if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); + return; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + // check for lot overlimit drop restriction + if ((targetPlayerObj->getAccountNumLots() > targetObj->getMaxNumberOfLots()) && targetObj->getObjVars().hasItem("lotOverlimit.structure_id")) + { + NetworkId lotOverlimitStructure; + if (targetObj->getObjVars().getItem("lotOverlimit.structure_id", lotOverlimitStructure) && lotOverlimitStructure.isValid()) + { + if (GameObjectTypes::isTypeOf(containingPOB->getGameObjectType(), SharedObjectTemplate::GOT_building) && (containingPOB->getNetworkId() != lotOverlimitStructure)) + { + std::string lotOverlimitStructureName; + std::string lotOverlimitStructureLocation; + + IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); + IGNORE_RETURN(targetObj->getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); + + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are currently over the lot limit, and cannot drop any item into (or move around items within) any factory or structure, other than the %s structure located at %s that caused you to exceed the lot limit.", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); + return; + } + } + } + + if (!containingPOB->isOnAdminList(*targetObj)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + // see if there's any saved decoration layout to restore + if (!targetPlayerObj->getObjVars().hasItem("savedDecoration1.saveTime") && !targetPlayerObj->getObjVars().hasItem("savedDecoration2.saveTime") && !targetPlayerObj->getObjVars().hasItem("savedDecoration3.saveTime")) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You do not have any saved decoration layout."), Unicode::emptyString); + return; + } + + // poke script to pop up some SUI windows to let the user pick which save slot to use + MessageToQueue::getInstance().sendMessageToJava(targetObj->getNetworkId(), "handleRestoreDecorationLayout", std::vector(), 0, false); +} + +// ---------------------------------------------------------------------- + +static void commandFuncAreaPickRandomPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextAreaPickRandomPlayerCommandAllowed") && (targetObj->getObjVars().getType("timeNextAreaPickRandomPlayerCommandAllowed") == DynamicVariable::INT)) + { + int timeNextAreaPickRandomPlayerCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextAreaPickRandomPlayerCommandAllowed", timeNextAreaPickRandomPlayerCommandAllowed)) + { + if (timeNextAreaPickRandomPlayerCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextAreaPickRandomPlayerCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + // handle options + static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); + uint32 socialType = 0; + int range = 16; // default is 16m + + if (!params.empty()) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) + { + static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); + static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); + static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); + static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); + std::string emote; + + for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) + { + if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) + { + socialType = pointatSocialType; + } + else if (iter->find(paramsEmote1) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(7); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + else if (iter->find(paramsEmote2) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(6); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + else + { + range = ::atoi(Unicode::wideToNarrow(*iter).c_str()); + if ((range < 1) || (range > 256)) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("Range must be 1-256."), Unicode::emptyString); + return; + } + } + } + } + } + + std::vector playersInRange; + ServerWorld::findPlayerCreaturesInRange(targetObj->getPosition_w(), static_cast(range), playersInRange); + if (playersInRange.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("No eligible players found within %dm.", range)), Unicode::emptyString); + } + else + { + std::vector validPlayers; + CreatureObject const * co; + for (std::vector::const_iterator iter = playersInRange.begin(); iter != playersInRange.end(); ++iter) + { + co = (*iter)->asCreatureObject(); + if (!co || !PlayerCreatureController::getPlayerObject(co)) + continue; + + // always include self, even if I am invisible + if (co->getNetworkId() == targetObj->getNetworkId()) + { + validPlayers.push_back(*iter); + continue; + } + + // don't include invisible players + if (co->isHidden() || !co->isVisible() || !co->getCoverVisibility()) + continue; + + validPlayers.push_back(*iter); + } + + if (validPlayers.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("No eligible players found within %dm.", range)), Unicode::emptyString); + } + else + { + int const random = ::rand() % validPlayers.size(); + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Player \"%s\" within %dm was randomly chosen.", Unicode::wideToNarrow(validPlayers[random]->getAssignedObjectName()).c_str(), range)), Unicode::emptyString); + + // do emote at the selected player, if requested + if (socialType > 0) + { + // if I'm the one selected, use the /pointat social to point at myself + // since other socials may not make sense when I am the target + doSocial(*targetObj, validPlayers[random]->getNetworkId(), ((validPlayers[random]->getNetworkId() == targetObj->getNetworkId()) ? pointatSocialType : socialType)); + } + } + } + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextAreaPickRandomPlayerCommandAllowed", (timeNow + 30))); +} + +// ---------------------------------------------------------------------- + +static void commandFuncRoomPickRandomPlayer(Command const &, NetworkId const &actor, NetworkId const &, Unicode::String const & params) +{ + CreatureObject * const targetObj = dynamic_cast(ServerWorld::findObjectByNetworkId(actor)); + if (!targetObj) + return; + + PlayerObject const * const targetPlayerObj = PlayerCreatureController::getPlayerObject(targetObj); + if (!targetPlayerObj) + return; + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*targetObj)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("You must be standing inside a room of a structure or POB ship to do this."), Unicode::emptyString); + return; + } + + // prevent spamming of the command + Client const * const client = targetObj->getClient(); + if (!client) + return; + + int const timeNow = static_cast(::time(NULL)); + if (!client->isGod() && targetObj->getObjVars().hasItem("timeNextRoomPickRandomPlayerCommandAllowed") && (targetObj->getObjVars().getType("timeNextRoomPickRandomPlayerCommandAllowed") == DynamicVariable::INT)) + { + int timeNextRoomPickRandomPlayerCommandAllowed = 0; + if (targetObj->getObjVars().getItem("timeNextRoomPickRandomPlayerCommandAllowed", timeNextRoomPickRandomPlayerCommandAllowed)) + { + if (timeNextRoomPickRandomPlayerCommandAllowed > timeNow) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %ds before you can run this command again.", (timeNextRoomPickRandomPlayerCommandAllowed - timeNow))), Unicode::emptyString); + return; + } + } + } + + // handle options + static uint32 const pointatSocialType = SocialsManager::getSocialTypeByName("pointat"); + uint32 socialType = 0; + + if (!params.empty()) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(Unicode::toLower(params), tokens, NULL, NULL) && !tokens.empty()) + { + static Unicode::String const paramsPoint1 = Unicode::narrowToWide("-point"); + static Unicode::String const paramsPoint2 = Unicode::narrowToWide("point"); + static Unicode::String const paramsEmote1 = Unicode::narrowToWide("-emote="); + static Unicode::String const paramsEmote2 = Unicode::narrowToWide("emote="); + std::string emote; + + for (Unicode::UnicodeStringVector::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) + { + if ((*iter == paramsPoint1) || (*iter == paramsPoint2)) + { + socialType = pointatSocialType; + } + else if (iter->find(paramsEmote1) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(7); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + else if (iter->find(paramsEmote2) == 0) + { + emote = Unicode::wideToNarrow(*iter).substr(6); + socialType = SocialsManager::getSocialTypeByName(emote); + if (socialType == 0) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("\"%s\" is not a valid emote.", emote.c_str())), Unicode::emptyString); + return; + } + } + } + } + } + + std::vector validPlayers; + Container const * const cellContainer = ContainerInterface::getContainer(*containingCell); + if (cellContainer) + { + Object const * object; + ServerObject const * serverObject; + CreatureObject const * creatureObject; + for (ContainerConstIterator iter = cellContainer->begin(); iter != cellContainer->end(); ++iter) + { + object = (*iter).getObject(); + if (!object) + continue; + + serverObject = object->asServerObject(); + if (!serverObject) + continue; + + creatureObject = serverObject->asCreatureObject(); + if (!creatureObject || !PlayerCreatureController::getPlayerObject(creatureObject)) + continue; + + // always include self, even if I am invisible + if (creatureObject->getNetworkId() == targetObj->getNetworkId()) + { + validPlayers.push_back(serverObject); + continue; + } + + // don't include invisible players + if (creatureObject->isHidden() || !creatureObject->isVisible() || !creatureObject->getCoverVisibility()) + continue; + + validPlayers.push_back(serverObject); + } + } + + if (validPlayers.empty()) + { + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide("No eligible players found in this room."), Unicode::emptyString); + } + else + { + int const random = ::rand() % validPlayers.size(); + Chat::sendSystemMessage(*targetObj, Unicode::narrowToWide(FormattedString<1024>().sprintf("Player \"%s\" was randomly chosen out of %d players in this room.", Unicode::wideToNarrow(validPlayers[random]->getAssignedObjectName()).c_str(), validPlayers.size())), Unicode::emptyString); + + // do emote at the selected player, if requested + if (socialType > 0) + { + // if I'm the one selected, use the /pointat social to point at myself + // since other socials may not make sense when I am the target + doSocial(*targetObj, validPlayers[random]->getNetworkId(), ((validPlayers[random]->getNetworkId() == targetObj->getNetworkId()) ? pointatSocialType : socialType)); + } + } + + // set cooldown + if (!client->isGod()) + IGNORE_RETURN(targetObj->setObjVarItem("timeNextRoomPickRandomPlayerCommandAllowed", (timeNow + 30))); +} + +// ====================================================================== + +void CommandCppFuncs::install() +{ + // console style commands + CommandTable::addCppFunction("console_all", commandFuncConsoleAll); + CommandTable::addCppFunction("console_combat", commandFuncConsoleCombat); + CommandTable::addCppFunction("console_craft", commandFuncConsoleCraft); + CommandTable::addCppFunction("console_database", commandFuncConsoleDatabase); + CommandTable::addCppFunction("console_manufacture", commandFuncConsoleManufacture); + CommandTable::addCppFunction("console_money", commandFuncConsoleMoney); + CommandTable::addCppFunction("console_npc", commandFuncConsoleNpc); + CommandTable::addCppFunction("console_object", commandFuncConsoleObject); + CommandTable::addCppFunction("console_objvar", commandFuncConsoleObjvar); + CommandTable::addCppFunction("console_resource", commandFuncConsoleResource); + CommandTable::addCppFunction("console_script", commandFuncConsoleScript); + CommandTable::addCppFunction("console_server", commandFuncConsoleServer); + CommandTable::addCppFunction("console_skill", commandFuncConsoleSkill); + + // communication commands + CommandTable::addCppFunction("social", commandFuncSocial); + CommandTable::addCppFunction("socialInternal", commandFuncSocialInternal); + CommandTable::addCppFunction("spatialChat", commandFuncSpatialChat); + CommandTable::addCppFunction("spatialChatInternal", commandFuncSpatialChatInternal); + CommandTable::addCppFunction("setMood", commandFuncSetMood); + CommandTable::addCppFunction("setMoodInternal", commandFuncSetMoodInternal); + CommandTable::addCppFunction("systemMessage", commandFuncSystemMessage); +// CommandTable::addCppFunction("combatSpam", commandFuncCombatSpam); + + // admin commands + CommandTable::addCppFunction("admin_setGodMode", commandFuncAdminSetGodMode); + CommandTable::addCppFunction("admin_kick", commandFuncAdminKick); + CommandTable::addCppFunction("admin_planetwarp", commandFuncAdminPlanetwarp); + CommandTable::addCppFunction("admin_teleport", commandFuncAdminTeleport); + CommandTable::addCppFunction("admin_teleportTo", commandFuncAdminTeleportTo); + CommandTable::addCppFunction("admin_listGuilds", commandFuncAdminListGuilds); + CommandTable::addCppFunction("editBank", commandFuncAdminEditBank); + CommandTable::addCppFunction("editStats", commandFuncAdminEditStats); + CommandTable::addCppFunction("editAppearance", commandFuncAdminEditAppearance); + CommandTable::addCppFunction("grantTitle", commandFuncAdminGrantTitle); + CommandTable::addCppFunction("credits", commandFuncAdminCredits); + CommandTable::addCppFunction("getStationName", commandFuncAdminGetStationName); + CommandTable::addCppFunction("emptyMailTarget", commandFuncEmptyMailTarget); + CommandTable::addCppFunction("setPlayerAppearance", commandFuncSetPlayerAppearance); + CommandTable::addCppFunction("revertPlayerAppearance", commandFuncRevertPlayerAppearance); + + // auction commands + CommandTable::addCppFunction("auction_create", commandFuncAuctionCreate); + CommandTable::addCppFunction("auction_create_immediate", commandFuncAuctionCreateImmediate); + CommandTable::addCppFunction("auction_bid", commandFuncAuctionBid); + CommandTable::addCppFunction("auction_cancel", commandFuncAuctionCancel); + CommandTable::addCppFunction("auction_accept", commandFuncAuctionAccept); + CommandTable::addCppFunction("auction_query", commandFuncAuctionQuery); + CommandTable::addCppFunction("auction_retrieve", commandFuncAuctionRetrieve); + + // cell/building permissions commands + CommandTable::addCppFunction("addBannedPlayer", commandFuncAddBannedPlayer); + CommandTable::addCppFunction("removeBannedPlayer", commandFuncRemoveBannedPlayer); + CommandTable::addCppFunction("addAllowedPlayer", commandFuncAddAllowedPlayer); + CommandTable::addCppFunction("removeAllowedPlayer", commandFuncRemoveAllowedPlayer); + CommandTable::addCppFunction("setPublicState", commandFuncSetPublicState); + CommandTable::addCppFunction("setOwner", commandFuncSetOwner); + + CommandTable::addCppFunction("setPosture", commandSetPosture); + CommandTable::addCppFunction("duel", commandFuncDuel); + CommandTable::addCppFunction("endDuel", commandFuncEndDuel); + + // ui + CommandTable::addCppFunction("setWaypointActiveStatus", commandFuncSetWaypointActiveStatus); + CommandTable::addCppFunction("setWaypointName", commandFuncSetWaypointName); + + // harvester + CommandTable::addCppFunction("harvesterActivate", commandFuncHarvesterActivate); + CommandTable::addCppFunction("harvesterDeactivate", commandFuncHarvesterDeactivate); + CommandTable::addCppFunction("harvesterHarvest", commandFuncHarvesterHarvest); + CommandTable::addCppFunction("harvesterSelectResource", commandFuncHarvesterSelectResource); + CommandTable::addCppFunction("harvesterDiscardHopper", commandFuncHarvesterDiscardHopper); + CommandTable::addCppFunction("harvesterMakeCrate", commandFuncHarvesterMakeCrate); + CommandTable::addCppFunction("harvesterGetResourceData", commandFuncHarvesterGetResourceData); + + // syncronized ui + CommandTable::addCppFunction("synchronizedUiListen" , commandFuncSynchronizedUiListen); + CommandTable::addCppFunction("synchronizedUiStopListening", commandFuncSynchronizedUiStopListening); + + // resource + CommandTable::addCppFunction("resourceSetName", commandFuncResourceSetName); + + // resource container + CommandTable::addCppFunction("resourceContainerTransfer", commandFuncResourceContainerTransfer); + CommandTable::addCppFunction("resourceContainerSplit", commandFuncResourceContainerSplit); + + // survey + CommandTable::addCppFunction("makeSurvey", commandFuncMakeSurvey); + CommandTable::addCppFunction("requestSurvey", commandFuncRequestSurvey); + CommandTable::addCppFunction("requestCoreSample", commandFuncRequestCoreSample); + + CommandTable::addCppFunction("transferItemWeapon", commandFuncTransferWeapon); + CommandTable::addCppFunction("transferItemArmor", commandFuncTransferArmor); + CommandTable::addCppFunction("transferItemMisc", commandFuncTransferMisc); + CommandTable::addCppFunction("openContainer", commandFuncOpenContainer); + CommandTable::addCppFunction("closeContainer", commandFuncCloseContainer); + CommandTable::addCppFunction("openLotteryContainer", commandFuncOpenLotteryContainer); + CommandTable::addCppFunction("closeLotteryContainer", commandFuncCloseLotteryContainer); + CommandTable::addCppFunction("giveItem", commandFuncGiveItem); + + // grouping + CommandTable::addCppFunction("groupInvite", commandFuncGroupInvite); + CommandTable::addCppFunction("groupUninvite", commandFuncGroupUninvite); + CommandTable::addCppFunction("groupJoin", commandFuncGroupJoin); + CommandTable::addCppFunction("groupDecline", commandFuncGroupDecline); + CommandTable::addCppFunction("groupDisband", commandFuncGroupDisband); + CommandTable::addCppFunction("kickFromShip", commandFuncKickFromShip); + CommandTable::addCppFunction("groupChat", commandFuncGroupChat); + CommandTable::addCppFunction("groupMakeLeader", commandFuncGroupMakeLeader); + CommandTable::addCppFunction("groupMakeMasterLooter", commandFuncGroupMakeMasterLooter); + CommandTable::addCppFunction("createGroupPickup", commandFuncCreateGroupPickup); + CommandTable::addCppFunction("useGroupPickup", commandFuncUseGroupPickup); + CommandTable::addCppFunction("groupTextChatRoomRejoin", commandFuncGroupTextChatRoomRejoin); + CommandTable::addCppFunction("groupPickRandomGroupMember", commandFuncGroupPickRandomGroupMember); + + // guilds + CommandTable::addCppFunction("guildChat", commandFuncGuildChat); + CommandTable::addCppFunction("guildTextChatRoomRejoin", commandFuncGuildTextChatRoomRejoin); + CommandTable::addCppFunction("guildPickRandomGuildMember", commandFuncGuildPickRandomGuildMember); + + // city + CommandTable::addCppFunction("cityChat", commandFuncCityChat); + CommandTable::addCppFunction("cityTextChatRoomRejoin", commandFuncCityTextChatRoomRejoin); + CommandTable::addCppFunction("cityPickRandomCitizen", commandFuncCityPickRandomCitizen); + + //chat + CommandTable::addCppFunction("auctionChat", commandFuncAuctionChat); + CommandTable::addCppFunction("planetChat", commandFuncPlanetChat); + + // crafting + CommandTable::addCppFunction("requestResourceWeights", commandFuncRequestResourceWeights); + CommandTable::addCppFunction("requestResourceWeightsBatch", commandFuncRequestResourceWeightsBatch); + CommandTable::addCppFunction("requestDraftSlots", commandFuncRequestDraftSlots); + CommandTable::addCppFunction("requestDraftSlotsBatch", commandFuncRequestDraftSlotsBatch); + CommandTable::addCppFunction("requestManfSchematicSlots", commandFuncRequestManfSchematicSlots); + CommandTable::addCppFunction("requestCraftingSession", commandFuncRequestCraftingSession); + CommandTable::addCppFunction("requestCraftingSessionFail",commandFuncRequestCraftingSessionFail); + CommandTable::addCppFunction("selectDraftSchematic", commandFuncSelectDraftSchematic); + CommandTable::addCppFunction("nextCraftingStage", commandFuncNextCraftingStage); + CommandTable::addCppFunction("createPrototype", commandFuncCreatePrototype); + CommandTable::addCppFunction("createManfSchematic", commandFuncCreateManfSchematic); + CommandTable::addCppFunction("cancelCraftingSession", commandFuncCancelCraftingSession); + CommandTable::addCppFunction("stopCraftingSession", commandFuncStopCraftingSession); + CommandTable::addCppFunction("restartCraftingSession", commandFuncRestartCraftingSession); + CommandTable::addCppFunction("extractObject", commandFuncExtractObject); + CommandTable::addCppFunction("repair", commandFuncRepair); + CommandTable::addCppFunction("factoryCrateSplit", commandFuncFactoryCrateSplit); + + // misc + CommandTable::addCppFunction("showDanceVisuals", commandFuncShowDanceVisuals); + CommandTable::addCppFunction("showMusicianVisuals", commandFuncShowMusicianVisuals); + CommandTable::addCppFunction("placeStructure", commandFuncPlaceStructure); + CommandTable::addCppFunction("getAttributes", commandFuncGetAttributes); + CommandTable::addCppFunction("getAttributesBatch", commandFuncGetAttributesBatch); + CommandTable::addCppFunction("sitServer", commandFuncSitServer); + CommandTable::addCppFunction("jumpServer", commandFuncJumpServer); + CommandTable::addCppFunction("purchaseTicket", commandFuncPurchaseTicket); + CommandTable::addCppFunction("addFriend", commandFuncAddFriend); + CommandTable::addCppFunction("removeFriend", commandFuncRemoveFriend); + CommandTable::addCppFunction("getFriendList", commandFuncGetFriendList); + CommandTable::addCppFunction("addIgnore", commandFuncAddIgnore); + CommandTable::addCppFunction("removeIgnore", commandFuncRemoveIgnore); + CommandTable::addCppFunction("getIgnoreList", commandFuncGetIgnoreList); + CommandTable::addCppFunction("requestBiography", commandFuncRequestBiography); + CommandTable::addCppFunction("setBiography", commandFuncSetBiography); + CommandTable::addCppFunction("requestWaypointAtPosition", commandFuncRequestWaypointAtPosition); + CommandTable::addCppFunction("serverDestroyObject", commandFuncServerDestroyObject); + CommandTable::addCppFunction("setSpokenLanguage", commandFuncSetSpokenLanguage); + CommandTable::addCppFunction("applyPowerup", commandFuncApplyPowerup); + CommandTable::addCppFunction("report", commandFuncReport); + CommandTable::addCppFunction("resetCooldowns", commandFuncResetCooldowns); + CommandTable::addCppFunction("spewCommandQueue", commandFuncSpewCommandQueue); + CommandTable::addCppFunction("locateStructure", commandFuncLocateStructure); + CommandTable::addCppFunction("locateVendor", commandFuncLocateVendor); + CommandTable::addCppFunction("showCtsHistory", commandFuncShowCtsHistory); + CommandTable::addCppFunction("pickupAllRoomItemsIntoInventory", commandFuncPickupAllRoomItemsIntoInventory); + CommandTable::addCppFunction("dropAllInventoryItemsIntoRoom", commandFuncDropAllInventoryItemsIntoRoom); + CommandTable::addCppFunction("saveDecorationLayout", commandFuncSaveDecorationLayout); + CommandTable::addCppFunction("restoreDecorationLayout", commandFuncRestoreDecorationLayout); + CommandTable::addCppFunction("areaPickRandomPlayer", commandFuncAreaPickRandomPlayer); + CommandTable::addCppFunction("roomPickRandomPlayer", commandFuncRoomPickRandomPlayer); + + // match making + CommandTable::addCppFunction("setMatchMakingPersonalId", commandFuncSetMatchMakingPersonalId); + CommandTable::addCppFunction("setMatchMakingCharacterId", commandFuncSetMatchMakingCharacterId); + CommandTable::addCppFunction("requestCharacterMatch", commandFuncRequestCharacterMatch); + CommandTable::addCppFunction("toggleSearchableByCtsSourceGalaxy", commandFuncToggleSearchableByCtsSourceGalaxy); + CommandTable::addCppFunction("toggleDisplayLocationInSearchResults", commandFuncToggleDisplayLocationInSearchResults); + CommandTable::addCppFunction("toggleAnonymous", commandFuncToggleAnonymous); + CommandTable::addCppFunction("toggleHelper", commandFuncToggleHelper); + CommandTable::addCppFunction("toggleRolePlay", commandFuncToggleRolePlay); + CommandTable::addCppFunction("toggleLookingForGroup", commandFuncToggleLookingForGroup); + CommandTable::addCppFunction("toggleAwayFromKeyBoard", commandFuncToggleAwayFromKeyBoard); + CommandTable::addCppFunction("toggleDisplayingFactionRank", commandFuncToggleDisplayingFactionRank); + CommandTable::addCppFunction("toggleOutOfCharacter", commandFuncToggleOutOfCharacter); + CommandTable::addCppFunction("toggleLookingForWork", commandFuncToggleLookingForWork); + + //skill + CommandTable::addCppFunction("revokeSkill", commandFuncRevokeSkill); + CommandTable::addCppFunction("setCurrentSkillTitle", commandFuncSetCurrentSkillTitle); + + //misc ui + CommandTable::addCppFunction("permissionListModify", commandFuncPermissionListModify); + CommandTable::addCppFunction("requestCharacterSheetInfo", commandFuncRequestCharacterSheetInfo); + CommandTable::addCppFunction("removeBuff", commandFuncRemoveBuff); + + // npc conversation + CommandTable::addCppFunction("npcConversationStart", commandFuncNpcConversationStart); + CommandTable::addCppFunction("npcConversationStop", commandFuncNpcConversationStop); + CommandTable::addCppFunction("npcConversationSelect", commandFuncNpcConversationSelect); + CommandTable::addCppFunction("handleUnstick", commandFuncUnstick); + CommandTable::addCppFunction("getAccountInfo", commandFuncGetAccountInfo); + CommandTable::addCppFunction("lag", commandFuncLag); + + //knowledgebase (i.e. holocron) + CommandTable::addCppFunction("executeKnowledgeBaseMessage", commandExecuteKnowledgeBaseMessage); + CommandTable::addCppFunction("reconnectToTransferServer", commandFuncReconnectToTransferServer); + CommandTable::addCppFunction("findFriend", commandFuncFindFriend); + + // godclient-specific functions + CommandTable::addCppFunction(FormManager::getFormCommandName(), commandFuncFormCommand); + + // space + CommandTable::addCppFunction("installShipComponent", commandFuncInstallShipComponents); + CommandTable::addCppFunction("uninstallShipComponent", commandFuncUninstallShipComponents); + CommandTable::addCppFunction("insertItemIntoShipComponentSlot", commandFuncInsertItemIntoShipComponentSlot); + CommandTable::addCppFunction("associateDroidControlDeviceWithShip", commandFuncAssociateDroidControlDeviceWithShip); + CommandTable::addCppFunction("unassociateDroidControlDeviceWithShip", commandFuncAssociateDroidControlDeviceWithShip); + + CommandTable::addCppFunction("serverAsteroidDataListen" , commandFuncServerAsteroidDataListen); + CommandTable::addCppFunction("serverAsteroidDataStopListening", commandFuncServerAsteroidDataStopListening); + + CommandTable::addCppFunction("boosterOn", commandFuncBoosterOn); + CommandTable::addCppFunction("boosterOff", commandFuncBoosterOff); + + CommandTable::addCppFunction("setFormation", commandFuncSetFormation); + CommandTable::addCppFunction("setFormationSlot", commandFuncSetFormationSlot); + CommandTable::addCppFunction("undock", commandFuncUnDock); + CommandTable::addCppFunction("launchIntoSpace", commandFuncLaunchIntoSpace); + CommandTable::addCppFunction("acceptQuest", commandFuncAcceptQuest); + CommandTable::addCppFunction("completeQuest", commandFuncReceiveReward); + CommandTable::addCppFunction("abandonQuest", commandFuncAbandonQuest); + + // exchange + CommandTable::addCppFunction("exchangeListCredits", commandFuncExchangeListCredits); + + // squelch + CommandTable::addCppFunction("squelch", commandFuncSquelch); + CommandTable::addCppFunction("unsquelch", commandFuncUnsquelch); + + // warden + CommandTable::addCppFunction("grantWarden", commandFuncGrantWarden); + CommandTable::addCppFunction("revokeWarden", commandFuncRevokeWarden); + CommandTable::addCppFunction("spammer", commandFuncSpammer); + CommandTable::addCppFunction("unspammer", commandFuncUnspammer); + CommandTable::addCppFunction("deputizeWarden", commandFuncDeputizeWarden); + CommandTable::addCppFunction("undeputizeWarden", commandFuncUndeputizeWarden); + + // unlocked slot management commands + CommandTable::addCppFunction("occupyUnlockedSlot", commandFuncOccupyUnlockedSlot); + CommandTable::addCppFunction("vacateUnlockedSlot", commandFuncVacateUnlockedSlot); + CommandTable::addCppFunction("swapUnlockedSlot", commandFuncSwapUnlockedSlot); +} + +// ---------------------------------------------------------------------- + +void CommandCppFuncs::remove() +{ +} + +// ====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserCraft.cpp b/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserCraft.cpp index 0fe21bd1a..6a28b3eb4 100644 --- a/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserCraft.cpp +++ b/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserCraft.cpp @@ -1,193 +1,193 @@ -// ====================================================================== -// -// ConsoleCommandParserCraft.cpp -// copyright (c) 2001 Sony Online Entertainment -// -// ====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/ConsoleCommandParserCraft.h" -#include "UnicodeUtils.h" -#include "serverGame/ConsoleCommandParserCraftStation.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/GameServer.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/ServerWorld.h" -#include "sharedFoundation/GameControllerMessage.h" - - -// ====================================================================== - -static const CommandParser::CmdInfo cmds[] = -{ - {"draft", 1, "", "Select a draft schematic to craft with"}, - {"fillslot", 3, " ", "Fill a draft schematic slot with an ingredient"}, - {"nextstage", 0, "", "Go to the next stage of crafting"}, - {"experiment", 3, " ", "Experiment to improve an attribute"}, - {"customize", 2, " ", "Set a customization property"}, - {"makeprototype", 1, "", "Create a prototype object"}, - {"makeschematic", 1, "", "Create manufacturing schematic"}, - {"stop", 0, "", "Stops the current crafting session"}, - {"enableSchematicFilter", 0, "", "Enables schematic filtering (god mode only)"}, - {"disableSchematicFilter", 0, "", "Disables schematic filtering (god mode only)"}, - {"", 0, "", ""} // this must be last -}; - - -//----------------------------------------------------------------- - -ConsoleCommandParserCraft::ConsoleCommandParserCraft (void) : -CommandParser ("craft", 0, "...", "Crafting related commands.", 0) -{ - createDelegateCommands (cmds); - addSubCommand(new ConsoleCommandParserCraftStation()); -} - -//----------------------------------------------------------------- - - -bool ConsoleCommandParserCraft::performParsing (const NetworkId & userId, const StringVector_t & argv, const String_t & originalCommand, String_t & result, const CommandParser * node) -{ - NOT_NULL (node); - UNREF(originalCommand); - - CreatureObject * creatureObject = safe_cast(ServerWorld::findObjectByNetworkId(userId)); - PlayerObject * playerObject = const_cast(PlayerCreatureController::getPlayerObject(creatureObject)); - - //----------------------------------------------------------------- - - if (isAbbrev( argv [0], "draft")) - { - int index = atoi(Unicode::wideToNarrow(argv[1]).c_str()) - 1; - - playerObject->selectDraftSchematic(index); - result += getErrorMessage (argv[0], ERR_SUCCESS); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "fillslot")) - { - int slot(atoi(Unicode::wideToNarrow(argv[1]).c_str())); - int option(atoi(Unicode::wideToNarrow(argv[2]).c_str())); - NetworkId ingredient(Unicode::wideToNarrow(argv[3])); - - if (playerObject->fillSlot(slot - 1, option - 1, ingredient)) - result += getErrorMessage (argv[0], ERR_SUCCESS); - else - result += getErrorMessage (argv[0], ERR_FILLSLOT_FAIL); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "nextstage")) - { - if (playerObject->goToNextCraftingStage()) - result += getErrorMessage (argv[0], ERR_SUCCESS); - else - result += getErrorMessage (argv[0], ERR_FAIL); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "experiment")) - { - int attribute(atoi(Unicode::wideToNarrow(argv[1]).c_str())); - int points(atoi(Unicode::wideToNarrow(argv[2]).c_str())); - int core(atoi(Unicode::wideToNarrow(argv[3]).c_str())); - - std::vector experiment; - experiment.push_back(MessageQueueCraftExperiment::ExperimentInfo(attribute - 1, points)); - if (playerObject->experiment(experiment, points, core)) - result += getErrorMessage (argv[0], ERR_SUCCESS); - else - result += getErrorMessage (argv[0], ERR_FILLSLOT_FAIL); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "customize")) - { - int property(atoi(Unicode::wideToNarrow(argv[1]).c_str())); - int value(atoi(Unicode::wideToNarrow(argv[2]).c_str())); - - if (playerObject->customize(property - 1, value)) - result += getErrorMessage (argv[0], ERR_SUCCESS); - else - result += getErrorMessage (argv[0], ERR_CUSTOMIZE_FAIL); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "makeprototype")) - { - std::vector customizations; - if (playerObject->setCustomizationData(argv[1], -1, customizations, 1) == - Crafting::CE_success && playerObject->createPrototype(true)) - { - result += getErrorMessage (argv[0], ERR_SUCCESS); - } - else - result += getErrorMessage (argv[0], ERR_FAIL); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "makeschematic")) - { - result += getErrorMessage (argv[0], ERR_FAIL); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "stop")) - { - playerObject->stopCrafting(true); - result += getErrorMessage (argv[0], ERR_SUCCESS); - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "enableSchematicFilter")) - { - if (creatureObject->getClient() == NULL || !creatureObject->getClient()->isGod()) - result += getErrorMessage (argv[0], ERR_FAIL); - else - { - creatureObject->enableSchematicFiltering(); - result += getErrorMessage (argv[0], ERR_SUCCESS); - } - } - - //----------------------------------------------------------------- - - else if (isAbbrev( argv [0], "disableSchematicFilter")) - { - if (creatureObject->getClient() == NULL || !creatureObject->getClient()->isGod()) - result += getErrorMessage (argv[0], ERR_FAIL); - else - { - creatureObject->disableSchematicFiltering(); - result += getErrorMessage (argv[0], ERR_SUCCESS); - } - } - - //----------------------------------------------------------------- - - - else - { - result += getErrorMessage(argv[0], ERR_NO_HANDLER); - } - - return true; -} - - -// ====================================================================== - - - - - +// ====================================================================== +// +// ConsoleCommandParserCraft.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/ConsoleCommandParserCraft.h" +#include "UnicodeUtils.h" +#include "serverGame/ConsoleCommandParserCraftStation.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/ServerWorld.h" +#include "sharedFoundation/GameControllerMessage.h" + + +// ====================================================================== + +static const CommandParser::CmdInfo cmds[] = +{ + {"draft", 1, "", "Select a draft schematic to craft with"}, + {"fillslot", 3, " ", "Fill a draft schematic slot with an ingredient"}, + {"nextstage", 0, "", "Go to the next stage of crafting"}, + {"experiment", 3, " ", "Experiment to improve an attribute"}, + {"customize", 2, " ", "Set a customization property"}, + {"makeprototype", 1, "", "Create a prototype object"}, + {"makeschematic", 1, "", "Create manufacturing schematic"}, + {"stop", 0, "", "Stops the current crafting session"}, + {"enableSchematicFilter", 0, "", "Enables schematic filtering (god mode only)"}, + {"disableSchematicFilter", 0, "", "Disables schematic filtering (god mode only)"}, + {"", 0, "", ""} // this must be last +}; + + +//----------------------------------------------------------------- + +ConsoleCommandParserCraft::ConsoleCommandParserCraft (void) : +CommandParser ("craft", 0, "...", "Crafting related commands.", 0) +{ + createDelegateCommands (cmds); + addSubCommand(new ConsoleCommandParserCraftStation()); +} + +//----------------------------------------------------------------- + + +bool ConsoleCommandParserCraft::performParsing (const NetworkId & userId, const StringVector_t & argv, const String_t & originalCommand, String_t & result, const CommandParser * node) +{ + NOT_NULL (node); + UNREF(originalCommand); + + CreatureObject * creatureObject = safe_cast(ServerWorld::findObjectByNetworkId(userId)); + PlayerObject * playerObject = const_cast(PlayerCreatureController::getPlayerObject(creatureObject)); + + //----------------------------------------------------------------- + + if (isAbbrev( argv [0], "draft")) + { + int index = atoi(Unicode::wideToNarrow(argv[1]).c_str()) - 1; + + playerObject->selectDraftSchematic(index); + result += getErrorMessage (argv[0], ERR_SUCCESS); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "fillslot")) + { + int slot(atoi(Unicode::wideToNarrow(argv[1]).c_str())); + int option(atoi(Unicode::wideToNarrow(argv[2]).c_str())); + NetworkId ingredient(Unicode::wideToNarrow(argv[3])); + + if (playerObject->fillSlot(slot - 1, option - 1, ingredient)) + result += getErrorMessage (argv[0], ERR_SUCCESS); + else + result += getErrorMessage (argv[0], ERR_FILLSLOT_FAIL); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "nextstage")) + { + if (playerObject->goToNextCraftingStage()) + result += getErrorMessage (argv[0], ERR_SUCCESS); + else + result += getErrorMessage (argv[0], ERR_FAIL); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "experiment")) + { + int attribute(atoi(Unicode::wideToNarrow(argv[1]).c_str())); + int points(atoi(Unicode::wideToNarrow(argv[2]).c_str())); + int core(atoi(Unicode::wideToNarrow(argv[3]).c_str())); + + std::vector experiment; + experiment.push_back(MessageQueueCraftExperiment::ExperimentInfo(attribute - 1, points)); + if (playerObject->experiment(experiment, points, core)) + result += getErrorMessage (argv[0], ERR_SUCCESS); + else + result += getErrorMessage (argv[0], ERR_FILLSLOT_FAIL); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "customize")) + { + int property(atoi(Unicode::wideToNarrow(argv[1]).c_str())); + int value(atoi(Unicode::wideToNarrow(argv[2]).c_str())); + + if (playerObject->customize(property - 1, value)) + result += getErrorMessage (argv[0], ERR_SUCCESS); + else + result += getErrorMessage (argv[0], ERR_CUSTOMIZE_FAIL); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "makeprototype")) + { + std::vector customizations; + if (playerObject->setCustomizationData(argv[1], -1, customizations, 1) == + Crafting::CE_success && playerObject->createPrototype(true)) + { + result += getErrorMessage (argv[0], ERR_SUCCESS); + } + else + result += getErrorMessage (argv[0], ERR_FAIL); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "makeschematic")) + { + result += getErrorMessage (argv[0], ERR_FAIL); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "stop")) + { + playerObject->stopCrafting(true); + result += getErrorMessage (argv[0], ERR_SUCCESS); + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "enableSchematicFilter")) + { + if (creatureObject->getClient() == NULL || !creatureObject->getClient()->isGod()) + result += getErrorMessage (argv[0], ERR_FAIL); + else + { + creatureObject->enableSchematicFiltering(); + result += getErrorMessage (argv[0], ERR_SUCCESS); + } + } + + //----------------------------------------------------------------- + + else if (isAbbrev( argv [0], "disableSchematicFilter")) + { + if (creatureObject->getClient() == NULL || !creatureObject->getClient()->isGod()) + result += getErrorMessage (argv[0], ERR_FAIL); + else + { + creatureObject->disableSchematicFiltering(); + result += getErrorMessage (argv[0], ERR_SUCCESS); + } + } + + //----------------------------------------------------------------- + + + else + { + result += getErrorMessage(argv[0], ERR_NO_HANDLER); + } + + return true; +} + + +// ====================================================================== + + + + + diff --git a/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpaceAi.cpp b/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpaceAi.cpp index d596f78cc..9972dcf59 100644 --- a/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpaceAi.cpp +++ b/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpaceAi.cpp @@ -119,7 +119,8 @@ bool ConsoleCommandParserSpaceAi::performParsing(const NetworkId & userId, const { Vector const & position_w = iterTransformList->getPosition_p(); - message += formattedString.sprintf("[%d] %.2f, %.2f, %.2f%s", index++, position_w.x, position_w.y, position_w.z, (index < static_cast(transformList.size())) ? "\n" : ""); + message += formattedString.sprintf("[%d] %.2f, %.2f, %.2f%s", (index+1), position_w.x, position_w.y, position_w.z, (index < static_cast(transformList.size())) ? "\n" : ""); + index++; } Chat::sendSystemMessage(*serverObject, Unicode::narrowToWide(message.c_str()), Unicode::emptyString); diff --git a/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpawner.cpp b/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpawner.cpp index 6aa34bf42..79de38b7e 100644 --- a/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpawner.cpp +++ b/src/engine/server/library/serverGame/src/shared/console/ConsoleCommandParserSpawner.cpp @@ -1,130 +1,130 @@ -// ====================================================================== -// -// ConsoleCommandParserSpawner.cpp -// copyright (c) 2001 Sony Online Entertainment -// -// ====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/ConsoleCommandParserSpawner.h" - -#include "UnicodeUtils.h" -#include "serverGame/CreatureObject.h" - -#include -#include - -// ====================================================================== - -namespace -{ - namespace CommandNames - { -#define MAKE_COMMAND(a) const char * const a = #a - MAKE_COMMAND(showQueue); - MAKE_COMMAND(showCreatures); -#undef MAKE_COMMAND - } - - const CommandParser::CmdInfo cmds[] = - { - {CommandNames::showQueue, 0, "", "Lists players on the spawn queue."}, - {CommandNames::showCreatures, 0, "[pc|npc]", "Lists all creatures on the server."}, - {"", 0, "", ""} // this must be last - }; - -} - -//----------------------------------------------------------------- - -ConsoleCommandParserSpawner::ConsoleCommandParserSpawner (void) : -CommandParser ("Spawner", 0, "...", "Spawner related commands.", 0) -{ - createDelegateCommands (cmds); -} - -//---------------------------------------------------------------------- - - -bool ConsoleCommandParserSpawner::performParsing (const NetworkId &, const StringVector_t & argv, const String_t & , String_t & result, const CommandParser *) -{ - // ---------------------------------------------------------------- - - if (isCommand (argv[0], CommandNames::showQueue)) - { - CreatureObject::showSpawnQueue(result); - return true; - } - - else if(isCommand (argv[0], CommandNames::showCreatures)) - { - bool npcOnly = false; - bool pcOnly = false; - if(argv.size() >= 2) - { - std::string arg2 = Unicode::wideToNarrow(argv[1]); - if(arg2 == "npc") - { - npcOnly = true; - } - else if(arg2 == "pc") - { - pcOnly = true; - } - } - - static const Unicode::String header(Unicode::narrowToWide(std::string("Creature Listing - ID: POS: Auth Server: Template Name\n"))); - result += header; - const CreatureObject::AllCreaturesSet & creatureList = CreatureObject::getAllCreatures(); - CreatureObject::AllCreaturesSet::const_iterator i; - int count = 0; - for(i = creatureList.begin(); i != creatureList.end(); ++i) - { - const CreatureObject * creature = (*i); - if(creature) - { - if(pcOnly && (!creature->isPlayerControlled()) ) - continue; - if(npcOnly && creature->isPlayerControlled()) - continue; - - std::string creatureEntry = creature->getNetworkId().getValueString(); - creatureEntry += ": "; - - char locBuffer[32] = {"\0"}; - Vector loc = creature->getTransform_o2w().getPosition_p(); - snprintf(locBuffer, sizeof(locBuffer), "%.0f, %.0f: ", loc.x, loc.z); - creatureEntry += locBuffer; - - snprintf(locBuffer, sizeof(locBuffer), "%lu: ", creature->getAuthServerProcessId()); - creatureEntry += locBuffer; - creatureEntry += creature->getObjectTemplateName(); - - creatureEntry += "\n"; - - result += Unicode::narrowToWide(creatureEntry); - count++; - } - } - char countBuffer[32] = {"\0"}; - snprintf(countBuffer, sizeof(countBuffer), "%d creatures listed: ", count); - result += Unicode::narrowToWide(std::string(countBuffer)); - return true; - } - - - else - { - result += getErrorMessage (argv[0], ERR_NO_HANDLER); - return false; - } - - return true; -} - -// ====================================================================== - - - - - +// ====================================================================== +// +// ConsoleCommandParserSpawner.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/ConsoleCommandParserSpawner.h" + +#include "UnicodeUtils.h" +#include "serverGame/CreatureObject.h" + +#include +#include + +// ====================================================================== + +namespace +{ + namespace CommandNames + { +#define MAKE_COMMAND(a) const char * const a = #a + MAKE_COMMAND(showQueue); + MAKE_COMMAND(showCreatures); +#undef MAKE_COMMAND + } + + const CommandParser::CmdInfo cmds[] = + { + {CommandNames::showQueue, 0, "", "Lists players on the spawn queue."}, + {CommandNames::showCreatures, 0, "[pc|npc]", "Lists all creatures on the server."}, + {"", 0, "", ""} // this must be last + }; + +} + +//----------------------------------------------------------------- + +ConsoleCommandParserSpawner::ConsoleCommandParserSpawner (void) : +CommandParser ("Spawner", 0, "...", "Spawner related commands.", 0) +{ + createDelegateCommands (cmds); +} + +//---------------------------------------------------------------------- + + +bool ConsoleCommandParserSpawner::performParsing (const NetworkId &, const StringVector_t & argv, const String_t & , String_t & result, const CommandParser *) +{ + // ---------------------------------------------------------------- + + if (isCommand (argv[0], CommandNames::showQueue)) + { + CreatureObject::showSpawnQueue(result); + return true; + } + + else if(isCommand (argv[0], CommandNames::showCreatures)) + { + bool npcOnly = false; + bool pcOnly = false; + if(argv.size() >= 2) + { + std::string arg2 = Unicode::wideToNarrow(argv[1]); + if(arg2 == "npc") + { + npcOnly = true; + } + else if(arg2 == "pc") + { + pcOnly = true; + } + } + + static const Unicode::String header(Unicode::narrowToWide(std::string("Creature Listing - ID: POS: Auth Server: Template Name\n"))); + result += header; + const CreatureObject::AllCreaturesSet & creatureList = CreatureObject::getAllCreatures(); + CreatureObject::AllCreaturesSet::const_iterator i; + int count = 0; + for(i = creatureList.begin(); i != creatureList.end(); ++i) + { + const CreatureObject * creature = (*i); + if(creature) + { + if(pcOnly && (!creature->isPlayerControlled()) ) + continue; + if(npcOnly && creature->isPlayerControlled()) + continue; + + std::string creatureEntry = creature->getNetworkId().getValueString(); + creatureEntry += ": "; + + char locBuffer[32] = {"\0"}; + Vector loc = creature->getTransform_o2w().getPosition_p(); + snprintf(locBuffer, sizeof(locBuffer), "%.0f, %.0f: ", loc.x, loc.z); + creatureEntry += locBuffer; + + snprintf(locBuffer, sizeof(locBuffer), "%lu: ", creature->getAuthServerProcessId()); + creatureEntry += locBuffer; + creatureEntry += creature->getObjectTemplateName(); + + creatureEntry += "\n"; + + result += Unicode::narrowToWide(creatureEntry); + count++; + } + } + char countBuffer[32] = {"\0"}; + snprintf(countBuffer, sizeof(countBuffer), "%d creatures listed: ", count); + result += Unicode::narrowToWide(std::string(countBuffer)); + return true; + } + + + else + { + result += getErrorMessage (argv[0], ERR_NO_HANDLER); + return false; + } + + return true; +} + +// ====================================================================== + + + + + diff --git a/src/engine/server/library/serverGame/src/shared/controller/AiShipController.cpp b/src/engine/server/library/serverGame/src/shared/controller/AiShipController.cpp index b14698b3e..d2bf69f76 100644 --- a/src/engine/server/library/serverGame/src/shared/controller/AiShipController.cpp +++ b/src/engine/server/library/serverGame/src/shared/controller/AiShipController.cpp @@ -1648,7 +1648,7 @@ void AiShipController::sendDebugAiToClients(AiDebugString & aiDebugString) float const turretMissChance = getTurretMissChance() * 100.0f; float const turretMissAngleDegrees = convertRadiansToDegrees(getTurretMissAngle()); - aiDebugString.addText(formattedString.sprintf("turret miss(%.0f%% @ %.0f°)\n", turretMissChance, turretMissAngleDegrees)); + aiDebugString.addText(formattedString.sprintf("turret miss(%.0f%% @ %.0f)\n", turretMissChance, turretMissAngleDegrees)); } } diff --git a/src/engine/server/library/serverGame/src/shared/core/Client.cpp b/src/engine/server/library/serverGame/src/shared/core/Client.cpp index cacf9ed32..038a790ae 100644 --- a/src/engine/server/library/serverGame/src/shared/core/Client.cpp +++ b/src/engine/server/library/serverGame/src/shared/core/Client.cpp @@ -1,2505 +1,2505 @@ -// ====================================================================== -// -// Client.cpp -// -// Copyright 2002 Sony Online Entertainment -// -// ====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/Client.h" - -#include "Archive/ByteStream.h" -#include "LocalizationManager.h" -#include "serverGame/BuildingObject.h" -#include "serverGame/Chat.h" -#include "serverGame/CityInterface.h" -#include "serverGame/CommoditiesMarket.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ConnectionServerConnection.h" -#include "serverGame/ConsentManager.h" -#include "serverGame/ConsoleManager.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/GameServer.h" -#include "serverGame/GuildInterface.h" -#include "serverGame/GuildMemberInfo.h" -#include "serverGame/GroupObject.h" -#include "serverGame/LogoutTracker.h" -#include "serverGame/NameManager.h" -#include "serverGame/ObjectTracker.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PlanetMapManagerServer.h" -#include "serverGame/PlanetObject.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/PlayerShipController.h" -#include "serverGame/PvpUpdateObserver.h" -#include "serverGame/ServerMessageForwarding.h" -#include "serverGame/ServerSecureTrade.h" -#include "serverGame/ServerTangibleObjectTemplate.h" -#include "serverGame/ServerUIManager.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/SpaceVisibilityManager.h" -#include "serverGame/ShipClientUpdateTracker.h" -#include "serverGame/ShipObject.h" -#include "serverGame/TriggerVolume.h" -#include "serverNetworkMessages/GameConnectionServerMessages.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptFunctionTable.h" -#include "serverScript/ScriptParameters.h" -#include "serverUtility/AdminAccountManager.h" -#include "serverUtility/ServerClock.h" -#include "sharedFoundation/Clock.h" -#include "sharedFoundation/CrcLowerString.h" -#include "sharedFoundation/DynamicVariable.h" -#include "sharedFoundation/DynamicVariableList.h" -#include "sharedFoundation/DynamicVariableLocationData.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/GameControllerMessage.h" -#include "sharedFoundation/Os.h" -#include "sharedGame/CommandTable.h" -#include "sharedGame/GuildRankDataTable.h" -#include "sharedGame/LfgDataTable.h" -#include "sharedGame/PlatformFeatureBits.h" -#include "sharedGame/RadialMenuManager.h" -#include "sharedGame/ShipSlotIdManager.h" -#include "sharedLog/Log.h" -#include "sharedMathArchive/TransformArchive.h" -#include "sharedMathArchive/VectorArchive.h" -#include "sharedMessageDispatch/Message.h" -#include "sharedMessageDispatch/Transceiver.h" -#include "sharedNetworkMessages/AcceptAuctionMessage.h" -#include "sharedNetworkMessages/AddMapLocationMessage.h" -#include "sharedNetworkMessages/AddMapLocationResponseMessage.h" -#include "sharedNetworkMessages/AuctionQueryHeadersMessage.h" -#include "sharedNetworkMessages/AuctionQueryMessage.h" -#include "sharedNetworkMessages/BidAuctionMessage.h" -#include "sharedNetworkMessages/CancelLiveAuctionMessage.h" -#include "sharedNetworkMessages/ChatAvatarId.h" -#include "sharedNetworkMessages/ChatEnum.h" -#include "sharedNetworkMessages/ChatInviteGroupToRoom.h" -#include "sharedNetworkMessages/ChatOnInviteGroupToRoom.h" -#include "sharedNetworkMessages/ChatPersistentMessageToServer.h" -#include "sharedNetworkMessages/CommandChannelMessages.h" -#include "sharedNetworkMessages/ConsentResponseMessage.h" -#include "sharedNetworkMessages/ConsoleChannelMessages.h" -#include "sharedNetworkMessages/ControllerMessageFactory.h" -#include "sharedNetworkMessages/CreateAuctionMessage.h" -#include "sharedNetworkMessages/CreateImmediateAuctionMessage.h" -#include "sharedNetworkMessages/CreateProjectileMessage.h" -#include "sharedNetworkMessages/ExpertiseRequestMessage.h" -#include "sharedNetworkMessages/FactionRequestMessage.h" -#include "sharedNetworkMessages/FactionResponseMessage.h" -#include "sharedNetworkMessages/GalaxyLoopTimesResponse.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/GetAuctionDetails.h" -#include "sharedNetworkMessages/GetMapLocationsMessage.h" -#include "sharedNetworkMessages/GuildRequestMessage.h" -#include "sharedNetworkMessages/GuildResponseMessage.h" -#include "sharedNetworkMessages/IsVendorOwnerMessage.h" -#include "sharedNetworkMessages/IsVendorOwnerResponseMessage.h" -#include "sharedNetworkMessages/NewbieTutorialResponse.h" -#include "sharedNetworkMessages/ObjectChannelMessages.h" -#include "sharedNetworkMessages/ObjectMenuRequestDataArchive.h" -#include "sharedNetworkMessages/ObjectMenuSelectMessage.h" -#include "sharedNetworkMessages/ParametersMessage.h" -#include "sharedNetworkMessages/PlanetTravelPointListRequest.h" -#include "sharedNetworkMessages/PlanetTravelPointListResponse.h" -#include "sharedNetworkMessages/PlayerMoneyRequest.h" -#include "sharedNetworkMessages/PlayerMoneyResponse.h" -#include "sharedNetworkMessages/RequestGalaxyLoopTimes.h" -#include "sharedNetworkMessages/RetrieveAuctionItemMessage.h" -#include "sharedNetworkMessages/RetrieveAuctionItemResponseMessage.h" -#include "sharedNetworkMessages/SceneChannelMessages.h" -#include "sharedNetworkMessages/SecureTradeMessages.h" -#include "sharedNetworkMessages/ShipUpdateTransformMessage.h" -#include "sharedNetworkMessages/StomachRequestMessage.h" -#include "sharedNetworkMessages/SuiEventNotification.h" -#include "sharedObject/ContainedByProperty.h" -#include "sharedObject/NetworkController.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/PortalProperty.h" -#include "sharedObject/SlottedContainer.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" -#include "sharedUtility/Location.h" -#include "sharedSkillSystem/SkillManager.h" -#include "unicodeArchive/UnicodeArchive.h" - -namespace ClientNamespace -{ - // list of object types, radial menu action permission - // override, to allow certain object types to have certain radial - // menu action invoked on them by non-owners of the object - std::set > s_radialMenuPermissionOverrideTemplateItemType; - std::set > s_radialMenuPermissionOverrideStaticItemType; - - // ---------------------------------------------------------------------- - - bool canManipulateObjectExceptionCheck(ServerObject const &target, int menuType, Container::ContainerErrorCode& errorCode) - { - if (errorCode == Container::CEC_NoPermission) - { - const std::string & objectStaticName = target.getStaticItemName(); - if (objectStaticName.empty()) - { - if (s_radialMenuPermissionOverrideTemplateItemType.count(std::make_pair(target.getTemplateCrc(), menuType)) > 0) - { - errorCode = Container::CEC_Success; - return true; - } - } - else if (s_radialMenuPermissionOverrideStaticItemType.count(std::make_pair(objectStaticName, menuType)) > 0) - { - errorCode = Container::CEC_Success; - return true; - } - } - - return false; - } - - // ---------------------------------------------------------------------- - - void remove() - { - } -} - -// ====================================================================== - -Client::ClientMessage::ClientMessage(const std::string & src) : -MessageDispatch::MessageBase(src.c_str()) -{ -} - -//----------------------------------------------------------------------- - -Client::ClientMessage::~ClientMessage() -{ -} - - - - -//----------------------------------------------------------------------- - -std::map< std::string, uint32 > Client::sm_outgoingBytesMap_Working; // working stats that will rotate after 1 minute -std::map< std::string, uint32 > Client::sm_outgoingBytesMap_Stats; // computed stats from the last minute -uint32 Client::sm_outgoingBytesMap_Worktime = 0 ; // time we started filling in the working map - - -// ====================================================================== - -Client::Client(ConnectionServerConnection & connection, const NetworkId & characterObjectId, const std::string& accountName, const std::string& ipAddr, bool isSecure, bool isSkipLoadScreen, unsigned int stationId, std::set const & observedObjects, uint32 gameFeatures, uint32 subscriptionFeatures, AccountFeatureIdList const & accountFeatureIds, unsigned int entitlementTotalTime, unsigned int entitlementEntitledTime, unsigned int entitlementTotalTimeSinceLastLogin, unsigned int entitlementEntitledTimeSinceLastLogin, int buddyPoints, std::vector > const & consumedRewardEvents, std::vector > const & claimedRewardItems, bool usingAdminLogin, CombatDataTable::CombatSpamFilterType combatSpamFilter, int combatSpamRangeSquaredFilter, int furnitureRotationDegree, bool hasUnoccupiedJediSlot, bool isJediSlotCharacter, bool sendToStarport ) : - MessageDispatch::Receiver(), - MessageDispatch::Emitter(), - m_accountName(accountName), - m_characterName(), - m_characterObjectId(characterObjectId), - m_connection(&connection), - m_controlledObjects(), - m_godLevel(0), - m_godMode(false), - m_godValidated(false), - m_ipAddress(ipAddr), - m_isReady(false), - m_isSecure(isSecure), - m_isSkipLoadScreen(isSkipLoadScreen), - m_primaryControlledObject(NetworkId::cms_invalid), - destroyNotifier(), - m_observing(), - m_openedContainers(), - m_watchedByList(), - m_lastNonIdleTime(ServerClock::getInstance().getGameTimeSeconds()), - m_stationId(stationId), - m_connectionServerLag(0), - m_gameServerLag(0), - m_gameFeatures(gameFeatures), - m_subscriptionFeatures(subscriptionFeatures), - m_accountFeatureIds(accountFeatureIds), - m_entitlementTotalTime(entitlementTotalTime), - m_entitlementEntitledTime(entitlementEntitledTime), - m_entitlementTotalTimeSinceLastLogin(entitlementTotalTimeSinceLastLogin), - m_entitlementEntitledTimeSinceLastLogin(entitlementEntitledTimeSinceLastLogin), - m_buddyPoints(buddyPoints), - m_previousObservedObjects(observedObjects), - m_syncUIs(), - m_consumedRewardEvents(consumedRewardEvents), - m_claimedRewardItems(claimedRewardItems), - m_usingAdminLogin(usingAdminLogin), - m_combatSpamFilter(combatSpamFilter), - m_combatSpamRangeSquaredFilter(combatSpamRangeSquaredFilter), - m_furnitureRotationDegree(furnitureRotationDegree), - m_hasUnoccupiedJediSlot(hasUnoccupiedJediSlot), - m_isJediSlotCharacter(isJediSlotCharacter), - m_sendToStarport( sendToStarport ) -{ - - connectToEmitter(connection, "ConnectionServerConnectionClosed"); - connectToEmitter(connection, "ConnectionServerConnectionDestroyed"); - - // Check god permissions - if ( ConfigServerGame::getAdminGodToAll() - || ( (!ConfigServerGame::getUseSecureLoginForGodAccess() || m_isSecure) - && AdminAccountManager::isAdminAccount(Unicode::toLower(accountName), m_godLevel) - && (!ConfigServerGame::getUseIPForGodAccess() || AdminAccountManager::isInternalIp(ipAddr)))) - { - m_godValidated = true; - if (ConfigServerGame::getAdminGodToAll()) - m_godLevel = ConfigServerGame::getAdminGodToAllGodLevel(); - } - - // See if our controlled object is ready yet. - ServerObject *obj = LogoutTracker::findPendingCharacterSave(characterObjectId); - if (obj) - { - // If we're waiting to be saved in the LogoutTracker, then we've been - // removed from our container, so restore our containment if need be. - Object *containerObject = ContainerInterface::getContainedByObject(*obj); - if (containerObject) - { - // Don't ever put the character into a packed house - ServerObject * const serverObject = containerObject->asServerObject(); - CellObject * const cellObject = (serverObject ? serverObject->asCellObject() : NULL); - BuildingObject * const buildingObject = (cellObject ? cellObject->getOwnerBuilding() : NULL); - - if ((buildingObject) && (!buildingObject->isInWorld())) - { - ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); - if (cby) - { - DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building is packed\n",characterObjectId.getValueString().c_str(), buildingObject->getNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building is packed",characterObjectId.getValueString().c_str(), buildingObject->getNetworkId().getValueString().c_str())); - - cby->setContainedBy(NetworkId::cms_invalid, true); - containerObject = 0; - - // attempt to put the character at the ejection point of the building - if (!ServerWorld::isSpaceScene()) - { - DynamicVariableLocationData ejectionPoint; - if (obj->getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) - { - obj->removeObjVarItem("building_ejection_point"); - obj->setPosition_p(ejectionPoint.pos); - } - } - } - } - else if (containerObject->isAuthoritative()) - { - // The cell depersist step will try to set the parent cell of the player. - // However, that procedure will fail because the "contained by" property - // says the player is in a container when they really are not. - ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); - if (cby) - { - // We need to remove and then re-add the property so that the - // property is updated immediately (as opposed to waiting for an alter) - cby->setContainedBy(NetworkId::cms_invalid, true); - obj->removeProperty(cby->getPropertyId()); - obj->addProperty(*cby, true); - } - - // save and restore the original transform. The existing transform should be in parent - // space, but it is in world. down through depersistContents there is an assumption that - // it is in parent space and gets transformed incorrectly. - Transform origTransform = obj->getTransform_o2p(); - - // NOTE: Depersist works slightly differently than when the player - // is loaded from the database since in this case the player - // is initialized when depersist is called - Container * const container = ContainerInterface::getContainer(*containerObject); - NOT_NULL(container); - IGNORE_RETURN(container->depersistContents(*obj)); - - // if failed to put character back into the container, then clean up the - // containment relationship so that the character is now out in the world - if (ContainerInterface::getContainedByObject(*obj) != containerObject) - { - IGNORE_RETURN(container->internalItemRemoved(*obj)); - - if (cby) - { - // We need to remove and then re-add the property so that the - // property is updated immediately (as opposed to waiting for an alter) - cby->setContainedBy(NetworkId::cms_invalid, true); - obj->removeProperty(cby->getPropertyId()); - obj->addProperty(*cby, true); - } - - // attempt to put the character at the ejection point of the building - if (!ServerWorld::isSpaceScene()) - { - DynamicVariableLocationData ejectionPoint; - if (obj->getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) - { - DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because could not put player back in building\n",characterObjectId.getValueString().c_str(), (buildingObject ? buildingObject->getNetworkId().getValueString().c_str() : containerObject->getNetworkId().getValueString().c_str()))); - LOG("CustomerService",("Login: Ejecting player %s from building %s, because could not put player back in building",characterObjectId.getValueString().c_str(), (buildingObject ? buildingObject->getNetworkId().getValueString().c_str() : containerObject->getNetworkId().getValueString().c_str()))); - - obj->removeObjVarItem("building_ejection_point"); - obj->setPosition_p(ejectionPoint.pos); - } - } - - containerObject = 0; - } - else - { - obj->setTransform_o2w(origTransform); - - // if the character was in a building, tell the building it has gained - // the player so the building demand load/unload system can work correctly - Object *buildingObj = ContainerInterface::getTopmostContainer(*containerObject); - if (buildingObj && buildingObj->asServerObject() && buildingObj->asServerObject()->asBuildingObject()) - buildingObj->asServerObject()->asBuildingObject()->gainedPlayer(*obj); - } - } - else - { - // The container is no longer authoritative on this server. Move us to a safe place - // outside the container. - Object * const topmostObject = ContainerInterface::getTopmostContainer(*obj); - BuildingObject * const topmostBuilding = dynamic_cast(topmostObject); - if (topmostBuilding) - { - DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building has changed authority\n",characterObjectId.getValueString().c_str(), topmostBuilding->getNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building has changed authority",characterObjectId.getValueString().c_str(), topmostBuilding->getNetworkId().getValueString().c_str())); - ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); - if (cby) - { - cby->setContainedBy(NetworkId::cms_invalid, true); - containerObject = 0; - - PortalProperty * const portalProperty = topmostBuilding->getPortalProperty(); - if (portalProperty) - { - ServerController * const controller = dynamic_cast(obj->getController()); - if (controller) - { - Transform destinationTransform(Transform::IF_none); - destinationTransform.multiply(topmostBuilding->getTransform_o2w(), portalProperty->getEjectionLocationTransform()); - obj->setTransform_o2p(destinationTransform); - } - } - } - } - else - WARNING(true,("Expected player %s to be in a building, but he was in some other type of object. Skipping authority fixup because something strange is going on.",characterObjectId.getValueString().c_str())); - } - } - else - { - // check for the case where we were in a container that isn't there anymore - ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); - if ((cby) && (cby->getContainedByNetworkId().isValid())) - { - DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building does not exist anymore\n",characterObjectId.getValueString().c_str(), cby->getContainedByNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building does not exist anymore",characterObjectId.getValueString().c_str(), cby->getContainedByNetworkId().getValueString().c_str())); - - cby->setContainedBy(NetworkId::cms_invalid, true); - - // attempt to put the character at the ejection point of the building - if (!ServerWorld::isSpaceScene()) - { - DynamicVariableLocationData ejectionPoint; - if (obj->getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) - { - obj->removeObjVarItem("building_ejection_point"); - obj->setPosition_p(ejectionPoint.pos); - } - } - } - } - - // Only add to the world if it in a location which should be in the world. - if (!containerObject || (containerObject->isInWorld() && containerObject->getContainerProperty()->isContentItemExposedWith(*obj))) - obj->addToWorld(); - - // Notify the object that it has a client about to load - obj->onClientAboutToLoad(); - - // We need to trigger having been made authoritative since we are an object which has been - // disconnected from the world. - obj->triggerMadeAuthoritative(); - - // Create proxies as needed - ProxyList const &proxyList = obj->getExposedProxyList(); - if (!proxyList.empty()) - { - ServerMessageForwarding::begin(std::vector(proxyList.begin(), proxyList.end())); - - obj->forwardServerCreateAndBaselines(); - - ServerMessageForwarding::end(); - } - } - else - obj = ServerWorld::findObjectByNetworkId(characterObjectId); - - if (obj) - { - obj->checkAndAddClientControl(this); - } - - // Send server-specific settings to the client - ParametersMessage const msg(ConfigServerGame::getWeatherUpdateSeconds()); - send(msg, true); - - ObjectTracker::addPlayer(); -} - -//----------------------------------------------------------------------- - -Client::~Client() -{ - ClientDestroy d(this); - destroyNotifier.emitMessage(d); - - if (ServerWorld::isSpaceScene()) - SpaceVisibilityManager::removeClient(*this); - - ObserveTracker::onClientDestroyed(*this); - ShipClientUpdateTracker::onClientDestroyed(*this); - - DEBUG_FATAL(!m_controlledObjects.empty(),("Deleting a client with a non-empty controlled objects list!\n")); - m_primaryControlledObject = NetworkId::cms_invalid; - - //clean up any orphaned SynchronizedUIs - for (std::vector >::iterator i = m_syncUIs.begin(); i != m_syncUIs.end(); ++i) - { - ServerSynchronizedUi* syncUI = i->getPointer(); - if (syncUI) - delete syncUI; - } - - ObjectTracker::removePlayer(); - - PvpUpdateObserver::removeClientFromPvpStatusCache(this); - - m_connection = 0; -} - -// ---------------------------------------------------------------------- - -void Client::install() -{ - // read in the list of object types, radial menu action permission - // override, to allow certain object types to have certain radial - // menu action invoked on them by non-owners of the object - char const * const radialMenuPermissionOverrideDataTableName = "datatables/player/radial_menu_permission_override.iff"; - DataTable * table = DataTableManager::getTable(radialMenuPermissionOverrideDataTableName, true); - if (table) - { - int const columnObjectTemplate = table->findColumnNumber("Object Template"); - int const columnCommand = table->findColumnNumber("Command"); - if ((columnObjectTemplate >= 0) && (columnCommand >= 0)) - { - std::string objectTemplate; - std::string command; - int commandMenuId; - - for (int i = 0, numRows = table->getNumRows(); i < numRows; ++i) - { - objectTemplate = table->getStringValue(columnObjectTemplate, i); - if (objectTemplate.empty()) - continue; - - command = table->getStringValue(columnCommand, i); - if (command.empty()) - continue; - - commandMenuId = RadialMenuManager::getMenuTypeByName(command); - if (commandMenuId == 0) - continue; - - if (objectTemplate.find(".iff") != std::string::npos) - ClientNamespace::s_radialMenuPermissionOverrideTemplateItemType.insert(std::make_pair(CrcLowerString::calculateCrc(objectTemplate.c_str()), commandMenuId)); - else - ClientNamespace::s_radialMenuPermissionOverrideStaticItemType.insert(std::make_pair(objectTemplate, commandMenuId)); - } - } - - DataTableManager::close(radialMenuPermissionOverrideDataTableName); - } - - ExitChain::add(ClientNamespace::remove, "ClientNamespace::remove"); -} - -//----------------------------------------------------------------------- - -void Client::addControlledObject(ServerObject &object) -{ - // check to see if it is in the list already - if (std::find(m_controlledObjects.begin(), m_controlledObjects.end(), &object) == m_controlledObjects.end()) - m_controlledObjects.push_back(&object); - else - DEBUG_WARNING(true, ("Client adding controlled object [%s] that is already controlled", object.getNetworkId().getValueString().c_str())); - - //finally set a pointer to the Client object on the object - object.setClient(*this); - ObserveTracker::onObjectControlled(*this, object, m_previousObservedObjects); - - // Any objects to be re-controlled have been at this point, so clean up any old objects that are no longer observed - ObserveTracker::onClientControlComplete(*this, m_previousObservedObjects); - m_previousObservedObjects.clear(); - - // If in space, add the client to SpaceVisibilityManager. Only do this for the topmost object the client controls that is in the world. - if (ServerWorld::isSpaceScene()) - { - Object * topmost = ContainerInterface::getTopmostContainer(object); - NOT_NULL(topmost); - NOT_NULL(topmost->asServerObject()); - if (topmost->isInWorld()) - SpaceVisibilityManager::addClient(*this, *(topmost->asServerObject())); - } - - // Restore god mode after changing servers - CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); - if (primaryControlledObject) - { - if (primaryControlledObject->hasCommand(AdminAccountManager::getAdminCommandName())) - setGodMode(true); - } -} - -// ---------------------------------------------------------------------- - -void Client::clearControlledObjects() -{ - while (!m_controlledObjects.empty()) - removeControlledObject(**m_controlledObjects.begin()); - - PvpUpdateObserver::removeClientFromPvpStatusCache(this); -} - -// ---------------------------------------------------------------------- - -ServerObject *Client::findControlledObject(NetworkId const &oid) const -{ - for (std::vector::const_iterator i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) - if ((*i) && (*i)->getNetworkId() == oid) - return *i; - return 0; -} - -// ---------------------------------------------------------------------- - -std::vector const &Client::getControlledObjects() const -{ - return m_controlledObjects; //lint !e1536 //low access -} - -//----------------------------------------------------------------------- - -bool Client::isControlled(NetworkId const &id) const -{ - std::vector::const_iterator i; - for(i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) - { - ServerObject * object = *i; - if(object && object->getNetworkId() == id) - return true; - } - return false; -} - -//----------------------------------------------------------------------- - -void Client::onLoadPlayer(CreatureObject &newCharacter) -{ - if (m_primaryControlledObject != NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Already have a primary object!")); - if (m_primaryControlledObject == newCharacter.getNetworkId()) - return; - } - - m_primaryControlledObject = CachedNetworkId(newCharacter); - - assumeControl(newCharacter); -} - -//----------------------------------------------------------------------- - -void Client::assumeControl(CreatureObject &newCharacter) -{ - DEBUG_FATAL(newCharacter.getNetworkId() != m_primaryControlledObject, ("Tried to assume control of the wrong object?")); - - // Add the object to the controlled object list - addControlledObject(newCharacter); - - // Register player name with the global list - std::string const &firstName = Unicode::wideToNarrow(Unicode::toLower(newCharacter.getAssignedObjectFirstName())); - std::string const &fullName = Unicode::wideToNarrow(newCharacter.getAssignedObjectName()); - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(&newCharacter); - NameManager::getInstance().addPlayer(newCharacter.getNetworkId(), (playerObject ? playerObject->getStationId() : static_cast(m_stationId)), firstName, fullName, 0, Os::getRealSystemTime(), true); - - static const std::string loginTrace("TRACE_LOGIN"); - LOG(loginTrace, ("sending ControlAssumed(%s, %s)", m_primaryControlledObject.getValueString().c_str(), ConfigServerGame::getGroundScene())); - - ControlAssumed const controlMessage( - m_primaryControlledObject, - ConfigServerGame::getGroundScene(), - m_isSkipLoadScreen, - newCharacter.getTransform_o2w().getPosition_p(), - newCharacter.getObjectFrameK_w().theta(), - newCharacter.getSharedTemplateName(), - static_cast(ServerClock::getInstance().getGameTimeSeconds())); - - sendToConnectionServer(controlMessage); - - m_isSkipLoadScreen = false; -} - -//----------------------------------------------------------------------- - -void Client::receiveClientMessage(const GameNetworkMessage & message) -{ - try - { - - // Ignore any messages if the character is not loaded yet. - if (m_primaryControlledObject == NetworkId::cms_invalid) - { - DEBUG_REPORT_LOG(true,("Ignoring message for character %s because it is not loaded yet.\n",m_characterObjectId.getValueString().c_str())); - return; - } - - ServerObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); - - if (!primaryControlledObject) - { - DEBUG_REPORT_LOG(true,("Ignoring message for character %s because object %s cannot be found.\n", - m_characterObjectId.getValueString().c_str(), m_primaryControlledObject.getValueString().c_str())); - return; - } - - //----------------------------------------------------------------- - - if (message.isType("ShipUpdateTransformMessage")) - { - Archive::ReadIterator readIterator = static_cast(message).getByteStream().begin(); - ShipUpdateTransformMessage const shipUpdateTransformMessage(readIterator); - - for (std::vector::const_iterator i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) - { - ShipObject * const ship = (*i)->asShipObject(); - if (ship) - { - PlayerShipController * const playerShipController = safe_cast(ship->getController()); - if (playerShipController) - playerShipController->receiveTransform(shipUpdateTransformMessage); - } - } - } - - //---------------------------------------------------------------------- - - else if (message.isType("CreateProjectileMessage")) - { - Archive::ReadIterator readIterator = static_cast(message).getByteStream().begin(); - CreateProjectileMessage const createProjectileMessage(readIterator); - - // pilots can fire from non-turrets, gunners can fire their turret - ServerObject * const characterObject = getCharacterObject(); - if (characterObject) - { - ServerObject * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*characterObject)); - if (containedBy) - { - SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*containedBy); - ShipObject * const shipObject = ShipObject::getContainingShipObject(containedBy); - - if ( (shipObject != NULL) - && (slottedContainer != NULL) - && !shipObject->hasCondition(TangibleObject::C_docking)) - { - bool shotOk = false; - - int const weaponIndex = createProjectileMessage.getWeaponIndex(); - if (weaponIndex >= 0 && weaponIndex < ShipChassisSlotType::cms_numWeaponIndices) - { - Container::ContainerErrorCode err = Container::CEC_Success; - if (shipObject->isTurret(weaponIndex)) - { - if ( slottedContainer->getObjectInSlot(ShipSlotIdManager::getPobShipGunnerSlotId(weaponIndex), err) == characterObject->getNetworkId() - || slottedContainer->getObjectInSlot(ShipSlotIdManager::getShipGunnerSlotId(weaponIndex), err) == characterObject->getNetworkId()) - shotOk = true; // gunner firing his turret - } - else - { - if ( slottedContainer->getObjectInSlot(ShipSlotIdManager::getShipPilotSlotId(), err) == characterObject->getNetworkId() - || slottedContainer->getObjectInSlot(ShipSlotIdManager::getPobShipPilotSlotId(), err) == characterObject->getNetworkId()) - shotOk = true; // pilot firing non-turret - } - } - - // only gods can fire while invulnerable - if (shipObject->isInvulnerable() && !isGod()) - shotOk = false; - - if (shotOk) - { - shipObject->enqueueFireShotClient( - *this, - weaponIndex, - createProjectileMessage.getTransform_p(), - createProjectileMessage.getTargetedComponent(), - createProjectileMessage.getSyncStampLong()); - } - } - } - } - } - - //---------------------------------------------------------------------- - - else if(message.isType("CmdSceneReady")) - { - m_isReady = true; - primaryControlledObject->onClientReady(this); - } - - //---------------------------------------------------------------------- - - else if(message.isType("SetCombatSpamFilter")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - m_combatSpamFilter = static_cast(msg.getValue()); - } - - //---------------------------------------------------------------------- - - else if(message.isType("SetCombatSpamRangeFilter")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - m_combatSpamRangeSquaredFilter = sqr(msg.getValue()); - } - - //---------------------------------------------------------------------- - - else if(message.isType("SetFurnitureRotationDegree")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - m_furnitureRotationDegree = msg.getValue(); - } - - //---------------------------------------------------------------------- - - else if(message.isType("GcwRegionsReq")) - { - GenericValueTypeMessage, float> > > > const rsp("GcwRegionsRsp", Pvp::getGcwScoreCategoryRegions()); - send(rsp, true); - - GenericValueTypeMessage > > const rsp2("GcwGroupsRsp", Pvp::getGcwScoreCategoryGroups()); - send(rsp2, true); - } - - //---------------------------------------------------------------------- - - else if(message.isType("SetJediSlotInfo")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - // this comes from the client (via the LoginServer) so should not be trusted; - // we cache them here to do preliminary checks to avoid unnecessarily sending - // commands to the LoginServer (assuming the values haven't been hacked on the - // client); when we do send the commands to the LoginServer, we'll check again there - m_hasUnoccupiedJediSlot = msg.getValue().first; - m_isJediSlotCharacter = msg.getValue().second; - } - - //---------------------------------------------------------------------- - - else if(message.isType("RotateFurnitureSetQuaternion")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > > const msg(ri); - - CreatureObject * creatureOwner = safe_cast(getCharacterObject()); - if (creatureOwner && creatureOwner->isAuthoritative()) - { - ServerObject const * target = ServerWorld::findObjectByNetworkId(msg.getValue().first); - if (target && target->isAuthoritative()) - { - static uint32 const commandHash = Crc::normalizeAndCalculate("rotateFurniture"); - const Command &command = CommandTable::getCommand(commandHash); - if (!command.isNull()) - { - // for obfuscation so players won't manually send us this command - Unicode::String params = Unicode::narrowToWide(FormattedString<512>().sprintf("(^-,=+_)internal_use_only_%s_quaternion(,+-=_^) %.10f %.10f %.10f %.10f %s", creatureOwner->getNetworkId().getValueString().c_str(), msg.getValue().second.first.first, msg.getValue().second.first.second, msg.getValue().second.second.first, msg.getValue().second.second.second, msg.getValue().first.getValueString().c_str())); - creatureOwner->commandQueueEnqueue(command, target->getNetworkId(), params, 0, false, static_cast(Command::CP_Default), true); - } - } - } - } - - //---------------------------------------------------------------------- - - else if(message.isType("SetLfgInterests")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(safe_cast(getCharacterObject())); - if (playerObject) - { - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(getCharacterObjectId()); - if (iterFind != connectedCharacterLfgData.end()) - { - BitArray lfgInterests = msg.getValue(); - - MatchMakingId const & id = playerObject->getMatchMakingCharacterProfileId(); - if (id.isBitSet(MatchMakingId::B_lookingForGroup)) - LfgDataTable::setBit("lfg", lfgInterests); - else - LfgDataTable::clearBit("lfg", lfgInterests); - - if (id.isBitSet(MatchMakingId::B_helper)) - LfgDataTable::setBit("helper", lfgInterests); - else - LfgDataTable::clearBit("helper", lfgInterests); - - if (id.isBitSet(MatchMakingId::B_rolePlay)) - LfgDataTable::setBit("rp", lfgInterests); - else - LfgDataTable::clearBit("rp", lfgInterests); - - if (id.isBitSet(MatchMakingId::B_lookingForWork)) - LfgDataTable::setBit("lfw", lfgInterests); - else - LfgDataTable::clearBit("lfw", lfgInterests); - - ServerUniverse::setConnectedCharacterInterestsData(getCharacterObjectId(), lfgInterests); - } - } - } - - //---------------------------------------------------------------------- - - else if(message.isType("RequestGroundObjectPlacement")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > > const msg(ri); - - ServerObject * const target = safe_cast(NetworkIdManager::getObjectById (msg.getValue().first)); - GameScriptObject * const scriptObject = target ? target->getScriptObject() : 0; - - if (!scriptObject) - { - return; - } - - int menuType = msg.getValue().second.first.first; - Vector loc(msg.getValue().second.first.second, msg.getValue().second.second.first, msg.getValue().second.second.second); - ScriptParams params; - params.addParam (getCharacterObjectId()); - params.addParam (menuType); - params.addParam (loc.x); - params.addParam (loc.y); - params.addParam (loc.z); - - IGNORE_RETURN (scriptObject->trigAllScripts(Scripting::TRIG_GROUND_TARGET_LOC, params)); - } - //---------------------------------------------------------------------- - - else if(message.isType("ShowBackpack")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - PlayerObject * player = dynamic_cast(NetworkIdManager::getObjectById (msg.getValue().first)); - - if(player) - player->modifyShowBackpack(msg.getValue().second); - - } - //---------------------------------------------------------------------- - - else if(message.isType("ShowHelmet")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - PlayerObject * player = dynamic_cast(NetworkIdManager::getObjectById (msg.getValue().first)); - - if(player) - player->modifyShowHelmet(msg.getValue().second); - - } - //---------------------------------------------------------------------- - - else if(message.isType("SetWaypointColor")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - if ((msg.getValue().second == "blue") || (msg.getValue().second == "green") || (msg.getValue().second == "orange") || (msg.getValue().second == "yellow") || (msg.getValue().second == "purple") || (msg.getValue().second == "white")) - { - Waypoint w = Waypoint::getWaypointById(msg.getValue().first); - if (w.isValid()) - { - w.setColor(Waypoint::getColorIdByName(msg.getValue().second)); - } - } - } - - //---------------------------------------------------------------------- - - else if (message.isType (ObjectMenuSelectMessage::MESSAGE_TYPE)) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - const ObjectMenuSelectMessage m (ri); - ServerObject * const target = safe_cast(NetworkIdManager::getObjectById (m.getNetworkId())); - GameScriptObject * const scriptObject = target ? target->getScriptObject() : 0; - Object * const targetContainedBy = target ? ContainerInterface::getContainedByObject(*target) : NULL; - const int menuType = m.getSelectedItemId(); - - static int examineMenuType = RadialMenuManager::getMenuTypeByName("EXAMINE"); - static int tradeMenuType = RadialMenuManager::getMenuTypeByName("TRADE_START"); - - CreatureObject* cobj = dynamic_cast(primaryControlledObject); - if (cobj && menuType != examineMenuType && menuType != tradeMenuType) - { - CreatureController* const controller = cobj->getCreatureController(); - if (controller && controller->getSecureTrade()) - { - controller->getSecureTrade()->cancelTrade(*cobj); - DEBUG_REPORT_LOG (true, ("Client ObjectMenuSelectMessage [%d] for [%s] canceling trade.\n", menuType, cobj->getNetworkId ().getValueString ().c_str ())); - } - } - - if (!scriptObject) - { - DEBUG_REPORT_LOG (true, ("Received an object menu select message from player %s for object %s, which does not exist or lacks a GameScriptObject.", m_characterObjectId.getValueString().c_str(),m.getNetworkId().getValueString().c_str())); - return; - } - - NOT_NULL(target); - - float range = 0.0f; - if (RadialMenuManager::getRangeForMenuType(menuType, range)) - { - Container::ContainerErrorCode errorCode = Container::CEC_Success; - if (!target->isAuthoritative()) - { - GenericValueTypeMessage > const rssMessage( - "RequestSameServer", - std::make_pair( - ContainerInterface::getTopmostContainer(*primaryControlledObject)->getNetworkId(), - ContainerInterface::getTopmostContainer(*target)->getNetworkId())); - GameServer::getInstance().sendToPlanetServer(rssMessage); - errorCode = Container::CEC_TryAgain; - } - else if (menuType != examineMenuType && targetContainedBy && targetContainedBy->asServerObject() && ( targetContainedBy->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron || targetContainedBy->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron_recipe ) ) - { - // Can only examine items that are contained in a holocron. - errorCode = Container::CEC_NoPermission; - } - else if (primaryControlledObject->canManipulateObject(*target, false, false, false, range, errorCode) - || ClientNamespace::canManipulateObjectExceptionCheck(*target, menuType, errorCode)) - { - ScriptParams params; - params.addParam (getCharacterObjectId()); - params.addParam (menuType); - - if (cobj && cobj->getObjVars().hasItem("cheater")) - { - std::string menuDesc = "unknown"; - bool tmp; - IGNORE_RETURN(RadialMenuManager::getCommandForMenuType(menuType, menuDesc, tmp)); - LOG("CustomerService",("SuspectedCheaterLog: %s has used a radial menu on object %s. Menu item %d (%s).", - PlayerObject::getAccountDescription(cobj).c_str(), - m.getNetworkId().getValueString().c_str(), - menuType, - menuDesc.c_str() )); - } - - IGNORE_RETURN (scriptObject->trigAllScripts(Scripting::TRIG_OBJECT_MENU_SELECT, params)); - } - if (errorCode != Container::CEC_Success) - ContainerInterface::sendContainerMessageToClient(*primaryControlledObject, errorCode); - } - else - { - DEBUG_REPORT_LOG(true, ("Received a message type %d that had no range in data (radial_menu.tab)\n", menuType)); - } - } - - //---------------------------------------------------------------------- - - else if(message.isType("ConGenericMessage")) - { - - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ConGenericMessage c(ri); - if (isGod()) - { - LOG("CustomerService",("Avatar:%s executing command: %s", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str(), c.getMsg().c_str())); - ConsoleMgr::processString(c.getMsg(), this, c.getMsgId()); - } - else - { - //Non-god user tried to use a console command - if (m_primaryControlledObject.getObject()) - { - LOG("CustomerService", ("CheatChannel:%s tried to execute a console command but they are not a god", - PlayerObject::getAccountDescription(m_primaryControlledObject.getObject()->getNetworkId()).c_str())); - ConsoleMgr::broadcastString("Only god users can execute console commands.", this, c.getMsgId()); - } - - } - } - - //----------------------------------------------------------------- - - else if(message.isType("ObjControllerMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ObjControllerMessage o(ri); - bool appended = false; - - // check to make sure the controller message is allowed from the client - bool allowFromClient = ControllerMessageFactory::allowFromClient(o.getMessage()); - - // log as a possible hack - if (!allowFromClient) - LOG("CustomerService", ("UnauthorizedControllerMessage: Player %s sent an unauthorized controller message %d for object %s.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str(), o.getMessage(), o.getNetworkId().getValueString().c_str())); - - // do we allow the controller message to get executed? - if (allowFromClient || isGod() || !ConfigServerGame::getEnableClientControllerMessageCheck()) - { - ServerObject * target = findControlledObject(o.getNetworkId()); - if(target !=0) - { - // apply the controller message - ServerController * controller = dynamic_cast(target->getController()); - if (controller != NULL) - { - uint32 flags = o.getFlags(); - flags &= ~GameControllerMessageFlags::SOURCE_REMOTE; - flags |= GameControllerMessageFlags::SOURCE_REMOTE_CLIENT; - controller->appendMessage(o.getMessage(), o.getValue(), o.getData(), flags); - appended = true; - } - } - else if (isGod()) - { - target = ServerWorld::findObjectByNetworkId(o.getNetworkId()); - - if (target) - { - ServerController * controller = dynamic_cast(target->getController()); - if (controller != NULL) - { - uint32 flags = o.getFlags(); - flags &= ~GameControllerMessageFlags::SOURCE_REMOTE; - flags |= GameControllerMessageFlags::SOURCE_REMOTE_CLIENT; - controller->appendMessage(o.getMessage(), o.getValue(), o.getData(), flags); - appended = true; - } - } - } - } - if (!appended) - delete o.getData(); - } - - //----------------------------------------------------------------- - //Secure Trade Messages - //----------------------------------------------------------------- - else if (message.isType("AddItemMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AddItemMessage m(ri); - - - ServerObject * item = ServerWorld::findObjectByNetworkId(m.getNetworkId()); - if (!item) - return; - - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->addItem(*playerObject, *item); - } - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - } - else if (message.isType("RemoveItemMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RemoveItemMessage m(ri); - - ServerObject * item = ServerWorld::findObjectByNetworkId(m.getNetworkId()); - if (!item) - return; - - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->removeItem(*playerObject, *item); - } - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - } - else if (message.isType("GiveMoneyMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GiveMoneyMessage m(ri); - - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->giveMoney(*playerObject, m.getAmount()); - } - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - } - else if (message.isType("AcceptTransactionMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AcceptTransactionMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->acceptOffer(*playerObject); - } - - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has accepted a secure trade. (Check trade logs for more detail.", PlayerObject::getAccountDescription(playerObject).c_str())); - } - - - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - - } - else if (message.isType("UnAcceptTransactionMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - UnAcceptTransactionMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->unacceptOffer(*playerObject); - } - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - - } - else if (message.isType("VerifyTradeMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - VerifyTradeMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->verifyTrade(*playerObject); - } - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - } - else if (message.isType("DenyTradeMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - DenyTradeMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->rejectOffer(*playerObject); - } - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - - } - else if (message.isType("AbortTradeMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AbortTradeMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - DEBUG_FATAL(!playerObject, ("No controller for player!\n")); - if(playerObject) //lint !e774 - { - PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); - if (playerController && playerController->getSecureTrade()) - { - playerController->getSecureTrade()->cancelTrade(*playerObject); - } - } - else - { - GameServer::getInstance().dropClient(m_characterObjectId); - } - - } - - else if (message.isType(SuiEventNotification::MessageType)) - { - ServerUIManager::receiveMessage(message); - } - - else if (message.isType("GuildRequestMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GuildRequestMessage const m(ri); - - NetworkId const &id = m.getTargetId(); - CreatureObject * const creatureObject = dynamic_cast(NetworkIdManager::getObjectById(id)); - if (creatureObject) - { - int const guildId = creatureObject->getGuildId(); - GuildMemberInfo const * const info = GuildInterface::getGuildMemberInfo(guildId, id); - GuildResponseMessage const responseMessage(id, GuildInterface::getGuildName(guildId), info ? info->m_title : std::string()); - send(responseMessage, true); - } - } - - else if (message.isType("StomachRequestMessage")) - { - CreatureObject *creatureObject = dynamic_cast(getCharacterObject()); - - if (creatureObject != NULL) - { - GameScriptObject *gameScriptObject = creatureObject->getScriptObject(); - - if(gameScriptObject != NULL) - { - ScriptParams scriptParams; - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_STOMACH_UPDATE, scriptParams)); - } - } - } - - else if (message.isType("FactionRequestMessage")) - { - int rebel = 0; - int imperial = 0; - int criminal = 0; - - CreatureObject * playerObject = dynamic_cast(getCharacterObject()); - if (playerObject) - { - float temp; - if (playerObject->getObjVars().getItem("faction.Rebel",temp)) - { - rebel = static_cast(temp); - } - if (playerObject->getObjVars().getItem("faction.Imperial",temp)) - { - imperial = static_cast(temp); - } - if (playerObject->getObjVars().getItem("faction.Hutt",temp)) - { - criminal = static_cast(temp); - } - - std::vector factionNames; - std::vector factionValues; - std::string currentName; - float currentValue; - DynamicVariableList::NestedList factionList(playerObject->getObjVars(),"faction"); - for(DynamicVariableList::NestedList::const_iterator i = factionList.begin(); i != factionList.end(); ++i) - { - currentName = i.getName(); - bool result = i.getValue(currentValue); - if(result) - { - factionNames.push_back(currentName); - factionValues.push_back(currentValue); - } - } - - FactionResponseMessage const msg(rebel, imperial, criminal, factionNames, factionValues); - send(msg, true); - } - } - - //---------------------------------------------------------------------- - - else if (message.isType (PlayerMoneyRequest::MessageType)) - { - Archive::ReadIterator ri = (*NON_NULL (static_cast(&message))).getByteStream().begin(); - const PlayerMoneyRequest m (ri); - - ServerObject * const playerObject = getCharacterObject(); - - WARNING (!playerObject, ("Got PlayerMoneyRequest for non-existant character (account=%s, networkid=%s)", m_accountName.c_str (), m_characterObjectId.getValueString ().c_str ())); - - if (playerObject) - { - PlayerMoneyResponse resp; - resp.m_balanceCash.set (playerObject->getCashBalance ()); - resp.m_balanceBank.set (playerObject->getBankBalance ()); - send (resp, true); - } - } - - //----------------------------------------------------------------- - - else if (message.isType("AcceptAuctionMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AcceptAuctionMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - CommoditiesMarket::auctionAccept(*playerObject, m.getItemId().getValue()); - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has accepted an auction for item %s", - PlayerObject::getAccountDescription(playerObject).c_str(), - m.getItemId().getValueString().c_str())); - } - } - else - { - WARNING(true, ("AcceptAuctionMessage: the player was not found")); - } - } - - else if (message.isType("BidAuctionMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - BidAuctionMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has bid on an auction for item %s, amount %d", - PlayerObject::getAccountDescription(playerObject).c_str(), - m.getItemId().getValueString().c_str(), - m.getBid())); - } - - CommoditiesMarket::auctionBid(*playerObject, m.getItemId().getValue(), m.getBid(), m.getMaxProxyBid()); - } - else - { - WARNING(true, ("BidAuctionMessage: the player was not found")); - } - } - - else if (message.isType("CancelLiveAuctionMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - CancelLiveAuctionMessage m(ri); - - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - CommoditiesMarket::auctionCancel(*playerObject, m.getItemId().getValue()); - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has cancelled an auction for item %s", - PlayerObject::getAccountDescription(playerObject).c_str(), - m.getItemId().getValueString().c_str())); - } - - } - else - { - WARNING(true, ("CancelLiveAuctionMessage: the player was not found")); - } - } - - else if (message.isType("CreateAuctionMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - CreateAuctionMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - NetworkId itemId = m.getItemId(); - NetworkId containerId = m.getContainerId(); - CommoditiesMarket::auctionCreate(*playerObject, itemId, m.getItemLocalizedName(), containerId, m.getMinimumBid(), m.getAuctionLength(), m.getUserDescription(), m.isPremium()); - - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has created an auction for item %s on vendor %s", - PlayerObject::getAccountDescription(playerObject).c_str(), - m.getItemId().getValueString().c_str(), - containerId.getValueString().c_str())); - } - } - else - { - WARNING(true, ("CreateAuctionMessage: the player was not found")); - } - } - - else if (message.isType("CreateImmediateAuctionMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - CreateImmediateAuctionMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - NetworkId itemId = m.getItemId(); - NetworkId containerId = m.getContainerId(); - if (m.isVendorTransfer()) - { - CommoditiesMarket::transferVendorItemFromStockroom(*playerObject, itemId, m.getItemLocalizedName(), m.getPrice(), m.getAuctionLength(), m.getUserDescription()); - } - else - { - CommoditiesMarket::auctionCreateImmediate(*playerObject, itemId, m.getItemLocalizedName(), containerId, m.getPrice(), m.getAuctionLength(), m.getUserDescription(), m.isPremium()); - } - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has created an immediate auction for item %s on vendor %s", - PlayerObject::getAccountDescription(playerObject).c_str(), - m.getItemId().getValueString().c_str(), - containerId.getValueString().c_str())); - } - } - else - { - WARNING(true, ("CreateImmediateAuctionMessage: the player was not found")); - } - } - - else if (message.isType("RelistItemsFromStockMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::vector >, int> > const m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - std::vector const & itemIds = m.getValue().first.first; - std::vector const & itemLocalizedNames = m.getValue().first.second; - int const timer = m.getValue().second; - NetworkId itemId; - std::vector::const_iterator iterId = itemIds.begin(); - std::vector::const_iterator iterName = itemLocalizedNames.begin(); - for (; ((iterId != itemIds.end()) && (iterName != itemLocalizedNames.end())); ++iterId, ++iterName) - { - itemId = *iterId; - CommoditiesMarket::transferVendorItemFromStockroom(*playerObject, itemId, *iterName, -1, timer, Unicode::String()); - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has created an immediate auction (relist) for item %s", - PlayerObject::getAccountDescription(playerObject).c_str(), - itemId.getValueString().c_str())); - } - } - } - else - { - WARNING(true, ("RelistItemsFromStockMessage: the player was not found")); - } - } - - else if (message.isType("RetrieveAuctionItemMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - RetrieveAuctionItemMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - NetworkId itemId = m.getItemId(); - ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(m.getContainerId())); - if (auctionContainer) - { - if (playerObject->isAuthoritative() && auctionContainer->isAuthoritative()) - { - CommoditiesMarket::auctionRetrieve(*playerObject, m.getItemId().getValue(), m.getItemId(), *auctionContainer); - if (playerObject->getObjVars().hasItem("cheater")) - { - LOG("CustomerService", ("SuspectedCheaterChannel: %s has retrieved an auction for item %s on vendor %s", - PlayerObject::getAccountDescription(playerObject).c_str(), - m.getItemId().getValueString().c_str(), - auctionContainer->getNetworkId().getValueString().c_str())); - } - } - } - else - { - LOG("CustomerService", ("Auction:Player %s attempted to retrieve an auction for container %Ld but failed.", PlayerObject::getAccountDescription(playerObject).c_str(), m.getContainerId().getValue())); - - RetrieveAuctionItemResponseMessage const msg(itemId, ar_INVALID_CONTAINER_ID);; - Client *client = playerObject->getClient(); - if (client) - { - client->send(msg, true); - } - } - } - else - { - WARNING(true, ("RetrieveAuctionMessage: the player was not found")); - } - } - else if (message.isType("AuctionQueryHeadersMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - AuctionQueryHeadersMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - CommoditiesMarket::auctionQueryHeaders(*playerObject, - m.getRequestId(), - m.getSearchType(), - m.getItemType(), - m.getItemTypeExactMatch(), - m.getItemTemplateId(), - m.getTextFilterAll(), - m.getTextFilterAny(), - m.getPriceFilterMin(), - m.getPriceFilterMax(), - m.getPriceFilterIncludesFee(), - m.getAdvancedSearch(), - m.getAdvancedSearchMatchAllAny(), - m.getContainer(), - m.getLocationSearchType(), - m.getMyVendorsOnly(), - m.getQueryOffset()); - } - } - else if (message.isType("GetAuctionDetails")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GetAuctionDetails m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - CommoditiesMarket::getAuctionDetails(*playerObject, - m.getItem()); - } - - } - else if (message.isType("IsVendorOwnerMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - IsVendorOwnerMessage m(ri); - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - CommoditiesMarket::isVendorOwner(*playerObject, m.getContainerId()); - } - - } - else if (message.isType("CommoditiesItemTypeListRequest")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const m(ri); - - static char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s.%d", GameServer::getInstance().getClusterName().c_str(), CommoditiesMarket::getItemTypeMapVersionNumber()); - buffer[sizeof(buffer)-1] = '\0'; - - if (m.getValue() != std::string(buffer)) - { - GenericValueTypeMessage > > > > const rsp("CommoditiesItemTypeListResponse", std::make_pair(std::string(buffer), CommoditiesMarket::getItemTypeMap())); - send(rsp, true); - } - } - else if (message.isType("CommoditiesResourceTypeListRequest")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const m(ri); - - static char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s.%d", GameServer::getInstance().getClusterName().c_str(), CommoditiesMarket::getResourceTypeMapVersionNumber()); - buffer[sizeof(buffer)-1] = '\0'; - - if (m.getValue() != std::string(buffer)) - { - GenericValueTypeMessage > > > const rsp("CommoditiesResourceTypeListResponse", std::make_pair(std::string(buffer), CommoditiesMarket::getResourceTypeMap())); - send(rsp, true); - } - } - else if (message.isType("CollectionServerFirstListRequest")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const m(ri); - - PlanetObject const * const planetObject = ServerUniverse::getInstance().getTatooinePlanet(); - if (planetObject) - { - static char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s.%d", GameServer::getInstance().getClusterName().c_str(), planetObject->getCollectionServerFirstUpdateNumber()); - buffer[sizeof(buffer)-1] = '\0'; - - if (m.getValue() != std::string(buffer)) - { - GenericValueTypeMessage, std::pair > > > > const rsp("CollectionServerFirstListResponse", std::make_pair(std::string(buffer), planetObject->getCollectionServerFirst())); - send(rsp, true); - } - } - } - - //----------------------------------------------------------------- - - else if (message.isType (PlanetTravelPointListRequest::cms_name)) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - const PlanetTravelPointListRequest requestMessage (readIterator); - - const std::string & planetName = requestMessage.getPlanetName (); - const PlanetObject* const planetObject = ServerUniverse::getInstance ().getPlanetByName (requestMessage.getPlanetName ()); - if (planetObject) - { - std::vector names; - planetObject->getTravelPointNameList (names); - - std::vector points; - planetObject->getTravelPointPointList (points); - - std::vector costs; - planetObject->getTravelPointCostList (costs); - - std::vector interplanetary; - planetObject->getTravelPointInterplanetaryList (interplanetary); - - PlanetTravelPointListResponse const rsp(planetName, names, points, costs, interplanetary, requestMessage.getSequenceId ()); - send(rsp, true); - } - else - DEBUG_WARNING (true, ("GameServer::receiveMessage: received request for travel point names from client [%s] for planet %s which does not exist", requestMessage.getPlanetName ().c_str (), requestMessage.getNetworkId ().getValueString ().c_str ())); - } - - //----------------------------------------------------------------- - - else if (message.isType (NewbieTutorialResponse::cms_name)) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - const NewbieTutorialResponse responseMessage (readIterator); - - static const std::string clientReadyString("clientReady"); - - if (responseMessage.getResponse() == clientReadyString) - { - for (std::vector::iterator i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) - { - ServerObject * const so = *i; - if (so) - so->onLoadingScreenComplete(); - } - } - - ScriptParams scriptParameters; - scriptParameters.addParam (responseMessage.getResponse ().c_str ()); - - if (primaryControlledObject->getScriptObject ()->trigAllScripts (Scripting::TRIG_NEWBIE_TUTORIAL_RESPONSE, scriptParameters) != SCRIPT_CONTINUE) - DEBUG_REPORT_LOG (true, ("OnNewbieTutorialResponse: did not return SCRIPT_CONTINUE\n")); - } - - //----------------------------------------------------------------- - - else if (message.isType("AddMapLocationMessage")) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - const AddMapLocationMessage msg (readIterator); - UNREF (msg); - - /* - MapLocation mapLocation(msg.getLocationId(), msg.getLocationName(), - Vector2d(msg.getLocationX(), msg.getLocationY()), - msg.getCategory(), msg.getSubCategory()); - - PlanetObject *planetObject = ServerUniverse::getInstance ().getPlanetByName (msg.getPlanetName ()); - if (planetObject) - { - planetObject->addMapLocation(mapLocation); - } - AddMapLocationResponseMessage responseMsg(msg.getLocationId()); - send(responseMsg, true); - */ - } - - //----------------------------------------------------------------- - - else if (message.isType(GetMapLocationsMessage::MessageType)) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - const GetMapLocationsMessage msg (readIterator); - - PlanetMapManagerServer::handleClientRequest (*this, msg); - } - - else if (message.isType("GetSpecificMapLocationsMessage")) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - const GenericValueTypeMessage > > msg (readIterator); - - PlanetMapManagerServer::handleClientRequestGetSpecificMapLocationsMessage (*this, msg.getValue()); - } - - else if (message.isType("ConsentResponseMessage")) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - ConsentResponseMessage const msg(readIterator); - ConsentManager::getInstance().handleResponse(msg); - } - - else if (message.isType("RequestGalaxyLoopTimes")) - { - // obfuscate the information so it's not obvious on the client that this is the server loop time - unsigned long loopTime = static_cast(Clock::frameTime() * 3193000.0f); // loop time (in ms) * 3193 - GalaxyLoopTimesResponse const msg(loopTime, loopTime); - send(msg, true); - } - else if (message.isType("LagRequest")) - { - GameNetworkMessage const msg("GameServerLagResponse"); - send(msg, true); - } - else if (message.isType("LagReport")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const report(ri); - m_connectionServerLag = report.getValue().first; - m_gameServerLag = report.getValue().second; - } - else if (message.isType("ChatInviteGroupToRoom")) - { - if (primaryControlledObject) - { - CreatureObject * const playerCreature = primaryControlledObject->asCreatureObject(); - if (playerCreature) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ChatInviteGroupToRoom const chat(ri); - - // We will need to notify the user if the group leader can not be found - bool foundGroupLeader = false; - - // Get the name of the group leader being invited - ChatAvatarId const & groupLeaderChatAvatarId = chat.getAvatarId(); - - // Convert the name to a network ID - NetworkId const groupLeaderNetworkId = NameManager::getInstance().getPlayerId(NameManager::normalizeName(Unicode::wideToNarrow(groupLeaderChatAvatarId.getName()))); - - // Try to get a group object corresponding to the player network ID - ServerObject const * const groupServerObject = ServerWorld::findObjectByNetworkId(GroupObject::getGroupIdForLeader(groupLeaderNetworkId)); - if (groupServerObject && groupServerObject->asGroupObject()) - { - // We now know the player is a group leader of a group - GroupObject const * const groupLeaderGroupObject = groupServerObject->asGroupObject(); - - // Make sure we have the correct player since we only searched by name - // (i.e. we may have been looking for a player with the same name but on a different cluster) - ChatAvatarId const playerChatAvatarId = Chat::constructChatAvatarId(NameManager::normalizeName(groupLeaderGroupObject->getGroupLeaderName())); - if (playerChatAvatarId == groupLeaderChatAvatarId) - { - // We found the group leader - foundGroupLeader = true; - - // We need to get the network IDs for all the group members - std::vector groupNetworkIds; - - GroupObject::GroupMemberVector const & groupMemberVector = groupLeaderGroupObject->getGroupMembers(); - for (unsigned i = 0; i < groupMemberVector.size(); ++i) - { - GroupObject::GroupMember const & groupMember = groupMemberVector[i]; - - groupNetworkIds.push_back(groupMember.first); - } - - // Pass the invitation to all the group members - Chat::inviteGroupMembers(m_primaryControlledObject, chat.getAvatarId(), chat.getRoomName(), groupNetworkIds); - } - } - - // If we couldn't find the group leader, let the player know - if (!foundGroupLeader) - { - ChatAvatarId const inviteeId = Chat::constructChatAvatarId(*playerCreature); - ChatOnInviteGroupToRoom msg(ERR_DESTAVATARDOESNTEXIST, chat.getRoomName(), inviteeId, chat.getAvatarId()); - send(msg, false); - } - } - } - } - else if (message.isType("ChatPersistentMessageToServer")) - { - if (primaryControlledObject) //lint !e774 - { - CreatureObject * const playerCreature = primaryControlledObject->asCreatureObject(); - if (playerCreature) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ChatPersistentMessageToServer const chat(ri); - std::string const &toName = chat.getToCharacterName().name; - if (!_stricmp(toName.c_str(), "guild")) - { - std::pair > const count = GuildInterface::mailToGuild(*playerCreature, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); - if (count.first < 0) - { - Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide("You do not have sufficient permission to send mail to guild members."), Unicode::emptyString); - } - else - { - Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("Your mail was sent to %d members of guild %s (%s).", count.first, count.second.first.c_str(), count.second.second.c_str())), Unicode::emptyString); - } - } - else if (!_strnicmp(toName.c_str(), "guild ", 6)) - { - // see if it's a valid guild rank - GuildRankDataTable::GuildRank const * guildRank = GuildRankDataTable::getRankForDisplayRankName(toName); - if (guildRank) - { - std::pair > const count = GuildInterface::mailToGuildRank(*playerCreature, guildRank->slotId, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); - if (count.first < 0) - { - Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide("You do not have sufficient permission to send mail to guild members."), Unicode::emptyString); - } - else - { - Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("Your mail was sent to %d members in rank %s of guild %s (%s).", count.first, guildRank->displayName.c_str(), count.second.first.c_str(), count.second.second.c_str())), Unicode::emptyString); - } - } - else - { - Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("\"%s\" is not a valid name.", toName.c_str())), Unicode::emptyString); - } - } - else if (!_stricmp(toName.c_str(), "citizens")) - { - std::pair const count = CityInterface::mailToCitizens(*playerCreature, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); - if (count.first < 0) - { - Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide("You do not have sufficient permission to send mail to citizens."), Unicode::emptyString); - } - else - { - Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("Your mail was sent to %d citizens of city %s.", count.first, count.second.c_str())), Unicode::emptyString); - } - } - - if (playerCreature->getObjVars().hasItem("cheater")) - { - LOGU("CustomerService", ("SuspectedCheaterChannel: %s is broadcasting a %s message that says '%s'", - PlayerObject::getAccountDescription(playerCreature).c_str(), - toName.c_str()), - chat.getMessage()); - } - } - } - } - else if (message.isType("ExpertiseRequestMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - ExpertiseRequestMessage const m(ri); - - std::vector const & addExpertisesNamesList = m.getAddExpertisesList(); - bool clearAllExpertisesFirst = m.getClearAllExpertisesFirst(); - std::string addList; - std::vector::const_iterator i; - for(i = addExpertisesNamesList.begin(); i != addExpertisesNamesList.end(); ++i) - { - addList += " "; - addList += *i; - } - CreatureObject * playerObject = safe_cast(getCharacterObject()); - if (playerObject) - { - LOG("CustomerService", ("ExpertiseRequestMessage: %s has requested to add expertises [%s] %s", - PlayerObject::getAccountDescription(playerObject).c_str(), - addList.c_str(), clearAllExpertisesFirst ? "(clearing first)" : "")); - playerObject->processExpertiseRequest(addExpertisesNamesList, clearAllExpertisesFirst); - } - } - else if (message.isType("UpdateSessionPlayTimeInfo")) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - GenericValueTypeMessage > > const msgPlayTimeInfo(readIterator); - - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(safe_cast(getCharacterObject())); - if (playerObject != NULL) - { - playerObject->setSessionPlayTimeInfo(msgPlayTimeInfo.getValue().first, msgPlayTimeInfo.getValue().second.first, msgPlayTimeInfo.getValue().second.second); - } - } - } - catch (Archive::ReadException &) - { - if (getCharacterObject()) - { - WARNING_STRICT_FATAL(true, ("A message was received from a client that could not be unpacked. Either the data was corrupt (intentionally or accidentally) or the client and server notion of the message are out of sync. The client will be disconnected. Character object is : %s :%s, IP=%s, accountname=%s", getCharacterObject()->getObjectTemplateName(), getCharacterObject()->getNetworkId().getValueString().c_str(), getIpAddress().c_str(), getAccountName().c_str())); - } - else - { - WARNING_STRICT_FATAL(true, ("A message was received from a client that could not be unpacked. Either the data was corrupt (intentionally or accidentally) or the client and server notion of the message are out of sync. The client will be disconnected. IP=%s, accountname=%s", getIpAddress().c_str(), getAccountName().c_str())); - } - if (getConnection()) - { - KickPlayer const kickMessage(m_characterObjectId, "Invalid Network Stream"); - GameServer::getInstance().sendToConnectionServers(kickMessage); - GameServer::getInstance().dropClient(m_characterObjectId); - } - } - - //----------------------------------------------------------------- -} - -//----------------------------------------------------------------------- - -void Client::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) -{ - UNREF(source); - - if ( message.isType("ConnectionServerConnectionClosed") - || message.isType("ConnectionServerConnectionDestroyed")) - { - //Connection server crashed - DEBUG_REPORT_LOG(true, ("Connection Server crashed. Client dropping.\n")); - m_connection = 0; - GameServer::getInstance().dropClient(m_characterObjectId); - } - else - { - if(&source != m_connection) - { - const MessageDispatch::Message * m = dynamic_cast *>(&message); - if(m) - { - ConGenericMessage const c(m->getValue(), 0); - send(c, true); - } - } - } -} - -//----------------------------------------------------------------------- - -void Client::removeControlledObject(ServerObject &object) -{ - if (m_primaryControlledObject == object.getNetworkId()) - { - ObserveTracker::onClientDestroyed(*this); - if (ServerWorld::isSpaceScene()) - SpaceVisibilityManager::removeClient(*this); - } - - std::vector::iterator iter = std::find(m_controlledObjects.begin(), m_controlledObjects.end(), &object); - if (iter != m_controlledObjects.end()) - IGNORE_RETURN(m_controlledObjects.erase(iter)); - else - DEBUG_WARNING(true, ("Client removing object [%s] that is not controlled", object.getNetworkId().getValueString().c_str())); - - object.clearClient(); -} - -//----------------------------------------------------------------------- - -void Client::selfDestruct() -{ - selfDestruct(false); -} -//----------------------------------------------------------------------- - -void Client::selfDestruct(const bool immediate) -{ - // @todo : this will eventually need to attach ai controllers to - // link dead objects. - std::vector controlledObjects = m_controlledObjects; - - // the controlled object list on the client is affected by clearClient, so work on a copy of the vector - for (std::vector::iterator i = controlledObjects.begin(); i != controlledObjects.end(); ++i) - { - if (*i) - { - if ((*i)->isAuthoritative()) - { - (*i)->handleDisconnect(immediate); - } - (*i)->clearClient(); - } - } - m_controlledObjects.clear(); - delete this; -} - -//----------------------------------------------------------------------- - -void Client::send(GameNetworkMessage const &outgoingMessage, bool reliable) const -{ - if (m_connection) - { - static std::vector v; - v.clear(); - v.push_back(m_characterObjectId); - GameClientMessage const msg(v, reliable, outgoingMessage); - - - uint32 now = Clock::timeMs(); - if ( sm_outgoingBytesMap_Worktime == 0 ) - sm_outgoingBytesMap_Worktime = now; - else if ( (now - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds - { - sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; - std::map< std::string, uint32 >::iterator iter; - for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) - { - iter->second = 0; - } - sm_outgoingBytesMap_Worktime = now; - } - sm_outgoingBytesMap_Working[ outgoingMessage.getCmdName() ] += msg.getByteStream().getSize(); - - - m_connection->send(msg, true); - } - else - { - DEBUG_REPORT_LOG(true, ("Tried to send message to a client without a connection server connection.\n")); - } -} - - -//----------------------------------------------------------------------- - -std::map< std::string, uint32 >& Client::getPacketBytesPerMinStats() -{ - uint32 now = Clock::timeMs(); - if ( sm_outgoingBytesMap_Worktime == 0 ) - sm_outgoingBytesMap_Worktime = now; - else if ( (now - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds - { - sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; - std::map< std::string, uint32 >::iterator iter; - for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) - { - iter->second = 0; - } - sm_outgoingBytesMap_Worktime = now; - } - - return sm_outgoingBytesMap_Stats; -} - - - -//----------------------------------------------------------------------- - -void Client::sendToConnectionServer(GameNetworkMessage const &msg) -{ - if (m_connection) - m_connection->send(msg, true); - else - { - DEBUG_REPORT_LOG(true, ("Tried to send message to a client without a connection server connection.\n")); - } -} - -//----------------------------------------------------------------------- - -uint16 Client::getServerSyncStampShort() const -{ - NOT_NULL(m_connection); - return m_connection->getSyncStampShort(); -} - -//----------------------------------------------------------------------- - -uint32 Client::getServerSyncStampLong() const -{ - NOT_NULL(m_connection); - return m_connection->getSyncStampLong(); -} - -//----------------------------------------------------------------------- - -float Client::computeDeltaTimeInSeconds(uint32 const syncStampLong) const -{ - uint32 const deltaTimeMilliseconds = syncStampLong - getServerSyncStampLong(); - - float deltaTime = 0.f; - if (deltaTimeMilliseconds > 0x7fffffff) - deltaTime = static_cast(static_cast(0xffffffff - deltaTimeMilliseconds)) / 1000.0f; - else - deltaTime = static_cast(static_cast(deltaTimeMilliseconds)) / 1000.0f; - - return deltaTime; -} - -//----------------------------------------------------------------------- - -bool Client::setGodMode(bool value) -{ - bool wasInGodMode = m_godMode; - m_godMode = value; - - if (value && !m_godValidated) - { - LOG("CustomerService", ("Avatar:%s denied god mode because it wasn't validated.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str() )); - m_godMode = false; - } - - CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); - if (!primaryControlledObject) - { - if (value && !wasInGodMode) - LOG("CustomerService", ("Avatar:%s denied god mode because it has no associated character.", m_accountName.c_str() )); - m_godMode = false; - return false; - } - - if (m_godMode) - IGNORE_RETURN(primaryControlledObject->grantCommand(AdminAccountManager::getAdminCommandName(), false)); - else - primaryControlledObject->revokeCommand(AdminAccountManager::getAdminCommandName(), false, true); - - if (m_godMode != wasInGodMode) - { - if (m_godMode) - LOG("CustomerService", ("Avatar:%s granted god mode %s level %d.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str(), AdminAccountManager::getAdminCommandName(), m_godLevel )); - else - LOG("CustomerService", ("Avatar:%s dropped god mode.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str())); - - // cell permissions may change for us for all cells, so observe all buildings in range for the change - CellPermissions::ViewerChangeObserver o(primaryControlledObject); - - ObserveTracker::onGodModeChanged(*this); - } - return (value == m_godMode); // return true if the value was set to what was requested, false otherwise -} - -//----------------------------------------------------------------------- - -void Client::addObserving(ServerObject* o) -{ - if (o) - { - IGNORE_RETURN(m_observing.insert(o)); - TangibleObject *to = o->asTangibleObject(); - if (to && PvpUpdateObserver::satisfyPvpSyncCondition(to->isNonPvpObject(), to->hasCondition(ServerTangibleObjectTemplate::C_invulnerable), (o->asCreatureObject() != NULL), to->getPvpFaction())) - addObservingPvpSync(to); - } -} - -//----------------------------------------------------------------------- - -void Client::addObservingPvpSync(TangibleObject* to) -{ - if (to) - { - IGNORE_RETURN(m_observingPvpSync.insert(to)); - PvpUpdateObserver::startObservingPvpSyncNotification(this, *to); - } -} - -//----------------------------------------------------------------------- - -void Client::removeObservingPvpSync(ServerObject* o) -{ - if (o && m_observingPvpSync.erase(reinterpret_cast(o))) - PvpUpdateObserver::stopObservingPvpSyncNotification(this, o->getNetworkId()); -} - -//----------------------------------------------------------------------- - -void Client::resetIdleTimeAfterCharacterTransfer() -{ - // set m_lastNonIdleTime such that idledTooLong() will be true in ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec() - unsigned long const currentGameTime = ServerClock::getInstance().getGameTimeSeconds(); - - if ((currentGameTime + ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec()) > ConfigServerGame::getIdleLogoutTimeSec()) - { - m_lastNonIdleTime = currentGameTime + ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec() - ConfigServerGame::getIdleLogoutTimeSec(); - - if (m_lastNonIdleTime > currentGameTime) - m_lastNonIdleTime = currentGameTime; - } - else - { - m_lastNonIdleTime = 0; - } -} - -//----------------------------------------------------------------------- - -void Client::resetIdleTime() -{ - m_lastNonIdleTime = ServerClock::getInstance().getGameTimeSeconds(); -} - -//----------------------------------------------------------------------- - -bool Client::idledTooLong() const -{ - return ServerClock::getInstance().getGameTimeSeconds()-m_lastNonIdleTime > ConfigServerGame::getIdleLogoutTimeSec(); -} - -//----------------------------------------------------------------------- - -const std::string & Client::getAccountName() const -{ - return m_accountName; -} - -//----------------------------------------------------------------------- - -const std::string & Client::getIpAddress() const -{ - return m_ipAddress; -} - -//----------------------------------------------------------------------- - -void Client::handleIdleDisconnect() const -{ - DEBUG_REPORT_LOG(true, ("Disconnecting %s for being idle too long.\n", m_characterObjectId.getValueString().c_str())); - KickPlayer const kickMessage(m_characterObjectId, "Idle Connection"); - GameServer::getInstance().sendToConnectionServers(kickMessage); - GameServer::getInstance().dropClient(m_characterObjectId); -} - -//----------------------------------------------------------------------- - -const unsigned int Client::getStationId() const -{ - return m_stationId; -} - -//----------------------------------------------------------------------- - -int Client::getConnectionServerLag() const -{ - return m_connectionServerLag; -} - -//----------------------------------------------------------------------- - -int Client::getGameServerLag() const -{ - return m_gameServerLag; -} - -//----------------------------------------------------------------------- - -void Client::addSynchronizedUi (ServerSynchronizedUi *syncUI) -{ - m_syncUIs.push_back(Watcher(syncUI)); -} - -//----------------------------------------------------------------------- - -void Client::removeSynchronizedUi(ServerSynchronizedUi const * const syncUI) -{ - for (std::vector >::iterator i = m_syncUIs.begin(); i != m_syncUIs.end(); ++i) - { - if (i->getPointer() == syncUI) - { - IGNORE_RETURN(m_syncUIs.erase(i)); - return; - } - } -} - -// ---------------------------------------------------------------------- - -void Client::openContainer(ServerObject &obj, int sequence, std::string const &slotDesc) -{ - if (ObserveTracker::onClientOpenedContainer(*this, obj, sequence, slotDesc)) - { - ScriptParams params; - params.addParam(getCharacterObjectId()); - IGNORE_RETURN(obj.getScriptObject()->trigAllScripts(Scripting::TRIG_OPENED_CONTAINER, params)); - } -} - -// ---------------------------------------------------------------------- - -void Client::closeContainer(ServerObject &obj) -{ - if (ObserveTracker::onClientClosedContainer(*this, obj)) - { - ScriptParams params; - params.addParam(getCharacterObjectId()); - IGNORE_RETURN(obj.getScriptObject()->trigAllScripts(Scripting::TRIG_CLOSED_CONTAINER, params)); - } -} - -//----------------------------------------------------------------------- - -void Client::observeContainer(ServerObject &obj, int sequence, std::string const &slotDesc) -{ - ObserveTracker::onClientOpenedContainer(*this, obj, sequence, slotDesc, false); -} - -//----------------------------------------------------------------------- - -bool Client::isFreeTrialAccount() const -{ - //Test code - - if (m_primaryControlledObject.getObject()) - { - if (safe_cast(m_primaryControlledObject.getObject())->getObjVars().hasItem("freeTrialAccount")) - return true; - } - - //End test code - - int const allFreeTrials = ClientSubscriptionFeature::FreeTrial | ClientSubscriptionFeature::FreeTrial2; - - return ((m_subscriptionFeatures & allFreeTrials) != 0) && - ((m_subscriptionFeatures & ClientSubscriptionFeature::Base) == 0); -} - -//----------------------------------------------------------------------- - -bool Client::isSecure() const -{ - return m_isSecure; -} - -// ---------------------------------------------------------------------- - -std::vector > const & Client::getConsumedRewardEvents() const -{ - return m_consumedRewardEvents; -} - -// ---------------------------------------------------------------------- - -std::vector > const & Client::getClaimedRewardItems() const -{ - return m_claimedRewardItems; -} - -// ---------------------------------------------------------------------- - -void Client::launchWebBrowser(std::string const & url) const -{ - GenericValueTypeMessage message("LaunchBrowserMessage", url); - send(message,true); -} - -// ---------------------------------------------------------------------- - -bool Client::isUsingAdminLogin() const -{ - return m_usingAdminLogin; -} - -// ---------------------------------------------------------------------- - -bool Client::shouldReceiveCombatSpam(NetworkId const & attacker, Vector const & attackerPosition_w, NetworkId const & defender, Vector const & defenderPosition_w) const -{ - PROFILER_AUTO_BLOCK_DEFINE("Client::shouldReceiveCombatSpam"); - - // none means no combat spam, period!!! - if (m_combatSpamFilter == CombatDataTable::CSFT_None) - return false; - - // some combat spam messages don't have an attacker or defender, always allow those - if (!attacker.isValid() && !defender.isValid()) - return true; - - // always receive combat spam if I'm the attacker or the defender - if (m_characterObjectId.isValid() && ((m_characterObjectId == attacker) || (m_characterObjectId == defender))) - return true; - - bool passFilter = false; - if (m_combatSpamFilter == CombatDataTable::CSFT_All) - { - passFilter = true; - } - else if (m_combatSpamFilter == CombatDataTable::CSFT_Group) - { - CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); - if (primaryControlledObject) - { - GroupObject const * group = primaryControlledObject->getGroup(); - if (group && (group->isGroupMember(attacker) || group->isGroupMember(defender))) - { - passFilter = true; - } - } - } - - if (!passFilter) - return false; - - // range check - CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); - if (primaryControlledObject) - { - Vector const playerPosition = primaryControlledObject->getPosition_w(); - - if ((attacker.isValid() && (playerPosition.magnitudeBetweenSquared(attackerPosition_w) <= m_combatSpamRangeSquaredFilter)) || (defender.isValid() && (playerPosition.magnitudeBetweenSquared(defenderPosition_w) <= m_combatSpamRangeSquaredFilter))) - return true; - } - - return false; -} - -// ---------------------------------------------------------------------- - -bool Client::getSendToStarport() const -{ - return m_sendToStarport; -} - - -// ---------------------------------------------------------------------- - -int Client::getBuddyPoints() const -{ - return m_buddyPoints; -} - -// ====================================================================== - +// ====================================================================== +// +// Client.cpp +// +// Copyright 2002 Sony Online Entertainment +// +// ====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/Client.h" + +#include "Archive/ByteStream.h" +#include "LocalizationManager.h" +#include "serverGame/BuildingObject.h" +#include "serverGame/Chat.h" +#include "serverGame/CityInterface.h" +#include "serverGame/CommoditiesMarket.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ConnectionServerConnection.h" +#include "serverGame/ConsentManager.h" +#include "serverGame/ConsoleManager.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/GuildInterface.h" +#include "serverGame/GuildMemberInfo.h" +#include "serverGame/GroupObject.h" +#include "serverGame/LogoutTracker.h" +#include "serverGame/NameManager.h" +#include "serverGame/ObjectTracker.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PlanetMapManagerServer.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/PlayerShipController.h" +#include "serverGame/PvpUpdateObserver.h" +#include "serverGame/ServerMessageForwarding.h" +#include "serverGame/ServerSecureTrade.h" +#include "serverGame/ServerTangibleObjectTemplate.h" +#include "serverGame/ServerUIManager.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/SpaceVisibilityManager.h" +#include "serverGame/ShipClientUpdateTracker.h" +#include "serverGame/ShipObject.h" +#include "serverGame/TriggerVolume.h" +#include "serverNetworkMessages/GameConnectionServerMessages.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptFunctionTable.h" +#include "serverScript/ScriptParameters.h" +#include "serverUtility/AdminAccountManager.h" +#include "serverUtility/ServerClock.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/DynamicVariable.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/DynamicVariableLocationData.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedFoundation/Os.h" +#include "sharedGame/CommandTable.h" +#include "sharedGame/GuildRankDataTable.h" +#include "sharedGame/LfgDataTable.h" +#include "sharedGame/PlatformFeatureBits.h" +#include "sharedGame/RadialMenuManager.h" +#include "sharedGame/ShipSlotIdManager.h" +#include "sharedLog/Log.h" +#include "sharedMathArchive/TransformArchive.h" +#include "sharedMathArchive/VectorArchive.h" +#include "sharedMessageDispatch/Message.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetworkMessages/AcceptAuctionMessage.h" +#include "sharedNetworkMessages/AddMapLocationMessage.h" +#include "sharedNetworkMessages/AddMapLocationResponseMessage.h" +#include "sharedNetworkMessages/AuctionQueryHeadersMessage.h" +#include "sharedNetworkMessages/AuctionQueryMessage.h" +#include "sharedNetworkMessages/BidAuctionMessage.h" +#include "sharedNetworkMessages/CancelLiveAuctionMessage.h" +#include "sharedNetworkMessages/ChatAvatarId.h" +#include "sharedNetworkMessages/ChatEnum.h" +#include "sharedNetworkMessages/ChatInviteGroupToRoom.h" +#include "sharedNetworkMessages/ChatOnInviteGroupToRoom.h" +#include "sharedNetworkMessages/ChatPersistentMessageToServer.h" +#include "sharedNetworkMessages/CommandChannelMessages.h" +#include "sharedNetworkMessages/ConsentResponseMessage.h" +#include "sharedNetworkMessages/ConsoleChannelMessages.h" +#include "sharedNetworkMessages/ControllerMessageFactory.h" +#include "sharedNetworkMessages/CreateAuctionMessage.h" +#include "sharedNetworkMessages/CreateImmediateAuctionMessage.h" +#include "sharedNetworkMessages/CreateProjectileMessage.h" +#include "sharedNetworkMessages/ExpertiseRequestMessage.h" +#include "sharedNetworkMessages/FactionRequestMessage.h" +#include "sharedNetworkMessages/FactionResponseMessage.h" +#include "sharedNetworkMessages/GalaxyLoopTimesResponse.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/GetAuctionDetails.h" +#include "sharedNetworkMessages/GetMapLocationsMessage.h" +#include "sharedNetworkMessages/GuildRequestMessage.h" +#include "sharedNetworkMessages/GuildResponseMessage.h" +#include "sharedNetworkMessages/IsVendorOwnerMessage.h" +#include "sharedNetworkMessages/IsVendorOwnerResponseMessage.h" +#include "sharedNetworkMessages/NewbieTutorialResponse.h" +#include "sharedNetworkMessages/ObjectChannelMessages.h" +#include "sharedNetworkMessages/ObjectMenuRequestDataArchive.h" +#include "sharedNetworkMessages/ObjectMenuSelectMessage.h" +#include "sharedNetworkMessages/ParametersMessage.h" +#include "sharedNetworkMessages/PlanetTravelPointListRequest.h" +#include "sharedNetworkMessages/PlanetTravelPointListResponse.h" +#include "sharedNetworkMessages/PlayerMoneyRequest.h" +#include "sharedNetworkMessages/PlayerMoneyResponse.h" +#include "sharedNetworkMessages/RequestGalaxyLoopTimes.h" +#include "sharedNetworkMessages/RetrieveAuctionItemMessage.h" +#include "sharedNetworkMessages/RetrieveAuctionItemResponseMessage.h" +#include "sharedNetworkMessages/SceneChannelMessages.h" +#include "sharedNetworkMessages/SecureTradeMessages.h" +#include "sharedNetworkMessages/ShipUpdateTransformMessage.h" +#include "sharedNetworkMessages/StomachRequestMessage.h" +#include "sharedNetworkMessages/SuiEventNotification.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/NetworkController.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/PortalProperty.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" +#include "sharedUtility/Location.h" +#include "sharedSkillSystem/SkillManager.h" +#include "unicodeArchive/UnicodeArchive.h" + +namespace ClientNamespace +{ + // list of object types, radial menu action permission + // override, to allow certain object types to have certain radial + // menu action invoked on them by non-owners of the object + std::set > s_radialMenuPermissionOverrideTemplateItemType; + std::set > s_radialMenuPermissionOverrideStaticItemType; + + // ---------------------------------------------------------------------- + + bool canManipulateObjectExceptionCheck(ServerObject const &target, int menuType, Container::ContainerErrorCode& errorCode) + { + if (errorCode == Container::CEC_NoPermission) + { + const std::string & objectStaticName = target.getStaticItemName(); + if (objectStaticName.empty()) + { + if (s_radialMenuPermissionOverrideTemplateItemType.count(std::make_pair(target.getTemplateCrc(), menuType)) > 0) + { + errorCode = Container::CEC_Success; + return true; + } + } + else if (s_radialMenuPermissionOverrideStaticItemType.count(std::make_pair(objectStaticName, menuType)) > 0) + { + errorCode = Container::CEC_Success; + return true; + } + } + + return false; + } + + // ---------------------------------------------------------------------- + + void remove() + { + } +} + +// ====================================================================== + +Client::ClientMessage::ClientMessage(const std::string & src) : +MessageDispatch::MessageBase(src.c_str()) +{ +} + +//----------------------------------------------------------------------- + +Client::ClientMessage::~ClientMessage() +{ +} + + + + +//----------------------------------------------------------------------- + +std::map< std::string, uint32 > Client::sm_outgoingBytesMap_Working; // working stats that will rotate after 1 minute +std::map< std::string, uint32 > Client::sm_outgoingBytesMap_Stats; // computed stats from the last minute +uint32 Client::sm_outgoingBytesMap_Worktime = 0 ; // time we started filling in the working map + + +// ====================================================================== + +Client::Client(ConnectionServerConnection & connection, const NetworkId & characterObjectId, const std::string& accountName, const std::string& ipAddr, bool isSecure, bool isSkipLoadScreen, unsigned int stationId, std::set const & observedObjects, uint32 gameFeatures, uint32 subscriptionFeatures, AccountFeatureIdList const & accountFeatureIds, unsigned int entitlementTotalTime, unsigned int entitlementEntitledTime, unsigned int entitlementTotalTimeSinceLastLogin, unsigned int entitlementEntitledTimeSinceLastLogin, int buddyPoints, std::vector > const & consumedRewardEvents, std::vector > const & claimedRewardItems, bool usingAdminLogin, CombatDataTable::CombatSpamFilterType combatSpamFilter, int combatSpamRangeSquaredFilter, int furnitureRotationDegree, bool hasUnoccupiedJediSlot, bool isJediSlotCharacter, bool sendToStarport ) : + MessageDispatch::Receiver(), + MessageDispatch::Emitter(), + m_accountName(accountName), + m_characterName(), + m_characterObjectId(characterObjectId), + m_connection(&connection), + m_controlledObjects(), + m_godLevel(0), + m_godMode(false), + m_godValidated(false), + m_ipAddress(ipAddr), + m_isReady(false), + m_isSecure(isSecure), + m_isSkipLoadScreen(isSkipLoadScreen), + m_primaryControlledObject(NetworkId::cms_invalid), + destroyNotifier(), + m_observing(), + m_openedContainers(), + m_watchedByList(), + m_lastNonIdleTime(ServerClock::getInstance().getGameTimeSeconds()), + m_stationId(stationId), + m_connectionServerLag(0), + m_gameServerLag(0), + m_gameFeatures(gameFeatures), + m_subscriptionFeatures(subscriptionFeatures), + m_accountFeatureIds(accountFeatureIds), + m_entitlementTotalTime(entitlementTotalTime), + m_entitlementEntitledTime(entitlementEntitledTime), + m_entitlementTotalTimeSinceLastLogin(entitlementTotalTimeSinceLastLogin), + m_entitlementEntitledTimeSinceLastLogin(entitlementEntitledTimeSinceLastLogin), + m_buddyPoints(buddyPoints), + m_previousObservedObjects(observedObjects), + m_syncUIs(), + m_consumedRewardEvents(consumedRewardEvents), + m_claimedRewardItems(claimedRewardItems), + m_usingAdminLogin(usingAdminLogin), + m_combatSpamFilter(combatSpamFilter), + m_combatSpamRangeSquaredFilter(combatSpamRangeSquaredFilter), + m_furnitureRotationDegree(furnitureRotationDegree), + m_hasUnoccupiedJediSlot(hasUnoccupiedJediSlot), + m_isJediSlotCharacter(isJediSlotCharacter), + m_sendToStarport( sendToStarport ) +{ + + connectToEmitter(connection, "ConnectionServerConnectionClosed"); + connectToEmitter(connection, "ConnectionServerConnectionDestroyed"); + + // Check god permissions + if ( ConfigServerGame::getAdminGodToAll() + || ( (!ConfigServerGame::getUseSecureLoginForGodAccess() || m_isSecure) + && AdminAccountManager::isAdminAccount(Unicode::toLower(accountName), m_godLevel) + && (!ConfigServerGame::getUseIPForGodAccess() || AdminAccountManager::isInternalIp(ipAddr)))) + { + m_godValidated = true; + if (ConfigServerGame::getAdminGodToAll()) + m_godLevel = ConfigServerGame::getAdminGodToAllGodLevel(); + } + + // See if our controlled object is ready yet. + ServerObject *obj = LogoutTracker::findPendingCharacterSave(characterObjectId); + if (obj) + { + // If we're waiting to be saved in the LogoutTracker, then we've been + // removed from our container, so restore our containment if need be. + Object *containerObject = ContainerInterface::getContainedByObject(*obj); + if (containerObject) + { + // Don't ever put the character into a packed house + ServerObject * const serverObject = containerObject->asServerObject(); + CellObject * const cellObject = (serverObject ? serverObject->asCellObject() : NULL); + BuildingObject * const buildingObject = (cellObject ? cellObject->getOwnerBuilding() : NULL); + + if ((buildingObject) && (!buildingObject->isInWorld())) + { + ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); + if (cby) + { + DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building is packed\n",characterObjectId.getValueString().c_str(), buildingObject->getNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building is packed",characterObjectId.getValueString().c_str(), buildingObject->getNetworkId().getValueString().c_str())); + + cby->setContainedBy(NetworkId::cms_invalid, true); + containerObject = 0; + + // attempt to put the character at the ejection point of the building + if (!ServerWorld::isSpaceScene()) + { + DynamicVariableLocationData ejectionPoint; + if (obj->getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) + { + obj->removeObjVarItem("building_ejection_point"); + obj->setPosition_p(ejectionPoint.pos); + } + } + } + } + else if (containerObject->isAuthoritative()) + { + // The cell depersist step will try to set the parent cell of the player. + // However, that procedure will fail because the "contained by" property + // says the player is in a container when they really are not. + ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); + if (cby) + { + // We need to remove and then re-add the property so that the + // property is updated immediately (as opposed to waiting for an alter) + cby->setContainedBy(NetworkId::cms_invalid, true); + obj->removeProperty(cby->getPropertyId()); + obj->addProperty(*cby, true); + } + + // save and restore the original transform. The existing transform should be in parent + // space, but it is in world. down through depersistContents there is an assumption that + // it is in parent space and gets transformed incorrectly. + Transform origTransform = obj->getTransform_o2p(); + + // NOTE: Depersist works slightly differently than when the player + // is loaded from the database since in this case the player + // is initialized when depersist is called + Container * const container = ContainerInterface::getContainer(*containerObject); + NOT_NULL(container); + IGNORE_RETURN(container->depersistContents(*obj)); + + // if failed to put character back into the container, then clean up the + // containment relationship so that the character is now out in the world + if (ContainerInterface::getContainedByObject(*obj) != containerObject) + { + IGNORE_RETURN(container->internalItemRemoved(*obj)); + + if (cby) + { + // We need to remove and then re-add the property so that the + // property is updated immediately (as opposed to waiting for an alter) + cby->setContainedBy(NetworkId::cms_invalid, true); + obj->removeProperty(cby->getPropertyId()); + obj->addProperty(*cby, true); + } + + // attempt to put the character at the ejection point of the building + if (!ServerWorld::isSpaceScene()) + { + DynamicVariableLocationData ejectionPoint; + if (obj->getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) + { + DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because could not put player back in building\n",characterObjectId.getValueString().c_str(), (buildingObject ? buildingObject->getNetworkId().getValueString().c_str() : containerObject->getNetworkId().getValueString().c_str()))); + LOG("CustomerService",("Login: Ejecting player %s from building %s, because could not put player back in building",characterObjectId.getValueString().c_str(), (buildingObject ? buildingObject->getNetworkId().getValueString().c_str() : containerObject->getNetworkId().getValueString().c_str()))); + + obj->removeObjVarItem("building_ejection_point"); + obj->setPosition_p(ejectionPoint.pos); + } + } + + containerObject = 0; + } + else + { + obj->setTransform_o2w(origTransform); + + // if the character was in a building, tell the building it has gained + // the player so the building demand load/unload system can work correctly + Object *buildingObj = ContainerInterface::getTopmostContainer(*containerObject); + if (buildingObj && buildingObj->asServerObject() && buildingObj->asServerObject()->asBuildingObject()) + buildingObj->asServerObject()->asBuildingObject()->gainedPlayer(*obj); + } + } + else + { + // The container is no longer authoritative on this server. Move us to a safe place + // outside the container. + Object * const topmostObject = ContainerInterface::getTopmostContainer(*obj); + BuildingObject * const topmostBuilding = dynamic_cast(topmostObject); + if (topmostBuilding) + { + DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building has changed authority\n",characterObjectId.getValueString().c_str(), topmostBuilding->getNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building has changed authority",characterObjectId.getValueString().c_str(), topmostBuilding->getNetworkId().getValueString().c_str())); + ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); + if (cby) + { + cby->setContainedBy(NetworkId::cms_invalid, true); + containerObject = 0; + + PortalProperty * const portalProperty = topmostBuilding->getPortalProperty(); + if (portalProperty) + { + ServerController * const controller = dynamic_cast(obj->getController()); + if (controller) + { + Transform destinationTransform(Transform::IF_none); + destinationTransform.multiply(topmostBuilding->getTransform_o2w(), portalProperty->getEjectionLocationTransform()); + obj->setTransform_o2p(destinationTransform); + } + } + } + } + else + WARNING(true,("Expected player %s to be in a building, but he was in some other type of object. Skipping authority fixup because something strange is going on.",characterObjectId.getValueString().c_str())); + } + } + else + { + // check for the case where we were in a container that isn't there anymore + ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*obj); + if ((cby) && (cby->getContainedByNetworkId().isValid())) + { + DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building does not exist anymore\n",characterObjectId.getValueString().c_str(), cby->getContainedByNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building does not exist anymore",characterObjectId.getValueString().c_str(), cby->getContainedByNetworkId().getValueString().c_str())); + + cby->setContainedBy(NetworkId::cms_invalid, true); + + // attempt to put the character at the ejection point of the building + if (!ServerWorld::isSpaceScene()) + { + DynamicVariableLocationData ejectionPoint; + if (obj->getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) + { + obj->removeObjVarItem("building_ejection_point"); + obj->setPosition_p(ejectionPoint.pos); + } + } + } + } + + // Only add to the world if it in a location which should be in the world. + if (!containerObject || (containerObject->isInWorld() && containerObject->getContainerProperty()->isContentItemExposedWith(*obj))) + obj->addToWorld(); + + // Notify the object that it has a client about to load + obj->onClientAboutToLoad(); + + // We need to trigger having been made authoritative since we are an object which has been + // disconnected from the world. + obj->triggerMadeAuthoritative(); + + // Create proxies as needed + ProxyList const &proxyList = obj->getExposedProxyList(); + if (!proxyList.empty()) + { + ServerMessageForwarding::begin(std::vector(proxyList.begin(), proxyList.end())); + + obj->forwardServerCreateAndBaselines(); + + ServerMessageForwarding::end(); + } + } + else + obj = ServerWorld::findObjectByNetworkId(characterObjectId); + + if (obj) + { + obj->checkAndAddClientControl(this); + } + + // Send server-specific settings to the client + ParametersMessage const msg(ConfigServerGame::getWeatherUpdateSeconds()); + send(msg, true); + + ObjectTracker::addPlayer(); +} + +//----------------------------------------------------------------------- + +Client::~Client() +{ + ClientDestroy d(this); + destroyNotifier.emitMessage(d); + + if (ServerWorld::isSpaceScene()) + SpaceVisibilityManager::removeClient(*this); + + ObserveTracker::onClientDestroyed(*this); + ShipClientUpdateTracker::onClientDestroyed(*this); + + DEBUG_FATAL(!m_controlledObjects.empty(),("Deleting a client with a non-empty controlled objects list!\n")); + m_primaryControlledObject = NetworkId::cms_invalid; + + //clean up any orphaned SynchronizedUIs + for (std::vector >::iterator i = m_syncUIs.begin(); i != m_syncUIs.end(); ++i) + { + ServerSynchronizedUi* syncUI = i->getPointer(); + if (syncUI) + delete syncUI; + } + + ObjectTracker::removePlayer(); + + PvpUpdateObserver::removeClientFromPvpStatusCache(this); + + m_connection = 0; +} + +// ---------------------------------------------------------------------- + +void Client::install() +{ + // read in the list of object types, radial menu action permission + // override, to allow certain object types to have certain radial + // menu action invoked on them by non-owners of the object + char const * const radialMenuPermissionOverrideDataTableName = "datatables/player/radial_menu_permission_override.iff"; + DataTable * table = DataTableManager::getTable(radialMenuPermissionOverrideDataTableName, true); + if (table) + { + int const columnObjectTemplate = table->findColumnNumber("Object Template"); + int const columnCommand = table->findColumnNumber("Command"); + if ((columnObjectTemplate >= 0) && (columnCommand >= 0)) + { + std::string objectTemplate; + std::string command; + int commandMenuId; + + for (int i = 0, numRows = table->getNumRows(); i < numRows; ++i) + { + objectTemplate = table->getStringValue(columnObjectTemplate, i); + if (objectTemplate.empty()) + continue; + + command = table->getStringValue(columnCommand, i); + if (command.empty()) + continue; + + commandMenuId = RadialMenuManager::getMenuTypeByName(command); + if (commandMenuId == 0) + continue; + + if (objectTemplate.find(".iff") != std::string::npos) + ClientNamespace::s_radialMenuPermissionOverrideTemplateItemType.insert(std::make_pair(CrcLowerString::calculateCrc(objectTemplate.c_str()), commandMenuId)); + else + ClientNamespace::s_radialMenuPermissionOverrideStaticItemType.insert(std::make_pair(objectTemplate, commandMenuId)); + } + } + + DataTableManager::close(radialMenuPermissionOverrideDataTableName); + } + + ExitChain::add(ClientNamespace::remove, "ClientNamespace::remove"); +} + +//----------------------------------------------------------------------- + +void Client::addControlledObject(ServerObject &object) +{ + // check to see if it is in the list already + if (std::find(m_controlledObjects.begin(), m_controlledObjects.end(), &object) == m_controlledObjects.end()) + m_controlledObjects.push_back(&object); + else + DEBUG_WARNING(true, ("Client adding controlled object [%s] that is already controlled", object.getNetworkId().getValueString().c_str())); + + //finally set a pointer to the Client object on the object + object.setClient(*this); + ObserveTracker::onObjectControlled(*this, object, m_previousObservedObjects); + + // Any objects to be re-controlled have been at this point, so clean up any old objects that are no longer observed + ObserveTracker::onClientControlComplete(*this, m_previousObservedObjects); + m_previousObservedObjects.clear(); + + // If in space, add the client to SpaceVisibilityManager. Only do this for the topmost object the client controls that is in the world. + if (ServerWorld::isSpaceScene()) + { + Object * topmost = ContainerInterface::getTopmostContainer(object); + NOT_NULL(topmost); + NOT_NULL(topmost->asServerObject()); + if (topmost->isInWorld()) + SpaceVisibilityManager::addClient(*this, *(topmost->asServerObject())); + } + + // Restore god mode after changing servers + CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); + if (primaryControlledObject) + { + if (primaryControlledObject->hasCommand(AdminAccountManager::getAdminCommandName())) + setGodMode(true); + } +} + +// ---------------------------------------------------------------------- + +void Client::clearControlledObjects() +{ + while (!m_controlledObjects.empty()) + removeControlledObject(**m_controlledObjects.begin()); + + PvpUpdateObserver::removeClientFromPvpStatusCache(this); +} + +// ---------------------------------------------------------------------- + +ServerObject *Client::findControlledObject(NetworkId const &oid) const +{ + for (std::vector::const_iterator i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) + if ((*i) && (*i)->getNetworkId() == oid) + return *i; + return 0; +} + +// ---------------------------------------------------------------------- + +std::vector const &Client::getControlledObjects() const +{ + return m_controlledObjects; //lint !e1536 //low access +} + +//----------------------------------------------------------------------- + +bool Client::isControlled(NetworkId const &id) const +{ + std::vector::const_iterator i; + for(i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) + { + ServerObject * object = *i; + if(object && object->getNetworkId() == id) + return true; + } + return false; +} + +//----------------------------------------------------------------------- + +void Client::onLoadPlayer(CreatureObject &newCharacter) +{ + if (m_primaryControlledObject != NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Already have a primary object!")); + if (m_primaryControlledObject == newCharacter.getNetworkId()) + return; + } + + m_primaryControlledObject = CachedNetworkId(newCharacter); + + assumeControl(newCharacter); +} + +//----------------------------------------------------------------------- + +void Client::assumeControl(CreatureObject &newCharacter) +{ + DEBUG_FATAL(newCharacter.getNetworkId() != m_primaryControlledObject, ("Tried to assume control of the wrong object?")); + + // Add the object to the controlled object list + addControlledObject(newCharacter); + + // Register player name with the global list + std::string const &firstName = Unicode::wideToNarrow(Unicode::toLower(newCharacter.getAssignedObjectFirstName())); + std::string const &fullName = Unicode::wideToNarrow(newCharacter.getAssignedObjectName()); + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(&newCharacter); + NameManager::getInstance().addPlayer(newCharacter.getNetworkId(), (playerObject ? playerObject->getStationId() : static_cast(m_stationId)), firstName, fullName, 0, Os::getRealSystemTime(), true); + + static const std::string loginTrace("TRACE_LOGIN"); + LOG(loginTrace, ("sending ControlAssumed(%s, %s)", m_primaryControlledObject.getValueString().c_str(), ConfigServerGame::getGroundScene())); + + ControlAssumed const controlMessage( + m_primaryControlledObject, + ConfigServerGame::getGroundScene(), + m_isSkipLoadScreen, + newCharacter.getTransform_o2w().getPosition_p(), + newCharacter.getObjectFrameK_w().theta(), + newCharacter.getSharedTemplateName(), + static_cast(ServerClock::getInstance().getGameTimeSeconds())); + + sendToConnectionServer(controlMessage); + + m_isSkipLoadScreen = false; +} + +//----------------------------------------------------------------------- + +void Client::receiveClientMessage(const GameNetworkMessage & message) +{ + try + { + + // Ignore any messages if the character is not loaded yet. + if (m_primaryControlledObject == NetworkId::cms_invalid) + { + DEBUG_REPORT_LOG(true,("Ignoring message for character %s because it is not loaded yet.\n",m_characterObjectId.getValueString().c_str())); + return; + } + + ServerObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); + + if (!primaryControlledObject) + { + DEBUG_REPORT_LOG(true,("Ignoring message for character %s because object %s cannot be found.\n", + m_characterObjectId.getValueString().c_str(), m_primaryControlledObject.getValueString().c_str())); + return; + } + + //----------------------------------------------------------------- + + if (message.isType("ShipUpdateTransformMessage")) + { + Archive::ReadIterator readIterator = static_cast(message).getByteStream().begin(); + ShipUpdateTransformMessage const shipUpdateTransformMessage(readIterator); + + for (std::vector::const_iterator i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) + { + ShipObject * const ship = (*i)->asShipObject(); + if (ship) + { + PlayerShipController * const playerShipController = safe_cast(ship->getController()); + if (playerShipController) + playerShipController->receiveTransform(shipUpdateTransformMessage); + } + } + } + + //---------------------------------------------------------------------- + + else if (message.isType("CreateProjectileMessage")) + { + Archive::ReadIterator readIterator = static_cast(message).getByteStream().begin(); + CreateProjectileMessage const createProjectileMessage(readIterator); + + // pilots can fire from non-turrets, gunners can fire their turret + ServerObject * const characterObject = getCharacterObject(); + if (characterObject) + { + ServerObject * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*characterObject)); + if (containedBy) + { + SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*containedBy); + ShipObject * const shipObject = ShipObject::getContainingShipObject(containedBy); + + if ( (shipObject != NULL) + && (slottedContainer != NULL) + && !shipObject->hasCondition(TangibleObject::C_docking)) + { + bool shotOk = false; + + int const weaponIndex = createProjectileMessage.getWeaponIndex(); + if (weaponIndex >= 0 && weaponIndex < ShipChassisSlotType::cms_numWeaponIndices) + { + Container::ContainerErrorCode err = Container::CEC_Success; + if (shipObject->isTurret(weaponIndex)) + { + if ( slottedContainer->getObjectInSlot(ShipSlotIdManager::getPobShipGunnerSlotId(weaponIndex), err) == characterObject->getNetworkId() + || slottedContainer->getObjectInSlot(ShipSlotIdManager::getShipGunnerSlotId(weaponIndex), err) == characterObject->getNetworkId()) + shotOk = true; // gunner firing his turret + } + else + { + if ( slottedContainer->getObjectInSlot(ShipSlotIdManager::getShipPilotSlotId(), err) == characterObject->getNetworkId() + || slottedContainer->getObjectInSlot(ShipSlotIdManager::getPobShipPilotSlotId(), err) == characterObject->getNetworkId()) + shotOk = true; // pilot firing non-turret + } + } + + // only gods can fire while invulnerable + if (shipObject->isInvulnerable() && !isGod()) + shotOk = false; + + if (shotOk) + { + shipObject->enqueueFireShotClient( + *this, + weaponIndex, + createProjectileMessage.getTransform_p(), + createProjectileMessage.getTargetedComponent(), + createProjectileMessage.getSyncStampLong()); + } + } + } + } + } + + //---------------------------------------------------------------------- + + else if(message.isType("CmdSceneReady")) + { + m_isReady = true; + primaryControlledObject->onClientReady(this); + } + + //---------------------------------------------------------------------- + + else if(message.isType("SetCombatSpamFilter")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + m_combatSpamFilter = static_cast(msg.getValue()); + } + + //---------------------------------------------------------------------- + + else if(message.isType("SetCombatSpamRangeFilter")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + m_combatSpamRangeSquaredFilter = sqr(msg.getValue()); + } + + //---------------------------------------------------------------------- + + else if(message.isType("SetFurnitureRotationDegree")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + m_furnitureRotationDegree = msg.getValue(); + } + + //---------------------------------------------------------------------- + + else if(message.isType("GcwRegionsReq")) + { + GenericValueTypeMessage, float> > > > const rsp("GcwRegionsRsp", Pvp::getGcwScoreCategoryRegions()); + send(rsp, true); + + GenericValueTypeMessage > > const rsp2("GcwGroupsRsp", Pvp::getGcwScoreCategoryGroups()); + send(rsp2, true); + } + + //---------------------------------------------------------------------- + + else if(message.isType("SetJediSlotInfo")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + // this comes from the client (via the LoginServer) so should not be trusted; + // we cache them here to do preliminary checks to avoid unnecessarily sending + // commands to the LoginServer (assuming the values haven't been hacked on the + // client); when we do send the commands to the LoginServer, we'll check again there + m_hasUnoccupiedJediSlot = msg.getValue().first; + m_isJediSlotCharacter = msg.getValue().second; + } + + //---------------------------------------------------------------------- + + else if(message.isType("RotateFurnitureSetQuaternion")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > > const msg(ri); + + CreatureObject * creatureOwner = safe_cast(getCharacterObject()); + if (creatureOwner && creatureOwner->isAuthoritative()) + { + ServerObject const * target = ServerWorld::findObjectByNetworkId(msg.getValue().first); + if (target && target->isAuthoritative()) + { + static uint32 const commandHash = Crc::normalizeAndCalculate("rotateFurniture"); + const Command &command = CommandTable::getCommand(commandHash); + if (!command.isNull()) + { + // for obfuscation so players won't manually send us this command + Unicode::String params = Unicode::narrowToWide(FormattedString<512>().sprintf("(^-,=+_)internal_use_only_%s_quaternion(,+-=_^) %.10f %.10f %.10f %.10f %s", creatureOwner->getNetworkId().getValueString().c_str(), msg.getValue().second.first.first, msg.getValue().second.first.second, msg.getValue().second.second.first, msg.getValue().second.second.second, msg.getValue().first.getValueString().c_str())); + creatureOwner->commandQueueEnqueue(command, target->getNetworkId(), params, 0, false, static_cast(Command::CP_Default), true); + } + } + } + } + + //---------------------------------------------------------------------- + + else if(message.isType("SetLfgInterests")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(safe_cast(getCharacterObject())); + if (playerObject) + { + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(getCharacterObjectId()); + if (iterFind != connectedCharacterLfgData.end()) + { + BitArray lfgInterests = msg.getValue(); + + MatchMakingId const & id = playerObject->getMatchMakingCharacterProfileId(); + if (id.isBitSet(MatchMakingId::B_lookingForGroup)) + LfgDataTable::setBit("lfg", lfgInterests); + else + LfgDataTable::clearBit("lfg", lfgInterests); + + if (id.isBitSet(MatchMakingId::B_helper)) + LfgDataTable::setBit("helper", lfgInterests); + else + LfgDataTable::clearBit("helper", lfgInterests); + + if (id.isBitSet(MatchMakingId::B_rolePlay)) + LfgDataTable::setBit("rp", lfgInterests); + else + LfgDataTable::clearBit("rp", lfgInterests); + + if (id.isBitSet(MatchMakingId::B_lookingForWork)) + LfgDataTable::setBit("lfw", lfgInterests); + else + LfgDataTable::clearBit("lfw", lfgInterests); + + ServerUniverse::setConnectedCharacterInterestsData(getCharacterObjectId(), lfgInterests); + } + } + } + + //---------------------------------------------------------------------- + + else if(message.isType("RequestGroundObjectPlacement")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > > const msg(ri); + + ServerObject * const target = safe_cast(NetworkIdManager::getObjectById (msg.getValue().first)); + GameScriptObject * const scriptObject = target ? target->getScriptObject() : 0; + + if (!scriptObject) + { + return; + } + + int menuType = msg.getValue().second.first.first; + Vector loc(msg.getValue().second.first.second, msg.getValue().second.second.first, msg.getValue().second.second.second); + ScriptParams params; + params.addParam (getCharacterObjectId()); + params.addParam (menuType); + params.addParam (loc.x); + params.addParam (loc.y); + params.addParam (loc.z); + + IGNORE_RETURN (scriptObject->trigAllScripts(Scripting::TRIG_GROUND_TARGET_LOC, params)); + } + //---------------------------------------------------------------------- + + else if(message.isType("ShowBackpack")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + PlayerObject * player = dynamic_cast(NetworkIdManager::getObjectById (msg.getValue().first)); + + if(player) + player->modifyShowBackpack(msg.getValue().second); + + } + //---------------------------------------------------------------------- + + else if(message.isType("ShowHelmet")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + PlayerObject * player = dynamic_cast(NetworkIdManager::getObjectById (msg.getValue().first)); + + if(player) + player->modifyShowHelmet(msg.getValue().second); + + } + //---------------------------------------------------------------------- + + else if(message.isType("SetWaypointColor")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + if ((msg.getValue().second == "blue") || (msg.getValue().second == "green") || (msg.getValue().second == "orange") || (msg.getValue().second == "yellow") || (msg.getValue().second == "purple") || (msg.getValue().second == "white")) + { + Waypoint w = Waypoint::getWaypointById(msg.getValue().first); + if (w.isValid()) + { + w.setColor(Waypoint::getColorIdByName(msg.getValue().second)); + } + } + } + + //---------------------------------------------------------------------- + + else if (message.isType (ObjectMenuSelectMessage::MESSAGE_TYPE)) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + const ObjectMenuSelectMessage m (ri); + ServerObject * const target = safe_cast(NetworkIdManager::getObjectById (m.getNetworkId())); + GameScriptObject * const scriptObject = target ? target->getScriptObject() : 0; + Object * const targetContainedBy = target ? ContainerInterface::getContainedByObject(*target) : NULL; + const int menuType = m.getSelectedItemId(); + + static int examineMenuType = RadialMenuManager::getMenuTypeByName("EXAMINE"); + static int tradeMenuType = RadialMenuManager::getMenuTypeByName("TRADE_START"); + + CreatureObject* cobj = dynamic_cast(primaryControlledObject); + if (cobj && menuType != examineMenuType && menuType != tradeMenuType) + { + CreatureController* const controller = cobj->getCreatureController(); + if (controller && controller->getSecureTrade()) + { + controller->getSecureTrade()->cancelTrade(*cobj); + DEBUG_REPORT_LOG (true, ("Client ObjectMenuSelectMessage [%d] for [%s] canceling trade.\n", menuType, cobj->getNetworkId ().getValueString ().c_str ())); + } + } + + if (!scriptObject) + { + DEBUG_REPORT_LOG (true, ("Received an object menu select message from player %s for object %s, which does not exist or lacks a GameScriptObject.", m_characterObjectId.getValueString().c_str(),m.getNetworkId().getValueString().c_str())); + return; + } + + NOT_NULL(target); + + float range = 0.0f; + if (RadialMenuManager::getRangeForMenuType(menuType, range)) + { + Container::ContainerErrorCode errorCode = Container::CEC_Success; + if (!target->isAuthoritative()) + { + GenericValueTypeMessage > const rssMessage( + "RequestSameServer", + std::make_pair( + ContainerInterface::getTopmostContainer(*primaryControlledObject)->getNetworkId(), + ContainerInterface::getTopmostContainer(*target)->getNetworkId())); + GameServer::getInstance().sendToPlanetServer(rssMessage); + errorCode = Container::CEC_TryAgain; + } + else if (menuType != examineMenuType && targetContainedBy && targetContainedBy->asServerObject() && ( targetContainedBy->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron || targetContainedBy->asServerObject()->getGameObjectType() == SharedObjectTemplate::GOT_chronicles_quest_holocron_recipe ) ) + { + // Can only examine items that are contained in a holocron. + errorCode = Container::CEC_NoPermission; + } + else if (primaryControlledObject->canManipulateObject(*target, false, false, false, range, errorCode) + || ClientNamespace::canManipulateObjectExceptionCheck(*target, menuType, errorCode)) + { + ScriptParams params; + params.addParam (getCharacterObjectId()); + params.addParam (menuType); + + if (cobj && cobj->getObjVars().hasItem("cheater")) + { + std::string menuDesc = "unknown"; + bool tmp; + IGNORE_RETURN(RadialMenuManager::getCommandForMenuType(menuType, menuDesc, tmp)); + LOG("CustomerService",("SuspectedCheaterLog: %s has used a radial menu on object %s. Menu item %d (%s).", + PlayerObject::getAccountDescription(cobj).c_str(), + m.getNetworkId().getValueString().c_str(), + menuType, + menuDesc.c_str() )); + } + + IGNORE_RETURN (scriptObject->trigAllScripts(Scripting::TRIG_OBJECT_MENU_SELECT, params)); + } + if (errorCode != Container::CEC_Success) + ContainerInterface::sendContainerMessageToClient(*primaryControlledObject, errorCode); + } + else + { + DEBUG_REPORT_LOG(true, ("Received a message type %d that had no range in data (radial_menu.tab)\n", menuType)); + } + } + + //---------------------------------------------------------------------- + + else if(message.isType("ConGenericMessage")) + { + + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ConGenericMessage c(ri); + if (isGod()) + { + LOG("CustomerService",("Avatar:%s executing command: %s", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str(), c.getMsg().c_str())); + ConsoleMgr::processString(c.getMsg(), this, c.getMsgId()); + } + else + { + //Non-god user tried to use a console command + if (m_primaryControlledObject.getObject()) + { + LOG("CustomerService", ("CheatChannel:%s tried to execute a console command but they are not a god", + PlayerObject::getAccountDescription(m_primaryControlledObject.getObject()->getNetworkId()).c_str())); + ConsoleMgr::broadcastString("Only god users can execute console commands.", this, c.getMsgId()); + } + + } + } + + //----------------------------------------------------------------- + + else if(message.isType("ObjControllerMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ObjControllerMessage o(ri); + bool appended = false; + + // check to make sure the controller message is allowed from the client + bool allowFromClient = ControllerMessageFactory::allowFromClient(o.getMessage()); + + // log as a possible hack + if (!allowFromClient) + LOG("CustomerService", ("UnauthorizedControllerMessage: Player %s sent an unauthorized controller message %d for object %s.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str(), o.getMessage(), o.getNetworkId().getValueString().c_str())); + + // do we allow the controller message to get executed? + if (allowFromClient || isGod() || !ConfigServerGame::getEnableClientControllerMessageCheck()) + { + ServerObject * target = findControlledObject(o.getNetworkId()); + if(target !=0) + { + // apply the controller message + ServerController * controller = dynamic_cast(target->getController()); + if (controller != NULL) + { + uint32 flags = o.getFlags(); + flags &= ~GameControllerMessageFlags::SOURCE_REMOTE; + flags |= GameControllerMessageFlags::SOURCE_REMOTE_CLIENT; + controller->appendMessage(o.getMessage(), o.getValue(), o.getData(), flags); + appended = true; + } + } + else if (isGod()) + { + target = ServerWorld::findObjectByNetworkId(o.getNetworkId()); + + if (target) + { + ServerController * controller = dynamic_cast(target->getController()); + if (controller != NULL) + { + uint32 flags = o.getFlags(); + flags &= ~GameControllerMessageFlags::SOURCE_REMOTE; + flags |= GameControllerMessageFlags::SOURCE_REMOTE_CLIENT; + controller->appendMessage(o.getMessage(), o.getValue(), o.getData(), flags); + appended = true; + } + } + } + } + if (!appended) + delete o.getData(); + } + + //----------------------------------------------------------------- + //Secure Trade Messages + //----------------------------------------------------------------- + else if (message.isType("AddItemMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AddItemMessage m(ri); + + + ServerObject * item = ServerWorld::findObjectByNetworkId(m.getNetworkId()); + if (!item) + return; + + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->addItem(*playerObject, *item); + } + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + } + else if (message.isType("RemoveItemMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RemoveItemMessage m(ri); + + ServerObject * item = ServerWorld::findObjectByNetworkId(m.getNetworkId()); + if (!item) + return; + + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->removeItem(*playerObject, *item); + } + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + } + else if (message.isType("GiveMoneyMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GiveMoneyMessage m(ri); + + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->giveMoney(*playerObject, m.getAmount()); + } + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + } + else if (message.isType("AcceptTransactionMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AcceptTransactionMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->acceptOffer(*playerObject); + } + + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has accepted a secure trade. (Check trade logs for more detail.", PlayerObject::getAccountDescription(playerObject).c_str())); + } + + + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + + } + else if (message.isType("UnAcceptTransactionMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + UnAcceptTransactionMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->unacceptOffer(*playerObject); + } + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + + } + else if (message.isType("VerifyTradeMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + VerifyTradeMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->verifyTrade(*playerObject); + } + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + } + else if (message.isType("DenyTradeMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + DenyTradeMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->rejectOffer(*playerObject); + } + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + + } + else if (message.isType("AbortTradeMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AbortTradeMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + DEBUG_FATAL(!playerObject, ("No controller for player!\n")); + if(playerObject) //lint !e774 + { + PlayerCreatureController* playerController = dynamic_cast(playerObject->getController()); + if (playerController && playerController->getSecureTrade()) + { + playerController->getSecureTrade()->cancelTrade(*playerObject); + } + } + else + { + GameServer::getInstance().dropClient(m_characterObjectId); + } + + } + + else if (message.isType(SuiEventNotification::MessageType)) + { + ServerUIManager::receiveMessage(message); + } + + else if (message.isType("GuildRequestMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GuildRequestMessage const m(ri); + + NetworkId const &id = m.getTargetId(); + CreatureObject * const creatureObject = dynamic_cast(NetworkIdManager::getObjectById(id)); + if (creatureObject) + { + int const guildId = creatureObject->getGuildId(); + GuildMemberInfo const * const info = GuildInterface::getGuildMemberInfo(guildId, id); + GuildResponseMessage const responseMessage(id, GuildInterface::getGuildName(guildId), info ? info->m_title : std::string()); + send(responseMessage, true); + } + } + + else if (message.isType("StomachRequestMessage")) + { + CreatureObject *creatureObject = dynamic_cast(getCharacterObject()); + + if (creatureObject != NULL) + { + GameScriptObject *gameScriptObject = creatureObject->getScriptObject(); + + if(gameScriptObject != NULL) + { + ScriptParams scriptParams; + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_STOMACH_UPDATE, scriptParams)); + } + } + } + + else if (message.isType("FactionRequestMessage")) + { + int rebel = 0; + int imperial = 0; + int criminal = 0; + + CreatureObject * playerObject = dynamic_cast(getCharacterObject()); + if (playerObject) + { + float temp; + if (playerObject->getObjVars().getItem("faction.Rebel",temp)) + { + rebel = static_cast(temp); + } + if (playerObject->getObjVars().getItem("faction.Imperial",temp)) + { + imperial = static_cast(temp); + } + if (playerObject->getObjVars().getItem("faction.Hutt",temp)) + { + criminal = static_cast(temp); + } + + std::vector factionNames; + std::vector factionValues; + std::string currentName; + float currentValue; + DynamicVariableList::NestedList factionList(playerObject->getObjVars(),"faction"); + for(DynamicVariableList::NestedList::const_iterator i = factionList.begin(); i != factionList.end(); ++i) + { + currentName = i.getName(); + bool result = i.getValue(currentValue); + if(result) + { + factionNames.push_back(currentName); + factionValues.push_back(currentValue); + } + } + + FactionResponseMessage const msg(rebel, imperial, criminal, factionNames, factionValues); + send(msg, true); + } + } + + //---------------------------------------------------------------------- + + else if (message.isType (PlayerMoneyRequest::MessageType)) + { + Archive::ReadIterator ri = (*NON_NULL (static_cast(&message))).getByteStream().begin(); + const PlayerMoneyRequest m (ri); + + ServerObject * const playerObject = getCharacterObject(); + + WARNING (!playerObject, ("Got PlayerMoneyRequest for non-existant character (account=%s, networkid=%s)", m_accountName.c_str (), m_characterObjectId.getValueString ().c_str ())); + + if (playerObject) + { + PlayerMoneyResponse resp; + resp.m_balanceCash.set (playerObject->getCashBalance ()); + resp.m_balanceBank.set (playerObject->getBankBalance ()); + send (resp, true); + } + } + + //----------------------------------------------------------------- + + else if (message.isType("AcceptAuctionMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AcceptAuctionMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + CommoditiesMarket::auctionAccept(*playerObject, m.getItemId().getValue()); + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has accepted an auction for item %s", + PlayerObject::getAccountDescription(playerObject).c_str(), + m.getItemId().getValueString().c_str())); + } + } + else + { + WARNING(true, ("AcceptAuctionMessage: the player was not found")); + } + } + + else if (message.isType("BidAuctionMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + BidAuctionMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has bid on an auction for item %s, amount %d", + PlayerObject::getAccountDescription(playerObject).c_str(), + m.getItemId().getValueString().c_str(), + m.getBid())); + } + + CommoditiesMarket::auctionBid(*playerObject, m.getItemId().getValue(), m.getBid(), m.getMaxProxyBid()); + } + else + { + WARNING(true, ("BidAuctionMessage: the player was not found")); + } + } + + else if (message.isType("CancelLiveAuctionMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + CancelLiveAuctionMessage m(ri); + + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + CommoditiesMarket::auctionCancel(*playerObject, m.getItemId().getValue()); + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has cancelled an auction for item %s", + PlayerObject::getAccountDescription(playerObject).c_str(), + m.getItemId().getValueString().c_str())); + } + + } + else + { + WARNING(true, ("CancelLiveAuctionMessage: the player was not found")); + } + } + + else if (message.isType("CreateAuctionMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + CreateAuctionMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + NetworkId itemId = m.getItemId(); + NetworkId containerId = m.getContainerId(); + CommoditiesMarket::auctionCreate(*playerObject, itemId, m.getItemLocalizedName(), containerId, m.getMinimumBid(), m.getAuctionLength(), m.getUserDescription(), m.isPremium()); + + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has created an auction for item %s on vendor %s", + PlayerObject::getAccountDescription(playerObject).c_str(), + m.getItemId().getValueString().c_str(), + containerId.getValueString().c_str())); + } + } + else + { + WARNING(true, ("CreateAuctionMessage: the player was not found")); + } + } + + else if (message.isType("CreateImmediateAuctionMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + CreateImmediateAuctionMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + NetworkId itemId = m.getItemId(); + NetworkId containerId = m.getContainerId(); + if (m.isVendorTransfer()) + { + CommoditiesMarket::transferVendorItemFromStockroom(*playerObject, itemId, m.getItemLocalizedName(), m.getPrice(), m.getAuctionLength(), m.getUserDescription()); + } + else + { + CommoditiesMarket::auctionCreateImmediate(*playerObject, itemId, m.getItemLocalizedName(), containerId, m.getPrice(), m.getAuctionLength(), m.getUserDescription(), m.isPremium()); + } + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has created an immediate auction for item %s on vendor %s", + PlayerObject::getAccountDescription(playerObject).c_str(), + m.getItemId().getValueString().c_str(), + containerId.getValueString().c_str())); + } + } + else + { + WARNING(true, ("CreateImmediateAuctionMessage: the player was not found")); + } + } + + else if (message.isType("RelistItemsFromStockMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::vector >, int> > const m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + std::vector const & itemIds = m.getValue().first.first; + std::vector const & itemLocalizedNames = m.getValue().first.second; + int const timer = m.getValue().second; + NetworkId itemId; + std::vector::const_iterator iterId = itemIds.begin(); + std::vector::const_iterator iterName = itemLocalizedNames.begin(); + for (; ((iterId != itemIds.end()) && (iterName != itemLocalizedNames.end())); ++iterId, ++iterName) + { + itemId = *iterId; + CommoditiesMarket::transferVendorItemFromStockroom(*playerObject, itemId, *iterName, -1, timer, Unicode::String()); + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has created an immediate auction (relist) for item %s", + PlayerObject::getAccountDescription(playerObject).c_str(), + itemId.getValueString().c_str())); + } + } + } + else + { + WARNING(true, ("RelistItemsFromStockMessage: the player was not found")); + } + } + + else if (message.isType("RetrieveAuctionItemMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + RetrieveAuctionItemMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + NetworkId itemId = m.getItemId(); + ServerObject *auctionContainer = dynamic_cast(NetworkIdManager::getObjectById(m.getContainerId())); + if (auctionContainer) + { + if (playerObject->isAuthoritative() && auctionContainer->isAuthoritative()) + { + CommoditiesMarket::auctionRetrieve(*playerObject, m.getItemId().getValue(), m.getItemId(), *auctionContainer); + if (playerObject->getObjVars().hasItem("cheater")) + { + LOG("CustomerService", ("SuspectedCheaterChannel: %s has retrieved an auction for item %s on vendor %s", + PlayerObject::getAccountDescription(playerObject).c_str(), + m.getItemId().getValueString().c_str(), + auctionContainer->getNetworkId().getValueString().c_str())); + } + } + } + else + { + LOG("CustomerService", ("Auction:Player %s attempted to retrieve an auction for container %Ld but failed.", PlayerObject::getAccountDescription(playerObject).c_str(), m.getContainerId().getValue())); + + RetrieveAuctionItemResponseMessage const msg(itemId, ar_INVALID_CONTAINER_ID);; + Client *client = playerObject->getClient(); + if (client) + { + client->send(msg, true); + } + } + } + else + { + WARNING(true, ("RetrieveAuctionMessage: the player was not found")); + } + } + else if (message.isType("AuctionQueryHeadersMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + AuctionQueryHeadersMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + CommoditiesMarket::auctionQueryHeaders(*playerObject, + m.getRequestId(), + m.getSearchType(), + m.getItemType(), + m.getItemTypeExactMatch(), + m.getItemTemplateId(), + m.getTextFilterAll(), + m.getTextFilterAny(), + m.getPriceFilterMin(), + m.getPriceFilterMax(), + m.getPriceFilterIncludesFee(), + m.getAdvancedSearch(), + m.getAdvancedSearchMatchAllAny(), + m.getContainer(), + m.getLocationSearchType(), + m.getMyVendorsOnly(), + m.getQueryOffset()); + } + } + else if (message.isType("GetAuctionDetails")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GetAuctionDetails m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + CommoditiesMarket::getAuctionDetails(*playerObject, + m.getItem()); + } + + } + else if (message.isType("IsVendorOwnerMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + IsVendorOwnerMessage m(ri); + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + CommoditiesMarket::isVendorOwner(*playerObject, m.getContainerId()); + } + + } + else if (message.isType("CommoditiesItemTypeListRequest")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const m(ri); + + static char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s.%d", GameServer::getInstance().getClusterName().c_str(), CommoditiesMarket::getItemTypeMapVersionNumber()); + buffer[sizeof(buffer)-1] = '\0'; + + if (m.getValue() != std::string(buffer)) + { + GenericValueTypeMessage > > > > const rsp("CommoditiesItemTypeListResponse", std::make_pair(std::string(buffer), CommoditiesMarket::getItemTypeMap())); + send(rsp, true); + } + } + else if (message.isType("CommoditiesResourceTypeListRequest")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const m(ri); + + static char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s.%d", GameServer::getInstance().getClusterName().c_str(), CommoditiesMarket::getResourceTypeMapVersionNumber()); + buffer[sizeof(buffer)-1] = '\0'; + + if (m.getValue() != std::string(buffer)) + { + GenericValueTypeMessage > > > const rsp("CommoditiesResourceTypeListResponse", std::make_pair(std::string(buffer), CommoditiesMarket::getResourceTypeMap())); + send(rsp, true); + } + } + else if (message.isType("CollectionServerFirstListRequest")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const m(ri); + + PlanetObject const * const planetObject = ServerUniverse::getInstance().getTatooinePlanet(); + if (planetObject) + { + static char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s.%d", GameServer::getInstance().getClusterName().c_str(), planetObject->getCollectionServerFirstUpdateNumber()); + buffer[sizeof(buffer)-1] = '\0'; + + if (m.getValue() != std::string(buffer)) + { + GenericValueTypeMessage, std::pair > > > > const rsp("CollectionServerFirstListResponse", std::make_pair(std::string(buffer), planetObject->getCollectionServerFirst())); + send(rsp, true); + } + } + } + + //----------------------------------------------------------------- + + else if (message.isType (PlanetTravelPointListRequest::cms_name)) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + const PlanetTravelPointListRequest requestMessage (readIterator); + + const std::string & planetName = requestMessage.getPlanetName (); + const PlanetObject* const planetObject = ServerUniverse::getInstance ().getPlanetByName (requestMessage.getPlanetName ()); + if (planetObject) + { + std::vector names; + planetObject->getTravelPointNameList (names); + + std::vector points; + planetObject->getTravelPointPointList (points); + + std::vector costs; + planetObject->getTravelPointCostList (costs); + + std::vector interplanetary; + planetObject->getTravelPointInterplanetaryList (interplanetary); + + PlanetTravelPointListResponse const rsp(planetName, names, points, costs, interplanetary, requestMessage.getSequenceId ()); + send(rsp, true); + } + else + DEBUG_WARNING (true, ("GameServer::receiveMessage: received request for travel point names from client [%s] for planet %s which does not exist", requestMessage.getPlanetName ().c_str (), requestMessage.getNetworkId ().getValueString ().c_str ())); + } + + //----------------------------------------------------------------- + + else if (message.isType (NewbieTutorialResponse::cms_name)) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + const NewbieTutorialResponse responseMessage (readIterator); + + static const std::string clientReadyString("clientReady"); + + if (responseMessage.getResponse() == clientReadyString) + { + for (std::vector::iterator i = m_controlledObjects.begin(); i != m_controlledObjects.end(); ++i) + { + ServerObject * const so = *i; + if (so) + so->onLoadingScreenComplete(); + } + } + + ScriptParams scriptParameters; + scriptParameters.addParam (responseMessage.getResponse ().c_str ()); + + if (primaryControlledObject->getScriptObject ()->trigAllScripts (Scripting::TRIG_NEWBIE_TUTORIAL_RESPONSE, scriptParameters) != SCRIPT_CONTINUE) + DEBUG_REPORT_LOG (true, ("OnNewbieTutorialResponse: did not return SCRIPT_CONTINUE\n")); + } + + //----------------------------------------------------------------- + + else if (message.isType("AddMapLocationMessage")) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + const AddMapLocationMessage msg (readIterator); + UNREF (msg); + + /* + MapLocation mapLocation(msg.getLocationId(), msg.getLocationName(), + Vector2d(msg.getLocationX(), msg.getLocationY()), + msg.getCategory(), msg.getSubCategory()); + + PlanetObject *planetObject = ServerUniverse::getInstance ().getPlanetByName (msg.getPlanetName ()); + if (planetObject) + { + planetObject->addMapLocation(mapLocation); + } + AddMapLocationResponseMessage responseMsg(msg.getLocationId()); + send(responseMsg, true); + */ + } + + //----------------------------------------------------------------- + + else if (message.isType(GetMapLocationsMessage::MessageType)) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + const GetMapLocationsMessage msg (readIterator); + + PlanetMapManagerServer::handleClientRequest (*this, msg); + } + + else if (message.isType("GetSpecificMapLocationsMessage")) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + const GenericValueTypeMessage > > msg (readIterator); + + PlanetMapManagerServer::handleClientRequestGetSpecificMapLocationsMessage (*this, msg.getValue()); + } + + else if (message.isType("ConsentResponseMessage")) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + ConsentResponseMessage const msg(readIterator); + ConsentManager::getInstance().handleResponse(msg); + } + + else if (message.isType("RequestGalaxyLoopTimes")) + { + // obfuscate the information so it's not obvious on the client that this is the server loop time + unsigned long loopTime = static_cast(Clock::frameTime() * 3193000.0f); // loop time (in ms) * 3193 + GalaxyLoopTimesResponse const msg(loopTime, loopTime); + send(msg, true); + } + else if (message.isType("LagRequest")) + { + GameNetworkMessage const msg("GameServerLagResponse"); + send(msg, true); + } + else if (message.isType("LagReport")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const report(ri); + m_connectionServerLag = report.getValue().first; + m_gameServerLag = report.getValue().second; + } + else if (message.isType("ChatInviteGroupToRoom")) + { + if (primaryControlledObject) + { + CreatureObject * const playerCreature = primaryControlledObject->asCreatureObject(); + if (playerCreature) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ChatInviteGroupToRoom const chat(ri); + + // We will need to notify the user if the group leader can not be found + bool foundGroupLeader = false; + + // Get the name of the group leader being invited + ChatAvatarId const & groupLeaderChatAvatarId = chat.getAvatarId(); + + // Convert the name to a network ID + NetworkId const groupLeaderNetworkId = NameManager::getInstance().getPlayerId(NameManager::normalizeName(Unicode::wideToNarrow(groupLeaderChatAvatarId.getName()))); + + // Try to get a group object corresponding to the player network ID + ServerObject const * const groupServerObject = ServerWorld::findObjectByNetworkId(GroupObject::getGroupIdForLeader(groupLeaderNetworkId)); + if (groupServerObject && groupServerObject->asGroupObject()) + { + // We now know the player is a group leader of a group + GroupObject const * const groupLeaderGroupObject = groupServerObject->asGroupObject(); + + // Make sure we have the correct player since we only searched by name + // (i.e. we may have been looking for a player with the same name but on a different cluster) + ChatAvatarId const playerChatAvatarId = Chat::constructChatAvatarId(NameManager::normalizeName(groupLeaderGroupObject->getGroupLeaderName())); + if (playerChatAvatarId == groupLeaderChatAvatarId) + { + // We found the group leader + foundGroupLeader = true; + + // We need to get the network IDs for all the group members + std::vector groupNetworkIds; + + GroupObject::GroupMemberVector const & groupMemberVector = groupLeaderGroupObject->getGroupMembers(); + for (unsigned i = 0; i < groupMemberVector.size(); ++i) + { + GroupObject::GroupMember const & groupMember = groupMemberVector[i]; + + groupNetworkIds.push_back(groupMember.first); + } + + // Pass the invitation to all the group members + Chat::inviteGroupMembers(m_primaryControlledObject, chat.getAvatarId(), chat.getRoomName(), groupNetworkIds); + } + } + + // If we couldn't find the group leader, let the player know + if (!foundGroupLeader) + { + ChatAvatarId const inviteeId = Chat::constructChatAvatarId(*playerCreature); + ChatOnInviteGroupToRoom msg(ERR_DESTAVATARDOESNTEXIST, chat.getRoomName(), inviteeId, chat.getAvatarId()); + send(msg, false); + } + } + } + } + else if (message.isType("ChatPersistentMessageToServer")) + { + if (primaryControlledObject) //lint !e774 + { + CreatureObject * const playerCreature = primaryControlledObject->asCreatureObject(); + if (playerCreature) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ChatPersistentMessageToServer const chat(ri); + std::string const &toName = chat.getToCharacterName().name; + if (!_stricmp(toName.c_str(), "guild")) + { + std::pair > const count = GuildInterface::mailToGuild(*playerCreature, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); + if (count.first < 0) + { + Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide("You do not have sufficient permission to send mail to guild members."), Unicode::emptyString); + } + else + { + Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("Your mail was sent to %d members of guild %s (%s).", count.first, count.second.first.c_str(), count.second.second.c_str())), Unicode::emptyString); + } + } + else if (!_strnicmp(toName.c_str(), "guild ", 6)) + { + // see if it's a valid guild rank + GuildRankDataTable::GuildRank const * guildRank = GuildRankDataTable::getRankForDisplayRankName(toName); + if (guildRank) + { + std::pair > const count = GuildInterface::mailToGuildRank(*playerCreature, guildRank->slotId, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); + if (count.first < 0) + { + Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide("You do not have sufficient permission to send mail to guild members."), Unicode::emptyString); + } + else + { + Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("Your mail was sent to %d members in rank %s of guild %s (%s).", count.first, guildRank->displayName.c_str(), count.second.first.c_str(), count.second.second.c_str())), Unicode::emptyString); + } + } + else + { + Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("\"%s\" is not a valid name.", toName.c_str())), Unicode::emptyString); + } + } + else if (!_stricmp(toName.c_str(), "citizens")) + { + std::pair const count = CityInterface::mailToCitizens(*playerCreature, chat.getSubject(), chat.getMessage(), chat.getOutOfBand()); + if (count.first < 0) + { + Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide("You do not have sufficient permission to send mail to citizens."), Unicode::emptyString); + } + else + { + Chat::sendSystemMessage(*playerCreature, Unicode::narrowToWide(FormattedString<512>().sprintf("Your mail was sent to %d citizens of city %s.", count.first, count.second.c_str())), Unicode::emptyString); + } + } + + if (playerCreature->getObjVars().hasItem("cheater")) + { + LOGU("CustomerService", ("SuspectedCheaterChannel: %s is broadcasting a %s message that says '%s'", + PlayerObject::getAccountDescription(playerCreature).c_str(), + toName.c_str()), + chat.getMessage()); + } + } + } + } + else if (message.isType("ExpertiseRequestMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + ExpertiseRequestMessage const m(ri); + + std::vector const & addExpertisesNamesList = m.getAddExpertisesList(); + bool clearAllExpertisesFirst = m.getClearAllExpertisesFirst(); + std::string addList; + std::vector::const_iterator i; + for(i = addExpertisesNamesList.begin(); i != addExpertisesNamesList.end(); ++i) + { + addList += " "; + addList += *i; + } + CreatureObject * playerObject = safe_cast(getCharacterObject()); + if (playerObject) + { + LOG("CustomerService", ("ExpertiseRequestMessage: %s has requested to add expertises [%s] %s", + PlayerObject::getAccountDescription(playerObject).c_str(), + addList.c_str(), clearAllExpertisesFirst ? "(clearing first)" : "")); + playerObject->processExpertiseRequest(addExpertisesNamesList, clearAllExpertisesFirst); + } + } + else if (message.isType("UpdateSessionPlayTimeInfo")) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + GenericValueTypeMessage > > const msgPlayTimeInfo(readIterator); + + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(safe_cast(getCharacterObject())); + if (playerObject != NULL) + { + playerObject->setSessionPlayTimeInfo(msgPlayTimeInfo.getValue().first, msgPlayTimeInfo.getValue().second.first, msgPlayTimeInfo.getValue().second.second); + } + } + } + catch (Archive::ReadException &) + { + if (getCharacterObject()) + { + WARNING_STRICT_FATAL(true, ("A message was received from a client that could not be unpacked. Either the data was corrupt (intentionally or accidentally) or the client and server notion of the message are out of sync. The client will be disconnected. Character object is : %s :%s, IP=%s, accountname=%s", getCharacterObject()->getObjectTemplateName(), getCharacterObject()->getNetworkId().getValueString().c_str(), getIpAddress().c_str(), getAccountName().c_str())); + } + else + { + WARNING_STRICT_FATAL(true, ("A message was received from a client that could not be unpacked. Either the data was corrupt (intentionally or accidentally) or the client and server notion of the message are out of sync. The client will be disconnected. IP=%s, accountname=%s", getIpAddress().c_str(), getAccountName().c_str())); + } + if (getConnection()) + { + KickPlayer const kickMessage(m_characterObjectId, "Invalid Network Stream"); + GameServer::getInstance().sendToConnectionServers(kickMessage); + GameServer::getInstance().dropClient(m_characterObjectId); + } + } + + //----------------------------------------------------------------- +} + +//----------------------------------------------------------------------- + +void Client::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) +{ + UNREF(source); + + if ( message.isType("ConnectionServerConnectionClosed") + || message.isType("ConnectionServerConnectionDestroyed")) + { + //Connection server crashed + DEBUG_REPORT_LOG(true, ("Connection Server crashed. Client dropping.\n")); + m_connection = 0; + GameServer::getInstance().dropClient(m_characterObjectId); + } + else + { + if(&source != m_connection) + { + const MessageDispatch::Message * m = dynamic_cast *>(&message); + if(m) + { + ConGenericMessage const c(m->getValue(), 0); + send(c, true); + } + } + } +} + +//----------------------------------------------------------------------- + +void Client::removeControlledObject(ServerObject &object) +{ + if (m_primaryControlledObject == object.getNetworkId()) + { + ObserveTracker::onClientDestroyed(*this); + if (ServerWorld::isSpaceScene()) + SpaceVisibilityManager::removeClient(*this); + } + + std::vector::iterator iter = std::find(m_controlledObjects.begin(), m_controlledObjects.end(), &object); + if (iter != m_controlledObjects.end()) + IGNORE_RETURN(m_controlledObjects.erase(iter)); + else + DEBUG_WARNING(true, ("Client removing object [%s] that is not controlled", object.getNetworkId().getValueString().c_str())); + + object.clearClient(); +} + +//----------------------------------------------------------------------- + +void Client::selfDestruct() +{ + selfDestruct(false); +} +//----------------------------------------------------------------------- + +void Client::selfDestruct(const bool immediate) +{ + // @todo : this will eventually need to attach ai controllers to + // link dead objects. + std::vector controlledObjects = m_controlledObjects; + + // the controlled object list on the client is affected by clearClient, so work on a copy of the vector + for (std::vector::iterator i = controlledObjects.begin(); i != controlledObjects.end(); ++i) + { + if (*i) + { + if ((*i)->isAuthoritative()) + { + (*i)->handleDisconnect(immediate); + } + (*i)->clearClient(); + } + } + m_controlledObjects.clear(); + delete this; +} + +//----------------------------------------------------------------------- + +void Client::send(GameNetworkMessage const &outgoingMessage, bool reliable) const +{ + if (m_connection) + { + static std::vector v; + v.clear(); + v.push_back(m_characterObjectId); + GameClientMessage const msg(v, reliable, outgoingMessage); + + + uint32 now = Clock::timeMs(); + if ( sm_outgoingBytesMap_Worktime == 0 ) + sm_outgoingBytesMap_Worktime = now; + else if ( (now - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds + { + sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; + std::map< std::string, uint32 >::iterator iter; + for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) + { + iter->second = 0; + } + sm_outgoingBytesMap_Worktime = now; + } + sm_outgoingBytesMap_Working[ outgoingMessage.getCmdName() ] += msg.getByteStream().getSize(); + + + m_connection->send(msg, true); + } + else + { + DEBUG_REPORT_LOG(true, ("Tried to send message to a client without a connection server connection.\n")); + } +} + + +//----------------------------------------------------------------------- + +std::map< std::string, uint32 >& Client::getPacketBytesPerMinStats() +{ + uint32 now = Clock::timeMs(); + if ( sm_outgoingBytesMap_Worktime == 0 ) + sm_outgoingBytesMap_Worktime = now; + else if ( (now - sm_outgoingBytesMap_Worktime) > 60000 ) // 60 seconds + { + sm_outgoingBytesMap_Stats = sm_outgoingBytesMap_Working; + std::map< std::string, uint32 >::iterator iter; + for ( iter = sm_outgoingBytesMap_Working.begin(); iter != sm_outgoingBytesMap_Working.end(); ++iter ) + { + iter->second = 0; + } + sm_outgoingBytesMap_Worktime = now; + } + + return sm_outgoingBytesMap_Stats; +} + + + +//----------------------------------------------------------------------- + +void Client::sendToConnectionServer(GameNetworkMessage const &msg) +{ + if (m_connection) + m_connection->send(msg, true); + else + { + DEBUG_REPORT_LOG(true, ("Tried to send message to a client without a connection server connection.\n")); + } +} + +//----------------------------------------------------------------------- + +uint16 Client::getServerSyncStampShort() const +{ + NOT_NULL(m_connection); + return m_connection->getSyncStampShort(); +} + +//----------------------------------------------------------------------- + +uint32 Client::getServerSyncStampLong() const +{ + NOT_NULL(m_connection); + return m_connection->getSyncStampLong(); +} + +//----------------------------------------------------------------------- + +float Client::computeDeltaTimeInSeconds(uint32 const syncStampLong) const +{ + uint32 const deltaTimeMilliseconds = syncStampLong - getServerSyncStampLong(); + + float deltaTime = 0.f; + if (deltaTimeMilliseconds > 0x7fffffff) + deltaTime = static_cast(static_cast(0xffffffff - deltaTimeMilliseconds)) / 1000.0f; + else + deltaTime = static_cast(static_cast(deltaTimeMilliseconds)) / 1000.0f; + + return deltaTime; +} + +//----------------------------------------------------------------------- + +bool Client::setGodMode(bool value) +{ + bool wasInGodMode = m_godMode; + m_godMode = value; + + if (value && !m_godValidated) + { + LOG("CustomerService", ("Avatar:%s denied god mode because it wasn't validated.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str() )); + m_godMode = false; + } + + CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); + if (!primaryControlledObject) + { + if (value && !wasInGodMode) + LOG("CustomerService", ("Avatar:%s denied god mode because it has no associated character.", m_accountName.c_str() )); + m_godMode = false; + return false; + } + + if (m_godMode) + IGNORE_RETURN(primaryControlledObject->grantCommand(AdminAccountManager::getAdminCommandName(), false)); + else + primaryControlledObject->revokeCommand(AdminAccountManager::getAdminCommandName(), false, true); + + if (m_godMode != wasInGodMode) + { + if (m_godMode) + LOG("CustomerService", ("Avatar:%s granted god mode %s level %d.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str(), AdminAccountManager::getAdminCommandName(), m_godLevel )); + else + LOG("CustomerService", ("Avatar:%s dropped god mode.", PlayerObject::getAccountDescription(getCharacterObjectId()).c_str())); + + // cell permissions may change for us for all cells, so observe all buildings in range for the change + CellPermissions::ViewerChangeObserver o(primaryControlledObject); + + ObserveTracker::onGodModeChanged(*this); + } + return (value == m_godMode); // return true if the value was set to what was requested, false otherwise +} + +//----------------------------------------------------------------------- + +void Client::addObserving(ServerObject* o) +{ + if (o) + { + IGNORE_RETURN(m_observing.insert(o)); + TangibleObject *to = o->asTangibleObject(); + if (to && PvpUpdateObserver::satisfyPvpSyncCondition(to->isNonPvpObject(), to->hasCondition(ServerTangibleObjectTemplate::C_invulnerable), (o->asCreatureObject() != NULL), to->getPvpFaction())) + addObservingPvpSync(to); + } +} + +//----------------------------------------------------------------------- + +void Client::addObservingPvpSync(TangibleObject* to) +{ + if (to) + { + IGNORE_RETURN(m_observingPvpSync.insert(to)); + PvpUpdateObserver::startObservingPvpSyncNotification(this, *to); + } +} + +//----------------------------------------------------------------------- + +void Client::removeObservingPvpSync(ServerObject* o) +{ + if (o && m_observingPvpSync.erase(reinterpret_cast(o))) + PvpUpdateObserver::stopObservingPvpSyncNotification(this, o->getNetworkId()); +} + +//----------------------------------------------------------------------- + +void Client::resetIdleTimeAfterCharacterTransfer() +{ + // set m_lastNonIdleTime such that idledTooLong() will be true in ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec() + unsigned long const currentGameTime = ServerClock::getInstance().getGameTimeSeconds(); + + if ((currentGameTime + ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec()) > ConfigServerGame::getIdleLogoutTimeSec()) + { + m_lastNonIdleTime = currentGameTime + ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec() - ConfigServerGame::getIdleLogoutTimeSec(); + + if (m_lastNonIdleTime > currentGameTime) + m_lastNonIdleTime = currentGameTime; + } + else + { + m_lastNonIdleTime = 0; + } +} + +//----------------------------------------------------------------------- + +void Client::resetIdleTime() +{ + m_lastNonIdleTime = ServerClock::getInstance().getGameTimeSeconds(); +} + +//----------------------------------------------------------------------- + +bool Client::idledTooLong() const +{ + return ServerClock::getInstance().getGameTimeSeconds()-m_lastNonIdleTime > ConfigServerGame::getIdleLogoutTimeSec(); +} + +//----------------------------------------------------------------------- + +const std::string & Client::getAccountName() const +{ + return m_accountName; +} + +//----------------------------------------------------------------------- + +const std::string & Client::getIpAddress() const +{ + return m_ipAddress; +} + +//----------------------------------------------------------------------- + +void Client::handleIdleDisconnect() const +{ + DEBUG_REPORT_LOG(true, ("Disconnecting %s for being idle too long.\n", m_characterObjectId.getValueString().c_str())); + KickPlayer const kickMessage(m_characterObjectId, "Idle Connection"); + GameServer::getInstance().sendToConnectionServers(kickMessage); + GameServer::getInstance().dropClient(m_characterObjectId); +} + +//----------------------------------------------------------------------- + +const unsigned int Client::getStationId() const +{ + return m_stationId; +} + +//----------------------------------------------------------------------- + +int Client::getConnectionServerLag() const +{ + return m_connectionServerLag; +} + +//----------------------------------------------------------------------- + +int Client::getGameServerLag() const +{ + return m_gameServerLag; +} + +//----------------------------------------------------------------------- + +void Client::addSynchronizedUi (ServerSynchronizedUi *syncUI) +{ + m_syncUIs.push_back(Watcher(syncUI)); +} + +//----------------------------------------------------------------------- + +void Client::removeSynchronizedUi(ServerSynchronizedUi const * const syncUI) +{ + for (std::vector >::iterator i = m_syncUIs.begin(); i != m_syncUIs.end(); ++i) + { + if (i->getPointer() == syncUI) + { + IGNORE_RETURN(m_syncUIs.erase(i)); + return; + } + } +} + +// ---------------------------------------------------------------------- + +void Client::openContainer(ServerObject &obj, int sequence, std::string const &slotDesc) +{ + if (ObserveTracker::onClientOpenedContainer(*this, obj, sequence, slotDesc)) + { + ScriptParams params; + params.addParam(getCharacterObjectId()); + IGNORE_RETURN(obj.getScriptObject()->trigAllScripts(Scripting::TRIG_OPENED_CONTAINER, params)); + } +} + +// ---------------------------------------------------------------------- + +void Client::closeContainer(ServerObject &obj) +{ + if (ObserveTracker::onClientClosedContainer(*this, obj)) + { + ScriptParams params; + params.addParam(getCharacterObjectId()); + IGNORE_RETURN(obj.getScriptObject()->trigAllScripts(Scripting::TRIG_CLOSED_CONTAINER, params)); + } +} + +//----------------------------------------------------------------------- + +void Client::observeContainer(ServerObject &obj, int sequence, std::string const &slotDesc) +{ + ObserveTracker::onClientOpenedContainer(*this, obj, sequence, slotDesc, false); +} + +//----------------------------------------------------------------------- + +bool Client::isFreeTrialAccount() const +{ + //Test code + + if (m_primaryControlledObject.getObject()) + { + if (safe_cast(m_primaryControlledObject.getObject())->getObjVars().hasItem("freeTrialAccount")) + return true; + } + + //End test code + + int const allFreeTrials = ClientSubscriptionFeature::FreeTrial | ClientSubscriptionFeature::FreeTrial2; + + return ((m_subscriptionFeatures & allFreeTrials) != 0) && + ((m_subscriptionFeatures & ClientSubscriptionFeature::Base) == 0); +} + +//----------------------------------------------------------------------- + +bool Client::isSecure() const +{ + return m_isSecure; +} + +// ---------------------------------------------------------------------- + +std::vector > const & Client::getConsumedRewardEvents() const +{ + return m_consumedRewardEvents; +} + +// ---------------------------------------------------------------------- + +std::vector > const & Client::getClaimedRewardItems() const +{ + return m_claimedRewardItems; +} + +// ---------------------------------------------------------------------- + +void Client::launchWebBrowser(std::string const & url) const +{ + GenericValueTypeMessage message("LaunchBrowserMessage", url); + send(message,true); +} + +// ---------------------------------------------------------------------- + +bool Client::isUsingAdminLogin() const +{ + return m_usingAdminLogin; +} + +// ---------------------------------------------------------------------- + +bool Client::shouldReceiveCombatSpam(NetworkId const & attacker, Vector const & attackerPosition_w, NetworkId const & defender, Vector const & defenderPosition_w) const +{ + PROFILER_AUTO_BLOCK_DEFINE("Client::shouldReceiveCombatSpam"); + + // none means no combat spam, period!!! + if (m_combatSpamFilter == CombatDataTable::CSFT_None) + return false; + + // some combat spam messages don't have an attacker or defender, always allow those + if (!attacker.isValid() && !defender.isValid()) + return true; + + // always receive combat spam if I'm the attacker or the defender + if (m_characterObjectId.isValid() && ((m_characterObjectId == attacker) || (m_characterObjectId == defender))) + return true; + + bool passFilter = false; + if (m_combatSpamFilter == CombatDataTable::CSFT_All) + { + passFilter = true; + } + else if (m_combatSpamFilter == CombatDataTable::CSFT_Group) + { + CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); + if (primaryControlledObject) + { + GroupObject const * group = primaryControlledObject->getGroup(); + if (group && (group->isGroupMember(attacker) || group->isGroupMember(defender))) + { + passFilter = true; + } + } + } + + if (!passFilter) + return false; + + // range check + CreatureObject *primaryControlledObject = safe_cast(m_primaryControlledObject.getObject()); + if (primaryControlledObject) + { + Vector const playerPosition = primaryControlledObject->getPosition_w(); + + if ((attacker.isValid() && (playerPosition.magnitudeBetweenSquared(attackerPosition_w) <= m_combatSpamRangeSquaredFilter)) || (defender.isValid() && (playerPosition.magnitudeBetweenSquared(defenderPosition_w) <= m_combatSpamRangeSquaredFilter))) + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +bool Client::getSendToStarport() const +{ + return m_sendToStarport; +} + + +// ---------------------------------------------------------------------- + +int Client::getBuddyPoints() const +{ + return m_buddyPoints; +} + +// ====================================================================== + diff --git a/src/engine/server/library/serverGame/src/shared/core/ConfigServerGame.cpp b/src/engine/server/library/serverGame/src/shared/core/ConfigServerGame.cpp index f06f98ac3..cc5f64d90 100644 --- a/src/engine/server/library/serverGame/src/shared/core/ConfigServerGame.cpp +++ b/src/engine/server/library/serverGame/src/shared/core/ConfigServerGame.cpp @@ -1,580 +1,580 @@ -// -// ConfigServerGame.cpp -// asommers 9-11-2000 -// -// copyright 2000, verant interactive -// -#include "serverGame/FirstServerGame.h" -#include "serverGame/ConfigServerGame.h" -#include "serverUtility/ConfigServerUtility.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/NetworkId.h" -#include "sharedMath/Vector.h" - -#include - -//------------------------------------------------------------------- - -ConfigServerGame::Data* ConfigServerGame::data; -Vector ConfigServerGame::startingPosition; -std::map ConfigServerGame::m_components; - -//------------------------------------------------------------------- - -static ConfigServerGame::Data staticData; - -//------------------------------------------------------------------- - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("GameServer", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("GameServer", #a, b)) -#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("GameServer", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("GameServer", #a, b)) -#define KEY_NETWORKID(a,b) (data->a = NetworkId(std::string(ConfigFile::getKeyString("GameServer", #a, b)))) - -//------------------------------------------------------------------- - -void ConfigServerGame::install(void) -{ - ConfigServerUtility::install(); - data = &staticData; - - KEY_BOOL (allowDefaultTemplateParams, true); - KEY_BOOL (skipTutorial, false); - KEY_STRING (groundScene, 0); - KEY_STRING (spaceScene, 0); - KEY_INT (port, 0); - KEY_STRING (sceneID, "default"); - KEY_INT (preloadNumber, 0); - KEY_FLOAT (startX, 0.0f); - KEY_FLOAT (startY, 0.0f); - KEY_FLOAT (startZ, 0.0f); - startingPosition = Vector(data->startX,data->startY,data->startZ); - KEY_INT (taskManagerPort, 60001); - KEY_STRING (centralServerAddress, "localhost"); - KEY_INT (centralServerPort, 44451); - KEY_STRING (javaVMName, ""); - KEY_STRING (scriptPath, "../../data/sku.0/sys.server/compiled/game"); -#if defined(WIN32) - KEY_STRING (javaLibPath, "jvm.dll"); -#elif defined(linux) - // either the simple library .so name or the full path to the jvm library - KEY_STRING (javaLibPath, "libjvm.so"); -#else -#error unsupported platform -#endif - KEY_STRING (javaDebugPort, "8000"); - KEY_BOOL (useRemoteDebugJava, false); - KEY_BOOL (profileScripts, false); - KEY_BOOL (crashOnScriptError, false); - KEY_BOOL (compileScripts, false); - KEY_BOOL (trapScriptCrashes, true); - KEY_INT (scriptWatcherWarnTime, 5000); - KEY_INT (scriptWatcherInterruptTime, 5000); - KEY_INT (scriptStackErrorLimit, 35); - KEY_INT (scriptStackErrorLevel, 0); - KEY_BOOL (disableObjvarNullCheck, false); - KEY_INT (maxGameServerToSendUniverseData, 1000000); - KEY_INT (timeoutToAckUniverseDataReceived, 0); - KEY_BOOL (disableCombat, false); - KEY_STRING (combatConfigFile, "combat.cfg"); - KEY_FLOAT (combatDamageDelaySeconds, 0.0); - KEY_INT (triggerVolumeSystem, 0); - KEY_INT (defaultAutoExpireTargetDuration, 6); - KEY_FLOAT (interiorTargetDurationFactor, 1.0); - KEY_INT (minPoolValue, -100); - KEY_INT (minFaucetValue, 1); - KEY_INT (minDrainValue, 1); - KEY_INT (minEffectiveFaucetValue, 150); - KEY_FLOAT (defaultHealthRegen, 40.0f); - KEY_FLOAT (defaultActionRegen, 20.0f); - KEY_FLOAT (defaultMindRegen, 10.0f); - KEY_FLOAT (regenThreshold, 1.0f); - KEY_FLOAT (minForcePowerRegenRate, 1.0f); - KEY_BOOL (enableAttribModWarnings, true); - KEY_BOOL (checkAttribLimits, false); - KEY_INT (maxItemAttribBonus, 50); - KEY_INT (maxTotalAttribBonus, 500); - KEY_BOOL (enableNewJedi, false); - KEY_STRING (jediManagerTemplate, "object/jedi_manager/jedi_manager.iff"); - KEY_INT (maxJediBounties, 5); - KEY_INT (startForcePower, 10); - KEY_BOOL (logJediConcludes, false); - KEY_BOOL (forceJediConcludes, false); - KEY_INT (jediUpdateLocationTimeSeconds, 60 * 5); - KEY_STRING (planetObjectTemplate, "object/planet/planet.iff"); - KEY_BOOL (javaConsoleDebugMessages, false); - KEY_BOOL (useVerboseJava, false); - KEY_BOOL (logJavaGc, false); - KEY_INT (javaLocalRefLimit, 16); - KEY_STRING (reservedNameFile, "datatables/name/reserved.iff"); - KEY_INT (reservedObjectIds, 10000); - KEY_INT (minObjectIds, data->reservedObjectIds/2); // default is 1/2 of whatever is specifed for reservedObjectIds, so that the user can specify reservedObjectIds but doesn't have to specify minObjectIds - KEY_STRING (playerObjectTemplate, "object/player/player.iff"); - KEY_INT (clientOutOfRangeObjectCacheTimeMs, 20000); - KEY_INT (playerInterestRange, 300); - KEY_INT (pvpUpdateTimeMs, 10000); - KEY_INT (pvpTempFlagExpireTimeMs, 5*60*1000/2); // 2.5 minutes - KEY_INT (pvpGuildWarCoolDownPeriodTimeMs, 1*60*1000); // 1 minute - KEY_INT (pvpGuildWarExemptionExclusiveDelaySeconds, 5*60); // 5 minutes - KEY_INT (pvpBattlefieldEnemyFlagExpireTimeMs, 5*60*1000/2); // 2.5 minutes - KEY_STRING (pvpFactionOpponentsFilename, "datatables/pvp/faction_opponents.iff"); - KEY_STRING (pvpNonaggressiveFactionsFilename, "datatables/pvp/faction_nonaggressive.iff"); - KEY_STRING (pvpUnattackableFactionsFilename, "datatables/pvp/faction_unattackable.iff"); - KEY_STRING (pvpBountyTargetFactionsFilename, "datatables/pvp/faction_bountytarget.iff"); - KEY_BOOL (createAppearances,true); - KEY_STRING (adminAccountDataTable, "datatables/admin/us_admin.iff"); - KEY_BOOL (adminGodToAll, false); - KEY_INT (adminGodToAllGodLevel, 50); - KEY_BOOL (useSecureLoginForGodAccess, false); - KEY_BOOL (useIPForGodAccess, false); - KEY_BOOL (adminPersistAllCreates, false); - KEY_BOOL (buildCluster, false); - KEY_INT (requestSceneWarpTimeoutSeconds, 60); - KEY_BOOL (moveValidationEnabled, false); - KEY_FLOAT (moveSpeedTolerance, 1.03f); - KEY_INT (moveSpeedCheckFrequencyMs, 10000); - KEY_INT (moveSpeedCheckFailureLeewaySeconds, 5); - KEY_INT (moveSpeedCheckFailureLeewayCount, 5); - KEY_INT (moveSlowdownFudgeTimeMs, 5000); - KEY_BOOL (moveCheckDestinationCollision, true); - KEY_FLOAT (moveMaxDistance, 50.0f); - - // should be kept in sync with ConfigClientGame's disableMovementInventoryOverload - KEY_INT (moveValidationMaxInventoryOverload, 121); - - KEY_BOOL (moveValidationCheckForPastTimestamp, true); - KEY_BOOL (moveValidationCheckForFutureTimestamp, true); - KEY_BOOL (moveValidationCheckForTimestampDrift, true); - KEY_INT (moveValidationPastTimestampThresholdMs, 10000); - KEY_INT (moveValidationFutureTimestampThresholdMs, 10000); - KEY_INT (moveValidationTimestampDriftThresholdMs, 10000); - KEY_FLOAT (moveMaxDistanceLeewayPerUpdate, 2.0f); - KEY_BOOL (nameValidationAcceptAll, false); - KEY_FLOAT (tangiblePvpRegionCheckTime, 20.0f); - KEY_FLOAT (creaturePvpRegionCheckTime, 5.0f); - KEY_STRING (defaultLightArmorTemplate, "abstract/armor_statistics/armor/crafted/crafted_light_armor.iff"); - KEY_STRING (defaultMediumArmorTemplate, "abstract/armor_statistics/armor/crafted/crafted_medium_armor.iff"); - KEY_STRING (defaultHeavyArmorTemplate, "abstract/armor_statistics/armor/crafted/crafted_heavy_armor.iff"); - KEY_FLOAT (armorDamageReduction, 80.0f); - KEY_BOOL (stationPlayersEnabled, false); - KEY_BOOL (stationPlayersShowAllDebugInfo, false); - KEY_BOOL (commoditiesMarketEnabled, true); - KEY_INT (commoditiesServerServiceBindPort, 4069); - KEY_STRING (commoditiesServerServiceBindInterface, "localhost"); - KEY_BOOL (commoditiesShowAllDebugInfo, false); - KEY_INT (commoditiesQueryTimeoutSec, 60); - KEY_INT (commoditiesServerReconnectIntervalSec, 30); - KEY_INT (unclaimedAuctionItemDestroyTimeSec, 30*24*60*60); - KEY_INT (maxReimburseAmount, 0); - KEY_BOOL (logBaselines, false); - KEY_STRING (defaultVendorItemRestrictionFile, "datatables/commodity/vendor_item_restriction_default.iff"); - KEY_STRING (defaultVendorItemRestrictionRejectionMessage, "@ui_auc:reject_restricted_item"); - KEY_INT (weatherUpdateSeconds, 15*60); - KEY_STRING (instrumentDataTableFilename, "datatables/tangible/instrument_datatable.iff"); - KEY_STRING (performanceDataTableFilename, "datatables/performance/performance.iff"); - KEY_INT (createQueueScheduleTime, 75); - KEY_BOOL (disableResources, false); - KEY_INT (xpMultiplier, 1); - KEY_STRING (xpManagerTemplate, "object/xp_manager/xp_manager.iff"); - KEY_FLOAT (gcwXpBonus, 15.0f); - KEY_BOOL (reportAiStateChanges, false); - KEY_BOOL (reportAiWarnings, false); - KEY_BOOL (sendBreadcrumbs, false); - KEY_BOOL (movementWhileRetreatingThrowsException, false); - KEY_BOOL (hibernateEnabled, true); - KEY_BOOL (hibernateProxies, true); - KEY_FLOAT (hibernateDistance, 128.0f); - KEY_FLOAT (minHibernateAlter, 4.0f); - KEY_FLOAT (maxHibernateAlter, 6.0f); - KEY_INT (aiPulseQueuePerFrame, 100); - KEY_INT (aiPulseQueueMaxWaitTimeMs, 1000); - KEY_FLOAT (aiBaseAggroRadius, 24.0f); - KEY_FLOAT (aiMaxAggroRadius, 96.0f); - KEY_FLOAT (aiLeashRadius, 256.0f); - KEY_FLOAT (aiAssistRadius, 12.0f); - KEY_INT (minimumResourcePoolDrainRate, 0); - KEY_INT (secondsPerResourceTick, 60); - KEY_INT (resourceTimeScale, 60 * 60 * 24); - KEY_BOOL (disableCreateQueue, false); - KEY_STRING (craftingComponentTableFile0, "datatables/crafting/component.iff"); - KEY_STRING (craftingComponentTableFile1, "datatables/crafting/muzzle.iff"); - KEY_STRING (craftingComponentTableFile2, "datatables/crafting/scope.iff"); - KEY_STRING (craftingComponentTableFile3, "datatables/crafting/stock.iff"); - m_components[std::string("component")] = data->craftingComponentTableFile0; - m_components[std::string("muzzle")] = data->craftingComponentTableFile1; - m_components[std::string("scope")] = data->craftingComponentTableFile2; - m_components[std::string("stock")] = data->craftingComponentTableFile3; - KEY_BOOL (craftingComponentStrict, true); - KEY_INT (craftingXpChance, 50); - KEY_STRING (craftingXpPercentTable, "datatables/crafting/partial_xp_percent.iff"); - KEY_INT (maxObjectSkillModBonus, 25); - KEY_INT (maxSocketSkillModBonus, 25); - KEY_INT (maxSkillModSockets, 1); - KEY_FLOAT (baseDecayRate, 3600.0f); - KEY_FLOAT (weaponDecayThreshold, 25.0f); - KEY_STRING (regionFilesName, "datatables/region/planets.iff"); - KEY_INT (regionTreeDepth, 2); - KEY_STRING (battlefieldMarkerName, "datatables/battlefield/marker.iff"); - KEY_FLOAT (maxTeleportDistanceWithoutSceneWarp, 200.0f); - KEY_FLOAT (maxInstrumentPlayDistance, 3.0f); - KEY_STRING (characterNameGeneratorDirectory,"name"); - //KEY_FLOAT (statMigrationTimer, 60.0f * 10.0f); //value in seconds (currently defaults to 10 minutes) - KEY_INT (maxLotsPerAccount, 165); - KEY_INT (unsafeLogoutTimeMs, 3*60*1000); - KEY_INT (idleLogoutTimeSec, 30*60); - KEY_INT (idleLogoutTimeAfterCharacterTransferSec, 1*60); - KEY_STRING (fallbackDefaultWeapon, "object/weapon/melee/unarmed/unarmed_default.iff"); - KEY_BOOL (logObservers, false); - KEY_INT (lastKnownLocationsResetTimeSec, 60 * 60); // 1 hour - KEY_INT (maxMessageTosPerObjectPerFrame, 0); // unlimited - KEY_INT (maxMessageToTimePerObjectPerFrame, 0); // unlimited - KEY_INT (maxMessageToBounces, 100); // should be large enough to cover the worse case legitimate scenario of having to bounce through every game server - KEY_INT (missionRequestsPerFrame, 2); - KEY_BOOL (disableMissions, false); - KEY_INT (loopProfileLogThresholdMs, 3000); - KEY_INT (groundLoopProfileLogThresholdMs, 3000); - KEY_INT (spaceLoopProfileLogThresholdMs, 3000); - KEY_BOOL (pvpDisableCombat, false); - KEY_BOOL (logObjectLoading, false); - KEY_BOOL (enforcePlayerTriggerVolumesOnly, true); - KEY_FLOAT (locationTargetCheckIntervalSec, 5.0f); - KEY_STRING (gameServiceBindInterface, ""); - KEY_BOOL (logPvpUpdates, false); - KEY_FLOAT (npcConversationDistance, 6.0f); - KEY_INT (serverSpawnLimit, 1200); - KEY_INT (spawnQueueSize, 1); - KEY_INT (framesPerSpawn, 0); - KEY_BOOL (enableSpawningNearLoadBeacons, true); - KEY_BOOL (disableTravel, false); - KEY_BOOL (sendPlayerTransform, false); - KEY_FLOAT (watchedHarvesterAlterTime, 5.0f); - KEY_FLOAT (unwatchedHarvesterAlterTime, 900.0f); - KEY_FLOAT (harvesterExtractionRateMultiplier, 1.0f); - KEY_INT (nonCriticalTasksPerFrame, 5); - KEY_INT (maxMoney, 1000000000); // 1 billion (must be small enough to keep money within an int) - KEY_INT (maxGalacticReserveDepositBillion, 3); // 3 billion - KEY_INT (maxMoneyTransfer, 100000000); // 100 million - KEY_INT (maxFreeTrialMoney, 50000); //50k credits limited to demo customers - KEY_BOOL (enablePreload, true); - KEY_BOOL (buildPreloadLists, true); - KEY_BOOL (logAuthTransfer, false); - - KEY_INT (overrideUpdateRadius, 0); - KEY_FLOAT (buildingUpdateRadiusMultiplier, 1.0f); - KEY_INT (maxPopulationForNewbieTravel, 90); - KEY_BOOL (debugAllAreasOverpopulated, false); - KEY_INT (minNewbieTravelLocations, 5); - KEY_INT (numberOfMoveObjectLists, 0); - KEY_INT (sitOnObjectReportThreshold, 1000); - KEY_BOOL (fatalOnSitThreshold, false); - KEY_INT (databasePositionUpdateLongDelayIntervalMs, 3*60*1000); - KEY_INT (databasePositionUpdateShortDelayIntervalMs, 1*1000); - KEY_BOOL (logPositionUpdates, false); - - KEY_BOOL (checkOriginCreates, true); - KEY_BOOL (enableWho, false); - KEY_BOOL (debugGroupChat, false); - - KEY_INT (numberOfMissionsWantedInMissionBag, 10); // MUST be 10 (at the moment) - KEY_INT (missionCreationQueueSize, 4); - KEY_INT (connectToAllGameServersTimeout, 120); - KEY_INT (houseItemLimitMultiplier, 100); - KEY_INT (maxHouseItemLimit, 500); - KEY_BOOL (demandLoadHouseContents, true); - KEY_INT (unloadHouseContentsTime, 10 * 60); - KEY_INT (loadHouseContentsDelaySeconds, 0); - KEY_BOOL (boundarySpawningAllowed, true); - KEY_BOOL (debugMovement, false); - KEY_BOOL (spawnAllResources, true); - KEY_BOOL (skipUnreliableTransformsForOtherCells, false); - KEY_INT (maxPlayerSanityCheckFailures, 3); - KEY_BOOL (disablePlayerSanityChecker, false); - KEY_BOOL (deactivateHarvesterIfDamaged, true); - KEY_FLOAT (updateRange7Packets, 40.0f); - KEY_FLOAT (updateRange6Packets, 80.0f); - KEY_FLOAT (updateRange5Packets, 90.0f); - KEY_FLOAT (updateRange4Packets, 100.0f); - KEY_FLOAT (updateRange3Packets, 110.0f); - KEY_FLOAT (updateRange2Packets, 120.0f); - KEY_FLOAT (updateRange1Packets, 130.0f); - KEY_STRING (instantDeleteListDataTableName, "datatables/database/instant_delete_list.iff"); - KEY_BOOL (sendFrameProfilerInfo, false); - KEY_BOOL (logAllCommands, true); - KEY_BOOL (enableDebugControllerMessageSpam ,false); - KEY_BOOL (debugPvp, false); - KEY_BOOL (allowMasterObjectCreation, true); - KEY_BOOL (mountsEnabled, true); - KEY_BOOL (mountsSanityCheckerEnabled, false); - KEY_BOOL (mountsSanityCheckerBroadcastEnabled, false); - KEY_INT (mountsSanityCheckerBroadcastLimit, 5); - KEY_INT (universeCheckFrequencySeconds, 60 * 60); - KEY_BOOL (moveSimEnabled, false); - KEY_BOOL (exceptionOnObjVarZeroLengthArray, false); - KEY_BOOL (trackNonAuthoritativeObjvarSets, false); - KEY_FLOAT (triggerVolumeWarpDistance, 128.0f); - KEY_NETWORKID(maxGoldNetworkId, "0"); - KEY_BOOL (fatalOnMovingGoldObject, false); - KEY_INT (spatialChatLogMinutes, 5); - KEY_FLOAT (behaviorMaxAvoidanceStuckTime, 10.0f); - KEY_INT (behaviorMaxAvoidancePersistenceFrameCount, 4); - KEY_BOOL (shipsEnabled, true); - KEY_BOOL (logoutTriggerEnabled, true); - KEY_BOOL (loginAsBountyHunter, false); - KEY_INT (veteranRewardTradeInWaitPeriodSeconds, 30 * 24 * 60 * 60); // 30 days - KEY_BOOL (enableVeteranRewards, true); - KEY_BOOL (enableOneYearAnniversary, true); - KEY_INT (minEntitledTime, -1); - KEY_BOOL (veteranDebugTriggerAll, false); - KEY_BOOL (veteranDebugEnableOverrideAccountAge, false); - KEY_BOOL (enableNewVeteranRewards, true); - KEY_FLOAT (buddyPointTimeBonus, 30.0f/4.0f); // 4 buddy points = 30 days - -#ifdef _DEBUG - KEY_FLOAT (manufactureTimeOverride, 0.0f); -#endif - - KEY_INT (theaterCreationLimitMilliseconds, 25); - KEY_BOOL (fatalOnGoldPobChange, false); - KEY_INT (lineOfSightCacheDurationMs, 1500); - KEY_FLOAT (lineOfSightCacheMinHeight, 0.8f); - KEY_FLOAT (lineOfSightLocationRoundValue, 5.0f); - -#ifdef _DEBUG - // in debug mode, we default this to true so that unless - // a controller message is explicitly marked as being allowed - // from the client, it will be dropped when the game server - // receives it; this will have the effect of forcing the - // programmer to make a conscious decision to mark the - // controller message as allowable from the client; because - // controller message coming from the client is not secured, - // the mechanism to prevent a hacked client from sending the - // game server any controller message is to explicity "mark" - // those controller messages that are allowed from the client - KEY_BOOL (enableClientControllerMessageCheck, true); -#else - // for live, the this option will be set to true in the config file - KEY_BOOL (enableClientControllerMessageCheck, false); -#endif - - KEY_INT (maxWaypointsPerCharacter,100); // Keep this in sync with the maxWaypoints value in ConfigClientGame.cpp - KEY_FLOAT (maxSmallCreatureHeight, 0.7f); - KEY_FLOAT (smallCreatureUpdateRadius, 64.0f); - KEY_FLOAT (maxMediumCreatureHeight, 3.0f); - KEY_FLOAT (mediumCreatureUpdateRadius, 128.0f); - KEY_FLOAT (largeCreatureUpdateRadius, 256.0f); - KEY_INT (coolDownPersistThresholdSeconds, 1 * 60); - KEY_BOOL (checkNotifyRegions, true); - KEY_BOOL (allowRegionTriggerOverride, true); - KEY_INT (spacePlanetServerUpdatesPerFrame, 0); - KEY_FLOAT (hyperspaceRandomOffsetRange, 200); - - if (data->theaterCreationLimitMilliseconds <= 0) - { - data->theaterCreationLimitMilliseconds = 25; - WARNING(true, ("Config value [GameServer] theaterCreationLimitMilliseconds " - "out of range, setting to default value")); - } - - KEY_BOOL (sendAsteroidExtents, false); - KEY_BOOL (createZoneObjects, true); - KEY_INT (shipUpdatesPerSecond, 32); - KEY_BOOL (debugSpaceVisibilityManager, false); - KEY_INT (groundFrameRateLimit, 5); - KEY_INT (spaceFrameRateLimit, 12); - KEY_BOOL (aiLoggingEnabled, false); - KEY_BOOL (shipShotValidationEnabled, false); - KEY_INT (spaceAiEnemySearchesPerFrame, 15); - KEY_BOOL (groundShouldSleep, true); - KEY_BOOL (spaceShouldSleep, true); - KEY_BOOL (shipMoveValidationEnabled, false); - KEY_INT (shipMoveCheckIntervalMs, 1000); - KEY_INT (shipMoveCheckFudgeTimeMs, 5000); - KEY_FLOAT (shipMoveCheckTolerance, 1.03f); - KEY_FLOAT (shipMoveCheckTimeToleranceSeconds, 0.1f); - KEY_INT (spaceAiAvoidanceChecksPerFrame, 64); - KEY_BOOL (spaceAiUsePathRefinement, true); - KEY_BOOL (aiClientDebugEnabled, false); - KEY_BOOL (shipClientUpdateDebugEnabled, false); - KEY_FLOAT (shipLoadInvulnerableTimeWithoutClient, 120.f); - KEY_FLOAT (shipLoadInvulnerableTimeWithClient, 10.f); - KEY_FLOAT (creatureLoadInvulnerableTimeWithoutClient, 120.f); - KEY_FLOAT (creatureLoadInvulnerableTimeWithClient, 1.f); - KEY_BOOL (buildoutAreaEditingEnabled, false); - KEY_BOOL (debugFloorPathNodeCount, false); // this flag checks cells to make sure the floor part count equals the path graph node count - KEY_INT (populationReportTimeSeconds, 600); - KEY_FLOAT(maxCombatRange, 96.0f); - KEY_BOOL (blockBuildRegionPlacement,false); - - KEY_INT (npeMinInstancePopulation,20); - KEY_INT (npeMaxInstancePopulation,50); - KEY_BOOL (stripNonFreeAssetsFromPlayersInTutorial, false); - - // weekly time (in GMT) when GCW rating recalculation occurs - KEY_INT (gcwRecalcTimeDayOfWeek, 4); // Sunday=0, Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6 - KEY_INT (gcwRecalcTimeHour, 19); // 0 - 23 - KEY_INT (gcwRecalcTimeMinute, 0); // 0 - 59 - KEY_INT (gcwRecalcTimeSecond, 0); // 0 - 59 - - // weekly time (in GMT) when GCW score decay occurs; - // additional time(s) can be specified in the config file if - // you want the GCW score decay to occur more than once a week; - // the following time is ignored if any time(s) is specified - // in the config file; if no time(s) is specified in the - // config file, it will use the following time as the default - KEY_INT (gcwScoreDecayTimeDayOfWeek, 1); // Sunday=0, Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6 - KEY_INT (gcwScoreDecayTimeHour, 19); // 0 - 23 - KEY_INT (gcwScoreDecayTimeMinute, 0); // 0 - 59 - KEY_INT (gcwScoreDecayTimeSecond, 0); // 0 - 59 - - KEY_INT (chatStatisticsReportIntervalSeconds, 60); - KEY_INT (chatSpamLimiterNumCharacters, 400); - KEY_INT (chatSpamLimiterIntervalMinutes, 15); - KEY_BOOL (chatSpamLimiterEnabledForFreeTrial, true); - KEY_INT (chatSpamNotifyPlayerWhenLimitedIntervalSeconds, 30); // <= 0 to disable - - KEY_INT (pendingLoadRequestLimit, 1000000000); // unlimited - - KEY_BOOL (enableCityCitizenshipFixup, true); - - KEY_INT (cityCitizenshipInactivePackupStartTimeEpoch, 1243839660); // June 1st 2009 12:01AM PDT - KEY_INT (cityCitizenshipInactivePackupInactiveTimeSeconds, 90 * 24 * 60 * 60); // 90 days - - KEY_STRING (retroactivePlayerCityCreationTimeFilename, ""); - - KEY_INT (wardenSquelchDurationSeconds, 6 * 60 * 60); // 6 hours - KEY_BOOL (enableWarden, true); - KEY_BOOL (enableWardenCanSquelchSecuredLogin, false); - KEY_BOOL (enableWardenToDeputizeWarden, true); - - KEY_BOOL (disableCollectionServerFirstGrantForSecuredLogin, false); - - KEY_INT (locateStructureCommandIntervalSeconds, 24 * 60 * 60); // 24 hours - - KEY_INT (locateVendorCommandIntervalSeconds, 15 * 60); // 15 minutes - - KEY_INT (ctsDefaultScriptDictionarySizeBytes, 10 * 1024 * 1024); // 10M - KEY_STRING (retroactiveCtsHistoryFilename, ""); - KEY_BOOL (allowIgnoreFreeCtsTimeRestriction, false); - - KEY_INT (groupPickupPointApprovalRangeSquared, 20 * 20); - KEY_INT (groupPickupPointTimeLimitSeconds, 2 * 60); - KEY_INT (groupPickupTravelPlayerCityPercent, 10); - - KEY_BOOL (groupInviteInviterCombatRestriction, false); - KEY_BOOL (groupInviteInviteeCombatRestriction, false); - KEY_BOOL (groupJoinInviterCombatRestriction, false); - KEY_BOOL (groupJoinInviteeCombatRestriction, false); - - KEY_INT (characterMatchMaxMatchCount, 32); - - KEY_BOOL (enableOccupyUnlockedSlotCommand, true); - KEY_BOOL (enableVacateUnlockedSlotCommand, true); - KEY_BOOL (enableSwapUnlockedSlotCommand, true); - KEY_INT (occupyVacateUnlockedSlotCommandCooldownSeconds, 24 * 60 * 60); // 24 hours - - KEY_INT (accountFeatureIdForMonthlyBoosterPack, 5032); - KEY_INT (accountFeatureIdForTcgBetaAnnouncement, 5552); - - KEY_BOOL (logEventObjectCreation, false); - KEY_BOOL (logEventObjectDestruction, false); - KEY_STRING (housePackupAccountListDataTableName, "datatables/house_packup/house_packup_accounts.iff"); - - KEY_INT (pickDropAllRoomItemsNumberOfItemsPerRound, 5); - - KEY_BOOL (enableCovertImperialMercenary, false); - KEY_BOOL (enableOvertImperialMercenary, false); - KEY_BOOL (enableCovertRebelMercenary, false); - KEY_BOOL (enableOvertRebelMercenary, false); - KEY_INT (broadcastGcwScoreToOtherGalaxiesIntervalSeconds, 15 * 60); // 15 minutes - KEY_BOOL (broadcastGcwScoreToOtherGalaxies, false); - KEY_BOOL (receiveGcwScoreFromOtherGalaxies, false); - KEY_INT (trackGcwPercentileHistoryCount, 10); - KEY_BOOL (gcwFactionalPresenceDisableForSecuredLogin, false); - - KEY_INT (gcwFactionalPresenceMountedPct, 20); // 0 to disable FP while on a vehicle/mount, 100 for no FP penalty while on a vehicle/mount - // clamp to 0 - 100 - data->gcwFactionalPresenceMountedPct = std::min(std::max(data->gcwFactionalPresenceMountedPct, 0), 100); - - KEY_INT (gcwFactionalPresenceLevelPct, 10); - KEY_INT (gcwFactionalPresenceGcwRankBonusPct, 10); - KEY_INT (gcwFactionalPresenceAlignedCityBonusPct, 100); - KEY_INT (gcwFactionalPresenceAlignedCityRankBonusPct, 10); - KEY_INT (gcwFactionalPresenceAlignedCityAgeBonusPct, 5); - KEY_INT (gcwGuildMinMembersForGcwRegionDefender, 10); - KEY_INT (gcwRegionDefenderTotalBonusPct, 20); - KEY_INT (gcwDaysRequiredForGcwRegionDefenderBonus, 3); - - KEY_FLOAT (regionFlagUpdateTime, 0.5f); - - if (data->baseDecayRate <= 1.0f) - data->baseDecayRate = 1.0f; - - if (data->weaponDecayThreshold < 0.0f) - data->weaponDecayThreshold = 0.0f; - else if (data->weaponDecayThreshold > 100.0f) - data->weaponDecayThreshold = 100.0f; - data->weaponDecayThreshold /= 100.0f; - - if (data->armorDamageReduction < 0.0f) - data->armorDamageReduction = 0.0f; - else if (data->armorDamageReduction > 100.0f) - data->armorDamageReduction = 100.0f; - data->armorDamageReduction = 1.0f - data->armorDamageReduction / 100.0f; - - if (data->gcwXpBonus < 0.0f) - data->gcwXpBonus = 0.0f; - data->gcwXpBonus /= 100.0f; - - // GCW score decay time(s) - data->gcwScoreDecayTime.clear(); - int index = 0; - char const * dayOfWeek = NULL; - char const * hour = NULL; - char const * minute = NULL; - char const * second = NULL; - do - { - dayOfWeek = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeDayOfWeek", index, 0); - hour = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeHour", index, 0); - minute = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeMinute", index, 0); - second = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeSecond", index, 0); - - if (dayOfWeek && hour && minute && second) - { - data->gcwScoreDecayTime.push_back(std::make_pair(std::make_pair(ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeDayOfWeek", index, 0), ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeHour", index, 0)), std::make_pair(ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeMinute", index, 0), ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeSecond", index, 0)))); - } - - ++index; - } - while (dayOfWeek && hour && minute && second); - - if (data->gcwScoreDecayTime.empty()) - { - data->gcwScoreDecayTime.push_back(std::make_pair(std::make_pair(data->gcwScoreDecayTimeDayOfWeek, data->gcwScoreDecayTimeHour), std::make_pair(data->gcwScoreDecayTimeMinute, data->gcwScoreDecayTimeSecond))); - } -} - -//------------------------------------------------------------------- - -void ConfigServerGame::remove(void) -{ - ConfigServerUtility::remove(); -} - -//------------------------------------------------------------------- - -const std::string & ConfigServerGame::getCraftingComponentTableFile( - const std::string & name) -{ -static const std::string NO_DATA; - - std::map::const_iterator iter; - iter = m_components.find(name); - if (iter != m_components.end()) - return (*iter).second; - if (!m_components.empty()) - return m_components["component"]; - return NO_DATA; -} - -// ====================================================================== +// +// ConfigServerGame.cpp +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +#include "serverGame/FirstServerGame.h" +#include "serverGame/ConfigServerGame.h" +#include "serverUtility/ConfigServerUtility.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/NetworkId.h" +#include "sharedMath/Vector.h" + +#include + +//------------------------------------------------------------------- + +ConfigServerGame::Data* ConfigServerGame::data; +Vector ConfigServerGame::startingPosition; +std::map ConfigServerGame::m_components; + +//------------------------------------------------------------------- + +static ConfigServerGame::Data staticData; + +//------------------------------------------------------------------- + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("GameServer", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("GameServer", #a, b)) +#define KEY_FLOAT(a,b) (data->a = ConfigFile::getKeyFloat("GameServer", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("GameServer", #a, b)) +#define KEY_NETWORKID(a,b) (data->a = NetworkId(std::string(ConfigFile::getKeyString("GameServer", #a, b)))) + +//------------------------------------------------------------------- + +void ConfigServerGame::install(void) +{ + ConfigServerUtility::install(); + data = &staticData; + + KEY_BOOL (allowDefaultTemplateParams, true); + KEY_BOOL (skipTutorial, false); + KEY_STRING (groundScene, 0); + KEY_STRING (spaceScene, 0); + KEY_INT (port, 0); + KEY_STRING (sceneID, "default"); + KEY_INT (preloadNumber, 0); + KEY_FLOAT (startX, 0.0f); + KEY_FLOAT (startY, 0.0f); + KEY_FLOAT (startZ, 0.0f); + startingPosition = Vector(data->startX,data->startY,data->startZ); + KEY_INT (taskManagerPort, 60001); + KEY_STRING (centralServerAddress, "localhost"); + KEY_INT (centralServerPort, 44451); + KEY_STRING (javaVMName, ""); + KEY_STRING (scriptPath, "../../data/sku.0/sys.server/compiled/game"); +#if defined(WIN32) + KEY_STRING (javaLibPath, "jvm.dll"); +#elif defined(linux) + // either the simple library .so name or the full path to the jvm library + KEY_STRING (javaLibPath, "libjvm.so"); +#else +#error unsupported platform +#endif + KEY_STRING (javaDebugPort, "8000"); + KEY_BOOL (useRemoteDebugJava, false); + KEY_BOOL (profileScripts, false); + KEY_BOOL (crashOnScriptError, false); + KEY_BOOL (compileScripts, false); + KEY_BOOL (trapScriptCrashes, true); + KEY_INT (scriptWatcherWarnTime, 5000); + KEY_INT (scriptWatcherInterruptTime, 5000); + KEY_INT (scriptStackErrorLimit, 35); + KEY_INT (scriptStackErrorLevel, 0); + KEY_BOOL (disableObjvarNullCheck, false); + KEY_INT (maxGameServerToSendUniverseData, 1000000); + KEY_INT (timeoutToAckUniverseDataReceived, 0); + KEY_BOOL (disableCombat, false); + KEY_STRING (combatConfigFile, "combat.cfg"); + KEY_FLOAT (combatDamageDelaySeconds, 0.0); + KEY_INT (triggerVolumeSystem, 0); + KEY_INT (defaultAutoExpireTargetDuration, 6); + KEY_FLOAT (interiorTargetDurationFactor, 1.0); + KEY_INT (minPoolValue, -100); + KEY_INT (minFaucetValue, 1); + KEY_INT (minDrainValue, 1); + KEY_INT (minEffectiveFaucetValue, 150); + KEY_FLOAT (defaultHealthRegen, 40.0f); + KEY_FLOAT (defaultActionRegen, 20.0f); + KEY_FLOAT (defaultMindRegen, 10.0f); + KEY_FLOAT (regenThreshold, 1.0f); + KEY_FLOAT (minForcePowerRegenRate, 1.0f); + KEY_BOOL (enableAttribModWarnings, true); + KEY_BOOL (checkAttribLimits, false); + KEY_INT (maxItemAttribBonus, 50); + KEY_INT (maxTotalAttribBonus, 500); + KEY_BOOL (enableNewJedi, false); + KEY_STRING (jediManagerTemplate, "object/jedi_manager/jedi_manager.iff"); + KEY_INT (maxJediBounties, 5); + KEY_INT (startForcePower, 10); + KEY_BOOL (logJediConcludes, false); + KEY_BOOL (forceJediConcludes, false); + KEY_INT (jediUpdateLocationTimeSeconds, 60 * 5); + KEY_STRING (planetObjectTemplate, "object/planet/planet.iff"); + KEY_BOOL (javaConsoleDebugMessages, false); + KEY_BOOL (useVerboseJava, false); + KEY_BOOL (logJavaGc, false); + KEY_INT (javaLocalRefLimit, 16); + KEY_STRING (reservedNameFile, "datatables/name/reserved.iff"); + KEY_INT (reservedObjectIds, 10000); + KEY_INT (minObjectIds, data->reservedObjectIds/2); // default is 1/2 of whatever is specifed for reservedObjectIds, so that the user can specify reservedObjectIds but doesn't have to specify minObjectIds + KEY_STRING (playerObjectTemplate, "object/player/player.iff"); + KEY_INT (clientOutOfRangeObjectCacheTimeMs, 20000); + KEY_INT (playerInterestRange, 300); + KEY_INT (pvpUpdateTimeMs, 10000); + KEY_INT (pvpTempFlagExpireTimeMs, 5*60*1000/2); // 2.5 minutes + KEY_INT (pvpGuildWarCoolDownPeriodTimeMs, 1*60*1000); // 1 minute + KEY_INT (pvpGuildWarExemptionExclusiveDelaySeconds, 5*60); // 5 minutes + KEY_INT (pvpBattlefieldEnemyFlagExpireTimeMs, 5*60*1000/2); // 2.5 minutes + KEY_STRING (pvpFactionOpponentsFilename, "datatables/pvp/faction_opponents.iff"); + KEY_STRING (pvpNonaggressiveFactionsFilename, "datatables/pvp/faction_nonaggressive.iff"); + KEY_STRING (pvpUnattackableFactionsFilename, "datatables/pvp/faction_unattackable.iff"); + KEY_STRING (pvpBountyTargetFactionsFilename, "datatables/pvp/faction_bountytarget.iff"); + KEY_BOOL (createAppearances,true); + KEY_STRING (adminAccountDataTable, "datatables/admin/us_admin.iff"); + KEY_BOOL (adminGodToAll, false); + KEY_INT (adminGodToAllGodLevel, 50); + KEY_BOOL (useSecureLoginForGodAccess, false); + KEY_BOOL (useIPForGodAccess, false); + KEY_BOOL (adminPersistAllCreates, false); + KEY_BOOL (buildCluster, false); + KEY_INT (requestSceneWarpTimeoutSeconds, 60); + KEY_BOOL (moveValidationEnabled, false); + KEY_FLOAT (moveSpeedTolerance, 1.03f); + KEY_INT (moveSpeedCheckFrequencyMs, 10000); + KEY_INT (moveSpeedCheckFailureLeewaySeconds, 5); + KEY_INT (moveSpeedCheckFailureLeewayCount, 5); + KEY_INT (moveSlowdownFudgeTimeMs, 5000); + KEY_BOOL (moveCheckDestinationCollision, true); + KEY_FLOAT (moveMaxDistance, 50.0f); + + // should be kept in sync with ConfigClientGame's disableMovementInventoryOverload + KEY_INT (moveValidationMaxInventoryOverload, 121); + + KEY_BOOL (moveValidationCheckForPastTimestamp, true); + KEY_BOOL (moveValidationCheckForFutureTimestamp, true); + KEY_BOOL (moveValidationCheckForTimestampDrift, true); + KEY_INT (moveValidationPastTimestampThresholdMs, 10000); + KEY_INT (moveValidationFutureTimestampThresholdMs, 10000); + KEY_INT (moveValidationTimestampDriftThresholdMs, 10000); + KEY_FLOAT (moveMaxDistanceLeewayPerUpdate, 2.0f); + KEY_BOOL (nameValidationAcceptAll, false); + KEY_FLOAT (tangiblePvpRegionCheckTime, 20.0f); + KEY_FLOAT (creaturePvpRegionCheckTime, 5.0f); + KEY_STRING (defaultLightArmorTemplate, "abstract/armor_statistics/armor/crafted/crafted_light_armor.iff"); + KEY_STRING (defaultMediumArmorTemplate, "abstract/armor_statistics/armor/crafted/crafted_medium_armor.iff"); + KEY_STRING (defaultHeavyArmorTemplate, "abstract/armor_statistics/armor/crafted/crafted_heavy_armor.iff"); + KEY_FLOAT (armorDamageReduction, 80.0f); + KEY_BOOL (stationPlayersEnabled, false); + KEY_BOOL (stationPlayersShowAllDebugInfo, false); + KEY_BOOL (commoditiesMarketEnabled, true); + KEY_INT (commoditiesServerServiceBindPort, 4069); + KEY_STRING (commoditiesServerServiceBindInterface, "localhost"); + KEY_BOOL (commoditiesShowAllDebugInfo, false); + KEY_INT (commoditiesQueryTimeoutSec, 60); + KEY_INT (commoditiesServerReconnectIntervalSec, 30); + KEY_INT (unclaimedAuctionItemDestroyTimeSec, 30*24*60*60); + KEY_INT (maxReimburseAmount, 0); + KEY_BOOL (logBaselines, false); + KEY_STRING (defaultVendorItemRestrictionFile, "datatables/commodity/vendor_item_restriction_default.iff"); + KEY_STRING (defaultVendorItemRestrictionRejectionMessage, "@ui_auc:reject_restricted_item"); + KEY_INT (weatherUpdateSeconds, 15*60); + KEY_STRING (instrumentDataTableFilename, "datatables/tangible/instrument_datatable.iff"); + KEY_STRING (performanceDataTableFilename, "datatables/performance/performance.iff"); + KEY_INT (createQueueScheduleTime, 75); + KEY_BOOL (disableResources, false); + KEY_INT (xpMultiplier, 1); + KEY_STRING (xpManagerTemplate, "object/xp_manager/xp_manager.iff"); + KEY_FLOAT (gcwXpBonus, 15.0f); + KEY_BOOL (reportAiStateChanges, false); + KEY_BOOL (reportAiWarnings, false); + KEY_BOOL (sendBreadcrumbs, false); + KEY_BOOL (movementWhileRetreatingThrowsException, false); + KEY_BOOL (hibernateEnabled, true); + KEY_BOOL (hibernateProxies, true); + KEY_FLOAT (hibernateDistance, 128.0f); + KEY_FLOAT (minHibernateAlter, 4.0f); + KEY_FLOAT (maxHibernateAlter, 6.0f); + KEY_INT (aiPulseQueuePerFrame, 100); + KEY_INT (aiPulseQueueMaxWaitTimeMs, 1000); + KEY_FLOAT (aiBaseAggroRadius, 24.0f); + KEY_FLOAT (aiMaxAggroRadius, 96.0f); + KEY_FLOAT (aiLeashRadius, 256.0f); + KEY_FLOAT (aiAssistRadius, 12.0f); + KEY_INT (minimumResourcePoolDrainRate, 0); + KEY_INT (secondsPerResourceTick, 60); + KEY_INT (resourceTimeScale, 60 * 60 * 24); + KEY_BOOL (disableCreateQueue, false); + KEY_STRING (craftingComponentTableFile0, "datatables/crafting/component.iff"); + KEY_STRING (craftingComponentTableFile1, "datatables/crafting/muzzle.iff"); + KEY_STRING (craftingComponentTableFile2, "datatables/crafting/scope.iff"); + KEY_STRING (craftingComponentTableFile3, "datatables/crafting/stock.iff"); + m_components[std::string("component")] = data->craftingComponentTableFile0; + m_components[std::string("muzzle")] = data->craftingComponentTableFile1; + m_components[std::string("scope")] = data->craftingComponentTableFile2; + m_components[std::string("stock")] = data->craftingComponentTableFile3; + KEY_BOOL (craftingComponentStrict, true); + KEY_INT (craftingXpChance, 50); + KEY_STRING (craftingXpPercentTable, "datatables/crafting/partial_xp_percent.iff"); + KEY_INT (maxObjectSkillModBonus, 25); + KEY_INT (maxSocketSkillModBonus, 25); + KEY_INT (maxSkillModSockets, 1); + KEY_FLOAT (baseDecayRate, 3600.0f); + KEY_FLOAT (weaponDecayThreshold, 25.0f); + KEY_STRING (regionFilesName, "datatables/region/planets.iff"); + KEY_INT (regionTreeDepth, 2); + KEY_STRING (battlefieldMarkerName, "datatables/battlefield/marker.iff"); + KEY_FLOAT (maxTeleportDistanceWithoutSceneWarp, 200.0f); + KEY_FLOAT (maxInstrumentPlayDistance, 3.0f); + KEY_STRING (characterNameGeneratorDirectory,"name"); + //KEY_FLOAT (statMigrationTimer, 60.0f * 10.0f); //value in seconds (currently defaults to 10 minutes) + KEY_INT (maxLotsPerAccount, 165); + KEY_INT (unsafeLogoutTimeMs, 3*60*1000); + KEY_INT (idleLogoutTimeSec, 30*60); + KEY_INT (idleLogoutTimeAfterCharacterTransferSec, 1*60); + KEY_STRING (fallbackDefaultWeapon, "object/weapon/melee/unarmed/unarmed_default.iff"); + KEY_BOOL (logObservers, false); + KEY_INT (lastKnownLocationsResetTimeSec, 60 * 60); // 1 hour + KEY_INT (maxMessageTosPerObjectPerFrame, 0); // unlimited + KEY_INT (maxMessageToTimePerObjectPerFrame, 0); // unlimited + KEY_INT (maxMessageToBounces, 100); // should be large enough to cover the worse case legitimate scenario of having to bounce through every game server + KEY_INT (missionRequestsPerFrame, 2); + KEY_BOOL (disableMissions, false); + KEY_INT (loopProfileLogThresholdMs, 3000); + KEY_INT (groundLoopProfileLogThresholdMs, 3000); + KEY_INT (spaceLoopProfileLogThresholdMs, 3000); + KEY_BOOL (pvpDisableCombat, false); + KEY_BOOL (logObjectLoading, false); + KEY_BOOL (enforcePlayerTriggerVolumesOnly, true); + KEY_FLOAT (locationTargetCheckIntervalSec, 5.0f); + KEY_STRING (gameServiceBindInterface, ""); + KEY_BOOL (logPvpUpdates, false); + KEY_FLOAT (npcConversationDistance, 6.0f); + KEY_INT (serverSpawnLimit, 1200); + KEY_INT (spawnQueueSize, 1); + KEY_INT (framesPerSpawn, 0); + KEY_BOOL (enableSpawningNearLoadBeacons, true); + KEY_BOOL (disableTravel, false); + KEY_BOOL (sendPlayerTransform, false); + KEY_FLOAT (watchedHarvesterAlterTime, 5.0f); + KEY_FLOAT (unwatchedHarvesterAlterTime, 900.0f); + KEY_FLOAT (harvesterExtractionRateMultiplier, 1.0f); + KEY_INT (nonCriticalTasksPerFrame, 5); + KEY_INT (maxMoney, 1000000000); // 1 billion (must be small enough to keep money within an int) + KEY_INT (maxGalacticReserveDepositBillion, 3); // 3 billion + KEY_INT (maxMoneyTransfer, 100000000); // 100 million + KEY_INT (maxFreeTrialMoney, 50000); //50k credits limited to demo customers + KEY_BOOL (enablePreload, true); + KEY_BOOL (buildPreloadLists, true); + KEY_BOOL (logAuthTransfer, false); + + KEY_INT (overrideUpdateRadius, 0); + KEY_FLOAT (buildingUpdateRadiusMultiplier, 1.0f); + KEY_INT (maxPopulationForNewbieTravel, 90); + KEY_BOOL (debugAllAreasOverpopulated, false); + KEY_INT (minNewbieTravelLocations, 5); + KEY_INT (numberOfMoveObjectLists, 0); + KEY_INT (sitOnObjectReportThreshold, 1000); + KEY_BOOL (fatalOnSitThreshold, false); + KEY_INT (databasePositionUpdateLongDelayIntervalMs, 3*60*1000); + KEY_INT (databasePositionUpdateShortDelayIntervalMs, 1*1000); + KEY_BOOL (logPositionUpdates, false); + + KEY_BOOL (checkOriginCreates, true); + KEY_BOOL (enableWho, false); + KEY_BOOL (debugGroupChat, false); + + KEY_INT (numberOfMissionsWantedInMissionBag, 10); // MUST be 10 (at the moment) + KEY_INT (missionCreationQueueSize, 4); + KEY_INT (connectToAllGameServersTimeout, 120); + KEY_INT (houseItemLimitMultiplier, 100); + KEY_INT (maxHouseItemLimit, 500); + KEY_BOOL (demandLoadHouseContents, true); + KEY_INT (unloadHouseContentsTime, 10 * 60); + KEY_INT (loadHouseContentsDelaySeconds, 0); + KEY_BOOL (boundarySpawningAllowed, true); + KEY_BOOL (debugMovement, false); + KEY_BOOL (spawnAllResources, true); + KEY_BOOL (skipUnreliableTransformsForOtherCells, false); + KEY_INT (maxPlayerSanityCheckFailures, 3); + KEY_BOOL (disablePlayerSanityChecker, false); + KEY_BOOL (deactivateHarvesterIfDamaged, true); + KEY_FLOAT (updateRange7Packets, 40.0f); + KEY_FLOAT (updateRange6Packets, 80.0f); + KEY_FLOAT (updateRange5Packets, 90.0f); + KEY_FLOAT (updateRange4Packets, 100.0f); + KEY_FLOAT (updateRange3Packets, 110.0f); + KEY_FLOAT (updateRange2Packets, 120.0f); + KEY_FLOAT (updateRange1Packets, 130.0f); + KEY_STRING (instantDeleteListDataTableName, "datatables/database/instant_delete_list.iff"); + KEY_BOOL (sendFrameProfilerInfo, false); + KEY_BOOL (logAllCommands, true); + KEY_BOOL (enableDebugControllerMessageSpam ,false); + KEY_BOOL (debugPvp, false); + KEY_BOOL (allowMasterObjectCreation, true); + KEY_BOOL (mountsEnabled, true); + KEY_BOOL (mountsSanityCheckerEnabled, false); + KEY_BOOL (mountsSanityCheckerBroadcastEnabled, false); + KEY_INT (mountsSanityCheckerBroadcastLimit, 5); + KEY_INT (universeCheckFrequencySeconds, 60 * 60); + KEY_BOOL (moveSimEnabled, false); + KEY_BOOL (exceptionOnObjVarZeroLengthArray, false); + KEY_BOOL (trackNonAuthoritativeObjvarSets, false); + KEY_FLOAT (triggerVolumeWarpDistance, 128.0f); + KEY_NETWORKID(maxGoldNetworkId, "0"); + KEY_BOOL (fatalOnMovingGoldObject, false); + KEY_INT (spatialChatLogMinutes, 5); + KEY_FLOAT (behaviorMaxAvoidanceStuckTime, 10.0f); + KEY_INT (behaviorMaxAvoidancePersistenceFrameCount, 4); + KEY_BOOL (shipsEnabled, true); + KEY_BOOL (logoutTriggerEnabled, true); + KEY_BOOL (loginAsBountyHunter, false); + KEY_INT (veteranRewardTradeInWaitPeriodSeconds, 30 * 24 * 60 * 60); // 30 days + KEY_BOOL (enableVeteranRewards, true); + KEY_BOOL (enableOneYearAnniversary, true); + KEY_INT (minEntitledTime, -1); + KEY_BOOL (veteranDebugTriggerAll, false); + KEY_BOOL (veteranDebugEnableOverrideAccountAge, false); + KEY_BOOL (enableNewVeteranRewards, true); + KEY_FLOAT (buddyPointTimeBonus, 30.0f/4.0f); // 4 buddy points = 30 days + +#ifdef _DEBUG + KEY_FLOAT (manufactureTimeOverride, 0.0f); +#endif + + KEY_INT (theaterCreationLimitMilliseconds, 25); + KEY_BOOL (fatalOnGoldPobChange, false); + KEY_INT (lineOfSightCacheDurationMs, 1500); + KEY_FLOAT (lineOfSightCacheMinHeight, 0.8f); + KEY_FLOAT (lineOfSightLocationRoundValue, 5.0f); + +#ifdef _DEBUG + // in debug mode, we default this to true so that unless + // a controller message is explicitly marked as being allowed + // from the client, it will be dropped when the game server + // receives it; this will have the effect of forcing the + // programmer to make a conscious decision to mark the + // controller message as allowable from the client; because + // controller message coming from the client is not secured, + // the mechanism to prevent a hacked client from sending the + // game server any controller message is to explicity "mark" + // those controller messages that are allowed from the client + KEY_BOOL (enableClientControllerMessageCheck, true); +#else + // for live, the this option will be set to true in the config file + KEY_BOOL (enableClientControllerMessageCheck, false); +#endif + + KEY_INT (maxWaypointsPerCharacter,100); // Keep this in sync with the maxWaypoints value in ConfigClientGame.cpp + KEY_FLOAT (maxSmallCreatureHeight, 0.7f); + KEY_FLOAT (smallCreatureUpdateRadius, 64.0f); + KEY_FLOAT (maxMediumCreatureHeight, 3.0f); + KEY_FLOAT (mediumCreatureUpdateRadius, 128.0f); + KEY_FLOAT (largeCreatureUpdateRadius, 256.0f); + KEY_INT (coolDownPersistThresholdSeconds, 1 * 60); + KEY_BOOL (checkNotifyRegions, true); + KEY_BOOL (allowRegionTriggerOverride, true); + KEY_INT (spacePlanetServerUpdatesPerFrame, 0); + KEY_FLOAT (hyperspaceRandomOffsetRange, 200); + + if (data->theaterCreationLimitMilliseconds <= 0) + { + data->theaterCreationLimitMilliseconds = 25; + WARNING(true, ("Config value [GameServer] theaterCreationLimitMilliseconds " + "out of range, setting to default value")); + } + + KEY_BOOL (sendAsteroidExtents, false); + KEY_BOOL (createZoneObjects, true); + KEY_INT (shipUpdatesPerSecond, 32); + KEY_BOOL (debugSpaceVisibilityManager, false); + KEY_INT (groundFrameRateLimit, 5); + KEY_INT (spaceFrameRateLimit, 12); + KEY_BOOL (aiLoggingEnabled, false); + KEY_BOOL (shipShotValidationEnabled, false); + KEY_INT (spaceAiEnemySearchesPerFrame, 15); + KEY_BOOL (groundShouldSleep, true); + KEY_BOOL (spaceShouldSleep, true); + KEY_BOOL (shipMoveValidationEnabled, false); + KEY_INT (shipMoveCheckIntervalMs, 1000); + KEY_INT (shipMoveCheckFudgeTimeMs, 5000); + KEY_FLOAT (shipMoveCheckTolerance, 1.03f); + KEY_FLOAT (shipMoveCheckTimeToleranceSeconds, 0.1f); + KEY_INT (spaceAiAvoidanceChecksPerFrame, 64); + KEY_BOOL (spaceAiUsePathRefinement, true); + KEY_BOOL (aiClientDebugEnabled, false); + KEY_BOOL (shipClientUpdateDebugEnabled, false); + KEY_FLOAT (shipLoadInvulnerableTimeWithoutClient, 120.f); + KEY_FLOAT (shipLoadInvulnerableTimeWithClient, 10.f); + KEY_FLOAT (creatureLoadInvulnerableTimeWithoutClient, 120.f); + KEY_FLOAT (creatureLoadInvulnerableTimeWithClient, 1.f); + KEY_BOOL (buildoutAreaEditingEnabled, false); + KEY_BOOL (debugFloorPathNodeCount, false); // this flag checks cells to make sure the floor part count equals the path graph node count + KEY_INT (populationReportTimeSeconds, 600); + KEY_FLOAT(maxCombatRange, 96.0f); + KEY_BOOL (blockBuildRegionPlacement,false); + + KEY_INT (npeMinInstancePopulation,20); + KEY_INT (npeMaxInstancePopulation,50); + KEY_BOOL (stripNonFreeAssetsFromPlayersInTutorial, false); + + // weekly time (in GMT) when GCW rating recalculation occurs + KEY_INT (gcwRecalcTimeDayOfWeek, 4); // Sunday=0, Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6 + KEY_INT (gcwRecalcTimeHour, 19); // 0 - 23 + KEY_INT (gcwRecalcTimeMinute, 0); // 0 - 59 + KEY_INT (gcwRecalcTimeSecond, 0); // 0 - 59 + + // weekly time (in GMT) when GCW score decay occurs; + // additional time(s) can be specified in the config file if + // you want the GCW score decay to occur more than once a week; + // the following time is ignored if any time(s) is specified + // in the config file; if no time(s) is specified in the + // config file, it will use the following time as the default + KEY_INT (gcwScoreDecayTimeDayOfWeek, 1); // Sunday=0, Monday=1, Tuesday=2, Wednesday=3, Thursday=4, Friday=5, Saturday=6 + KEY_INT (gcwScoreDecayTimeHour, 19); // 0 - 23 + KEY_INT (gcwScoreDecayTimeMinute, 0); // 0 - 59 + KEY_INT (gcwScoreDecayTimeSecond, 0); // 0 - 59 + + KEY_INT (chatStatisticsReportIntervalSeconds, 60); + KEY_INT (chatSpamLimiterNumCharacters, 400); + KEY_INT (chatSpamLimiterIntervalMinutes, 15); + KEY_BOOL (chatSpamLimiterEnabledForFreeTrial, true); + KEY_INT (chatSpamNotifyPlayerWhenLimitedIntervalSeconds, 30); // <= 0 to disable + + KEY_INT (pendingLoadRequestLimit, 1000000000); // unlimited + + KEY_BOOL (enableCityCitizenshipFixup, true); + + KEY_INT (cityCitizenshipInactivePackupStartTimeEpoch, 1243839660); // June 1st 2009 12:01AM PDT + KEY_INT (cityCitizenshipInactivePackupInactiveTimeSeconds, 90 * 24 * 60 * 60); // 90 days + + KEY_STRING (retroactivePlayerCityCreationTimeFilename, ""); + + KEY_INT (wardenSquelchDurationSeconds, 6 * 60 * 60); // 6 hours + KEY_BOOL (enableWarden, true); + KEY_BOOL (enableWardenCanSquelchSecuredLogin, false); + KEY_BOOL (enableWardenToDeputizeWarden, true); + + KEY_BOOL (disableCollectionServerFirstGrantForSecuredLogin, false); + + KEY_INT (locateStructureCommandIntervalSeconds, 24 * 60 * 60); // 24 hours + + KEY_INT (locateVendorCommandIntervalSeconds, 15 * 60); // 15 minutes + + KEY_INT (ctsDefaultScriptDictionarySizeBytes, 10 * 1024 * 1024); // 10M + KEY_STRING (retroactiveCtsHistoryFilename, ""); + KEY_BOOL (allowIgnoreFreeCtsTimeRestriction, false); + + KEY_INT (groupPickupPointApprovalRangeSquared, 20 * 20); + KEY_INT (groupPickupPointTimeLimitSeconds, 2 * 60); + KEY_INT (groupPickupTravelPlayerCityPercent, 10); + + KEY_BOOL (groupInviteInviterCombatRestriction, false); + KEY_BOOL (groupInviteInviteeCombatRestriction, false); + KEY_BOOL (groupJoinInviterCombatRestriction, false); + KEY_BOOL (groupJoinInviteeCombatRestriction, false); + + KEY_INT (characterMatchMaxMatchCount, 32); + + KEY_BOOL (enableOccupyUnlockedSlotCommand, true); + KEY_BOOL (enableVacateUnlockedSlotCommand, true); + KEY_BOOL (enableSwapUnlockedSlotCommand, true); + KEY_INT (occupyVacateUnlockedSlotCommandCooldownSeconds, 24 * 60 * 60); // 24 hours + + KEY_INT (accountFeatureIdForMonthlyBoosterPack, 5032); + KEY_INT (accountFeatureIdForTcgBetaAnnouncement, 5552); + + KEY_BOOL (logEventObjectCreation, false); + KEY_BOOL (logEventObjectDestruction, false); + KEY_STRING (housePackupAccountListDataTableName, "datatables/house_packup/house_packup_accounts.iff"); + + KEY_INT (pickDropAllRoomItemsNumberOfItemsPerRound, 5); + + KEY_BOOL (enableCovertImperialMercenary, false); + KEY_BOOL (enableOvertImperialMercenary, false); + KEY_BOOL (enableCovertRebelMercenary, false); + KEY_BOOL (enableOvertRebelMercenary, false); + KEY_INT (broadcastGcwScoreToOtherGalaxiesIntervalSeconds, 15 * 60); // 15 minutes + KEY_BOOL (broadcastGcwScoreToOtherGalaxies, false); + KEY_BOOL (receiveGcwScoreFromOtherGalaxies, false); + KEY_INT (trackGcwPercentileHistoryCount, 10); + KEY_BOOL (gcwFactionalPresenceDisableForSecuredLogin, false); + + KEY_INT (gcwFactionalPresenceMountedPct, 20); // 0 to disable FP while on a vehicle/mount, 100 for no FP penalty while on a vehicle/mount + // clamp to 0 - 100 + data->gcwFactionalPresenceMountedPct = std::min(std::max(data->gcwFactionalPresenceMountedPct, 0), 100); + + KEY_INT (gcwFactionalPresenceLevelPct, 10); + KEY_INT (gcwFactionalPresenceGcwRankBonusPct, 10); + KEY_INT (gcwFactionalPresenceAlignedCityBonusPct, 100); + KEY_INT (gcwFactionalPresenceAlignedCityRankBonusPct, 10); + KEY_INT (gcwFactionalPresenceAlignedCityAgeBonusPct, 5); + KEY_INT (gcwGuildMinMembersForGcwRegionDefender, 10); + KEY_INT (gcwRegionDefenderTotalBonusPct, 20); + KEY_INT (gcwDaysRequiredForGcwRegionDefenderBonus, 3); + + KEY_FLOAT (regionFlagUpdateTime, 0.5f); + + if (data->baseDecayRate <= 1.0f) + data->baseDecayRate = 1.0f; + + if (data->weaponDecayThreshold < 0.0f) + data->weaponDecayThreshold = 0.0f; + else if (data->weaponDecayThreshold > 100.0f) + data->weaponDecayThreshold = 100.0f; + data->weaponDecayThreshold /= 100.0f; + + if (data->armorDamageReduction < 0.0f) + data->armorDamageReduction = 0.0f; + else if (data->armorDamageReduction > 100.0f) + data->armorDamageReduction = 100.0f; + data->armorDamageReduction = 1.0f - data->armorDamageReduction / 100.0f; + + if (data->gcwXpBonus < 0.0f) + data->gcwXpBonus = 0.0f; + data->gcwXpBonus /= 100.0f; + + // GCW score decay time(s) + data->gcwScoreDecayTime.clear(); + int index = 0; + char const * dayOfWeek = NULL; + char const * hour = NULL; + char const * minute = NULL; + char const * second = NULL; + do + { + dayOfWeek = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeDayOfWeek", index, 0); + hour = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeHour", index, 0); + minute = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeMinute", index, 0); + second = ConfigFile::getKeyString("GameServer", "gcwScoreDecayTimeSecond", index, 0); + + if (dayOfWeek && hour && minute && second) + { + data->gcwScoreDecayTime.push_back(std::make_pair(std::make_pair(ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeDayOfWeek", index, 0), ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeHour", index, 0)), std::make_pair(ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeMinute", index, 0), ConfigFile::getKeyInt("GameServer", "gcwScoreDecayTimeSecond", index, 0)))); + } + + ++index; + } + while (dayOfWeek && hour && minute && second); + + if (data->gcwScoreDecayTime.empty()) + { + data->gcwScoreDecayTime.push_back(std::make_pair(std::make_pair(data->gcwScoreDecayTimeDayOfWeek, data->gcwScoreDecayTimeHour), std::make_pair(data->gcwScoreDecayTimeMinute, data->gcwScoreDecayTimeSecond))); + } +} + +//------------------------------------------------------------------- + +void ConfigServerGame::remove(void) +{ + ConfigServerUtility::remove(); +} + +//------------------------------------------------------------------- + +const std::string & ConfigServerGame::getCraftingComponentTableFile( + const std::string & name) +{ +static const std::string NO_DATA; + + std::map::const_iterator iter; + iter = m_components.find(name); + if (iter != m_components.end()) + return (*iter).second; + if (!m_components.empty()) + return m_components["component"]; + return NO_DATA; +} + +// ====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/core/GameServer.cpp b/src/engine/server/library/serverGame/src/shared/core/GameServer.cpp index fad853bde..d7bf0c214 100644 --- a/src/engine/server/library/serverGame/src/shared/core/GameServer.cpp +++ b/src/engine/server/library/serverGame/src/shared/core/GameServer.cpp @@ -1,6094 +1,6094 @@ -// GameServer.cpp -// copyright 2000 Verant Interactive -// Author: Justin Randall - -//----------------------------------------------------------------------- - -#include "serverGame/FirstServerGame.h" -#include "serverGame/GameServer.h" - -#include "serverGame/AiMovementBase.h" -#include "serverGame/AiCreatureController.h" -#include "serverGame/AiShipController.h" -#include "serverGame/AttribModNameManager.h" -#include "serverGame/AuthTransferTracker.h" -#include "serverGame/BiographyManager.h" -#include "serverGame/BuildingObject.h" -#include "serverGame/CellObject.h" -#include "serverGame/CentralConnection.h" -#include "serverGame/CharacterMatchManager.h" -#include "serverGame/Chat.h" -#include "serverGame/ChatServerConnection.h" -#include "serverGame/CitizenInfo.h" -#include "serverGame/CityInfo.h" -#include "serverGame/CityInterface.h" -#include "serverGame/CityObject.h" -#include "serverGame/Client.h" -#include "serverGame/ClusterWideDataClient.h" -#include "serverGame/CombatTracker.h" -#include "serverGame/CommandCppFuncs.h" -#include "serverGame/CommoditiesMarket.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ConnectionServerConnection.h" -#include "serverGame/ConsoleManager.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/CustomerServiceServerConnection.h" -#include "serverGame/DatabaseProcessConnection.h" -#include "serverGame/GameServerMetricsData.h" -#include "serverGame/GuildInterface.h" -#include "serverGame/GuildObject.h" -#include "serverGame/HarvesterInstallationObject.h" -#include "serverGame/LogoutTracker.h" -#include "serverGame/ManufactureInstallationObject.h" -#include "serverGame/MessageToQueue.h" -#include "serverGame/MissileManager.h" -#include "serverGame/NameManager.h" -#include "serverGame/NewbieTutorial.h" -#include "serverGame/NonCriticalTaskQueue.h" -#include "serverGame/ObjectIdManager.h" -#include "serverGame/ObjectTracker.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PlanetObject.h" -#include "serverGame/PlanetServerConnection.h" -#include "serverGame/PlayerCreationManagerServer.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/PlayerSanityChecker.h" -#include "serverGame/PlayerShipController.h" -#include "serverGame/PositionUpdateTracker.h" -#include "serverGame/PurgeManager.h" -#include "serverGame/Region.h" -#include "serverGame/RegionMaster.h" -#include "serverGame/ResourceTypeObject.h" -#include "serverGame/ServerAsteroidManager.h" -#include "serverGame/SceneGlobalData.h" -#include "serverGame/ServerBuildoutManager.h" -#include "serverGame/ServerCommandPermissionManager.h" -#include "serverGame/ServerCommandTable.h" -#include "serverGame/ServerController.h" -#include "serverGame/ServerCreatureObjectTemplate.h" -#include "serverGame/ServerImageDesignerManager.h" -#include "serverGame/ServerMessageForwarding.h" -#include "serverGame/ServerObjectTerrainModificationNotification.h" -#include "serverGame/ServerUIManager.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/ShipAiReactionManager.h" -#include "serverGame/ShipClientUpdateTracker.h" -#include "serverGame/ShipObject.h" -#include "serverGame/StationPlayersCollectorAPI.h" -#include "serverGame/SurveySystem.h" -#include "serverGame/TangibleObject.h" -#include "serverGame/TaskManagerConnection.h" -#include "serverGame/VeteranRewardManager.h" -#include "serverMetrics/MetricsManager.h" -#include "serverNetworkMessages/AccountFeatureIdRequest.h" -#include "serverNetworkMessages/AccountFeatureIdResponse.h" -#include "serverNetworkMessages/AddCharacterMessage.h" -#include "serverNetworkMessages/AddResourceTypeMessage.h" -#include "serverNetworkMessages/AdjustAccountFeatureIdResponse.h" -#include "serverNetworkMessages/AiMovementMessage.h" -#include "serverNetworkMessages/AiCreatureStateMessage.h" -#include "serverNetworkMessages/AuthTransferClientMessage.h" -#include "serverNetworkMessages/BiographyMessage.h" -#include "serverNetworkMessages/CentralGameServerMessages.h" -#include "serverNetworkMessages/CentralPingMessage.h" -#include "serverNetworkMessages/CharacterNamesMessage.h" -#include "serverNetworkMessages/ChatServerOnline.h" -#include "serverNetworkMessages/ChunkCompleteMessage.h" -#include "serverNetworkMessages/ClaimRewardsReplyMessage.h" -#include "serverNetworkMessages/CreateDynamicRegionCircleMessage.h" -#include "serverNetworkMessages/CreateDynamicRegionRectangleMessage.h" -#include "serverNetworkMessages/CreateDynamicSpawnRegionCircleMessage.h" -#include "serverNetworkMessages/CreateGroupMessage.h" -#include "serverNetworkMessages/CreateObjectMessage.h" -#include "serverNetworkMessages/CreateSyncUiMessage.h" -#include "serverNetworkMessages/EnableNewJediTrackingMessage.h" -#include "serverNetworkMessages/EndBaselinesMessage.h" -#include "serverNetworkMessages/ExcommunicateGameServerMessage.h" -#include "serverNetworkMessages/FactionalSystemMessage.h" -#include "serverNetworkMessages/FailedToLoadObjectMessage.h" -#include "serverNetworkMessages/FeatureIdTransactionResponse.h" -#include "serverNetworkMessages/FirstPlanetGameServerIdMessage.h" -#include "serverNetworkMessages/GameConnectionServerMessages.h" -#include "serverNetworkMessages/GameGameServerMessages.h" -#include "serverNetworkMessages/GameServerConnectAck.h" -#include "serverNetworkMessages/GameServerReadyMessage.h" -#include "serverNetworkMessages/GameServerUniverseLoadedMessage.h" -#include "serverNetworkMessages/GameTaskManagerMessages.h" -#include "serverNetworkMessages/GetMoneyFromOfflineObjectMessage.h" -#include "serverNetworkMessages/LoadContainedObjectMessage.h" -#include "serverNetworkMessages/LoadContentsMessage.h" -#include "serverNetworkMessages/LocateObjectResponseMessage.h" -#include "serverNetworkMessages/LocatePlayerResponseMessage.h" -#include "serverNetworkMessages/LoadObjectMessage.h" -#include "serverNetworkMessages/LoadStructureMessage.h" -#include "serverNetworkMessages/LoadUniverseMessage.h" -#include "serverNetworkMessages/LocateStructureMessage.h" -#include "serverNetworkMessages/LocationResponse.h" -#include "serverNetworkMessages/MessageToAckMessage.h" -#include "serverNetworkMessages/NewClient.h" -#include "serverNetworkMessages/PersistedPlayerMessage.h" -#include "serverNetworkMessages/PlayedTimeAccumMessage.h" -#include "serverNetworkMessages/PopulationListMessage.h" -#include "serverNetworkMessages/PreloadRequestCompleteMessage.h" -#include "serverNetworkMessages/ProfilerOperationMessage.h" -#include "serverNetworkMessages/RandomName.h" -#include "serverNetworkMessages/ReloadAdminTableMessage.h" -#include "serverNetworkMessages/ReloadCommandTableMessage.h" -#include "serverNetworkMessages/ReloadDatatableMessage.h" -#include "serverNetworkMessages/ReloadScriptMessage.h" -#include "serverNetworkMessages/ReloadTemplateMessage.h" -#include "serverNetworkMessages/RenameCharacterMessage.h" -#include "serverNetworkMessages/RetrievedItemLoadMessage.h" -#include "serverNetworkMessages/SceneTransferMessages.h" -#include "serverNetworkMessages/SetAuthoritativeMessage.h" -#include "serverNetworkMessages/SetPlanetServerMessage.h" -#include "serverNetworkMessages/SetUniverseAuthoritativeMessage.h" -#include "serverNetworkMessages/StructuresForPurgeMessage.h" -#include "serverNetworkMessages/SynchronizeScriptVarDeltasMessage.h" -#include "serverNetworkMessages/SynchronizeScriptVarsMessage.h" -#include "serverNetworkMessages/TeleportMessage.h" -#include "serverNetworkMessages/TeleportToMessage.h" -#include "serverNetworkMessages/TransferCharacterData.h" -#include "serverNetworkMessages/TransferCharacterDataArchive.h" -#include "serverNetworkMessages/TransferReplyMoveValidation.h" -#include "serverNetworkMessages/UnloadObjectMessage.h" -#include "serverNetworkMessages/UnloadProxyMessage.h" -#include "serverNetworkMessages/UpdateObjectPositionMessage.h" -#include "serverNetworkMessages/UploadCharacterMessage.h" -#include "serverNetworkMessages/VerifyAndLockName.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptDictionary.h" -#include "serverScript/ScriptParameters.h" -#include "serverUtility/AdminAccountManager.h" -#include "serverUtility/ServerClock.h" -#include "Session/CommonAPI/CommonAPI.h" -#include "sharedCollision/CollisionProperty.h" -#include "sharedDebug/DebugFlags.h" -#include "sharedDebug/DebugMonitor.h" -#include "sharedDebug/Profiler.h" -#include "sharedFile/Iff.h" -#include "sharedFile/TreeFile.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/Clock.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/ConfigSharedFoundation.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/DynamicVariableList.h" -#include "sharedFoundation/ExitChain.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/GameControllerMessage.h" -#include "sharedFoundation/Os.h" -#include "sharedGame/AppearanceManager.h" -#include "sharedGame/CombatDataTable.h" -#include "sharedGame/CommandTable.h" -#include "sharedGame/OutOfBandPackager.h" -#include "sharedGame/PlatformFeatureBits.h" -#include "sharedGame/ProsePackage.h" -#include "sharedGame/PvpData.h" -#include "sharedGame/QuestManager.h" -#include "sharedLog/FileLogObserver.h" -#include "sharedLog/Log.h" -#include "sharedMessageDispatch/MessageManager.h" -#include "sharedNetwork/NetworkSetupData.h" -#include "sharedNetwork/Service.h" -#include "sharedNetworkMessages/BaselinesMessage.h" -#include "sharedNetworkMessages/BatchBaselinesMessage.h" -#include "sharedNetworkMessages/ConsoleChannelMessages.h" -#include "sharedNetworkMessages/DeltasMessage.h" -#include "sharedNetworkMessages/FrameEndMessage.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/HyperspaceMessage.h" -#include "sharedNetworkMessages/MessageQueueGenericValueType.h" -#include "sharedNetworkMessages/NameErrors.h" -#include "sharedNetworkMessages/ObjectChannelMessages.h" -#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" -#include "sharedNetworkMessages/SlowDownEffectMessage.h" -#include "sharedNetworkMessages/UpdateContainmentMessage.h" -#include "sharedObject/AlterScheduler.h" -#include "sharedObject/AppearanceTemplateList.h" -#include "sharedObject/CellProperty.h" -#include "sharedObject/ContainedByProperty.h" -#include "sharedObject/Container.h" -#include "sharedObject/NetworkController.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectList.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedObject/PortalProperty.h" -#include "sharedObject/SlotIdManager.h" -#include "sharedObject/SlottedContainer.h" -#include "sharedPathfinding/Pathfinding.h" -#include "sharedSkillSystem/SkillManager.h" -#include "sharedSkillSystem/SkillObject.h" -#include "sharedTerrain/ProceduralTerrainAppearance.h" -#include "sharedTerrain/TerrainObject.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" -#include "swgSharedUtility/SpeciesRestrictions.h" -#include "unicodeArchive/UnicodeArchive.h" - -#include - -//----------------------------------------------------------------------- - -//#undef PROFILE_INDIVIDUAL_MESSAGES -#define PROFILE_INDIVIDUAL_MESSAGES 1 - -#ifdef PROFILE_INDIVIDUAL_MESSAGES - #define MESSAGE_PROFILER_BLOCK(a) PROFILER_AUTO_BLOCK_DEFINE(a) -#else - #define MESSAGE_PROFILER_BLOCK(a) NOP -#endif - -//----------------------------------------------------------------------- - -namespace GameServerNamespace -{ - bool gs_gameServerReady = false; - const float IDLE_CLIENTS_CHECK_TIME_SEC = 30.0f; - ServerCommandPermissionManager * s_permissionManager = 0; - - unsigned long s_frameTime; - uint64 s_totalObjectCreateMessagesReceived; - uint64 s_totalObjectCreateMessagesSent; - bool s_metricsManagerInstalled = false; - uint32 s_lastTaskKeepaliveTime = 0; - -#ifdef _DEBUG - int s_extraDelayPerFrameMs = 0; // to emulate long loop time -#endif - - std::set s_clusterStartupResidenceStructureListResponse; - std::map > s_clusterStartupResidenceStructureListByStructure; - - unsigned long getFrameRateLimit(); - void broadCastHyperspaceOnWarp(ServerObject const * owner); - ShipObject *getAttachedShip(CreatureObject *creature); - - std::map s_pendingLoadRequests; - - struct CtsSourceCharacterInfo - { - time_t transferTime; - std::string sourceCluster; - NetworkId sourceCharacterId; - std::string sourceCharacterName; - int sourceCharacterBornDate; - std::vector > sourceCharacterRetroactiveObjvars; - }; - - // any particular target character may have gone through multiple transfers - // so we want to keep a list (ordered by transfer time) of all the transfers - // the character has gone through - // - // for release build, we only care about transfers into our cluster; - // for debug build, read them all so we can test out the logic to - // make sure it works for all clusters - // - // transfer time, source character info - // target character id - // target cluster - // \/ \/ \/ -#ifdef _DEBUG - std::map > > s_retroactiveCtsHistoryList; -#else - std::map > s_retroactiveCtsHistoryListThisCluster; -#endif - - void loadRetroactiveCtsHistory(); - - // retroactive player city creation time - // - // city creation time - // city id - // cluster - // \/ \/ \/ -#ifdef _DEBUG - std::map > s_retroactivePlayerCityCreationTime; -#else - std::map s_retroactivePlayerCityCreationTimeThisCluster; -#endif - - void loadRetroactivePlayerCityCreationTime(); - - bool getConfigSetting(const char *section, const char *key, int & value) - { - const ConfigFile::Section * sec = ConfigFile::getSection(section); - if (sec == NULL) - return false; - - const ConfigFile::Key * ky = sec->findKey(key); - if (ky == NULL) - return false; - - value = ky->getAsInt(ky->getCount()-1, value); - return true; - } - - const std::string OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER("hasOutstandingRequestSceneTransfer"); - bool checkAndSetOutstandingRequestSceneTransfer(ServerObject & object); - - void handleFactionalSystemMessage(FactionalSystemMessage const & msg); - void handleMessageToPlayersOnPlanet(std::string const & methodName, std::vector const & params, float delay, Vector const & loc, float radius, bool includeDisconnectedPlayers); - void handleMessageLocateStructureByOwnerIdReq(GameServer & gsInstance, uint32 responsePid, bool isGod, NetworkId const & ownerId, NetworkId const & ownerResidenceId, NetworkId const & responseId); - void handleMessageLocateStructureByOwnerIdRsp(NetworkId const & responseId, std::vector const & response); - void handleAdjustAccountFeatureIdResponse(AdjustAccountFeatureIdResponse const & msg); - void handleAccountFeatureIdResponse(AccountFeatureIdResponse const & msg); - - namespace SlotNames - { - static const ConstCharCrcLowerString appearance ("appearance_inventory"); - } - - const char* s_appearanceTemplate = "object/tangible/inventory/appearance_inventory.iff"; - -} - -using namespace GameServerNamespace; - -//---------------------------------------------------------------------- - -GameServer * GameServer::ms_instance = 0; - -//----------------------------------------------------------------------- - -GameServer::GameServer() : -MessageDispatch::Receiver(), -m_done (false), -m_processId (0), -m_preloadAreaId (0), -m_databaseProcessId (0), -m_gameServerPids (), -m_centralService (), -m_centralServerConnection (0), -m_customerServiceServerConnection (0), -m_connectionServerVector (new ConnectionServerVector), -m_planetServerConnection (0), -m_databaseProcessConnection (0), -m_pendingDatabaseProcessConnection (0), -m_taskManagerConnection (), -m_clients (new ClientMap), -m_clientService (), -m_clusterName (), -m_clusterId (0), -m_firstGameServerForPlanet (0), -m_pendingContainedObjects (new PendingContainedObjectsMap), -m_charactersPendingCreation (new CharactersPendingCreationMap), -m_metricsData (0), -m_gameServerReadyObjectIds (false), -m_gameServerReadyDatabaseConnected (false), -m_gameServerReadyPlanetConnected (false), -m_connectionTimeout (false), -m_chatServerConnection (0) -{ - IGNORE_RETURN(SkillManager::getInstance().getRoot ()); - - ObjectIdManager::getInstance(); - // set up central server connection - m_centralService = new CentralServerConnection(ConfigServerGame::getCentralServerAddress(), ConfigServerGame::getCentralServerPort()); - connectToMessage("CentralConnectionOpened"); - connectToMessage("CentralConnectionClosed"); - - //Add connection server messages - connectToMessage("ConnectionServerAddress"); - connectToMessage("ConnectionServerClosed"); - connectToMessage("NewClient"); - - connectToMessage("TaskConnectionClosed"); - - // set up Commodity server connection - connectToMessage("CommoditiesServerConnectionClosed"); - - // application messages - connectToMessage("BaselinesMessage"); - connectToMessage("BatchBaselinesMessage"); - connectToMessage("DeltasMessage"); - connectToMessage("ChunkCompleteMessage"); - connectToMessage("CentralGameServerSetProcessId"); - connectToMessage("GameServerSetupMessage"); - connectToMessage("LoadUniverseMessage"); - connectToMessage("PlanetConnectionClosed"); - connectToMessage("PlanetConnectionOpened"); - connectToMessage("SetPlanetServerMessage"); - connectToMessage("SetUniverseAuthoritativeMessage"); - connectToMessage("CentralCreateCharacter"); - connectToMessage("CreateDynamicSpawnRegionCircle"); - connectToMessage("CreateDynamicRegionCircleMessage"); - connectToMessage("CreateDynamicRegionRectangleMessage"); - connectToMessage("CreateGroupMessage"); - connectToMessage("CreateObjectByCrcMessage"); - connectToMessage("CreateSyncUiMessage"); - connectToMessage("DropClient"); - connectToMessage("EnableNewJediTrackingMessage"); - connectToMessage("EndBaselinesMessage"); - connectToMessage("GameSetProcessId"); - connectToMessage("GameServerConnectAck"); - connectToMessage("LoadObjectMessage"); - connectToMessage("ObjControllerMessage"); - connectToMessage("ProfilerOperationMessage"); - connectToMessage("SetAuthoritativeMessage"); - connectToMessage("SynchronizationMessage"); - connectToMessage("TaskShutdownGameServer"); - connectToMessage("UniverseCompleteMessage"); - connectToMessage("GameServerUniverseLoadedMessage"); - connectToMessage("AddResourceTypeMessage"); - connectToMessage("AddImportedResourceType"); - connectToMessage("PreloadRequestCompleteMessage"); - connectToMessage("UnloadObjectMessage"); - connectToMessage("VerifyNameResponse"); - connectToMessage("SceneTransferMessage"); - connectToMessage("RandomNameRequest"); // from connection server - connectToMessage("VerifyAndLockNameRequest"); // from connection server - - connectToMessage("ChatServerOnline"); - connectToMessage("ChatServerConnectionClosed"); - connectToMessage("TeleportMessage"); - connectToMessage("TeleportToMessage"); - connectToMessage("RetrievedItemLoadMessage"); - connectToMessage("UnloadProxyMessage"); - connectToMessage("BiographyMessage"); - connectToMessage("LoadContainedObjectMessage"); - connectToMessage("LoadContentsMessage"); - connectToMessage("FirstPlanetGameServerIdMessage"); - connectToMessage("ReloadAdminTableMessage"); - connectToMessage("ReloadCommandTableMessage"); - connectToMessage(ReloadDatatableMessage::ms_messageName); - connectToMessage("ReloadScriptMessage"); - connectToMessage("ReloadTemplateMessage"); - connectToMessage("AuthTransferConfirmMessage"); - connectToMessage("ConnectionServerConnectionDestroyed"); - connectToMessage("PersistedPlayerMessage"); - connectToMessage("RenameCharacterMessageEx"); - connectToMessage("PopulationListMessage"); - connectToMessage("UpdateObjectPositionMessage"); - connectToMessage("UpdateContainmentMessage"); - connectToMessage("SynchronizeScriptVarsMessage"); - connectToMessage("SynchronizeScriptVarDeltasMessage"); - connectToMessage("CentralPingMessage"); - connectToMessage("AddGameServer"); - connectToMessage("ExcommunicateGameServerMessage"); - connectToMessage("LocateObject"); - connectToMessage("LocateObjectByTemplateName"); - connectToMessage("LocatePlayerByPartialName"); - connectToMessage("LocateWarden"); - connectToMessage("LocateCreatureByCreatureName"); - connectToMessage("LSBOIReq"); - connectToMessage("LSBOIRsp"); - connectToMessage("LocateStructureMessage"); - connectToMessage("LoadStructureMessage"); - connectToMessage("LocateObjectResponseMessage"); - connectToMessage("LocatePlayerResponseMessage"); - connectToMessage("PlayerSanityCheck"); - connectToMessage("PlayerSanityCheckSuccess"); - connectToMessage("PlayerSanityCheckProxy"); - connectToMessage("PlayerSanityCheckProxyFail"); - connectToMessage("EnablePlayerSanityCheckerMessage"); - connectToMessage("StartSaveReplyMessage"); - connectToMessage("DatabaseConsoleReplyMessage"); - connectToMessage("FindAuthObject"); - connectToMessage("CharacterNamesMessage"); - connectToMessage("DownloadCharacterMessage"); - connectToMessage("UploadCharacterMessage"); - connectToMessage("LocationResponse"); - connectToMessage("ReleaseCharacterNameByIdMessage"); - connectToMessage("AddAttribModName"); - connectToMessage("AddAttribModNamesList"); - connectToMessage("CustomerServiceServerGameServerServiceAddress"); - connectToMessage("AiCreatureStateMessage"); - connectToMessage("UnloadPersistedCharacter"); - connectToMessage("AboutToLoadCharacterFromDB"); - connectToMessage("AuthTransferClientMessage"); - connectToMessage("ClearTheaterMessage"); - connectToMessage("SetTheaterMessage"); - connectToMessage("PageChangeAuthority"); - connectToMessage("ManualDepleteResourceMessage"); - connectToMessage("GetMoneyFromOfflineObjectMessage"); - connectToMessage("ClaimRewardsReplyMessage"); - connectToMessage("SetOverrideAccountAgeMessage"); - connectToMessage("StructuresForPurgeMessage"); - connectToMessage(SlowDownEffectMessage::MessageType); - connectToMessage("PlayedTimeAccumMessage"); - connectToMessage("RequestLoadAckMessage"); - connectToMessage("FactionalSystemMessage"); - connectToMessage("MessageToPlayersOnPlanet"); - connectToMessage("ReportSystemClockTime"); - connectToMessage("ReportSystemClockTimeResponse"); - connectToMessage("ReportPlanetaryTime"); - connectToMessage("ReportPlanetaryTimeResponse"); - connectToMessage("ClusterStartComplete"); - connectToMessage("CSRSLReq"); - connectToMessage("CSRSLRsp"); - connectToMessage("PopStatReq"); - connectToMessage("GcwScoreStatReq"); - connectToMessage("GcwScoreStatRaw"); - connectToMessage("GcwScoreStatPct"); - connectToMessage("LLTStatReq"); - connectToMessage("LfgStatReq"); - connectToMessage("ClusterId"); - connectToMessage("OccupyUnlockedSlotRsp"); - connectToMessage("VacateUnlockedSlotRsp"); - connectToMessage("SwapUnlockedSlotRsp"); - connectToMessage("AdjustAccountFeatureIdResponse"); - connectToMessage("AccountFeatureIdResponse"); - connectToMessage("FeatureIdTransactionResponse"); - connectToMessage("TransferReplyMoveValidation"); - connectToMessage("TransferReplyNameValidation"); - - // Cluster wide data client - ClusterWideDataClient::install(); - ClusterWideDataClient::registerMessage(*this); - - m_taskManagerConnection = new TaskManagerConnection("127.0.0.1", ConfigServerGame::getTaskManagerPort()); -} - -//----------------------------------------------------------------------- - -GameServer::~GameServer() -{ - m_chatServerConnection = 0; - delete m_clients; - m_clients = 0; - delete m_connectionServerVector; - m_connectionServerVector = 0; - - delete m_pendingContainedObjects; - m_pendingContainedObjects = 0; - delete m_charactersPendingCreation; - m_charactersPendingCreation = 0; -} - -//---------------------------------------------------------------------- - -void GameServer::install () -{ - DEBUG_FATAL (ms_instance, ("already installed")); - ms_instance = new GameServer; -} - -//---------------------------------------------------------------------- - -void GameServer::remove () -{ - // ok to remove an uninstalled GameServer singleton. - delete ms_instance; - ms_instance = 0; -} - -//----------------------------------------------------------------------- - -uint64 GameServer::getTotalObjectCreatesReceived() // static -{ - return s_totalObjectCreateMessagesReceived; -} - -//----------------------------------------------------------------------- - -uint64 GameServer::getTotalObjectCreatesSent() // static - { - return s_totalObjectCreateMessagesSent; -} - -//----------------------------------------------------------------------- - -void GameServer::incrementTotalObjectCreatesSent() // static - { - ++s_totalObjectCreateMessagesSent; -} - -//----------------------------------------------------------------------- -void GameServer::reportClusterStartupResidenceStructure(int cityId, const NetworkId & structureId, const NetworkId & ownerId) // static -{ - s_clusterStartupResidenceStructureListByStructure[structureId] = std::make_pair(cityId, ownerId); -} - -//----------------------------------------------------------------------- - -void GameServer::reportBuildingObjectDestroyed(const NetworkId & structureId) -{ - if (!s_clusterStartupResidenceStructureListByStructure.empty()) - IGNORE_RETURN(s_clusterStartupResidenceStructureListByStructure.erase(structureId)); -} - -//----------------------------------------------------------------------- - -/** - * Establish a connection to a game server (if not already connected). - */ -void GameServer::connectToDatabaseProcess(std::string const &address, uint16 port, uint32 pid) -{ - FATAL(m_pendingDatabaseProcessConnection, ("Tried to connect to database process with connection still pending?")); - FATAL(m_databaseProcessConnection, ("Tried to connect to database process when alrady connected?")); - - m_pendingDatabaseProcessConnection = new DatabaseProcessConnection(address, port, pid); - - LOG("GameGameConnect", ("Game Server %lu is connecting to database process, pid %lu, addr %s port %d", m_processId, pid, address.c_str(), static_cast(port))); -} - -//------------------------------------------------------------------- - -/** - * Create a proxy for an object we own on another server. - * - * If address is specified, it will establish a connection and queue - * the task to be done later, if necessary. Otherwise, it will FATAL - * if not connected. - * @see GameServerConnectionHandler::addGameServer - */ - -void GameServer::createRemoteProxy(uint32 remoteProcessId, ServerObject *object) -{ - - WARNING_STRICT_FATAL(!object, ("Told to create an object on %d we know nothing about!\n", remoteProcessId)); - NetworkId objectId = object->getNetworkId(); - - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(),("createRemoteProxy(%lu,%s)\n",remoteProcessId, objectId.getValueString().c_str())); - - if (remoteProcessId == 0) - { - DEBUG_FATAL(true, ("Invalid ProcessId in GameServer::CreateRemoteProxy()\n")); - return; - } - - - //If we have the object in the world and we are auth for it, create it. - if (object) - { - if (object->isAuthoritative()) - { - if(GameServer::getProcessId() != remoteProcessId) - { - object->addServerToProxyList(remoteProcessId); - } - } - else - { - //Can't create an object if we're not authoritative. - // Forward the message to the auth server. - - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(),("Forwarding proxy request for %s to authoritative server\n",objectId.getValueString().c_str())); - - ServerMessageForwarding::begin(object->getAuthServerProcessId()); - - LoadObjectMessage const loadObjectMessage(objectId, remoteProcessId); - ServerMessageForwarding::send(loadObjectMessage); - - ServerMessageForwarding::end(); - } - } -} - -// ---------------------------------------------------------------------- - -void GameServer::createProxyOnAllServers(ServerObject *object) -{ - for (std::vector::const_iterator i = m_gameServerPids.begin(); i != m_gameServerPids.end(); ++i) - createRemoteProxy(*i, object); -} - -// ---------------------------------------------------------------------- - -void GameServer::debugIO (void) -{ -#ifdef _DEBUG -// DebugMonitor::flushOutput(); -// DebugMonitor::clearScreen(); - DebugFlags::callReportRoutines(); -#endif -} - -//----------------------------------------------------------------------- - -void GameServer::deliverMessageToClientObject(const NetworkId &oid, const Archive::ByteStream & source) -{ - const ClientMap::iterator i = m_clients->find(oid); - if(i != m_clients->end()) - { - Archive::ReadIterator ri = source.begin(); - GameNetworkMessage const msg(ri); - (*i).second->receiveClientMessage(msg); - } - else - { - DEBUG_REPORT_LOG(true, ("Received message for unknown client %s\n", oid.getValueString().c_str())); - } -} - -//----------------------------------------------------------------------- - -void GameServer::dropClient(const NetworkId& oid) -{ - dropClient(oid, false); -} -//----------------------------------------------------------------------- - -void GameServer::dropClient(const NetworkId& oid, const bool immediate) -{ - DEBUG_REPORT_LOG(true,("Dropping client %s\n",oid.getValueString().c_str())); - - const ClientMap::iterator i = m_clients->find(oid); - if(i != m_clients->end()) - { - Client* client = const_cast((*i).second); - m_clients->erase(i); - client->selfDestruct(immediate); - } -} - -//----------------------------------------------------------------------- - -unsigned long GameServer::getFrameTime() const -{ - return s_frameTime; -} - -//----------------------------------------------------------------------- - -Client * GameServer::getClient(const NetworkId& networkId) -{ - ClientMap::iterator i = m_clients->find(networkId); - if (i != m_clients->end()) - { - return i->second; - } - return NULL; -} - -//----------------------------------------------------------------------- -const Service * GameServer::getClientService() const -{ - return m_clientService; -} - -// ---------------------------------------------------------------------- - -bool GameServer::isGameServerConnected(uint32 processId) const -{ - return std::binary_search(m_gameServerPids.begin(), m_gameServerPids.end(), processId); -} - -//----------------------------------------------------------------------- - -ConnectionServerConnection * GameServer::getConnectionServerConnection(const std::string & connectionServerIp, const uint16 connectionServerPort) -{ - ConnectionServerConnection * result = 0; - - if (m_connectionServerVector) - { - for (ConnectionServerVector::iterator i = m_connectionServerVector->begin(); i != m_connectionServerVector->end(); ++i) - { - if (((*i)->getRemoteAddress() == connectionServerIp) && ((*i)->getRemotePort() == connectionServerPort)) - { - result = *i; - break; - } - } - } - - return result; -} - -//----------------------------------------------------------------------- - -void GameServer::initialize() -{ - //@todo, this function seems wrong to me. This should happen in install or in the constructor. - //Right now this gets called at the beginning of ::run - - ServerCommandTable::load(); - loadTerrain (); - - ShipObject::install(); - AiShipController::install(); - AICreatureController::install(); - ShipAiReactionManager::install(); - PlayerShipController::install(); - MissileManager::install(); - ShipClientUpdateTracker::install(); - ServerAsteroidManager::install(); - QuestManager::install(); - VeteranRewardManager::install(); - SceneGlobalData::install(); - StationPlayersCollectorAPI::install(); - ServerObject::install(); - TangibleObject::install(); - Client::install(); - - m_metricsData = new GameServerMetricsData; - s_permissionManager = new ServerCommandPermissionManager(); -} - -// ---------------------------------------------------------------------- - -void GameServer::loadTerrain () -{ - if (TerrainObject::getInstance ()) - { - TerrainObject::getInstance ()->removeFromWorld (); - delete TerrainObject::getInstance (); - } - - char const * const terrainFileName = ConfigServerGame::getGroundScene(); - FATAL(!terrainFileName || !TreeFile::exists(terrainFileName), ("%s is not a valid terrain file", terrainFileName)); - - TerrainObject * const terrainObject = new TerrainObject(ServerWorld::getTerrainObjectNotification()); - terrainObject->setDebugName("terrain"); - Appearance * const appearance = AppearanceTemplateList::createAppearance(terrainFileName); - terrainObject->setAppearance(appearance); - - ProceduralTerrainAppearance * const proceduralTerrainAppearance = dynamic_cast(appearance); - if (proceduralTerrainAppearance) - ServerObjectTerrainModificationNotification::setTerrainAppearance(proceduralTerrainAppearance); - - terrainObject->addToWorld(); -} - -// ---------------------------------------------------------------------- - -void GameServer::shutdown() -{ - delete s_permissionManager; - s_permissionManager = 0; - if(s_metricsManagerInstalled) - MetricsManager::remove(); - delete m_metricsData; - m_metricsData = 0; - - m_centralService = 0; - m_planetServerConnection = 0; - - if (m_customerServiceServerConnection != NULL) - { - m_customerServiceServerConnection->disconnect(); - } -} - -// ---------------------------------------------------------------------- - -void GameServer::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) -{ - static Archive::ReadIterator ri; - static Archive::ByteStream bs; - - PROFILER_AUTO_BLOCK_DEFINE("GameServer::receiveMessage"); - - // advise the TaskManager that the gameserver isn't dead in cases where - // the server is handling a LOT of LoadObjectMessages and creating - // proxies. - if(getInstance().m_taskManagerConnection) - { - if(Clock::timeMs() - s_lastTaskKeepaliveTime > 60000) - { - static const GenericValueTypeMessage gameServerTaskManagerKeepAlive("GameServerTaskManagerKeepAlive", Os::getProcessId()); - getInstance().m_taskManagerConnection->send(gameServerTaskManagerKeepAlive, true); - s_lastTaskKeepaliveTime = Clock::timeMs(); - } - } - - ServerConnection * const serverConnection = const_cast(dynamic_cast(&source)); - - if(message.isType("CentralConnectionOpened")) - { - MESSAGE_PROFILER_BLOCK("CentralConnectionOpened"); - if (!m_centralServerConnection) - m_centralServerConnection = const_cast(static_cast(&source)); - } - else if (message.isType("CustomerServiceServerGameServerServiceAddress")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const address(ri); - - DEBUG_REPORT_LOG(true, ("GameServer: Creating customer service server connection @ (%s:%d)\n", address.getValue().first.c_str(), address.getValue().second)); - - if (m_customerServiceServerConnection != NULL) - { - m_customerServiceServerConnection->disconnect(); - } - - m_customerServiceServerConnection = new CustomerServiceServerConnection(address.getValue().first, address.getValue().second); - } - else if(message.isType("BaselinesMessage")) - { - MESSAGE_PROFILER_BLOCK("BaselinesMessage"); - ri = static_cast(message).getByteStream().begin(); - BaselinesMessage const m(ri); - ServerObject *so = ServerWorld::findUninitializedObjectByNetworkId(m.getTarget()); - if (so) - { - so->applyBaselines(m); - } - else - { - // find any object - so = safe_cast(NetworkIdManager::getObjectById(m.getTarget())); - if (so) - { - DEBUG_WARNING(true, ("Applied baselines on object %s which is already initialized.", m.getTarget().getValueString().c_str())); - so->applyBaselines(m); - } - else - { - DEBUG_WARNING(true, ("Got baselines on object %s which could not be found.", m.getTarget().getValueString().c_str())); - } - } - } - else if(message.isType("BatchBaselinesMessage")) - { - MESSAGE_PROFILER_BLOCK("BaselinesMessage"); - ri = static_cast(message).getByteStream().begin(); - BatchBaselinesMessage const m(ri); - - std::vector const & baselines = m.getData(); - - ServerObject * lastObject = NULL; - - for (std::vector::const_iterator i=baselines.begin(); i!=baselines.end(); ++i) - { - // There's a good chance the baselines for an object will come together, so remember the previous object - // and don't look it up again if the network id hasn't changed. - if (!lastObject || lastObject->getNetworkId() != i->m_networkId) - { - lastObject = ServerWorld::findUninitializedObjectByNetworkId(i->m_networkId); - - if (!lastObject) - { - lastObject = safe_cast(NetworkIdManager::getObjectById(i->m_networkId)); - if (lastObject) - { - WARNING(true, ("Applied baselines on object %s which is already initialized.", i->m_networkId.getValueString().c_str())); - - } - else - { - WARNING(true, ("Got baselines on object %s which could not be found.", i->m_networkId.getValueString().c_str())); - } - } - } - if (lastObject) - { - lastObject->applyBaselines(i->m_packageId, i->m_package); - } - } - } - else if(message.isType("DeltasMessage")) - { - MESSAGE_PROFILER_BLOCK("DeltasMessage"); - ri = static_cast(message).getByteStream().begin(); - DeltasMessage const m(ri); - ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(m.getTarget())); - if (so) - so->applyDeltas(m); - else - DEBUG_WARNING(true, ("Got DeltasMessage on object %s, which could not be found.", m.getTarget().getValueString().c_str())); - } - - else if(message.isType("ChunkCompleteMessage")) - { - MESSAGE_PROFILER_BLOCK("ChunkCompleteMessage"); - ri = static_cast(message).getByteStream().begin(); - ChunkCompleteMessage const m(ri); - GameServer::getInstance().sendToPlanetServer(m); - - std::vector > const & chunks = m.getChunks(); - for (std::vector >::const_iterator i=chunks.begin(); i!=chunks.end(); ++i) - ServerBuildoutManager::onChunkComplete(i->first, i->second); - } - - else if(message.isType("CentralConnectionClosed")) - { - MESSAGE_PROFILER_BLOCK("CentralConnectionClosed"); - // @ todo : shutdown gracefully - DEBUG_REPORT_LOG(true, ("The connection to the central server has been closed\n")); - setDone("CentralConnectionClosed : %s", serverConnection->getDisconnectReason().c_str()); - m_centralServerConnection = 0; - } - else if(message.isType("TaskConnectionOpened")) - { - MESSAGE_PROFILER_BLOCK("TaskConnectionOpened"); - DEBUG_REPORT_LOG(true, ("The connection with the task manager has been established\n")); - } - else if(message.isType("TaskConnectionClosed")) - { - MESSAGE_PROFILER_BLOCK("TaskConnectionClosed"); - DEBUG_REPORT_LOG(true, ("The connection to the task manager has closed\n")); - m_taskManagerConnection = 0; - } - else if (message.isType("AddGameServer")) - { - MESSAGE_PROFILER_BLOCK("AddGameServer"); - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const addGameServerMessage(ri); - - uint32 const pid = addGameServerMessage.getValue(); - - DEBUG_REPORT_LOG(true, ("Received AddGameServer for server %lu.\n", pid)); - - FATAL(std::find(m_gameServerPids.begin(), m_gameServerPids.end(), pid) != m_gameServerPids.end(), ("Got AddGameServer for server %lu which we thought was already running?", pid)); - - m_gameServerPids.push_back(pid); - std::sort(m_gameServerPids.begin(), m_gameServerPids.end()); - } - else if (message.isType("ExcommunicateGameServerMessage")) - { - MESSAGE_PROFILER_BLOCK("ExcommunicateGameServerMessage"); - ri = static_cast(message).getByteStream().begin(); - ExcommunicateGameServerMessage msg(ri); - - uint32 const pid = msg.getServerId(); - - DEBUG_REPORT_LOG(true, ("Received ExcommunicateGameServer for server %lu.\n", pid)); - LOG("GameGameConnect", ("Server %lu was told that server %lu has gone away by Central", getProcessId(), pid)); - - FATAL(pid == getProcessId(), ("Crashing because Central told us to (probably indicates we weren't responding to pings)")); - - std::vector::iterator i = std::find(m_gameServerPids.begin(), m_gameServerPids.end(), pid); - if (i != m_gameServerPids.end()) - { - m_gameServerPids.erase(i); - - MessageToQueue::getInstance().onGameServerDisconnect(pid); - ServerUniverse::getInstance().onServerConnectionClosed(pid); - AuthTransferTracker::handleGameServerDisconnect(pid); - } - } - else if(message.isType("CommoditiesServerConnectionClosed")) - { - DEBUG_REPORT_LOG(true, ("CommoditiesServer connection closed\n")); - CommoditiesMarket::closeCommoditiesServerConnection(); - } - else if (message.isType("ConnectionServerAddress")) - { - MESSAGE_PROFILER_BLOCK("ConnectionServerAddress"); - // Central is telling us about a new connection server. - ri = static_cast(message).getByteStream().begin(); - ConnectionServerAddress const msg(ri); - ConnectionServerConnection * const newConn = new ConnectionServerConnection(msg.getGameServiceAddress(), msg.getGameServicePort()); - m_connectionServerVector->push_back(newConn); - } - else if (message.isType("ConnectionServerConnectionClosed") || message.isType("ConnectionServerConnectionDestroyed")) - { - MESSAGE_PROFILER_BLOCK("ConnectionServerConnectionClosed"); - ConnectionServerConnection const * const c = dynamic_cast(&source); - ConnectionServerVector::iterator i = std::find(m_connectionServerVector->begin(), m_connectionServerVector->end(), c); - if (i != m_connectionServerVector->end()) - { - m_connectionServerVector->erase(i); - } - } - else if(message.isType("NewClient")) - { - MESSAGE_PROFILER_BLOCK("NewClient"); - static std::string const loginTrace("TRACE_LOGIN"); - ri = static_cast(message).getByteStream().begin(); - NewClient const msg(ri); - LOG(loginTrace, ("NewClient(%s)", msg.getNetworkId().getValueString().c_str())); - - //@todo make sure this holds up with non players (like vehicles) - //because right not, we construct a new client object for EACH object - //even ones that could be controlled by the same client. - //Also is it possible to receive this message for an object we already control? - - if (m_clients->find(msg.getNetworkId()) != m_clients->end()) - { - // inconsistant state, drop the client - LOG(loginTrace, ("NewClient(%s) : Error! Getting a NewClient message for a client that already exists", msg.getNetworkId().getValueString().c_str())); - - KickPlayer const kickMessage(msg.getNetworkId(), "Duplicate Client"); - sendToConnectionServers(kickMessage); - dropClient(msg.getNetworkId()); - return; - } - - // don't allow login if the character is in the middle of CTS or has been successfully CTS(ed) - ServerObject * const obj = ServerWorld::findObjectByNetworkId(msg.getNetworkId()); - if (obj) - { - bool kickRequested = false; - - DynamicVariableList const & objVars = obj->getObjVars(); - int timeOut; - if (objVars.getItem("disableLoginCtsInProgress", timeOut)) - { - if (timeOut > static_cast(ServerClock::getInstance().getGameTimeSeconds())) - { - MessageToQueue::getInstance().sendMessageToC(obj->getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); - kickRequested = true; - } - else - { - obj->removeObjVarItem("disableLoginCtsInProgress"); - } - } - - int transferredTime; - if (!kickRequested && objVars.getItem("disableLoginCtsCompleted", transferredTime) && !msg.getUsingAdminLogin()) - { - MessageToQueue::getInstance().sendMessageToC(obj->getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); - kickRequested = true; - } - } - - LOG(loginTrace, ("NewClient(%s) : A new client is being created from connection server", msg.getNetworkId().getValueString().c_str())); - std::set const observedObjectSet(msg.getObservedObjects().begin(), msg.getObservedObjects().end()); - Client * const c = new Client( - const_cast(static_cast(source)), - msg.getNetworkId(), - msg.getAccountName(), - msg.getIpAddress(), - msg.getIsSecure(), - msg.getIsSkipLoadScreen(), - msg.getStationId(), - observedObjectSet, - msg.getGameFeatures(), - msg.getSubscriptionFeatures(), - Client::AccountFeatureIdList(), - msg.getEntitlementTotalTime(), - msg.getEntitlementEntitledTime(), - msg.getEntitlementTotalTimeSinceLastLogin(), - msg.getEntitlementEntitledTimeSinceLastLogin(), - msg.getBuddyPoints(), - msg.getConsumedRewardEvents(), - msg.getClaimedRewardItems(), - msg.getUsingAdminLogin(), - CombatDataTable::CSFT_All, - 128, - 90, - false, - false, - msg.getSendToStarport() ); - - ClientMap::iterator f = m_clients->find(msg.getNetworkId()); - - if(f != m_clients->end()) - m_clients->erase(msg.getNetworkId()); - - m_clients->insert(std::make_pair(msg.getNetworkId(), c)); - - if (!msg.getUsingAdminLogin()) - { - AccountFeatureIdRequest const req(NetworkId::cms_invalid, GameServer::getInstance().getProcessId(), msg.getNetworkId(), static_cast(msg.getStationId()), PlatformGameCode::SWG, AccountFeatureIdRequest::RR_Reload); - c->sendToConnectionServer(req); - } - } - else if(message.isType("AuthTransferClientMessage")) - { - MESSAGE_PROFILER_BLOCK("AuthTransferClientMessage"); - static const std::string loginTrace("TRACE_LOGIN"); - ri = static_cast(message).getByteStream().begin(); - AuthTransferClientMessage const msg(ri); - LOG(loginTrace, ("AuthTransferClientMessage(%s)", msg.getNetworkId().getValueString().c_str())); - - //@todo make sure this holds up with non players (like vehicles) - //because right not, we construct a new client object for EACH object - //even ones that could be controlled by the same client. - //Also is it possible to receive this message for an object we already control? - - if (m_clients->find(msg.getNetworkId()) != m_clients->end()) - { - // inconsistant state, drop the client - LOG(loginTrace, ("AuthTransferClientMessage(%s) : Error! Getting a AuthTransferClientMessage message for a client that already exists", msg.getNetworkId().getValueString().c_str())); - KickPlayer const kickMessage(msg.getNetworkId(), "Duplicate Client"); - sendToConnectionServers(kickMessage); - dropClient(msg.getNetworkId()); - return; - } - - // locate the connection server for the client - ConnectionServerConnection * const connectionServer = getConnectionServerConnection(msg.getConnectionServerIp(), msg.getConnectionServerPort()); - - if (!connectionServer) - { - // inconsistant state, drop the client - LOG(loginTrace, ("AuthTransferClientMessage(%s) : Error! Getting a AuthTransferClientMessage message for a client but could not locate connection server (%s:%hu)", msg.getNetworkId().getValueString().c_str(), msg.getConnectionServerIp().c_str(), msg.getConnectionServerPort())); - KickPlayer const kickMessage(msg.getNetworkId(), "Invalid Connection Server"); - sendToConnectionServers(kickMessage); - dropClient(msg.getNetworkId()); - return; - } - - LOG(loginTrace, ("AuthTransferClientMessage(%s) : A new client is being created from game server %lu", msg.getNetworkId().getValueString().c_str(), msg.getSourceServerPid())); - - std::set observedObjectSet(msg.getObservedObjects().begin(), msg.getObservedObjects().end()); - Client * c = new Client(*connectionServer, msg.getNetworkId(), msg.getAccount(), msg.getIpAddress(), msg.getSecure(), msg.getSkipLoadScreen(), msg.getStationId(), observedObjectSet, msg.getGameFeatures(), msg.getSubscriptionFeatures(), msg.getAccountFeatureIds(), msg.getEntitlementTotalTime(), msg.getEntitlementEntitledTime(), msg.getEntitlementTotalTimeSinceLastLogin(), msg.getEntitlementEntitledTimeSinceLastLogin(), msg.getBuddyPoints(), msg.getConsumedRewardEvents(), msg.getClaimedRewardItems(), msg.getUsingAdminLogin(), static_cast(msg.getCombatSpamFilter()), msg.getCombatSpamRangeSquaredFilter(), msg.getFurnitureRotationDegree(), msg.getHasUnoccupiedJediSlot(), msg.getIsJediSlotCharacter()); - ClientMap::iterator f = m_clients->find(msg.getNetworkId()); - - if(f != m_clients->end()) - m_clients->erase(msg.getNetworkId()); - - m_clients->insert(std::make_pair(msg.getNetworkId(), c)); - } - - //--- - // application messages - else if(message.isType("CentralGameServerSetProcessId")) - { - MESSAGE_PROFILER_BLOCK("CentralGameServerSetProcessId"); - ri = static_cast(message).getByteStream().begin(); - CentralGameServerSetProcessId const m(ri); - - m_processId = m.getProcessId(); - LOG("GameServer", ("I am process %d", m_processId)); - LOG("GameGameConnect", ("Received CentralGameServerSetProcessId message for pid %d", m_processId)); - DEBUG_FATAL(m.getClockSubtractInterval()==0,("Got 0 for the clock subtract interval (probably indicates we connected to Central too early).\n")); - ServerClock::getInstance().setSubtractInterval(m.getClockSubtractInterval()); - m_clusterName = m.getClusterName(); - - ScriptParams s; - s.addParam(m_clusterName.c_str()); - GameScriptObject::runOneScript("base_class", "setGalaxyName", "s", s); - Chat::createSystemRooms(m_clusterName, ServerWorld::getSceneId()); - - if (!m_centralServerConnection) - { - m_centralServerConnection = const_cast(static_cast(&source)); - DEBUG_FATAL(true, ("m_centralServerConnection should have already been set when receiving CentralConnectionOpened.")); - } - - CentralGameServerConnect const connectMessage( - ConfigServerGame::getSceneID(), - "", - 0, - "", - 0); - - m_centralServerConnection->send(connectMessage, true); - - loadRetroactiveCtsHistory(); - loadRetroactivePlayerCityCreationTime(); - } - else if (message.isType("SetAuthoritativeMessage")) - { - MESSAGE_PROFILER_BLOCK("SetAuthoritativeMessage"); - ri = static_cast(message).getByteStream().begin(); - SetAuthoritativeMessage const t(ri); - - ServerObject * const object = ServerWorld::findObjectByNetworkId(t.getId()); - if (object) - { - bool allowed = true; - - // if the PlanetServer is asking us to transfer authority for an object that - // is contained, reject it, because contained object must have the same authority - // as its container; this can happen in a race condition where authority transfer - // is requested, and while the request is happening, the object moves into a container - if ((&source == m_planetServerConnection) && !t.getSceneChange() && object->isAuthoritative()) - { - Object const * const topmostContainer = ContainerInterface::getTopmostContainer(*object); - - if (topmostContainer != object) - { - WARNING(true, ("Denying authority transfer for (%s) from game server (%lu) to game server (%lu) because it is contained by (%s)", object->getDebugInformation().c_str(), GameServer::getInstance().getProcessId(), t.getProcess(), (topmostContainer ? topmostContainer->getDebugInformation().c_str() : "NULL"))); - - allowed = false; - - GenericValueTypeMessage > const denyMessage( - "DenySetAuthoritativeMessage", - std::make_pair(t.getId(), GameServer::getInstance().getProcessId())); - - sendToPlanetServer(denyMessage); - - object->updatePositionOnPlanetServer(true); - } - } - - if (allowed) - { - if (t.getGoalIsValid()) - object->transferAuthority(t.getProcess(), !t.getSceneChange(), t.getHandlingCrash(), t.getGoalCell(), t.getGoalTransform(), false); - else - object->transferAuthority(t.getProcess(), !t.getSceneChange(), t.getHandlingCrash(), false); - } - } - } - else if(message.isType("LoadObjectMessage")) - { - MESSAGE_PROFILER_BLOCK("LoadObjectMessage"); - - ri = static_cast(message).getByteStream().begin(); - LoadObjectMessage const t(ri); - - ServerObject * const target = ServerWorld::findObjectByNetworkId(t.getId()); - if (target) - createRemoteProxy(t.getProcess(), target); - else - WARNING(true, ("Told to create object %s on %d we know nothing about (received LoadObjectMessage for an object not on this server, PlanetServer is probably confused)", t.getId().getValueString().c_str(), t.getProcess())); - } - else if(message.isType("UnloadObjectMessage")) - { - MESSAGE_PROFILER_BLOCK("UnloadObjectMessage"); - ri = static_cast(message).getByteStream().begin(); - UnloadObjectMessage const t(ri); - - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Got unload object message for %s\n", t.getId().getValueString().c_str())); - - ServerObject * const object = ServerWorld::findObjectByNetworkId(t.getId()); - if (object) - object->unload(); - DEBUG_WARNING(! object, ("Handling unload object message but the object does not exist\n")); - } - else if(message.isType("UnloadProxyMessage")) - { - MESSAGE_PROFILER_BLOCK("UnloadProxyMessage"); - ri = static_cast(message).getByteStream().begin(); - UnloadProxyMessage const unloadProxyMessage(ri); - - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Received UnloadProxyMessage for object %s server %lu\n", unloadProxyMessage.getObjectId().getValueString().c_str(), unloadProxyMessage.getProxyGameServerId())); - - ServerObject * const object = ServerWorld::findObjectByNetworkId(unloadProxyMessage.getObjectId()); - if(object) - { - if(object->isAuthoritative()) - { - if (unloadProxyMessage.getProxyGameServerId() != getProcessId()) - object->removeServerFromProxyList(unloadProxyMessage.getProxyGameServerId()); - else - DEBUG_WARNING(true,("Can't unproxy object %s from this server because this server is authoritative.", unloadProxyMessage.getObjectId().getValueString().c_str())); - } - else - { - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(),("Forwarding UnloadProxyMessage for %s to authoritative server\n", unloadProxyMessage.getObjectId().getValueString().c_str())); - - ServerMessageForwarding::begin(object->getAuthServerProcessId()); - - ServerMessageForwarding::send(unloadProxyMessage); - - ServerMessageForwarding::end(); - } - } - else - DEBUG_WARNING(true, ("Received UnloadProxyMessage for object %s server %lu, but the object could not be found", unloadProxyMessage.getObjectId().getValueString().c_str(), unloadProxyMessage.getProxyGameServerId())); - } - else if(message.isType("ProfilerOperationMessage")) - { - MESSAGE_PROFILER_BLOCK("ProfilerOperationMessage"); - ri = static_cast(message).getByteStream().begin(); - ProfilerOperationMessage const m(ri); - uint32 const processId = m.getProcessId(); - if (processId == 0 || processId == getProcessId()) - Profiler::handleOperation(m.getOperation().c_str()); - } - else if(message.isType("CentralCreateCharacter")) - { - MESSAGE_PROFILER_BLOCK("CentralCreateCharacter"); - ri = static_cast(message).getByteStream().begin(); - handleCreateCharacter(new CentralCreateCharacter(ri)); - } - else if (message.isType("VerifyNameResponse")) - { - MESSAGE_PROFILER_BLOCK("VerifyNameResponse"); - ri = static_cast(message).getByteStream().begin(); - VerifyNameResponse vrn(ri); - - if (isCreatePending(vrn.getStationId())) - { - handleCharacterCreateNameVerification(vrn); - } - else - { - handleVerifyAndLockNameVerification(vrn); - } - } - else if (message.isType("RandomNameRequest")) - { - MESSAGE_PROFILER_BLOCK("RandomNameRequest"); - ri = static_cast(message).getByteStream().begin(); - RandomNameRequest const crnr(ri); - handleNameRequest(crnr); - } - else if (message.isType("VerifyAndLockNameRequest")) - { - MESSAGE_PROFILER_BLOCK("VerifyAndLockNameRequest"); - ri = static_cast(message).getByteStream().begin(); - VerifyAndLockNameRequest const valnr(ri); - handleVerifyAndLockNameRequest(valnr, true, true); - } - else if(message.isType("ObjControllerMessage")) - { - MESSAGE_PROFILER_BLOCK("ObjControllerMessage"); - - ri = static_cast(message).getByteStream().begin(); - ObjControllerMessage c(ri); - - // Could be in baselines so it may be initialized or it may not. Since we don't know we have to use NetworkIdManager to get it. - // The object could also have been destroyed due to an auth transfer, so if it has been and not all servers have confirmed it, - // we need to forward the message. - - bool appended = false; - - ServerObject * const target = safe_cast(NetworkIdManager::getObjectById(c.getNetworkId())); - if (target != NULL) - { - // valid target, get its controller - ServerController * const controller = safe_cast(target->getController()); - if (controller != NULL) - { - uint32 flags = c.getFlags(); - if(flags & GameControllerMessageFlags::DEST_AUTH_SERVER) - { - if(ConfigServerGame::getEnableDebugControllerMessageSpam()) - { - WARNING(! target->isAuthoritative(), ("Received a controller message (%d) destined for the authoritative object (%s:%s) on this server, but the object is NOT authoritative on this server", c.getMessage(), target->getObjectTemplateName(), target->getNetworkId().getValueString().c_str() )); - } - } - flags |= GameControllerMessageFlags::SOURCE_REMOTE_SERVER; - controller->appendMessage(c.getMessage(), c.getValue(), c.getData(), flags); - appended = true; - } - } - else - { - uint32 const destServer = AuthTransferTracker::getAuthTransferDest(c.getNetworkId()); - if (destServer) - { - if(ConfigServerGame::getEnableDebugControllerMessageSpam()) - { - WARNING(true, ("ObjControllerMessage %d for object %s arrived, but the object has transferred authority to server %d", c.getMessage(), c.getNetworkId().getValueString().c_str(), destServer)); - } - - ServerMessageForwarding::begin(destServer); - - ServerMessageForwarding::send(c); - - ServerMessageForwarding::end(); - } - else - DEBUG_WARNING(true, ("Got ObjControllerMessage for object %s, which could not be found.", c.getNetworkId().getValueString().c_str())); - } - - if (!appended) - delete c.getData(); - } - else if(message.isType("EndBaselinesMessage")) - { - MESSAGE_PROFILER_BLOCK("EndBaselinesMessage"); - ri = static_cast(message).getByteStream().begin(); - EndBaselinesMessage const t(ri); - ServerObject * const object = ServerWorld::findUninitializedObjectByNetworkId(t.getId()); - if (object != NULL) - { - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Received EndBaselinesMessage for %s\n", t.getId().getValueString().c_str())); - ServerController * const controller = dynamic_cast(object->getController()); - NOT_NULL(controller); - - bool const fromDbServer = serverConnection && serverConnection == m_databaseProcessConnection; - object->serverObjectEndBaselines(fromDbServer); - } - else - { - ServerObject * const badObject = ServerWorld::findObjectByNetworkId(t.getId()); - WARNING(!badObject, ("Got EndBaeslinesMessage on object (%s) that doesn't exist!", t.getId().getValueString().c_str())); - WARNING(badObject, ("Got EndBaselinesMessage on object (%s : %s) which has already been created and placed in the world!", badObject->getTemplateName(), badObject->getNetworkId().getValueString().c_str())); - } - } - else if(message.isType("TaskShutdownGameServer")) - { - MESSAGE_PROFILER_BLOCK("TaskShutdownGameServer"); - setDone("TaskShutdownGameServer"); - } - else if (message.isType("CreateObjectByCrcMessage")) - { - s_totalObjectCreateMessagesReceived ++; - - MESSAGE_PROFILER_BLOCK("CreateObjectByCrcMessage"); - ri = static_cast(message).getByteStream().begin(); - - NetworkId networkId; - uint32 templateCrc; - bool createAuthoritative; - - CreateObjectByCrcMessage const t(ri); - networkId = t.getId(); - templateCrc = t.getCrc(); - createAuthoritative = t.getCreateAuthoritative(); - - NOT_NULL(serverConnection); - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("CreateObjectMessageByName %s:%s\n", ObjectTemplateList::lookUp(templateCrc).getString(), networkId.getValueString().c_str())); - - Object * const object = NetworkIdManager::getObjectById(networkId); - bool okToCreate = true; - if (object) - { - DEBUG_REPORT_LOG(true, ("WARNING: GOT create message for object %s that already exists!\n", networkId.getValueString().c_str())); - if (object->getKill()) - { - delete object; - okToCreate = true; - } - else - { - WARNING_STRICT_FATAL(true, ("Hey, Got create message for object %s That isn't being deleted!", networkId.getValueString().c_str())); - okToCreate = false; - } - } - - if (okToCreate) - { - //-- Since space is single-server, we will never have proxied space objects and we can ignore the hyperspace variable in the CreateObjectBy*Message message. - ServerWorld::createProxyObject(templateCrc, networkId, createAuthoritative); - } - } - else if(message.isType("CreateSyncUiMessage")) - { - MESSAGE_PROFILER_BLOCK("CreateSyncUiMessage"); - ri = static_cast(message).getByteStream().begin(); - CreateSyncUiMessage const msg(ri); - ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(msg.getId())); - if (so) - so->addSynchronizedUi(msg.getClients()); - } - else if(message.isType("SynchronizeScriptVarsMessage")) - { - MESSAGE_PROFILER_BLOCK("SynchronizeScriptVarsMessage"); - ri = static_cast(message).getByteStream().begin(); - SynchronizeScriptVarsMessage const msg(ri); - ServerObject *so = ServerWorld::findUninitializedObjectByNetworkId(msg.getNetworkId()); - if (so) - { - GameScriptObject const * const script = so->getScriptObject(); - if (script) - script->unpackScriptVars(msg.getData()); - } - else - { - so = safe_cast(NetworkIdManager::getObjectById(msg.getNetworkId())); - DEBUG_WARNING(so, ("Got SynchronizeScriptVarsMessage for initialized object")); - } - } - else if (message.isType("SynchronizeScriptVarDeltasMessage")) - { - MESSAGE_PROFILER_BLOCK("SynchronizeScriptVarDeltasMessage"); - ri = static_cast(message).getByteStream().begin(); - SynchronizeScriptVarDeltasMessage const msg(ri); - ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(msg.getNetworkId())); - if (so) - { - GameScriptObject const * const script = so->getScriptObject(); - if (script) - script->unpackDeltaScriptVars(msg.getData()); - } - else - DEBUG_WARNING(true,("Got SynchronizeScriptVarDeltasMessage on object %s, which could not be found.", msg.getNetworkId().getValueString().c_str())); - } - else if(message.isType("UpdateObjectPositionMessage")) - { - MESSAGE_PROFILER_BLOCK("UpdateObjectPositionMessage"); - ri = static_cast(message).getByteStream().begin(); - UpdateObjectPositionMessage const msg(ri); - ServerObject * const so = ServerWorld::findUninitializedObjectByNetworkId(msg.getNetworkId()); - if (so) - so->applyObjectPositionUpdate(msg); - } - else if(message.isType("UpdateContainmentMessage")) - { - MESSAGE_PROFILER_BLOCK("UpdateContainmentMessage"); - ri = static_cast(message).getByteStream().begin(); - UpdateContainmentMessage const msg(ri); - ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(msg.getNetworkId())); - if (so) - { - // Handle the containment update. - so->updateContainment(msg.getContainerId(), msg.getSlotArrangement()); - } - } - else if(message.isType("DropClient")) - { - MESSAGE_PROFILER_BLOCK("DropClient"); - ri = static_cast(message).getByteStream().begin(); - DropClient const msg(ri); - dropClient(msg.getNetworkId(), msg.getImmediate()); - } - else if(message.isType("SetPlanetServerMessage")) - { - MESSAGE_PROFILER_BLOCK("SetPlanetServerMessage"); - DEBUG_REPORT_LOG(true,("Received SetPlanetServerMessage\n")); - ri = static_cast(message).getByteStream().begin(); - SetPlanetServerMessage const m(ri); - m_planetServerConnection = new PlanetServerConnection(m.getAddress(),m.getPort()); - } - else if (message.isType("PlanetConnectionOpened")) - { - MESSAGE_PROFILER_BLOCK("PlanetConnectionOpened"); - m_planetServerConnection = const_cast(static_cast(&source)); - DEBUG_REPORT_LOG(true, ("Connection with the Planet server has been established\n")); - onPlanetServerConnectionEstablished(); - } - else if (message.isType("PlanetConnectionClosed")) - { - MESSAGE_PROFILER_BLOCK("PlanetConnectionClosed"); - if (m_planetServerConnection) - { - m_planetServerConnection->setDisconnectReason("received PlanetConnectionClosed"); - m_planetServerConnection->disconnect(); - } - m_planetServerConnection = 0; - setDone("PlanetConnectionClosed : %s", serverConnection->getDisconnectReason().c_str()); - } - else if (message.isType("GameServerSetupMessage")) - { - MESSAGE_PROFILER_BLOCK("GameServerSetupMessage"); - LOG("GameGameConnect", ("Game Server %d Received GameServerSetupMessage.", m_processId)); - - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > > const m(ri); - - m_gameServerPids = m.getValue().first; - std::sort(m_gameServerPids.begin(), m_gameServerPids.end()); - - ServerMessageForwarding::beginBroadcast(); - - GenericValueTypeMessage const addGameServerMessage("AddGameServer", getProcessId()); - ServerMessageForwarding::send(addGameServerMessage); - - ServerMessageForwarding::end(); - - uint32 const databaseProcessId = m.getValue().second.first; - std::string const &databaseProcessAddress = m.getValue().second.second.first; - uint16 const databaseProcessPort = m.getValue().second.second.second; - - connectToDatabaseProcess(databaseProcessAddress, databaseProcessPort, databaseProcessId); - - m_connectionTimeout = Clock::timeMs() + ConfigServerGame::getConnectToAllGameServersTimeout() * 1000; - } - else if (message.isType("LoadUniverseMessage")) - { - MESSAGE_PROFILER_BLOCK("LoadUniverseMessage"); - ri = static_cast(message).getByteStream().begin(); - LoadUniverseMessage const msg(ri); - - DEBUG_REPORT_LOG(true,("Got LoadUniverseMessage\n")); - ServerUniverse::getInstance().requestCreateProxiesOnServer(msg.getProcess()); - } - else if (message.isType("SetUniverseAuthoritativeMessage")) - { - MESSAGE_PROFILER_BLOCK("SetUniverseAuthoritativeMessage"); - ri = static_cast(message).getByteStream().begin(); - SetUniverseAuthoritativeMessage const m(ri); - ServerUniverse::getInstance().setUniverseProcess(m.getProcess()); - } - else if (message.isType("AddResourceTypeMessage")) - { - ri = static_cast(message).getByteStream().begin(); - AddResourceTypeMessage const msg(ri); - ServerUniverse::getInstance().handleAddResourceTypeMessage(msg); - } - else if (message.isType("AddImportedResourceType")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - if (!ServerUniverse::getInstance().getImportedResourceTypeById(msg.getValue().first)) - IGNORE_RETURN(ResourceTypeObject::addImportedResourceType(msg.getValue().second)); - } - else if (message.isType("UniverseCompleteMessage")) - { - MESSAGE_PROFILER_BLOCK("UniverseCompleteMessage"); - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - ServerUniverse::getInstance().universeComplete(msg.getValue()); - GameServerUniverseLoadedMessage const reply(getProcessId(), msg.getValue()); - GameServer::getInstance().sendToCentralServer(reply); - GameServer::getInstance().sendToPlanetServer(reply); - gs_gameServerReady = true; - } - else if (message.isType("GameServerUniverseLoadedMessage")) - { - MESSAGE_PROFILER_BLOCK("GameServerUniverseLoadedMessage"); - ri = static_cast(message).getByteStream().begin(); - GameServerUniverseLoadedMessage const msg(ri); - - ServerUniverse::getInstance().universeLoadedAck(msg.getProcessId()); - } - else if (message.isType("PreloadRequestCompleteMessage")) - { - MESSAGE_PROFILER_BLOCK("PreloadRequestCompleteMessage"); - LOG("Preload", ("Game Server %d received preloadRequestCompleteMessage from database", getInstance().m_processId)); - ri = static_cast(message).getByteStream().begin(); - PreloadRequestCompleteMessage const msg(ri); - - DEBUG_REPORT_LOG(true,("Got PreloadRequestCompleteMessage. We are server %lu in the preload list\n",msg.getPreloadAreaId())); - - m_preloadAreaId = msg.getPreloadAreaId(); - MetricsManager::install(m_metricsData, true, "GameServer", ServerWorld::getSceneId(), msg.getPreloadAreaId()); - s_metricsManagerInstalled = true; - GameServer::getInstance().sendToPlanetServer(msg); - - // Our assigned preload number should be the same as the preload number we were started with; - // The cluster will still work but the restartgameserver.pl script may end up restarting the wrong - // game server because of the mismatch; it's worth putting out a log to look into what went wrong -#ifndef _DEBUG - if (static_cast(msg.getPreloadAreaId()) != ConfigServerGame::getPreloadNumber()) - LOG("Preload", ("Game Server %d got assigned preload number %lu but was launched with preload number %d", getInstance().m_processId, msg.getPreloadAreaId(), ConfigServerGame::getPreloadNumber())); -#endif - - // Notify ServerWorld that preloading is complete, so it can trigger scripts as appropriate - ServerWorld::onPreloadComplete(); - } - else if (message.isType("SceneTransferMessage")) - { - MESSAGE_PROFILER_BLOCK("SceneTransferMessage"); - ri = static_cast(message).getByteStream().begin(); - SceneTransferMessage const msg(ri); - - ServerObject * obj = ServerWorld::findObjectByNetworkId(msg.getNetworkId()); - if (obj) - obj->removeObjVarItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER); - - if (obj && obj->isAuthoritative() && isGameServerConnected(msg.getDestinationGameServer()) && (!obj->isPlayerControlled() || obj->getClient())) - { - if (obj->getSceneId() == msg.getSceneName()) - { - WARNING_STRICT_FATAL(true, ("Same scene planetwarps are no longer supported!")); - if (obj->getClient()) - dropClient(obj->getNetworkId()); - obj->unload(); - } - else - { - // Mounts: if it is a rider that is trying to planet warp, change the planet warp object - // to be the mount. - CreatureObject *const objAsCreature = obj->asCreatureObject(); - if (objAsCreature) - { - if (objAsCreature->getState(States::RidingMount)) - { - // The obj instance is a mounted rider. Replace obj with the mount. - CreatureObject *const mountObject = objAsCreature->getMountedCreature(); - if (mountObject) - { - // Set the proper position for the rider to that for the - // scene transfer. Failure to take this step causes the - // ServerObject::setClient() call on the destination server - // to have the wrong position for the player, thus setting - // up location-based containment improperly, screwing up - // the client's view of the world. - obj->setPosition_p(msg.getPosition_w()); - - // Replace obj with mount. - obj = mountObject; - } - else - { - LOG("mounts-bug", ("GS::SceneTransferMessage: server id=[%d],rider id=[%s] has RidingMount state but getMountedCreature() returns NULL.", static_cast(getProcessId()), obj->getNetworkId().getValueString().c_str())); - objAsCreature->emergencyDismountForRider(); - } - } - else - { - ShipObject * const ship = getAttachedShip(objAsCreature); - if (ship) - { - // Set the proper position for the rider to that for the - // scene transfer. Failure to take this step causes the - // ServerObject::setClient() call on the destination server - // to have the wrong position for the player, thus setting - // up location-based containment improperly, screwing up - // the client's view of the world. - obj->setPosition_w(msg.getPosition_w()); - - obj = ship; - } - } - } - - // Proceed with scene transfer on the transfer focus object. - bool doSceneChange = false; - - if (ContainerInterface::getTopmostContainer(*obj) == obj) - doSceneChange = true; - else - { - Transform tr(obj->getTransform_o2w()); - if (tr.isNaN()) - { - WARNING(true, ("Scene change for %s with nan in transform (i=%g,%g,%g j=%g,%g,%g k=%g,%g,%g, p=%g,%g,%g)", - obj->getDebugInformation().c_str(), - tr.getLocalFrameI_p().x, tr.getLocalFrameI_p().y, tr.getLocalFrameI_p().z, - tr.getLocalFrameJ_p().x, tr.getLocalFrameJ_p().y, tr.getLocalFrameJ_p().z, - tr.getLocalFrameK_p().x, tr.getLocalFrameK_p().y, tr.getLocalFrameK_p().z, - tr.getPosition_p().x, tr.getPosition_p().y, tr.getPosition_p().z)); - tr.resetRotate_l2p(); - } - Container::ContainerErrorCode err = Container::CEC_Success; - doSceneChange = ContainerInterface::transferItemToWorld(*obj, tr, 0, err); - } - - if (doSceneChange) - { - obj->setSceneIdOnThisAndContents(msg.getSceneName()); - - //-- As soon as we change the scene id on the object, tell central about the - // scene change. This fixes a bug that can occur if the authority transfer - // never completes where Central is left thinking we're still on this gameserver's - // scene (the source scene) but the object's data says we're on the destination - // due to the scene set above. - GenericValueTypeMessage > > const setSceneMsg("SetSceneForPlayer", std::make_pair(msg.getNetworkId(), std::make_pair(msg.getSceneName(), false))); - GameServer::getInstance().sendToCentralServer(setSceneMsg); - - if (!msg.getSceneName().empty()) - { - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(msg.getNetworkId()); - if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.locationPlanet != msg.getSceneName())) - ServerUniverse::setConnectedCharacterPlanetData(msg.getNetworkId(), msg.getSceneName()); - } - - obj->getContainedByProperty()->setContainedBy(NetworkId::cms_invalid); - obj->setPosition_p(msg.getPosition_w()); - if (msg.getContainerId() != NetworkId::cms_invalid) - obj->setInteriorTeleportDestination(msg.getContainerId(), msg.getContainerName(), msg.getPosition_p()); - if (!msg.getScriptCallback().empty()) - obj->setTeleportScriptCallback(msg.getScriptCallback()); - obj->transferAuthority(msg.getDestinationGameServer(), false, false, false); - obj->clearProxyList(); - } - } - } - } - else if (message.isType("ChatServerOnline")) - { - MESSAGE_PROFILER_BLOCK("ChatServerOnline"); - // a chat server advised the central server that it is online and - // is ready for game servers to connect to it. - ri = static_cast(message).getByteStream().begin(); - ChatServerOnline const cso(ri); - - if (m_chatServerConnection) - { - //we shouldn't have one already, but if we do then close it and - //accept the new one. - WARNING(true, ("We got notification of a new chat server coming online while we still had connection to an existing. We're going to disconnect from the old one and connect to the new one. This shouldn't cause any real problems, but we shouldn't have lingering chat connections laying around.")); - m_chatServerConnection->setDisconnectReason("got ChatServerOnline message"); - m_chatServerConnection->disconnect(); - m_chatServerConnection = 0; - Chat::setChatServer(m_chatServerConnection); - } - - if(! m_chatServerConnection) - { - REPORT_LOG(true, ("New chat server connection active\n")); - m_chatServerConnection = new ChatServerConnection(cso.getAddress(), cso.getPort()); - Chat::setChatServer(m_chatServerConnection); - if(! m_clusterName.empty()) - { - Chat::createSystemRooms(m_clusterName, ServerWorld::getSceneId()); - } - } - } - else if(message.isType("ChatServerConnectionClosed")) - { - MESSAGE_PROFILER_BLOCK("ChatServerConnectionClosed"); - REPORT_LOG(true, ("GameServer: Chat Server connection closed\n")); - if (m_chatServerConnection) - { - m_chatServerConnection->setDisconnectReason("got ChatServerConnectionClosed message"); - m_chatServerConnection->disconnect(); - - // if there is an interruption of service on the network - // between the GameServer and ChatServer, but the ChatServer - // is still running, the game server might never reconnect. Advise - // Central that the GameServer has lost a connection with the chat - // server - GameNetworkMessage const chatClosed("ChatClosedConnectionWithGameServer"); - sendToCentralServer(chatClosed); - } - m_chatServerConnection = 0; - } - else if(message.isType("TeleportMessage")) - { - MESSAGE_PROFILER_BLOCK("TeleportMessage"); - ri = static_cast(message).getByteStream().begin(); - TeleportMessage const msg(ri); - handleTeleportMessage(msg); - } - else if (message.isType("TeleportToMessage")) - { - MESSAGE_PROFILER_BLOCK("TeleportToMessage"); - ri = static_cast(message).getByteStream().begin(); - TeleportToMessage const msg(ri); - ServerObject * const serverObj = safe_cast(NetworkIdManager::getObjectById(msg.getTargetId())); - if (serverObj && serverObj->isAuthoritative()) - { - - // send teleport message - Object const * const firstParent = ContainerInterface::getFirstParentInWorld(*serverObj); - if (firstParent) - { - ServerMessageForwarding::begin(msg.getProcessId()); - - TeleportMessage const teleportMessage( - msg.getActorId(), - serverObj->getSceneId(), - firstParent->getPosition_w(), - firstParent->getAttachedTo() ? firstParent->getAttachedTo()->getNetworkId() : NetworkId::cms_invalid, - firstParent->getPosition_p()); - ServerMessageForwarding::send(teleportMessage); - - ServerMessageForwarding::end(); - } - } - } - else if(message.isType("RetrievedItemLoadMessage")) - { - MESSAGE_PROFILER_BLOCK("RetrievedItemLoadMessage"); - ri = static_cast(message).getByteStream().begin(); - RetrievedItemLoadMessage const msg(ri); - handleRetrievedItemLoadMessage(msg); - } - else if(message.isType("BiographyMessage")) - { - MESSAGE_PROFILER_BLOCK("BiographyMessage"); - ri = static_cast(message).getByteStream().begin(); - BiographyMessage const msg(ri); - BiographyManager::onBiographyRetrieved(msg.getOwner(),msg.getBio()); - } - else if(message.isType("LoadContainedObjectMessage")) - { - MESSAGE_PROFILER_BLOCK("LoadContainedObjectMessage"); - ri = static_cast(message).getByteStream().begin(); - LoadContainedObjectMessage const m(ri); - ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(m.getContainerId())); - if (obj) - { - WARNING(!obj->isAuthoritative(), ("Got LoadContainedObjectMessage, but the container is not authoritative. Container is %s, Object id %s", - obj->getDebugInformation().c_str(), m.getObjectId().getValueString().c_str())); - - obj->onContainedObjectLoaded(m.getObjectId()); - } - else - { - WARNING(true, ("Got LoadContainedObjectMessage, but could not find the container. Container id %s, Object id %s", - m.getContainerId().getValueString().c_str(), m.getObjectId().getValueString().c_str())); - } - } - else if(message.isType("LoadContentsMessage")) - { - MESSAGE_PROFILER_BLOCK("LoadContentsMessage"); - ri = static_cast(message).getByteStream().begin(); - LoadContentsMessage const m(ri); - ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(m.getContainerId())); - if (obj) - { - WARNING(!obj->isAuthoritative(),("Got LoadContentsMessage, but the container is not authoritative. Container is %s", - obj->getDebugInformation().c_str())); - - obj->onAllContentsLoaded(); - } - else - { - WARNING(true,("Got LoadContentsMessage, but could not find the container. Container id %s", - m.getContainerId().getValueString().c_str())); - } - } - else if(message.isType("FirstPlanetGameServerIdMessage")) - { - MESSAGE_PROFILER_BLOCK("FirstPlanetGameServerIdMessage"); - ri = static_cast(message).getByteStream().begin(); - FirstPlanetGameServerIdMessage const msg(ri); - m_firstGameServerForPlanet = msg.getGameServerId(); - DEBUG_REPORT_LOG(true,("First game server for %s is %lu\n",ServerWorld::getSceneId().c_str(),m_firstGameServerForPlanet)); - } - else if(message.isType("CreateDynamicRegionCircleMessage")) - { - MESSAGE_PROFILER_BLOCK("CreateDynamicRegionCircleMessage"); - ri = static_cast(message).getByteStream().begin(); - CreateDynamicRegionCircleMessage const msg(ri); - RegionMaster::createNewDynamicRegion(msg.getCenterX(), msg.getCenterZ(), msg.getRadius(), msg.getName(), msg.getPlanet(), msg.getPvp(), msg.getBuildable(), msg.getMunicipal(), msg.getGeography(), msg.getMinDifficulty(), msg.getMaxDifficulty(), msg.getSpawnable(), msg.getMission(), msg.getVisible(), msg.getNotify()); - } - else if(message.isType("CreateDynamicRegionRectangleMessage")) - { - MESSAGE_PROFILER_BLOCK("CreateDynamicRegionRectangleMessage"); - ri = static_cast(message).getByteStream().begin(); - CreateDynamicRegionRectangleMessage const msg(ri); - RegionMaster::createNewDynamicRegion(msg.getMinX(), msg.getMinZ(), msg.getMaxX(), msg.getMaxZ(), msg.getName(), msg.getPlanet(), msg.getPvp(), msg.getBuildable(), msg.getMunicipal(), msg.getGeography(), msg.getMinDifficulty(), msg.getMaxDifficulty(), msg.getSpawnable(), msg.getMission(), msg.getVisible(), msg.getNotify()); - } - else if(message.isType("CreateGroupMessage")) - { - MESSAGE_PROFILER_BLOCK("CreateGroupMessage"); - ri = static_cast(message).getByteStream().begin(); - CreateGroupMessage const msg(ri); - ServerUniverse::getInstance().createGroup(msg.getLeader(), msg.getMembers()); - } - else if(message.isType("ReloadAdminTableMessage")) - { - MESSAGE_PROFILER_BLOCK("ReloadAdminTableMessage"); - ri = static_cast(message).getByteStream().begin(); - ReloadAdminTableMessage const msg(ri); - handleReloadAdminTableMessage(msg); - } - else if(message.isType("ReloadCommandTableMessage")) - { - MESSAGE_PROFILER_BLOCK("ReloadCommandTableMessage"); - ri = static_cast(message).getByteStream().begin(); - ReloadCommandTableMessage const msg(ri); - handleReloadCommandTableMessage(msg); - } - else if (message.isType(ReloadDatatableMessage::ms_messageName)) - { - MESSAGE_PROFILER_BLOCK(ReloadDatatableMessage::ms_messageName); - ri = static_cast(message).getByteStream().begin(); - ReloadDatatableMessage const msg(ri); - handleReloadDatatableMessage(msg); - } - else if(message.isType("ReloadScriptMessage")) - { - MESSAGE_PROFILER_BLOCK("ReloadScriptMessage"); - ri = static_cast(message).getByteStream().begin(); - ReloadScriptMessage const msg(ri); - handleReloadScriptMessage(msg); - } - else if(message.isType("ReloadTemplateMessage")) - { - MESSAGE_PROFILER_BLOCK("ReloadTemplateMessage"); - ri = static_cast(message).getByteStream().begin(); - ReloadTemplateMessage const msg(ri); - handleReloadTemplateMessage(msg); - } - else if(message.isType("EnableNewJediTrackingMessage")) - { - MESSAGE_PROFILER_BLOCK("EnableNewJediTrackingMessage"); - ri = static_cast(message).getByteStream().begin(); - EnableNewJediTrackingMessage const msg(ri); - handleEnableNewJediTrackingMessage(msg); - } - else - { - // GameServer::receiveMessage() is getting too big for the compiler to handle - // so some of the message handling is done in the private helper receiveMessage2() - receiveMessage2(source, message); - } -} - -// ---------------------------------------------------------------------- -// GameServer::receiveMessage() is getting too big for the compiler to handle -// so some of the message handling is done in this private helper receiveMessage2() - -void GameServer::receiveMessage2(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) -{ - static Archive::ReadIterator ri; - static Archive::ByteStream bs; - - PROFILER_AUTO_BLOCK_DEFINE("GameServer::receiveMessage2"); - - if(message.isType("AuthTransferConfirmMessage")) - { - MESSAGE_PROFILER_BLOCK("AuthTransferConfirmMessage"); - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - AuthTransferTracker::handleConfirmAuthTransfer(msg.getValue().first, msg.getValue().second); - } - else if(message.isType("PersistedPlayerMessage")) - { - MESSAGE_PROFILER_BLOCK("PersistedPlayerMessage"); - ri = static_cast(message).getByteStream().begin(); - PersistedPlayerMessage const msg(ri); - LogoutTracker::onPersisted(msg.getPlayerId()); - sendToPlanetServer(msg); - } - else if(message.isType("RenameCharacterMessageEx")) - { - MESSAGE_PROFILER_BLOCK("RenameCharacterMessageEx"); - ri = static_cast(message).getByteStream().begin(); - RenameCharacterMessageEx msg(ri); - NameManager::getInstance().renamePlayer(msg.getCharacterId(), msg.getNewName(), msg.getNewName()); - - // update the character's name in the citizen and guild listing - if (ServerUniverse::getInstance().isAuthoritative()) - { - std::string const newName(Unicode::wideToNarrow(msg.getNewName())); - GuildInterface::verifyGuildMemberName(msg.getCharacterId(), newName); - CityInterface::verifyCitizenName(msg.getCharacterId(), newName); - CityInterface::verifyPgcChroniclerName(msg.getCharacterId(), newName); - } - } - else if(message.isType("PopulationListMessage")) - { - MESSAGE_PROFILER_BLOCK("PopulationListMessage"); - ri = static_cast(message).getByteStream().begin(); - PopulationListMessage const msg(ri); - ServerUniverse::getInstance().updatePopulationList(msg.getList()); - } - else if (message.isType("CentralPingMessage")) - { - MESSAGE_PROFILER_BLOCK("CentralPingMessage"); - CentralPingMessage const reply; - sendToCentralServer(reply); - } - else if (message.isType("LocateObject")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > const msg(ri); - - uint32 const responsePid = msg.getValue().first; - NetworkId const &targetId = msg.getValue().second.first; - NetworkId const &responseId = msg.getValue().second.second; - - ServerObject const * const targetObj = safe_cast(NetworkIdManager::getObjectById(targetId)); - if (targetObj) - { - std::vector containers; - for (Object const *o = ContainerInterface::getContainedByObject(*targetObj); o; o = ContainerInterface::getContainedByObject(*o)) - containers.push_back(o->getNetworkId()); - - NetworkId residenceOf; - if (!targetObj->getObjVars().getItem("player_structure.residence.building", residenceOf)) - residenceOf = NetworkId::cms_invalid; - - LocateObjectResponseMessage const msg( - targetId, - responseId, - responsePid, - targetObj->findPosition_w(), - ConfigServerGame::getSceneID(), - targetObj->getObjectTemplateName(), - getProcessId(), - containers, - targetObj->isAuthoritative(), - residenceOf); - - sendToCentralServer(msg); - } - } - else if (message.isType("LocateObjectByTemplateName")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > const msg(ri); - - uint32 const responsePid = msg.getValue().first; - uint32 const templateCrc = msg.getValue().second.first; - NetworkId const & responseId = msg.getValue().second.second; - - NetworkIdManager::NetworkIdObjectHashMap const & allObjects = NetworkIdManager::getAllObjects(); - for (NetworkIdManager::NetworkIdObjectHashMap::const_iterator iter = allObjects.begin(); iter != allObjects.end(); ++iter) - { - if (!iter->second->isAuthoritative()) - { - continue; - } - - ObjectTemplate const * const objectTemplate = iter->second->getObjectTemplate(); - if (objectTemplate && (objectTemplate->getCrcName().getCrc() == templateCrc)) - { - std::vector containers; - for (Object const *o = ContainerInterface::getContainedByObject(*(iter->second)); o; o = ContainerInterface::getContainedByObject(*o)) - containers.push_back(o->getNetworkId()); - - LocateObjectResponseMessage const msg( - iter->second->getNetworkId(), - responseId, - responsePid, - iter->second->findPosition_w(), - ConfigServerGame::getSceneID(), - objectTemplate->getName(), - getProcessId(), - containers, - true, - NetworkId::cms_invalid); - - sendToCentralServer(msg); - } - } - } - else if (message.isType("LocatePlayerByPartialName")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > const msg(ri); - - uint32 const responsePid = msg.getValue().first; - std::string const & partialName = msg.getValue().second.first; - NetworkId const & responseId = msg.getValue().second.second; - - // Try to find player objects with matching names - std::set const &players = PlayerObject::getAllPlayerObjects(); - if (!players.empty()) - { - // Convert the player name to wide character string - Unicode::String const widePartialName = Unicode::toLower(Unicode::utf8ToWide(partialName)); - - // See if a player object has a "matching" first name - std::set::const_iterator i; - for (i = players.begin(); i != players.end(); ++i) - { - PlayerObject const * const playerObject = *i; - CreatureObject const * const creatureObject = playerObject->getCreatureObject(); - - // don't include logged out players waiting to be saved or not initialized - if (!creatureObject || !creatureObject->isInWorld() || !creatureObject->isAuthoritative() || !creatureObject->getClient()) - continue; - - // Lower case the first name of the player for the comparison - Unicode::String lowerCasePlayerName = Unicode::toLower(creatureObject->getAssignedObjectFirstName()); - - // Try to find the partial name somewhere within the player name - if (partialName == "*" || lowerCasePlayerName.find(widePartialName) != Unicode::String::npos) - { - LocatePlayerResponseMessage const msg( - creatureObject->getNetworkId(), - responseId, - responsePid, - ConfigServerGame::getSceneID(), - creatureObject->findPosition_w(), - getProcessId()); - - sendToCentralServer(msg); - } - } - } - } - else if (message.isType("LocateWarden")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - uint32 const responsePid = msg.getValue().first; - NetworkId const & responseId = msg.getValue().second; - - // Try to find warden player objects - std::set const &players = PlayerObject::getAllPlayerObjects(); - if (!players.empty()) - { - std::set::const_iterator i; - for (i = players.begin(); i != players.end(); ++i) - { - PlayerObject const * const playerObject = *i; - CreatureObject const * const creatureObject = playerObject->getCreatureObject(); - - // don't include logged out players waiting to be saved or not initialized - if (!creatureObject || !creatureObject->isInWorld() || !creatureObject->isAuthoritative() || !creatureObject->getClient()) - continue; - - if (playerObject->isWarden()) - { - LocatePlayerResponseMessage const msg( - creatureObject->getNetworkId(), - responseId, - responsePid, - ConfigServerGame::getSceneID(), - creatureObject->findPosition_w(), - getProcessId()); - - sendToCentralServer(msg); - } - } - } - } - else if (message.isType("LocateCreatureByCreatureName")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > const msg(ri); - - uint32 const responsePid = msg.getValue().first; - std::string const & creatureName = msg.getValue().second.first; - NetworkId const & responseId = msg.getValue().second.second; - - CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures(); - for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i) - { - CreatureObject const * const creatureObj = *i; - if (creatureObj->isAuthoritative()) - { - AICreatureController const * const aiCreatureController = AICreatureController::asAiCreatureController(creatureObj->getController()); - if (aiCreatureController == NULL) - { - continue; - } - - PersistentCrcString const & pcsCreatureName = aiCreatureController->getCreatureName(); - if (pcsCreatureName.isEmpty()) - { - continue; - } - - if (creatureName != pcsCreatureName.getString()) - { - continue; - } - - std::vector containers; - for (Object const *o = ContainerInterface::getContainedByObject(*creatureObj); o; o = ContainerInterface::getContainedByObject(*o)) - containers.push_back(o->getNetworkId()); - - LocateObjectResponseMessage const msg( - creatureObj->getNetworkId(), - responseId, - responsePid, - creatureObj->findPosition_w(), - ConfigServerGame::getSceneID(), - creatureObj->getObjectTemplateName(), - getProcessId(), - containers, - true, - NetworkId::cms_invalid); - - sendToCentralServer(msg); - } - } - } - else if (message.isType("LSBOIReq")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair, NetworkId> > > const locateStructureByOwnerIdReq(ri); - - handleMessageLocateStructureByOwnerIdReq(*this, locateStructureByOwnerIdReq.getValue().first.first, locateStructureByOwnerIdReq.getValue().first.second, locateStructureByOwnerIdReq.getValue().second.first.first, locateStructureByOwnerIdReq.getValue().second.first.second, locateStructureByOwnerIdReq.getValue().second.second); - } - else if (message.isType("LSBOIRsp")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::vector > > const locateStructureByOwnerIdRsp(ri); - - handleMessageLocateStructureByOwnerIdRsp(locateStructureByOwnerIdRsp.getValue().first.second, locateStructureByOwnerIdRsp.getValue().second); - } - else if (message.isType("ReportSystemClockTime")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - -#ifdef WIN32 - std::string hostName = NetworkHandler::getHostName(); -#else - std::string hostName = NetworkHandler::getHumanReadableHostName(); -#endif - - std::string time = FormattedString<1024>().sprintf("(%3d,%5dms) %30s.%-2lu (%3lu) on %35s:%-7d (%lu) ", ObjectTracker::getNumPlayers(), static_cast(Clock::frameTime()*1000), ServerWorld::getSceneId().c_str(), m_preloadAreaId, m_processId, hostName.c_str(), Os::getProcessId(), ServerClock::getInstance().getGameTimeSeconds()); - time += CalendarTime::convertEpochToTimeStringGMT(::time(NULL)); - - GenericValueTypeMessage > > rsctr( - "ReportSystemClockTimeResponse", std::make_pair(msg.getValue().first, std::make_pair(time, msg.getValue().second))); - - sendToCentralServer(rsctr); - } - else if (message.isType("ReportSystemClockTimeResponse")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > const msg(ri); - - ConsoleMgr::broadcastString(msg.getValue().second.first, msg.getValue().second.second); - } - else if (message.isType("ReportPlanetaryTime")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - time_t const timeNow = ::time(NULL); - std::string time = FormattedString<1024>().sprintf("%30s.%-2lu (%3lu) (%lu) (%ld, ", ServerWorld::getSceneId().c_str(), m_preloadAreaId, m_processId, ServerClock::getInstance().getGameTimeSeconds(), timeNow); - time += CalendarTime::convertEpochToTimeStringGMT(timeNow); - time += ")"; - - const TerrainObject* const terrainObject = TerrainObject::getInstance(); - if (terrainObject) - { - const float environmentCycleTime = terrainObject->getEnvironmentCycleTime(); - if (environmentCycleTime > 0.f) - { - const float day = fmodf(static_cast(ServerClock::getInstance().getGameTimeSeconds()), environmentCycleTime) / environmentCycleTime; - int hour = 6 + static_cast(day * 24.f * 60.f) / 60; - if (hour >= 24) - hour -= 24; - const int minute = static_cast(fmodf(day * 24.f * 60.f, 60.f)); - - time += FormattedString<1024>().sprintf(" (%g, %02d:%02d, %f)", environmentCycleTime, hour, minute, day); - } - else - { - time += FormattedString<1024>().sprintf(" (environmentCycleTime %g is <= 0.f)", environmentCycleTime); - } - } - else - { - time += " (terrainObject is NULL)"; - } - - GenericValueTypeMessage > > rptr( - "ReportPlanetaryTimeResponse", std::make_pair(msg.getValue().first, std::make_pair(time, msg.getValue().second))); - - sendToCentralServer(rptr); - } - else if (message.isType("ReportPlanetaryTimeResponse")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > const msg(ri); - - ConsoleMgr::broadcastString(msg.getValue().second.first, msg.getValue().second.second); - } - else if (message.isType("ClusterStartComplete")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - if (msg.getValue()) - { - // cluster initial start has completed - if (ServerUniverse::getInstance().isAuthoritative()) - { - // add player city travel points - std::map const & allCities = CityInterface::getAllCityInfo(); - for (std::map::const_iterator iter = allCities.begin(); iter != allCities.end(); ++iter) - { - CityInfo const & ci = iter->second; - if (ci.getCityName().empty()) - continue; - - if ((ci.getRadius() >= 400) && (ci.getTravelCost() > 0)) - { - PlanetObject *planet = ServerUniverse::getInstance().getPlanetByName(ci.getPlanet()); - if (planet) - { - planet->addTravelPoint( - ci.getCityName(), - ci.getTravelLoc(), - ci.getTravelCost(), - ci.getTravelInterplanetary(), - TravelPoint::TPT_PC_Shuttleport); - } - } - } - - // do some sanity check of GCW score - GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); - CityObject const * const co = ServerUniverse::getInstance().getMasterCityObject(); - if (go && go->isAuthoritative() && co && co->isAuthoritative()) - { - // depersist GCW score, if it hasn't already been done - std::map const & gcwImperialScorePercentile = go->getGcwImperialScorePercentile(); - if (gcwImperialScorePercentile.empty()) - { - // this will also calculate the GCW Region Defender Bonus - go->depersistGcwImperialScorePercentile(); - } - else - { - // for sanity's sake, (re)calculate the GCW Region Defender Bonus - for (std::map::const_iterator iter = gcwImperialScorePercentile.begin(); iter != gcwImperialScorePercentile.end(); ++iter) - go->updateGcwRegionDefenderBonus(iter->first); - } - } - } - - if (ConfigServerGame::getEnableCityCitizenshipFixup() && ServerUniverse::getInstance().isAuthoritative()) - { - std::vector const & allGameServerPids = getAllGameServerPids(); - if (!allGameServerPids.empty()) - { - ServerMessageForwarding::beginBroadcast(); - GenericValueTypeMessage clusterStartupResidenceStructureListRequest("CSRSLReq", getProcessId()); - ServerMessageForwarding::send(clusterStartupResidenceStructureListRequest); - ServerMessageForwarding::end(); - - s_clusterStartupResidenceStructureListResponse.clear(); - for (std::vector::const_iterator iter = allGameServerPids.begin(); iter != allGameServerPids.end(); ++iter) - IGNORE_RETURN(s_clusterStartupResidenceStructureListResponse.insert(*iter)); - } - else - { - s_clusterStartupResidenceStructureListByStructure.clear(); - s_clusterStartupResidenceStructureListResponse.clear(); - } - } - else if (!ConfigServerGame::getEnableCityCitizenshipFixup()) - { - s_clusterStartupResidenceStructureListByStructure.clear(); - s_clusterStartupResidenceStructureListResponse.clear(); - } - } - else - { - s_clusterStartupResidenceStructureListByStructure.clear(); - s_clusterStartupResidenceStructureListResponse.clear(); - } - } - else if (message.isType("CSRSLReq")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const clusterStartupResidenceStructureListRequest(ri); - - ServerMessageForwarding::begin(clusterStartupResidenceStructureListRequest.getValue()); - - std::map > clusterStartupResidenceStructureListByCity; - if (!s_clusterStartupResidenceStructureListByStructure.empty()) - { - for (std::map >::const_iterator iter = s_clusterStartupResidenceStructureListByStructure.begin(); iter != s_clusterStartupResidenceStructureListByStructure.end(); ++iter) - IGNORE_RETURN(clusterStartupResidenceStructureListByCity[iter->second.first].insert(iter->second.second)); - } - - GenericValueTypeMessage > > > clusterStartupResidenceStructureListResponse("CSRSLRsp", std::make_pair(getProcessId(), clusterStartupResidenceStructureListByCity)); - ServerMessageForwarding::send(clusterStartupResidenceStructureListResponse); - ServerMessageForwarding::end(); - - s_clusterStartupResidenceStructureListByStructure.clear(); - s_clusterStartupResidenceStructureListResponse.clear(); - } - else if (message.isType("CSRSLRsp")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > > > const clusterStartupResidenceStructureListResponse(ri); - - if (s_clusterStartupResidenceStructureListResponse.erase(clusterStartupResidenceStructureListResponse.getValue().first) != 0) - { - static std::map > s_clusterStartupResidenceStructureListByCity; - - std::map > const & residenceList = clusterStartupResidenceStructureListResponse.getValue().second; - if (!residenceList.empty()) - { - for (std::map >::const_iterator iter = residenceList.begin(); iter != residenceList.end(); ++iter) - { - if (!iter->second.empty()) - s_clusterStartupResidenceStructureListByCity[iter->first].insert(iter->second.begin(), iter->second.end()); - } - } - - if (s_clusterStartupResidenceStructureListResponse.empty()) - { - // add our own information to the list - if (!s_clusterStartupResidenceStructureListByStructure.empty()) - { - for (std::map >::const_iterator iter = s_clusterStartupResidenceStructureListByStructure.begin(); iter != s_clusterStartupResidenceStructureListByStructure.end(); ++iter) - IGNORE_RETURN(s_clusterStartupResidenceStructureListByCity[iter->second.first].insert(iter->second.second)); - } - - // we now have the complete list of every declared structure within - // city limits; besides the mayor, only owners of these structures - // can be in the citizenship list, so fix up the citizenship list - // of all cities right now - - // skip the fixup if it looks like the cluster was started - // without loading the entire planet because it means structures - // were not loaded, so we don't have the information to determine citizenship - if (!s_clusterStartupResidenceStructureListByCity.empty()) - { - // cities that have no declared structures don't have anything in - // the report, so we have to manually add in those cities - std::map > allCityMayors; - std::map const & allCities = CityInterface::getAllCityInfo(); - - for (std::map::const_iterator iterAllCities = allCities.begin(); iterAllCities != allCities.end(); ++iterAllCities) - { - if (s_clusterStartupResidenceStructureListByCity.count(iterAllCities->first) <= 0) - IGNORE_RETURN(s_clusterStartupResidenceStructureListByCity.insert(std::make_pair(iterAllCities->first, std::set()))); - - if (iterAllCities->second.getLeaderId().isValid()) - allCityMayors[iterAllCities->second.getLeaderId()] = std::make_pair(iterAllCities->first, iterAllCities->second.getCityName()); - } - - // remove citizens (except the mayor) that do not have a declared structure inside the city limits - // if necessary, add as citizen those that have a declared structure inside the city limits - std::string cityName; - std::string citizenName; - int citizenLastLoginTime = 0; - NetworkId currentCityMayor; - CitizenInfo const * currentCityMayorCitizenInfo; - std::string currentCityMayorName; - std::vector citizensToRemove; - std::string citizensToRemoveNames; - std::string citizensToRemoveDeletedNames; - std::string citizensToRemoveInactiveNames; - std::string citizensToAddNames; - bool needToAddMayorAsCitizen; - bool removeCurrentCitizen; - bool removeCurrentCitizenDeleted; - bool removeCurrentCitizenInactive; - bool hasDeclaredResidence; - int const timeNow = static_cast(::time(NULL)); - bool const citizenInactivePackupActive = (ConfigServerGame::getCityCitizenshipInactivePackupStartTimeEpoch() <= timeNow); - std::map, CitizenInfo> const & allCitizens = CityInterface::getAllCitizensInfo(); - for (std::map >::iterator iterCityId = s_clusterStartupResidenceStructureListByCity.begin(); iterCityId != s_clusterStartupResidenceStructureListByCity.end(); ++iterCityId) - { - CityInfo const & cityInfo = CityInterface::getCityInfo(iterCityId->first); - - cityName = cityInfo.getCityName(); - if (cityName.empty()) - continue; - - if (!cityInfo.getCityHallId().isValid()) - continue; - - currentCityMayor = cityInfo.getLeaderId(); - if (currentCityMayor.isValid()) - currentCityMayorCitizenInfo = CityInterface::getCitizenInfo(iterCityId->first, currentCityMayor); - else - currentCityMayorCitizenInfo = NULL; - - if (currentCityMayorCitizenInfo) - currentCityMayorName = currentCityMayorCitizenInfo->m_citizenName; - else - currentCityMayorName.clear(); - - if (currentCityMayor.isValid() && !currentCityMayorCitizenInfo) - needToAddMayorAsCitizen = true; - else - needToAddMayorAsCitizen = false; - - LOG("CityFixup", ("City %d (%s:%s, %s:%s) has %d declared structures within its city limits.", iterCityId->first, cityName.c_str(), cityInfo.getCityHallId().getValueString().c_str(), currentCityMayorName.c_str(), currentCityMayor.getValueString().c_str(), iterCityId->second.size())); - - // remove any current citizen who has not logged in for 90 days and is not marked - // as a "protected citizen" OR who no longer exists in the DB OR who does not have - // a declared structure in the city EXCEPT the mayor of the city; also remove any - // current citizen who is a mayor of another city, since mayor can only be the - // citizen of the city that they are mayor of - static const Unicode::String mailSubjectRemove = Unicode::narrowToWide("@" + StringId("city/city", "city_fixup_remove_citizens_subject").getCanonicalRepresentation()); - citizensToRemove.clear(); - citizensToRemoveNames.clear(); - citizensToRemoveDeletedNames.clear(); - citizensToRemoveInactiveNames.clear(); - for (std::map, CitizenInfo>::const_iterator iterCurrentCitizen = allCitizens.lower_bound(std::make_pair(iterCityId->first, NetworkId::cms_invalid)); iterCurrentCitizen != allCitizens.end(); ++iterCurrentCitizen) - { - if (iterCurrentCitizen->first.first != iterCityId->first) - break; - - // the erase() will tell us whether this current citizen is confirmed to have - // a declared structure in the city; what it also does for us is whoever is left - // in the list after all the erase() is done are people who have a declared - // structure in the city but are not current citizens, and will need to be added - // as citizens - citizenName = iterCurrentCitizen->second.m_citizenName; - removeCurrentCitizen = false; - removeCurrentCitizenDeleted = false; - removeCurrentCitizenInactive = false; - hasDeclaredResidence = (iterCityId->second.erase(iterCurrentCitizen->first.second) >= 1); - - // mayor never gets removed - if (iterCurrentCitizen->first.second != currentCityMayor) - { - if (!hasDeclaredResidence) - { - // remove citizen because he doesn't have a declared residence inside the city limits - removeCurrentCitizen = true; - LOG("CustomerService", ("CityFixup: removed %s (%s) (no declared residence) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); - } - else if (allCityMayors.count(iterCurrentCitizen->first.second) >= 1) - { - // remove citizen because he is already the mayor of another city - removeCurrentCitizen = true; - LOG("CustomerService", ("CityFixup: removed %s (%s) (already mayor of %d:%s) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), allCityMayors[iterCurrentCitizen->first.second].first, allCityMayors[iterCurrentCitizen->first.second].second.c_str(), iterCityId->first, cityName.c_str())); - } - else - { - citizenLastLoginTime = NameManager::getInstance().getPlayerLastLoginTime(iterCurrentCitizen->first.second); - if (citizenLastLoginTime <= 0) - { - // remove citizen because he no longer exists in the DB - removeCurrentCitizen = true; - removeCurrentCitizenDeleted = true; - LOG("CustomerService", ("CityFixup: removed %s (%s) (deleted) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); - } - else if (citizenInactivePackupActive && ((citizenLastLoginTime + ConfigServerGame::getCityCitizenshipInactivePackupInactiveTimeSeconds()) <= timeNow) && !(iterCurrentCitizen->second.m_citizenPermissions & CitizenPermissions::InactiveProtected)) - { - // remove citizen because he has not logged in for 90 days and is not marked as a "protected citizen" - removeCurrentCitizen = true; - removeCurrentCitizenInactive = true; - LOG("CustomerService", ("CityFixup: removed %s (%s) (inactive %s) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), CalendarTime::convertSecondsToDHMS(static_cast(timeNow - citizenLastLoginTime)).c_str(), iterCityId->first, cityName.c_str())); - } - } - } - - if (removeCurrentCitizen) - { - // build up list of citizens to remove - citizensToRemove.push_back(iterCurrentCitizen->first.second); - - // build list of citizens that gets removed to send mail to mayor - if (!currentCityMayorName.empty()) - { - if (removeCurrentCitizenDeleted) - { - if (!citizensToRemoveDeletedNames.empty()) - citizensToRemoveDeletedNames += "\r\n"; - - citizensToRemoveDeletedNames += citizenName; - - // send multiple mail if there are too many names - if (citizensToRemoveDeletedNames.size() > 2000) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_remove_deleted_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToRemoveDeletedNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); - - citizensToRemoveDeletedNames.clear(); - } - } - else if (removeCurrentCitizenInactive) - { - if (!citizensToRemoveInactiveNames.empty()) - citizensToRemoveInactiveNames += "\r\n"; - - citizensToRemoveInactiveNames += citizenName; - citizensToRemoveInactiveNames += " (offline "; - citizensToRemoveInactiveNames += CalendarTime::convertSecondsToDHMS(static_cast(timeNow - citizenLastLoginTime)); - citizensToRemoveInactiveNames += ")"; - - // send multiple mail if there are too many names - if (citizensToRemoveInactiveNames.size() > 2000) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_remove_inactive_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToRemoveInactiveNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); - - citizensToRemoveInactiveNames.clear(); - } - } - else - { - if (!citizensToRemoveNames.empty()) - citizensToRemoveNames += "\r\n"; - - citizensToRemoveNames += citizenName; - - // send multiple mail if there are too many names - if (citizensToRemoveNames.size() > 2000) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_remove_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToRemoveNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); - - citizensToRemoveNames.clear(); - } - } - } - } - } - - if (!currentCityMayorName.empty()) - { - if (!citizensToRemoveDeletedNames.empty()) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_remove_deleted_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToRemoveDeletedNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); - } - - if (!citizensToRemoveInactiveNames.empty()) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_remove_inactive_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToRemoveInactiveNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); - } - - if (!citizensToRemoveNames.empty()) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_remove_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToRemoveNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); - } - } - - // remove citizens - for (std::vector::const_iterator iterCitizenToRemove = citizensToRemove.begin(); iterCitizenToRemove != citizensToRemove.end(); ++iterCitizenToRemove) - { - CityInterface::removeCitizen(iterCityId->first, *iterCitizenToRemove, false); - } - - // add mayor as a citizen if necessary - if (needToAddMayorAsCitizen) - IGNORE_RETURN(iterCityId->second.insert(currentCityMayor)); - - // add citizens - static const Unicode::String mailSubjectAdd = Unicode::narrowToWide("@" + StringId("city/city", "city_fixup_add_citizens_subject").getCanonicalRepresentation()); - citizensToAddNames.clear(); - for (std::set::const_iterator iterCitizenToAdd = iterCityId->second.begin(); iterCitizenToAdd != iterCityId->second.end(); ++iterCitizenToAdd) - { - // make sure it's a valid player - if (!NameManager::getInstance().isPlayer(*iterCitizenToAdd)) - continue; - - // citizens who have not logged in within the past 90 days should not be - // added as a citizen EXCEPT for the mayor who should always be a citizen - if ((*iterCitizenToAdd != currentCityMayor) && citizenInactivePackupActive) - { - citizenLastLoginTime = NameManager::getInstance().getPlayerLastLoginTime(*iterCitizenToAdd); - if ((citizenLastLoginTime <= 0) || ((citizenLastLoginTime + ConfigServerGame::getCityCitizenshipInactivePackupInactiveTimeSeconds()) <= timeNow)) - continue; - } - - // don't add someone who is already a mayor of another city, unless - // we are adding this city's mayor as a citizen of this city - if ((*iterCitizenToAdd != currentCityMayor) && (allCityMayors.count(*iterCitizenToAdd) >= 1)) - continue; - - // add the new citizen - citizenName = NameManager::getInstance().getPlayerFullName(*iterCitizenToAdd); - if (citizenName.empty()) - continue; - - // build list of citizens that gets added to send mail to mayor - if (!currentCityMayorName.empty()) - { - if (!citizensToAddNames.empty()) - citizensToAddNames += "\r\n"; - - citizensToAddNames += citizenName; - - // send multiple mail if there are too many names - if (citizensToAddNames.size() > 2000) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_add_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToAddNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectAdd, Unicode::emptyString, oob); - - citizensToAddNames.clear(); - } - } - - if (*iterCitizenToAdd == currentCityMayor) - LOG("CustomerService", ("CityFixup: added %s (%s) (is mayor) as citizen of city %d (%s).", iterCitizenToAdd->getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); - else - LOG("CustomerService", ("CityFixup: added %s (%s) (has declared residence) as citizen of city %d (%s).", iterCitizenToAdd->getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); - - CityInterface::setCitizenInfo(iterCityId->first, *iterCitizenToAdd, citizenName, NetworkId::cms_invalid, CitizenPermissions::Citizen); - } - - if (!citizensToAddNames.empty() && !currentCityMayorName.empty()) - { - ProsePackage pp; - pp.stringId = StringId("city/city", "city_fixup_add_citizens_body"); - pp.target.str = Unicode::narrowToWide(citizensToAddNames); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectAdd, Unicode::emptyString, oob); - } - } - } - - s_clusterStartupResidenceStructureListByCity.clear(); - s_clusterStartupResidenceStructureListByStructure.clear(); - s_clusterStartupResidenceStructureListResponse.clear(); - - CityInterface::checkForDualCitizenship(); - } - } - } - else if (message.isType("LocateStructureMessage")) - { - ri = static_cast(message).getByteStream().begin(); - LocateStructureMessage const msg(ri); - GameServer::getInstance().sendToCentralServer(msg); - } - else if (message.isType("LoadStructureMessage")) - { - ri = static_cast(message).getByteStream().begin(); - LoadStructureMessage const msg(ri); - - ServerObject * const house = ServerWorld::findObjectByNetworkId(msg.getStructureId()); - if (house) - { - //result += Unicode::narrowToWide("Error. Object already loaded."); - std::string replyMessage = "Structure " + msg.getStructureId().getValueString() + " already loaded"; - Chat::sendSystemMessage(msg.getWhoRequested(), Unicode::narrowToWide(replyMessage), Unicode::String()); - } - else - { - LoadContentsMessage const lcm(msg.getStructureId()); - GameServer::getInstance().sendToDatabaseServer(lcm); - std::string const replyMessage = "Structure " + msg.getStructureId().getValueString() + " is being loaded"; - Chat::sendSystemMessage(msg.getWhoRequested(), Unicode::narrowToWide(replyMessage), Unicode::String()); - } - } - else if (message.isType("LocateObjectResponseMessage")) - { - ri = static_cast(message).getByteStream().begin(); - LocateObjectResponseMessage const msg(ri); - - ServerObject * const responseObject = safe_cast(NetworkIdManager::getObjectById(msg.getResponseId())); - if (responseObject && responseObject->isAuthoritative()) - { - int const cityId = CityInterface::getCityAtLocation(msg.getScene(), static_cast(msg.getPosition_w().x), static_cast(msg.getPosition_w().z), 0); - std::string const cityName = CityInterface::getCityInfo(cityId).getCityName(); - - NetworkId const residenceOf = msg.getResidenceOf(); - std::string residenceOfName; - if (residenceOf.isValid()) - residenceOfName = NameManager::getInstance().getPlayerFullName(residenceOf); - - ScriptParams params; - params.addParam(msg.getTargetId(), "target"); - params.addParam(msg.getPosition_w(), "location"); - params.addParam(msg.getScene().c_str(), "scene"); - params.addParam(msg.getSharedTemplateName().c_str(), "sharedTemplateName"); - params.addParam(static_cast(msg.getTargetPid()), "pid"); - params.addParam(msg.getContainers(), "containers"); - params.addParam(msg.getIsAuthoritative(), "isAuthoritative"); - params.addParam(cityId, "cityId"); - params.addParam(cityName.c_str(), "cityName"); - params.addParam(residenceOf, "residenceOfId"); - params.addParam(residenceOfName.c_str(), "residenceOfName"); - - ScriptDictionaryPtr dictionary; - responseObject->getScriptObject()->makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(responseObject->getNetworkId(), "foundObject", dictionary->getSerializedData(), 0, false); - } - } - } - else if (message.isType("LocatePlayerResponseMessage")) - { - ri = static_cast(message).getByteStream().begin(); - LocatePlayerResponseMessage const msg(ri); - - ServerObject * const responseObject = safe_cast(NetworkIdManager::getObjectById(msg.getResponseId())); - if (responseObject && responseObject->isAuthoritative() && responseObject->getClient()) - { - std::string playerInfo = FormattedString<512>().sprintf("%s (%s) is on server %lu. %s (%.2f, %.2f, %.2f)", - msg.getTargetId().getValueString().c_str(), - NameManager::getInstance().getPlayerFullName(msg.getTargetId()).c_str(), - msg.getTargetPid(), msg.getScene().c_str(), - msg.getPosition_w().x, msg.getPosition_w().y, msg.getPosition_w().z); - - ConsoleMgr::broadcastString(playerInfo, responseObject->getClient()); - } - } - else if(message.isType("PlayerSanityCheck")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - PlayerSanityChecker::handlePlayerSanityCheck(msg.getValue().first, msg.getValue().second); - } - else if(message.isType("PlayerSanityCheckSuccess")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - PlayerSanityChecker::handlePlayerSanityCheckSuccess(msg.getValue()); - } - else if(message.isType("PlayerSanityCheckProxy")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - PlayerSanityChecker::handlePlayerSanityCheckProxy(msg.getValue().first, msg.getValue().second); - } - else if(message.isType("PlayerSanityCheckProxyFail")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - PlayerSanityChecker::handlePlayerSanityCheckProxyFail(msg.getValue().first, msg.getValue().second); - } - else if (message.isType("EnablePlayerSanityCheckerMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - PlayerSanityChecker::enable(msg.getValue()); - } - else if(message.isType("StartSaveReplyMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - ServerObject const * const requestedBy = safe_cast(NetworkIdManager::getObjectById(msg.getValue().first)); - - if (requestedBy) - { - if (msg.getValue().second) - Chat::sendSystemMessage(*requestedBy,Unicode::narrowToWide("Save has been started"),Unicode::String()); - else - Chat::sendSystemMessage(*requestedBy,Unicode::narrowToWide("Save could not be started because one was already in progress"),Unicode::String()); - } - } - else if(message.isType("DatabaseConsoleReplyMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - Chat::sendSystemMessage(msg.getValue().first,Unicode::narrowToWide(msg.getValue().second),Unicode::String()); - } - else if(message.isType("FindAuthObject")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - ServerObject const * const so = safe_cast(NetworkIdManager::getObjectById(msg.getValue().first)); - bool const found = so && so->isAuthoritative(); - - GenericValueTypeMessage, bool> > const authResponse( - "FindAuthObjectResponse", - std::make_pair(msg.getValue(), found)); - sendToPlanetServer(authResponse); - } - else if(message.isType("CharacterNamesMessage")) - { - ri = static_cast(message).getByteStream().begin(); - CharacterNamesMessage const msg(ri); - NameManager::getInstance().addPlayers(msg.getIds(), msg.getStationIds(), msg.getNames(), msg.getFullNames(), msg.getCreateTimes(), msg.getLoginTimes()); - } - else if (message.isType ("LocationResponse")) - { - Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); - LocationResponse const locationResponse (readIterator); - - //-- get the script object to invole the trigger on - Object * const object = NetworkIdManager::getObjectById (locationResponse.getNetworkId ()); - if (!object) - { - DEBUG_WARNING (true, ("LocationResponse: could not resolve object %s which asked for a location", locationResponse.getNetworkId ().getValueString ().c_str ())); - return; - } - - ServerObject * const scriptObject = object->asServerObject (); - if (!scriptObject) - { - DEBUG_WARNING (true, ("LocationResponse: object id=%s template=%s is not a server object", object->getNetworkId ().getValueString ().c_str (), object->getObjectTemplateName ())); - return; - } - - //-- if the location is valid, create a reservation object - Vector position_w (locationResponse.getX (), 0.f, locationResponse.getZ ()); - ServerObject * serverObject = 0; - if (locationResponse.getValid ()) - { - //-- construct the name - char objectTemplateName [512]; - snprintf (objectTemplateName, 512, "object/tangible/location/location_%i.iff", static_cast (locationResponse.getRadius ())); - - //-- get the height of the terrain - TerrainObject const * const terrainObject = TerrainObject::getConstInstance (); - if (terrainObject) - terrainObject->getHeightForceChunkCreation (position_w, position_w.y); - - //-- create the object - Transform tr; - tr.setPosition_p(position_w); - serverObject = ServerWorld::createNewObject(objectTemplateName, tr, 0, false); - DEBUG_REPORT_LOG (!serverObject, ("LocationResponse: failed to create object %s\n", objectTemplateName)); - if (serverObject) - serverObject->addToWorld (); - } - - //-- inform script of the result - ScriptParams scriptParameters; - scriptParameters.addParam (locationResponse.getLocationId ().c_str()); - scriptParameters.addParam (serverObject ? serverObject->getNetworkId () : NetworkId::cms_invalid); - scriptParameters.addParam (position_w); - scriptParameters.addParam (locationResponse.getRadius ()); - - if (scriptObject->getScriptObject ()->trigAllScripts (Scripting::TRIG_LOCATION_RECEIVED, scriptParameters) != SCRIPT_CONTINUE) - DEBUG_REPORT_LOG (true, ("LocationResponse: TRIG_LOCATION_RECEIVED: did not return SCRIPT_CONTINUE\n")); - } - else if (message.isType("ReleaseCharacterNameByIdMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - NameManager::getInstance().releasePlayerName(msg.getValue()); - } - else if (message.isType("AddAttribModName")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - AttribModNameManager::getInstance().addAttribModNameFromRemote(msg.getValue().c_str()); - } - else if (message.isType("AddAttribModNamesList")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - DEBUG_REPORT_LOG(true, ("Received attrib mod names list <%s> from remote server\n", msg.getValue().c_str())); - AttribModNameManager::getInstance().addAttribModNamesListFromRemote(msg.getValue().c_str()); - } - else if(ClusterWideDataClient::handleMessage(source, message)) - { - // nothing else to do with the message since it was - // handled by the Cluster wide data client - } - else if (message.isType("AiCreatureStateMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - NetworkId const & networkId = msg.getValue().m_networkId; - AiMovementMessage const & movement = msg.getValue().m_movement; - - CreatureObject * const creatureObject = CreatureObject::getCreatureObject(networkId); - - if (creatureObject != NULL) - { - Controller * const controller = creatureObject->getController(); - - if (controller != NULL) - { - DEBUG_LOG("debug_ai", ("GameServer::receiveMessage() Received AiCreatureStateMessage for networkId(%s) movementType(%s)", networkId.getValueString().c_str(), AiMovementBase::getMovementString(movement.getMovementType()))); - - int const flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_SERVER; - - // Movement - - controller->appendMessage(CM_aiSetMovement, 0, new AiMovementMessage(movement), flags); - } - else - { - WARNING(true, ("GameServer::receiveMessage() Received AiCreatureStateMessage for networkId(%s) movementType(%s) but the object does not have a Controller", networkId.getValueString().c_str(), AiMovementBase::getMovementString(movement.getMovementType()))); - } - } - else - { - WARNING(true, ("GameServer::receiveMessage() Received AiCreatureStateMessage for networkId(%s) movementType(%s) but could not resolve to a CreatureObject", networkId.getValueString().c_str(), AiMovementBase::getMovementString(movement.getMovementType()))); - } - } - else if (message.isType("UnloadPersistedCharacter")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const upc(ri); - - ServerObject * const object = ServerWorld::findObjectByNetworkId(upc.getValue()); - if (object) - { - WARNING(true, ("Unloaded character object (%s) which has been persisted but still exists on this game server", object->getDebugInformation().c_str())); - object->unload(); - } - } - else if (message.isType("AboutToLoadCharacterFromDB")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const atlcfdb(ri); - - ServerObject * const object = ServerWorld::findObjectByNetworkId(atlcfdb.getValue().first); - if (object) - { - WARNING(true, ("Unloaded character object (%s) because the character object is about to be loaded from the DB onto game server (%lu), I am game server (%lu)", object->getDebugInformation().c_str(), atlcfdb.getValue().second, getProcessId())); - object->unload(); - } - } - else if (message.isType("ClearTheaterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const ctm(ri); - - ServerUniverse::getInstance().remoteClearTheater(ctm.getValue()); - } - else if (message.isType("SetTheaterMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const stm(ri); - - ServerUniverse::getInstance().remoteSetTheater(stm.getValue().first, stm.getValue().second); - } - else if (message.isType("PageChangeAuthority")) - { - ServerUIManager::receiveMessage(message); - } - else if (message.isType("PlayedTimeAccumMessage")) - { - Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); - PlayedTimeAccumMessage const ptam(ri); - Object * obj = NetworkIdManager::getObjectById(ptam.getNetworkId()); - if (obj != NULL && obj->asServerObject() != NULL && obj->asServerObject()->asCreatureObject() != NULL) - { - CreatureObject * target = obj->asServerObject()->asCreatureObject(); - PlayerObject *targetPlayer = target->asPlayerObject(); - if(targetPlayer) - { - targetPlayer->setPlayedTimeAccumOnly(ptam.getPlayedTimeAccum()); - } - else - { - target->setPseudoPlayedTime(ptam.getPlayedTimeAccum()); - } - } - - } - else if (message.isType("ManualDepleteResourceMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - ServerUniverse::getInstance().manualDepleteResource(msg.getValue()); - } - else if (message.isType("ClaimRewardsReplyMessage")) - { - ri = static_cast(message).getByteStream().begin(); - ClaimRewardsReplyMessage msg(ri); - VeteranRewardManager::handleClaimRewardsReply(msg.getStationId(), msg.getPlayer(), msg.getRewardEvent(), msg.getRewardItem(), msg.getAccountFeatureId(), msg.getConsumeAccountFeatureId(), msg.getPreviousAccountFeatureIdCount(), msg.getCurrentAccountFeatureIdCount(), msg.getResult(), true); - } - else if (message.isType("SetOverrideAccountAgeMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - - VeteranRewardManager::setOverrideAccountAge(msg.getValue()); - } - else if (message.isType("GetMoneyFromOfflineObjectMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GetMoneyFromOfflineObjectMessage msg(ri); - - std::string const & callback = msg.getSuccess() ? msg.getSuccessCallback() : msg.getFailCallback(); - MessageToQueue::getInstance().sendMessageToJava(msg.getReplyTo(), callback, msg.getPackedDictionary(), 0, false); - } - else if (message.isType(SlowDownEffectMessage::MessageType)) - { - ri = static_cast(message).getByteStream().begin(); - SlowDownEffectMessage msg(ri); - - // get the attacker - Object * obj = NetworkIdManager::getObjectById(msg.getSource()); - if (obj != NULL && obj->asServerObject() != NULL && obj->asServerObject()->asCreatureObject() != NULL) - { - CreatureObject * attacker = obj->asServerObject()->asCreatureObject(); - - // get the target - obj = NetworkIdManager::getObjectById(msg.getTarget()); - if (obj != NULL && obj->asServerObject() != NULL && obj->asServerObject()->asTangibleObject() != NULL) - { - TangibleObject * defender = obj->asServerObject()->asTangibleObject(); - if (attacker->isAuthoritative()) - attacker->addSlowDownEffect(*defender, msg.getConeLength(), msg.getConeAngle(), msg.getSlopeAngle(), msg.getExpireTime()); - else - attacker->addSlowDownEffectProxy(*defender, msg.getConeLength(), msg.getConeAngle(), msg.getSlopeAngle(), msg.getExpireTime()); - } - } - } - else if (message.isType("StructuresForPurgeMessage")) - { - ri = static_cast(message).getByteStream().begin(); - StructuresForPurgeMessage msg(ri); - PurgeManager::handleStructuresAndVendorsForPurge(msg.getStationId(), msg.getStructures(), msg.getVendors(), msg.getWarnOnly()); - } - else if (message.isType("RequestLoadAckMessage")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage msg(ri); - - GenericValueTypeMessage reply("LoadAckMessage",msg.getValue()); - sendToDatabaseServer(reply); - } - else if (message.isType("FactionalSystemMessage")) - { - ri = static_cast(message).getByteStream().begin(); - FactionalSystemMessage msg(ri); - handleFactionalSystemMessage(msg); - } - else if (message.isType("MessageToPlayersOnPlanet")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage >, std::pair >, std::pair > > const msg(ri); - handleMessageToPlayersOnPlanet(msg.getValue().first.first.first, msg.getValue().first.first.second, msg.getValue().first.second.first, msg.getValue().second.first, msg.getValue().second.second, msg.getValue().first.second.second); - } - else if (message.isType("PopStatReq")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const populationStatisticsRequest(ri); - UNREF(populationStatisticsRequest); - - const GenericValueTypeMessage > populationStatisticsResponse("PopStatRsp", LfgCharacterData::calculateStatistics(ServerUniverse::getConnectedCharacterLfgData())); - sendToCentralServer(populationStatisticsResponse); - } - else if (message.isType("GcwScoreStatReq")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const gcwScoreStatisticsRequest(ri); - UNREF(gcwScoreStatisticsRequest); - - static const std::map > emptyGcwScore; - PlanetObject const * const tatooine = ServerUniverse::getInstance().getTatooinePlanet(); - - static const std::map emptyGcwScorePercentile; - GuildObject const * const guildObject = ServerUniverse::getInstance().getMasterGuildObject(); - - const GenericValueTypeMessage, std::pair >, std::map > > > > gcwScoreStatisticsResponse("GcwScoreStatRsp", std::make_pair((guildObject ? guildObject->getGcwImperialScorePercentile() : emptyGcwScorePercentile), std::make_pair((tatooine ? tatooine->getGcwImperialScore() : emptyGcwScore), (tatooine ? tatooine->getGcwRebelScore() : emptyGcwScore)))); - sendToCentralServer(gcwScoreStatisticsResponse); - } - else if (message.isType("GcwScoreStatRaw")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage >, std::map > > > > const msg(ri); - if (ConfigServerGame::getReceiveGcwScoreFromOtherGalaxies() && ServerUniverse::getInstance().isAuthoritative() && _stricmp(getClusterName().c_str(), msg.getValue().first.c_str())) - { - GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); - if (go && go->isAuthoritative()) - { - go->setGcwRawScoreFromOtherGalaxy(msg.getValue().first, msg.getValue().second.first, msg.getValue().second.second); - } - } - } - else if (message.isType("GcwScoreStatPct")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::map > > > const msg(ri); - if (ConfigServerGame::getReceiveGcwScoreFromOtherGalaxies() && ServerUniverse::getInstance().isAuthoritative() && _stricmp(getClusterName().c_str(), msg.getValue().first.c_str())) - { - GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); - if (go && go->isAuthoritative()) - { - go->setGcwImperialScorePercentileFromOtherGalaxy(msg.getValue().first, msg.getValue().second.first, msg.getValue().second.second); - } - } - } - else if (message.isType("LLTStatReq")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const lastLoginTimeStatisticsRequest(ri); - UNREF(lastLoginTimeStatisticsRequest); - - static std::map > lastLoginTimeStatistics; - if (lastLoginTimeStatistics.empty()) - { - lastLoginTimeStatistics[(60 * 60 * 24 * 1)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day001"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 2)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day002"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 3)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day003"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 4)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day004"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 5)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day005"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 6)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day006"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 7)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day007"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 14)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day014"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 21)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day021"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 30)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day030"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 60)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day060"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 90)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day090"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 180)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day180"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 270)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day270"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 365)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Year1"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 730)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Year2"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 1095)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Year3"), 0); - lastLoginTimeStatistics[(60 * 60 * 24 * 9999)] = std::make_pair(std::string("totalCharacters"), 0); - } - - NameManager::getInstance().getPlayerWithLastLoginTimeAfterDistribution(lastLoginTimeStatistics); - - std::map >::iterator iter = lastLoginTimeStatistics.begin(); - std::map >::iterator previousIter = lastLoginTimeStatistics.begin(); - for (; iter != lastLoginTimeStatistics.end(); ++iter) - { - if (iter != previousIter) - iter->second.second += previousIter->second.second; - - previousIter = iter; - } - - static std::map > createTimeStatistics; - if (createTimeStatistics.empty()) - { - createTimeStatistics[(60 * 60 * 24 * 1)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day001"), 0); - createTimeStatistics[(60 * 60 * 24 * 2)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day002"), 0); - createTimeStatistics[(60 * 60 * 24 * 3)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day003"), 0); - createTimeStatistics[(60 * 60 * 24 * 4)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day004"), 0); - createTimeStatistics[(60 * 60 * 24 * 5)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day005"), 0); - createTimeStatistics[(60 * 60 * 24 * 6)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day006"), 0); - createTimeStatistics[(60 * 60 * 24 * 7)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day007"), 0); - createTimeStatistics[(60 * 60 * 24 * 14)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day014"), 0); - createTimeStatistics[(60 * 60 * 24 * 21)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day021"), 0); - createTimeStatistics[(60 * 60 * 24 * 30)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day030"), 0); - createTimeStatistics[(60 * 60 * 24 * 60)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day060"), 0); - createTimeStatistics[(60 * 60 * 24 * 90)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day090"), 0); - createTimeStatistics[(60 * 60 * 24 * 180)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day180"), 0); - createTimeStatistics[(60 * 60 * 24 * 270)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day270"), 0); - createTimeStatistics[(60 * 60 * 24 * 365)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Year1"), 0); - createTimeStatistics[(60 * 60 * 24 * 730)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Year2"), 0); - createTimeStatistics[(60 * 60 * 24 * 1095)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Year3"), 0); - createTimeStatistics[(60 * 60 * 24 * 9999)] = std::make_pair(std::string("totalCharacters"), 0); - } - - NameManager::getInstance().getPlayerWithCreateTimeAfterDistribution(createTimeStatistics); - - iter = createTimeStatistics.begin(); - previousIter = createTimeStatistics.begin(); - for (; iter != createTimeStatistics.end(); ++iter) - { - if (iter != previousIter) - iter->second.second += previousIter->second.second; - - previousIter = iter; - } - - const GenericValueTypeMessage >, std::map > > > lastLoginTimeStatisticsResponse("LLTStatRsp", std::make_pair(lastLoginTimeStatistics, createTimeStatistics)); - sendToCentralServer(lastLoginTimeStatisticsResponse); - } - else if (message.isType("LfgStatReq")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const characterMatchStatisticsRequest(ri); - UNREF(characterMatchStatisticsRequest); - - unsigned long numberOfCharacterMatchRequests, numberOfCharacterMatchResults, timeSpentOnCharacterMatchRequestsMs; - CharacterMatchManager::getMatchStatistics(numberOfCharacterMatchRequests, numberOfCharacterMatchResults, timeSpentOnCharacterMatchRequestsMs); - - if (numberOfCharacterMatchRequests || numberOfCharacterMatchResults || timeSpentOnCharacterMatchRequestsMs) - { - CharacterMatchManager::clearMatchStatistics(); - - const GenericValueTypeMessage > > characterMatchStatisticsResponse("LfgStatRsp", std::make_pair(numberOfCharacterMatchRequests, std::make_pair(numberOfCharacterMatchResults, timeSpentOnCharacterMatchRequestsMs))); - sendToCentralServer(characterMatchStatisticsResponse); - } - } - else if (message.isType("ClusterId")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage const msg(ri); - - if (m_clusterId == 0) - { - FATAL(((msg.getValue() < 1) || (msg.getValue() > 255)),("Cluster Id (%lu) must be between 1 and 255 inclusive", msg.getValue())); - - m_clusterId = static_cast(msg.getValue()); - } - } - else if (message.isType("OccupyUnlockedSlotRsp")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, uint32> > const occupyUnlockedSlotRsp(ri); - - char buffer[32]; - snprintf(buffer, sizeof(buffer)-1, "%d", occupyUnlockedSlotRsp.getValue().first.first); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(occupyUnlockedSlotRsp.getValue().first.second, - "C++OccupyUnlockedSlotRsp", - buffer, - 0, - false); - } - else if (message.isType("VacateUnlockedSlotRsp")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > const vacateUnlockedSlotRsp(ri); - - char buffer[32]; - snprintf(buffer, sizeof(buffer)-1, "%d", vacateUnlockedSlotRsp.getValue().first.first); - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(vacateUnlockedSlotRsp.getValue().first.second, - "C++VacateUnlockedSlotRsp", - buffer, - 0, - false); - } - else if (message.isType("SwapUnlockedSlotRsp")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage, std::pair > > > const swapUnlockedSlotRsp(ri); - - Archive::ByteStream bs; - swapUnlockedSlotRsp.pack(bs); - - MessageToQueue::getInstance().sendMessageToC(swapUnlockedSlotRsp.getValue().first.second, - "C++SwapUnlockedSlotRsp", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } - else if (message.isType("AdjustAccountFeatureIdResponse")) - { - ri = static_cast(message).getByteStream().begin(); - AdjustAccountFeatureIdResponse const msg(ri); - - handleAdjustAccountFeatureIdResponse(msg); - } - else if (message.isType("AccountFeatureIdResponse")) - { - ri = static_cast(message).getByteStream().begin(); - AccountFeatureIdResponse const msg(ri); - - handleAccountFeatureIdResponse(msg); - } - else if (message.isType("FeatureIdTransactionResponse")) - { - ri = static_cast(message).getByteStream().begin(); - FeatureIdTransactionResponse const msg(ri); - - Archive::ByteStream bs; - msg.pack(bs); - - MessageToQueue::getInstance().sendMessageToC(msg.getPlayer(), - "C++FeatureIdTransactionResponse", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } - else if (message.isType("TransferReplyMoveValidation")) - { - ri = static_cast(message).getByteStream().begin(); - TransferReplyMoveValidation const msg(ri); - - Archive::ByteStream bs; - msg.pack(bs); - - MessageToQueue::getInstance().sendMessageToC(msg.getSourceCharacterId(), - "C++TransferReplyMoveValidation", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } - else if (message.isType("TransferReplyNameValidation")) - { - ri = static_cast(message).getByteStream().begin(); - GenericValueTypeMessage > const msg(ri); - - Archive::ByteStream bs; - msg.pack(bs); - - MessageToQueue::getInstance().sendMessageToC(msg.getValue().second.getCharacterId(), - "C++TransferReplyNameValidation", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } - else if (message.isType("CreateDynamicSpawnRegionCircleMessage")) - { - ri = static_cast(message).getByteStream().begin(); - CreateDynamicSpawnRegionCircleMessage const msg(ri); - - RegionMaster::createNewDynamicRegionWithSpawn(msg.getCenterX(), msg.getCenterY(), msg.getCenterZ(), msg.getRadius(), msg.getName(), msg.getPlanet(), - msg.getPvp(), msg.getBuildable(), msg.getMunicipal(), msg.getGeography(), msg.getMinDifficulty(), msg.getMaxDifficulty(), - msg.getSpawnable(), msg.getMission(), msg.getVisible(), msg.getNotify(), msg.getSpawntable(), msg.getDuration()); - } -} - -// ---------------------------------------------------------------------- - -bool GameServer::isPlanetEnabledForCluster(std::string const &sceneName) const -{ - // look up [CentralServer] startPlanet=sceneName[:whatever] - - int index = 0; - char const * result = 0; - do - { - result = ConfigFile::getKeyString("CentralServer", "startPlanet", index++, 0); - // result must either match sceneName completely, or match all of sceneName and be followed by a ':' - if ( result - && ( !strcmp(result, sceneName.c_str()) - || ( !strncmp(result, sceneName.c_str(), sceneName.size()) - && result[sceneName.size()] == ':'))) - return true; - } while (result); - - return false; -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::broadCastHyperspaceOnWarp(ServerObject const * const owner) -{ - // warpingClient can be NULL if the owner is AI - Client const * const warpingClient = owner->getClient(); - - typedef std::map > DistributionList; - DistributionList distributionList; - - // Build distribution list of clients observing ship - { - typedef std::set ObserverList; - ObserverList const & observers = owner->getObservers(); - - ObserverList::const_iterator ii = observers.begin(); - ObserverList::const_iterator iiEnd = observers.end(); - for (; ii != iiEnd; ++ii) - { - Client * const client = *ii; - if (client != warpingClient) - { - distributionList[client->getConnection()].push_back(client->getCharacterObjectId()); - } - } - } - - // Send Message to distribution list - { - DistributionList::const_iterator ii = distributionList.begin(); - DistributionList::const_iterator iiEnd = distributionList.end(); - for (; ii != iiEnd; ++ii) - { - HyperspaceMessage const hyperspaceMessage(owner->getNetworkId()); - GameClientMessage const gameClientMessage(ii->second, true, hyperspaceMessage); - ii->first->send(gameClientMessage, true); - } - } -} - -/** - * Warping an object to a different scene. - */ -bool GameServer::requestSceneWarp(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newContainer, const Vector &newPosition_p, const char * scriptCallback, bool forceLoadScreen) -{ - ServerObject * const object = dynamic_cast(objectId.getObject()); - if (!object) - return false; - - if (!isPlanetEnabledForCluster(sceneName)) - { - DEBUG_WARNING(true, ("GameServer::requestSceneWarp(1) for unknown scene %s", sceneName.c_str())); - return false; - } - - Vector destPosition_w(newPosition_w); - - // clamp destination if in space - if ( !strncmp(sceneName.c_str(), "space_", 6) - && ( std::abs(newPosition_w.x) > 8000.f - || std::abs(newPosition_w.y) > 8000.f - || std::abs(newPosition_w.z) > 8000.f)) - { - WARNING(true, ("Tried to warp object %s outside of space zone boundaries (%g,%g,%g)", object->getDebugInformation().c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z)); - destPosition_w.set( - clamp(-8000.f, newPosition_w.x, 8000.f), - clamp(-8000.f, newPosition_w.y, 8000.f), - clamp(-8000.f, newPosition_w.z, 8000.f)); - } - - if (ServerWorld::getSceneId() == sceneName) - { - // if a pilot is doing a same scene warp, actually move the ship, and only allow in world coords - CreatureObject * const objAsCreature = object->asCreatureObject(); - if (objAsCreature) - { - ShipObject * const ship = getAttachedShip(objAsCreature); - if (ship) - { - broadCastHyperspaceOnWarp(ship); - ship->teleportObject(destPosition_w, NetworkId::cms_invalid, "", destPosition_w, scriptCallback ? scriptCallback : "", forceLoadScreen); - } - else - object->teleportObject(destPosition_w, newContainer, "", newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); - } - else - object->teleportObject(destPosition_w, newContainer, "", newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); - } - else - { - // don't send multiple RequestSceneTransfer message - if (!checkAndSetOutstandingRequestSceneTransfer(*object)) - { - RequestSceneTransfer const sceneTransferMessage(objectId, sceneName, getProcessId(), newPosition_p, destPosition_w, newContainer, scriptCallback); - sendToCentralServer(sceneTransferMessage); - } - } - - return true; -} - -//----------------------------------------------------------------------- - -/** - * Warping an object to a different scene. - */ -bool GameServer::requestSceneWarp(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newBuilding, const std::string &newContainerName, const Vector &newPosition_p, const char * scriptCallback, bool forceLoadScreen) -{ - ServerObject * const object = dynamic_cast(objectId.getObject()); - if (!object) - return false; - - if (!isPlanetEnabledForCluster(sceneName)) - { - DEBUG_WARNING(true, ("GameServer::requestSceneWarp(1) for unknown scene %s", sceneName.c_str())); - return false; - } - - Vector destPosition_w(newPosition_w); - - // clamp destination if in space - if ( !strncmp(sceneName.c_str(), "space_", 6) - && ( std::abs(newPosition_w.x) > 8000.f - || std::abs(newPosition_w.y) > 8000.f - || std::abs(newPosition_w.z) > 8000.f)) - { - WARNING(true, ("Tried to warp object %s outside of space zone boundaries (%g,%g,%g)", object->getDebugInformation().c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z)); - destPosition_w.set( - clamp(-8000.f, newPosition_w.x, 8000.f), - clamp(-8000.f, newPosition_w.y, 8000.f), - clamp(-8000.f, newPosition_w.z, 8000.f)); - } - - if (ServerWorld::getSceneId() == sceneName) - { - // if a pilot is doing a same scene warp, actually move the ship, and only allow in world coords - CreatureObject * const objAsCreature = object->asCreatureObject(); - if (objAsCreature) - { - ShipObject * const ship = getAttachedShip(objAsCreature); - if (ship) - { - broadCastHyperspaceOnWarp(ship); - ship->teleportObject(destPosition_w, NetworkId::cms_invalid, "", destPosition_w, scriptCallback ? scriptCallback : "", forceLoadScreen); - } - else - object->teleportObject(destPosition_w, newBuilding, newContainerName, newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); - } - else - object->teleportObject(destPosition_w, newBuilding, newContainerName, newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); - } - else - { - // don't send multiple RequestSceneTransfer message - if (!checkAndSetOutstandingRequestSceneTransfer(*object)) - { - RequestSceneTransfer const sceneTransferMessage(objectId, sceneName, getProcessId(), newPosition_p, destPosition_w, newBuilding, newContainerName, scriptCallback); - sendToCentralServer(sceneTransferMessage); - } - } - - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Warping an object to a different scene after a delay. - */ -bool GameServer::requestSceneWarpDelayed(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newContainer, const Vector &newPosition_p, float const delayTime, const char * scriptCallback, bool forceLoadScreen) -{ - Object * const o = objectId.getObject(); - ServerObject * const so = o ? o->asServerObject() : 0; - ShipObject * const ship = so ? so->asShipObject() : 0; - - if (!ship || !ship->isInWorld()) - return false; - - ship->setHyperspaceOnDestroy(true); - - typedef std::vector Passengers; - Passengers passengers; - - ship->findAllPassengers(passengers, true); - - Passengers::const_iterator ii = passengers.begin(); - Passengers::const_iterator iiEnd = passengers.end(); - - for (; ii != iiEnd; ++ii) - { - CreatureObject * const passenger = *ii; - Controller * const controller = passenger->getController(); - - if (controller != 0) - { - MessageQueueGenericValueType > * const data = new MessageQueueGenericValueType >(std::make_pair(sceneName, newPosition_w)); - - controller->appendMessage( - CM_aboutToHyperspace, - 0.0f, - data, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } - - char buf[1000]; - std::string callbackStr = scriptCallback; - snprintf(buf, sizeof(buf) - 1, "%s %.2f %.2f %.2f %s %.2f %.2f %.2f %s %d", sceneName.c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z, newContainer.getValueString().c_str(), newPosition_p.x, newPosition_p.y, newPosition_p.z, (!callbackStr.empty()) ? callbackStr.c_str() : "noCallback", (forceLoadScreen) ? 1 : 0); - MessageToQueue::getInstance().sendMessageToC(objectId, "C++SceneWarpDelayed", buf, static_cast(delayTime), false); - - return true; -} - -//----------------------------------------------------------------------- - -/** - * Warping an object to a different scene after a delay. - */ -bool GameServer::requestSceneWarpDelayed(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newBuilding, const std::string &newContainerName, const Vector &newPosition_p, float const delayTime, const char * scriptCallback, bool forceLoadScreen) -{ - Object * const o = objectId.getObject(); - ServerObject * const so = o ? o->asServerObject() : 0; - ShipObject * const ship = so ? so->asShipObject() : 0; - - if (!ship || !ship->isInWorld()) - return false; - - typedef std::vector Passengers; - Passengers passengers; - - ship->findAllPassengers(passengers, true); - - Passengers::const_iterator ii = passengers.begin(); - Passengers::const_iterator iiEnd = passengers.end(); - - for (; ii != iiEnd; ++ii) - { - CreatureObject * const passenger = *ii; - Controller * const controller = passenger->getController(); - - if (controller != 0) - { - MessageQueueGenericValueType > * const data = new MessageQueueGenericValueType >(std::make_pair(sceneName, newPosition_w)); - - controller->appendMessage( - CM_aboutToHyperspace, - 0.0f, - data, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } - - char buf[1000]; - std::string callbackStr = scriptCallback; - snprintf(buf, sizeof(buf) - 1, "%s %.2f %.2f %.2f %s %s %.2f %.2f %.2f %s %d", sceneName.c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z, newBuilding.getValueString().c_str(), newContainerName.c_str(), newPosition_p.x, newPosition_p.y, newPosition_p.z, (!callbackStr.empty()) ? callbackStr.c_str() : "none", (forceLoadScreen) ? 1 : 0); - MessageToQueue::getInstance().sendMessageToC(objectId, "C++SceneWarpDelayedContainer", buf, static_cast(delayTime), false); - - return true; -} - -// ---------------------------------------------------------------------- - -unsigned long GameServerNamespace::getFrameRateLimit() -{ - return ServerWorld::isSpaceScene() ? ConfigServerGame::getSpaceFrameRateLimit() : ConfigServerGame::getGroundFrameRateLimit(); -} - -// ---------------------------------------------------------------------- - -void GameServer::run(void) -{ - static const std::string frameLogChannel = "EndFrame:Time"; - static const std::string frameLogCount = "EndFrame:Objects"; - - getInstance().initialize(); - - unsigned long lastFrameTime = 0; - int oldFilesOpened = TreeFile::getNumberOfFilesOpenedTotal(); - int oldSizeOpened = TreeFile::getSizeOfFilesOpenedTotal(); - int newFilesOpened = 0; - int newSizeOpened = 0; - unsigned long startTime = Clock::timeMs(); - unsigned long lastFrameProcessStartTime = startTime; - - const unsigned long targetFrameTime = static_cast(1000.0f/getFrameRateLimit()); - - const GenericValueTypeMessage gameServerTaskManagerKeepAlive("GameServerTaskManagerKeepAlive", Os::getProcessId()); - - PROFILER_BLOCK_DEFINE(profileBlockMainLoop, "main loop"); - PROFILER_BLOCK_ENTER(profileBlockMainLoop); - - LOG("ServerStartup",("GameServer starting on %s", NetworkHandler::getHostName().c_str())); // no process id yet - s_frameTime = 0; - - while (!getInstance().getDone()) - { - if(getInstance().m_taskManagerConnection) - { - getInstance().m_taskManagerConnection->send(gameServerTaskManagerKeepAlive, true); - s_lastTaskKeepaliveTime = Clock::timeMs(); - } - - newFilesOpened = TreeFile::getNumberOfFilesOpenedTotal(); - newSizeOpened = TreeFile::getSizeOfFilesOpenedTotal(); - - if ( lastFrameTime > ConfigServerGame::getLoopProfileLogThresholdMs() - || (ServerWorld::isSpaceScene() && lastFrameTime > ConfigServerGame::getSpaceLoopProfileLogThresholdMs()) - || (!ServerWorld::isSpaceScene() && lastFrameTime > ConfigServerGame::getGroundLoopProfileLogThresholdMs())) - { - LOG("profile", ("Long loop (%u ms):\n%s", lastFrameTime, PROFILER_GET_LAST_FRAME_DATA())); - if (newFilesOpened > oldFilesOpened) - LOG("treefile", ("Long loop file stats: %d opened %d size", newFilesOpened - oldFilesOpened, newSizeOpened - oldSizeOpened)); - } - - oldFilesOpened = newFilesOpened; - oldSizeOpened = newSizeOpened; - - { - PROFILER_AUTO_BLOCK_DEFINE("NetFlushAllData"); - NetworkHandler::flushAndConfirmAll(); - } - - bool barrierReached = true; - - do - { - PROFILER_AUTO_BLOCK_DEFINE("BarrierWait"); - - { - PROFILER_AUTO_BLOCK_DEFINE("NetworkHandler::update"); - NetworkHandler::update(); - } - - if ( ServerWorld::isSpaceScene() && ConfigServerGame::getSpaceShouldSleep() - || !ServerWorld::isSpaceScene() && ConfigServerGame::getGroundShouldSleep()) - { - PROFILER_AUTO_BLOCK_DEFINE("Os::sleep"); - Os::sleep(1); - } - - if (ConfigServerGame::getCommoditiesMarketEnabled()) - { - PROFILER_AUTO_BLOCK_DEFINE("CommoditiesMarket::giveTime"); - CommoditiesMarket::giveTime(); - } - - // Note: adding 15 ms to the time passed here to adjust for minimum sleep times - barrierReached = Clock::timeMs()-lastFrameProcessStartTime+15 >= targetFrameTime; - - getInstance().debugIO(); - } while (!barrierReached && !getInstance().getDone()); - - lastFrameProcessStartTime = Clock::timeMs(); - - if (!Os::update()) - getInstance().setDone("OS condition (Parent pid change)"); - - { - PROFILER_AUTO_BLOCK_DEFINE("MetricsManager::update"); - if (s_metricsManagerInstalled) - MetricsManager::update(static_cast(lastFrameTime)); - } - - { - PROFILER_AUTO_BLOCK_DEFINE("ServerWorld::update"); - ServerWorld::update(Clock::frameTime()); - } - - { - PROFILER_AUTO_BLOCK_DEFINE("ServerUniverse::update"); - ServerUniverse::getInstance().update(Clock::frameTime()); - } - - NonCriticalTaskQueue::getInstance().update(); - { - PROFILER_AUTO_BLOCK_DEFINE("MessageToQueue::update"); - MessageToQueue::getInstance().update(Clock::frameTime()); - } - -#ifdef _DEBUG - // do an intentional sleep, to emulate long loop time - if (s_extraDelayPerFrameMs > 0) - { - PROFILER_AUTO_BLOCK_DEFINE("Os::sleep - extra"); - Os::sleep(s_extraDelayPerFrameMs); - } -#endif - - { - // Report the population at the same time on all game servers in the cluster - static bool alreadyReported(false); - if ((time(0) % ConfigServerGame::getPopulationReportTimeSeconds()) == 0) - { - if (!alreadyReported) - { - LOG("PopulationReport",("server %s:%lu population %i",ServerWorld::getSceneId().c_str(),getInstance().m_preloadAreaId,getInstance().m_clients->size())); - alreadyReported=true; - } - } - else - alreadyReported=false; - } - - unsigned long curTime = Clock::timeMs(); - lastFrameTime = curTime-startTime; - if (!getInstance().getDone()) - ServerClock::getInstance().incrementServerFrame(); - startTime = curTime; - - getInstance().checkIdleClients(Clock::frameTime()); - if (!getInstance().m_gameServerReadyDatabaseConnected && getInstance().m_connectionTimeout!=0 && (curTime > getInstance().m_connectionTimeout)) - FATAL(true,("Failed to resolve connections to all the other game servers within %i seconds",ConfigServerGame::getConnectToAllGameServersTimeout())); - - PROFILER_BLOCK_LEAVE(profileBlockMainLoop); - PROFILER_BLOCK_ENTER(profileBlockMainLoop); - if (getInstance().getDatabaseProcessId()) - { - FrameEndMessage const emptyFrameEndMessage(getInstance().getProcessId(), lastFrameTime, ""); - getInstance().sendToDatabaseServer(emptyFrameEndMessage); - if (ConfigServerGame::getSendFrameProfilerInfo()) - { - FrameEndMessage const frameEndMessage(getInstance().getProcessId(), lastFrameTime, PROFILER_GET_LAST_FRAME_DATA()); - getInstance().sendToPlanetServer(frameEndMessage); - } - else - getInstance().sendToPlanetServer(emptyFrameEndMessage); - NetworkHandler::clearBytesThisFrame(); - } - s_frameTime = curTime - lastFrameProcessStartTime; - } - - LOG("ServerStartup",("GameServer %lu exiting",getInstance().getProcessId())); - - PROFILER_BLOCK_LEAVE(profileBlockMainLoop); - - getInstance().shutdown(); - -} - -//----------------------------------------------------------------------- - -void GameServer::sendToDatabaseServer(GameNetworkMessage const &message) -{ - if (m_databaseProcessConnection) - m_databaseProcessConnection->send(message, true); - else - DEBUG_FATAL(!m_done, ("Unable to send network message to database server while not flagged for shutdown")); - } - -// ---------------------------------------------------------------------- - -std::vector const &GameServer::getAllGameServerPids() const -{ - return m_gameServerPids; -} - -// ---------------------------------------------------------------------- - -bool GameServer::hasConnectionsToOtherGameServers() const -{ - return !(m_gameServerPids.empty()); -} - -// ---------------------------------------------------------------------- - -void GameServer::sendToCentralServer(GameNetworkMessage const &message) -{ - if(m_centralServerConnection) - { - m_centralServerConnection->send(message, true); - } - else - { - DEBUG_REPORT_LOG(true,("Tried to send a message to Central Server, but it was not connected.\n")); - } -} - -// ---------------------------------------------------------------------- - -void GameServer::sendToPlanetServer(GameNetworkMessage const &message) -{ - if (m_planetServerConnection) - { - m_planetServerConnection->send(message, true); - } - else - { - DEBUG_REPORT_LOG(true,("Tried to send a message to Planet Server, but it was not connected.\n")); - } -} - -// ---------------------------------------------------------------------- - -void GameServer::sendToConnectionServers(GameNetworkMessage const &message) -{ - ConnectionServerVector v(*m_connectionServerVector); - for (ConnectionServerVector::iterator i = v.begin(); i != v.end(); ++i) - (*i)->send(message, true); -} - -// ---------------------------------------------------------------------- - -void GameServer::sendToCustomerServiceServer(GameNetworkMessage const &message) -{ - if (m_customerServiceServerConnection != NULL) - { - m_customerServiceServerConnection->send(message, true); - } - else - { - REPORT_LOG(true, ("GameServer::sendToCustomerServiceServer() ERROR: Unable to send to NULL customer service server connection\n")); - } -} - -// ---------------------------------------------------------------------- - -void GameServer::clearCustomerServiceServerConnection() -{ - if (m_customerServiceServerConnection != NULL) - { - m_customerServiceServerConnection->disconnect(); - } - - m_customerServiceServerConnection = NULL; -} - -// ---------------------------------------------------------------------- - -/** - * Call when we are connected to the database process. - * Prerequisite to gameServerReady() - */ -void GameServer::onDatabaseProcessConnectionEstablished() -{ - LOG("GameGameConnect", ("Game Server %lu is connected to database process", m_processId)); - m_gameServerReadyDatabaseConnected = true; - checkWhetherGameServerIsReady(); -} - -// ---------------------------------------------------------------------- - -/** - * Call when we have at least one block of objectId's. - * Prerequisite to gameServerReady() - */ -void GameServer::onReceivedFirstNetworkIdBlock() -{ - LOG("GameGameConnect", ("Game Server %lu has received first netId block", m_processId)); - m_gameServerReadyObjectIds = true; - checkWhetherGameServerIsReady(); -} - -// ---------------------------------------------------------------------- - -/** - * Call when we have at least one block of objectId's. - * Prerequisite to gameServerReady() - */ -void GameServer::onPlanetServerConnectionEstablished() -{ - LOG("GameGameConnect", ("Game Server %lu is connected to planet server", m_processId)); - m_gameServerReadyPlanetConnected = true; - checkWhetherGameServerIsReady(); -} - -// ---------------------------------------------------------------------- - -/** - * Call after each asynchronous step of initializing the game server. - * If all steps are completed, calls gameServerReady() - */ -void GameServer::checkWhetherGameServerIsReady() -{ - if (m_gameServerReadyDatabaseConnected && m_gameServerReadyObjectIds && m_gameServerReadyPlanetConnected) - gameServerReady(); -} - -// ---------------------------------------------------------------------- - -/** - * Call this function when we are ready to handle receiving objects. - * Notifies Central, who may tell other game servers to give - * us proxy objects now or may tell us to create new objects. - */ -void GameServer::gameServerReady() -{ - static int callCount(0); - UNREF(callCount); - DEBUG_FATAL(getProcessId()==0,("gameServerReady() was called before process ID was set.\n")); - DEBUG_FATAL((callCount++)!=0,("gameServerReady() was called more than once.\n")); - - LOG("GameGameConnect", ("Game Server %d is ready!", m_processId)); - GameServerReadyMessage const msg(static_cast(NON_NULL(TerrainObject::getInstance())->getMapWidthInMeters())); - sendToCentralServer(msg); - sendToPlanetServer(msg); -} - -// ---------------------------------------------------------------------- - -const StringId GameServer::verifyCharacterName(const std::string &templateName, const Unicode::String &name, bool forPlayer) const -{ - const ServerCreatureObjectTemplate * serverTemplate = getServerCreatureObjectTemplate(templateName); - if (!serverTemplate) - return NameErrors::nameDeclinedNotCreatureTemplate; - - const StringId & verified = verifyCharacterName(*serverTemplate, name, forPlayer); - serverTemplate->releaseReference(); - - return verified; -} - -// ---------------------------------------------------------------------- - -const StringId GameServer::verifyCharacterName(const ServerCreatureObjectTemplate &serverTemplate, const Unicode::String &name, bool forPlayer) const -{ - if (ConfigServerGame::getNameValidationAcceptAll()) - return NameErrors::nameApproved; - - if (name.empty()) - return NameErrors::nameDeclinedEmpty; - - // Check for appropriateness based on race - if (!NameManager::getInstance().isNameAppropriate(ConfigServerGame::getCharacterNameGeneratorDirectory(),serverTemplate.getNameGeneratorType(),name)) - return NameErrors::nameDeclinedRaciallyInappropriate; - - // Now match against reserved names and profanity - std::string reasonDescription; - if (NameManager::getInstance().isNameReserved(name,reasonDescription)) - return StringId(NameErrors::localizationFile,reasonDescription); - else - return NameErrors::nameApproved; -} - -//-------------------------------------------------------------------- - -void GameServer::handleCreateCharacter(const CentralCreateCharacter * createMessage) -{ - LOG("TraceCharacterCreation", ("%d received CentralCreateCharacter(%d, %s, ...)", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - if (m_charactersPendingCreation->find(createMessage->getStationId()) != m_charactersPendingCreation->end()) - { - LOG("TraceCharacterCreation", ("%d name verification for that name is still pending, sending GameCreateCharacterFailed(%d, %s, NameErrors::nameDeclinedRetry) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - DEBUG_REPORT_LOG(true, ("Received character creation request for account %li, but we are still pending a name verification for that id\n",createMessage->getStationId())); - GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedRetry, FormattedString<2048>().sprintf("%lu name verification for that name is still pending, sending GameCreateCharacterFailed(%lu, %s, NameErrors::nameDeclinedRetry) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - sendToCentralServer(characterCreateFailed); - delete createMessage; - return; - } - - const std::string & templateName = createMessage->getTemplateName(); - DEBUG_REPORT_LOG(true, ("Received character creation request for account %li (name %s, template %s)\n",createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str(), templateName.c_str())); - if(templateName.empty ()) - { - LOG("TraceCharacterCreation", ("%d sent an empty template name, sending GameCreateCharacterFailed(%d, %s, NameErrors::nameDeclinedNoTemplate) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - DEBUG_REPORT_LOG(true, ("The template was empty\n")); - // Tell central we couldn't create the character - GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedNoTemplate, FormattedString<2048>().sprintf("%lu sent an empty template name, sending GameCreateCharacterFailed(%lu, %s, NameErrors::nameDeclinedNoTemplate) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - sendToCentralServer(characterCreateFailed); - delete createMessage; - return; - } - - if (!SpeciesRestrictions::canCreateCharacter(createMessage->getGameFeatures(), Crc::calculate(templateName.c_str()))) - { - LOG("TraceCharacterCreation", ("%d sent a species template name their account was not authorized to use. Template was %s", createMessage->getStationId(), templateName.c_str())); - // Tell central we couldn't create the character - GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedNotAuthorizedForSpecies, FormattedString<2048>().sprintf("%lu sent a species template name their account was not authorized to use. Template was %s", createMessage->getStationId(), templateName.c_str())); - sendToCentralServer(characterCreateFailed); - delete createMessage; - return; - } - - StringId avatarReason = canCreateAvatar(templateName); - if (avatarReason != NameErrors::nameApproved) - { - LOG("TraceCharacterCreation", ("%d canCreateAvatar(%s) failed, sending GameCreateCharacterFailed(%d, %s, REASON) to central server", createMessage->getStationId(), createMessage->getTemplateName().c_str(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - DEBUG_REPORT_LOG(true, ("Can't create avatar\n")); - GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), avatarReason, FormattedString<2048>().sprintf("%lu canCreateAvatar(%s) failed, sending GameCreateCharacterFailed(%lu, %s, REASON) to central server", createMessage->getStationId(), createMessage->getTemplateName().c_str(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - sendToCentralServer(characterCreateFailed); - delete createMessage; - return; - } - - // verify the name against static tests - length, character set, etc. - StringId VerifyNameResponse = verifyCharacterName(templateName, createMessage->getCharacterName(), true); - if (VerifyNameResponse != NameErrors::nameApproved) - { - LOG("TraceCharacterCreation", ("%d VerifyNameResponse != NameErrors::nameApproved, sending GameCreateCharacterFailed(%d, %s, REASON) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), VerifyNameResponse, FormattedString<2048>().sprintf("%lu VerifyNameResponse != NameErrors::nameApproved, sending GameCreateCharacterFailed(%lu, %s, REASON) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - sendToCentralServer(characterCreateFailed); - delete createMessage; - return; - } - - // verify the name against known existing names - if (NameManager::getInstance().getPlayerId(NameManager::normalizeName(Unicode::wideToNarrow(createMessage->getCharacterName()))) != NetworkId::cms_invalid) - { - LOG("TraceCharacterCreation", ("%d character create name %s is in use, sending GameCreateCharacterFailed", createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - DEBUG_REPORT_LOG(true, ("Character create name %s is in use, declined for stationId %lu\n", Unicode::wideToNarrow(createMessage->getCharacterName()).c_str(), createMessage->getStationId())); - GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedInUse, FormattedString<2048>().sprintf("%lu character create name %s is in use, sending GameCreateCharacterFailed", createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - sendToCentralServer(characterCreateFailed); - delete createMessage; - return; - } - - // Now verify against the database. - LOG("TraceCharacterCreation", ("%d sending VerifyNameRequest(%d, %s, %s) to the database for validation", createMessage->getStationId(), createMessage->getStationId(), createMessage->getTemplateName().c_str(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); - VerifyNameRequest const vrn(createMessage->getStationId(), NetworkId::cms_invalid, createMessage->getTemplateName(), createMessage->getCharacterName()); - sendToDatabaseServer(vrn); - (*m_charactersPendingCreation)[createMessage->getStationId()] = createMessage; -} - -//-------------------------------------------------------------------- - -void GameServer::handleNameFailure(const RandomNameRequest &request, const StringId &errorMessage) -{ - LOG("TraceCharacterCreation", ("%d sending RandomNameResponse(%d, %s, REASON) to central server", request.getStationId(), request.getCreatureTemplate().c_str())); - RandomNameResponse const rnr(request.getStationId(), request.getCreatureTemplate(), Unicode::String(), errorMessage); - sendToCentralServer(rnr); -} - -//-------------------------------------------------------------------- - -void GameServer::handleNameRequest(const RandomNameRequest &request) -{ - DEBUG_REPORT_LOG(true, ("Random name requested for stationId %lu\n", request.getStationId())); - - std::map::iterator findPendingCreation=m_charactersPendingCreation->find(request.getStationId()); - if (findPendingCreation != m_charactersPendingCreation->end()) - { - LOG("TraceCharacterCreation", ("%d received random name request after CharacterCreationRequest, ignoring request", request.getStationId())); - DEBUG_REPORT_LOG(true, ("Received random name request after CharacterCreation request")); - return; - } - - bool success = false; - - const ObjectTemplate * const objectTemplate = ObjectTemplateList::fetch(request.getCreatureTemplate()); - if (objectTemplate) - { - const ServerCreatureObjectTemplate * const creatureTemplate = dynamic_cast(objectTemplate); - if (creatureTemplate) - { - // generate a name - Unicode::String randomName = NameManager::getInstance().generateUniqueRandomName(ConfigServerGame::getCharacterNameGeneratorDirectory(),creatureTemplate->getNameGeneratorType()); - - LOG("TraceCharacterCreation", ("%d generated name %s", request.getStationId(), Unicode::wideToNarrow(randomName).c_str(), request.getStationId(), request.getCreatureTemplate().c_str(), Unicode::wideToNarrow(randomName).c_str())); - - DEBUG_REPORT_LOG(true, ("VerifyNameResponse: random name %s approved for stationId %lu\n", Unicode::wideToNarrow(randomName).c_str(), request.getStationId())); - RandomNameResponse const response(request.getStationId(), request.getCreatureTemplate(), randomName, NameErrors::nameApproved); - sendToCentralServer(response); - - success = true; - } - else - { - LOG("TraceCharacterCreation", ("%d failed to get a creature template to service random name request. The request failed", request.getStationId())); - } - objectTemplate->releaseReference(); - } - else - { - LOG("TraceCharacterCreation", ("%d could not get an ObjectTemplate for name request", request.getStationId())); - } - - if (!success) - { - WARNING(true, ("Could not generate a random name for template %s (template may not exist or may not be a CreatureTemplate).\n", request.getCreatureTemplate().c_str())); - handleNameFailure(request, NameErrors::nameDeclinedNoTemplate); - } -} - -//-------------------------------------------------------------------- - -const StringId GameServer::handleVerifyAndLockNameRequest(const VerifyAndLockNameRequest &request, bool sendFailedResponseToCentralServer, bool verifyAgainstDb) -{ - REPORT_LOG(true, ("Verify and lock name requested for stationId %lu\n", request.getStationId())); - - const std::string & templateName = request.getTemplateName(); - DEBUG_REPORT_LOG(true, ("Received verify and lock name request for account %li (name %s, template %s)\n", request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str(), templateName.c_str())); - if(templateName.empty ()) - { - // Tell central we couldn't create the character - if (sendFailedResponseToCentralServer) - { - LOG("TraceCharacterCreation", ("%lu sent an empty template name for name verification, sending VerifyAndLockNameResponse(%lu, %s, NameErrors::nameDeclinedNoTemplate) to central server", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - DEBUG_REPORT_PRINT(true, ("%lu sent an empty template name for name verification, sending VerifyAndLockNameResponse(%lu, %s, NameErrors::nameDeclinedNoTemplate) to central server\n", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - - VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), NameErrors::nameDeclinedNoTemplate); - sendToCentralServer(verifyAndLockNameResponse); - } - - return NameErrors::nameDeclinedNoTemplate; - } - - if (!SpeciesRestrictions::canCreateCharacter(request.getGameFeatures(), Crc::calculate(templateName.c_str()))) - { - // Tell central we couldn't create the character - if (sendFailedResponseToCentralServer) - { - LOG("TraceCharacterCreation", ("%lu sent a species template name their account was not authorized to use, sending VerifyAndLockNameResponse to CentralServer. Template was %s", request.getStationId(), templateName.c_str())); - DEBUG_REPORT_PRINT(true, ("%lu sent a species template name their account was not authorized to use, sending VerifyAndLockNameResponse to CentralServer. Template was %s\n", request.getStationId(), templateName.c_str())); - - VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), NameErrors::nameDeclinedNotAuthorizedForSpecies); - sendToCentralServer(verifyAndLockNameResponse); - } - - return NameErrors::nameDeclinedNotAuthorizedForSpecies; - } - - StringId avatarReason = canCreateAvatar(templateName); - if (avatarReason != NameErrors::nameApproved) - { - if (sendFailedResponseToCentralServer) - { - LOG("TraceCharacterCreation", ("%lu canCreateAvatar(%s) failed, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server", request.getStationId(), request.getTemplateName().c_str(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - DEBUG_REPORT_PRINT(true, ("%lu canCreateAvatar(%s) failed, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server\n", request.getStationId(), request.getTemplateName().c_str(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - - VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), avatarReason); - sendToCentralServer(verifyAndLockNameResponse); - } - - return avatarReason; - } - - // verify the name against static tests - length, character set, etc. - StringId VerifyNameResponse = verifyCharacterName(templateName, request.getCharacterName(), true); - if (VerifyNameResponse != NameErrors::nameApproved) - { - if (sendFailedResponseToCentralServer) - { - LOG("TraceCharacterCreation", ("%lu VerifyNameResponse != NameErrors::nameApproved, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - DEBUG_REPORT_PRINT(true, ("%lu VerifyNameResponse != NameErrors::nameApproved, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server\n", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - - VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), VerifyNameResponse); - sendToCentralServer(verifyAndLockNameResponse); - } - - return VerifyNameResponse; - } - - // verify the name against known existing names - if (NameManager::getInstance().getPlayerId(NameManager::normalizeName(Unicode::wideToNarrow(request.getCharacterName()))) != NetworkId::cms_invalid) - { - if (sendFailedResponseToCentralServer) - { - LOG("TraceCharacterCreation", ("%lu character create name %s is in use, sending VerifyAndLockNameResponse", request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - DEBUG_REPORT_PRINT("TraceCharacterCreation", ("%lu character create name %s is in use, sending VerifyAndLockNameResponse\n", request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - - VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), NameErrors::nameDeclinedInUse); - sendToCentralServer(verifyAndLockNameResponse); - } - - return NameErrors::nameDeclinedInUse; - } - - // Now verify against the database. - if (verifyAgainstDb) - { - LOG("TraceCharacterCreation", ("%lu sending VerifyNameRequest(%lu, %s, %s) to the database for validation", request.getStationId(), request.getStationId(), request.getTemplateName().c_str(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); - VerifyNameRequest const vrn(request.getStationId(), request.getCharacterId(), request.getTemplateName(), request.getCharacterName()); - sendToDatabaseServer(vrn); - } - - return NameErrors::nameApproved; -} - -//-------------------------------------------------------------------- - -void GameServer::handleCharacterCreateNameVerification(const VerifyNameResponse &vrn) -{ - std::map::iterator findPendingCreation=m_charactersPendingCreation->find(vrn.getStationId()); - const CentralCreateCharacter * createMessage = findPendingCreation->second; - - if (vrn.getErrorMessage() != NameErrors::nameApproved) - { - LOG("TraceCharacterCreation", ("%d VeryfyNameResponse character create name %s declined, sending GameCreateCharacterFailed(%d, %s, %s)", vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); - DEBUG_REPORT_LOG(true, ("VerifyNameResponse: character create name %s declined (%s) for stationId %lu\n", Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str(), vrn.getStationId())); - GameCreateCharacterFailed const characterCreateFailed(vrn.getStationId(), vrn.getName(), vrn.getErrorMessage(), FormattedString<2048>().sprintf("%lu VeryfyNameResponse character create name %s declined, sending GameCreateCharacterFailed(%lu, %s, %s)", vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); - sendToCentralServer(characterCreateFailed); - m_charactersPendingCreation->erase(vrn.getStationId()); - delete createMessage; - return; - } - std::string templateName(createMessage->getTemplateName()); - - DEBUG_REPORT_LOG(true, ("VerifyNameResponse: character create name %s approved for stationId %lu\n", Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getStationId())); - - TangibleObject *newCharacterObject = 0; - - if (createMessage->getUseNewbieTutorial()) - { - Transform tr; - tr.setPosition_p(NewbieTutorial::getTutorialLocation()); - newCharacterObject = safe_cast(ServerWorld::createNewObject(templateName, tr, 0, false)); - } - else - { - Transform tr; - tr.setPosition_p(createMessage->getCoordinates()); - newCharacterObject = safe_cast(ServerWorld::createNewObject(templateName, tr, 0, false)); - } - - if (!newCharacterObject) - { - LOG("TraceCharacterCreation", ("%d could not create a new character object on the game server, sending GameCreateCharacterFailed(%d, %s, %s) to central server", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); - DEBUG_REPORT_LOG(true, ("handleCharacterCreateNameVerification: failed to create character object (name %s, template %s, stationId %lu)\n", Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getCreatureTemplate().c_str(), vrn.getStationId())); - GameCreateCharacterFailed const characterCreateFailed(vrn.getStationId(), vrn.getName(), NameErrors::nameDeclinedInternalError, FormattedString<2048>().sprintf("%lu could not create a new character object on the game server, sending GameCreateCharacterFailed(%lu, %s, %s) to central server", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); - sendToCentralServer(characterCreateFailed); - m_charactersPendingCreation->erase(vrn.getStationId()); - delete createMessage; - return; - } - - newCharacterObject->setObjectName(createMessage->getCharacterName()); - newCharacterObject->setOwnerId(newCharacterObject->getNetworkId()); - newCharacterObject->setPlayerControlled(true); - if (createMessage->getUseNewbieTutorial()) - NewbieTutorial::setupCharacterForTutorial(newCharacterObject); - else - NewbieTutorial::setupCharacterToSkipTutorial(newCharacterObject); - - CollisionProperty * collision = newCharacterObject->getCollisionProperty(); - if(collision) - { - collision->setPlayerControlled(true); - } - - //@todo: scale factor should probably be in TangibleObject, not CreatureObject - CreatureObject * const creature = dynamic_cast(newCharacterObject); - if (creature) - { - float scaleFactor = createMessage->getScaleFactor (); - const SharedObjectTemplate * const tmpl = safe_cast(creature->getSharedTemplate ()); - - if (tmpl) - { - const float scaleMax = tmpl->getScaleMax (); - const float scaleMin = tmpl->getScaleMin (); - - scaleFactor = std::min (scaleFactor, scaleMax); - scaleFactor = std::max (scaleFactor, scaleMin); - } - - creature->setScaleFactor (scaleFactor); - creature->setScale (Vector::xyz111 * scaleFactor); - } - - TangibleObject * tangibleObject = dynamic_cast(newCharacterObject); - //@todo we might ought enforce this be a CreatureObject - if (tangibleObject) - tangibleObject->setAppearanceData(createMessage->getAppearanceData()); - - // hair equip hack - if(!createMessage->getHairTemplateName().empty ()) - { - ServerObject * const hair = ServerWorld::createNewObject(createMessage->getHairTemplateName(), *newCharacterObject, false); - if (!hair) - { - DEBUG_WARNING(true, ("Could not create hair %s\n", createMessage->getHairTemplateName().c_str())); - } - else - { - TangibleObject * const tangible_hair = dynamic_cast(hair); - - if (tangible_hair) - tangible_hair->setAppearanceData (createMessage->getHairAppearanceData ()); - else - WARNING (true, ("Hair is not tangible, wtf. Can't customize it. (among other things, probably)...")); - } - } - - if (!createMessage->getProfession ().empty ()) - { - CreatureObject * const creature = dynamic_cast(newCharacterObject); - if (creature) - PlayerCreationManagerServer::setupPlayer (*creature, createMessage->getProfession (), createMessage->getStationId(), createMessage->getJedi()); - } - - if (!createMessage->getBiography().empty()) - { - BiographyManager::setBiography(newCharacterObject->getNetworkId(),createMessage->getBiography()); - } - - // ---------------------------------------------------------------------- - // Set up the PlayerObject - - ServerObject *playerServerObject = ServerWorld::createNewObject(ConfigServerGame::getPlayerObjectTemplate(), *newCharacterObject, false); - PlayerObject *play = dynamic_cast(playerServerObject); - if (play) - { - play->setStationId(createMessage->getStationId()); - play->setBornDate(); - play->setSkillTemplate(createMessage->getSkillTemplate(), true); - play->setWorkingSkill(createMessage->getWorkingSkill(), true); - - // Setup initial A-Tab inventory. - SlottedContainer * const container = ContainerInterface::getSlottedContainer(*newCharacterObject); - if(container) - { - SlotId slot; - Container::ContainerErrorCode tmp; - slot = SlotIdManager::findSlotId(GameServerNamespace::SlotNames::appearance); - if(slot != SlotId::invalid) - { - Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); - Object* appearanceInventory = itemId.getObject(); - if(appearanceInventory == NULL) - { - WARNING(true, ("Player %s has lost their appearance inventory", newCharacterObject->getNetworkId().getValueString().c_str())); - appearanceInventory = ServerWorld::createNewObject(s_appearanceTemplate, *newCharacterObject, slot, false); - if(!appearanceInventory) - { - DEBUG_FATAL(true, ("Could not create an appearance inventory for the player who lost theirs")); - } - } - } - } - } - else - { - LOG("TraceCharacterCreation", ("%d unable to create player object for new character %s", vrn.getStationId(), newCharacterObject->getNetworkId().getValueString().c_str())); - WARNING_STRICT_FATAL(true,("Unable to create PlayerObject for new character %s.\n",newCharacterObject->getNetworkId().getValueString().c_str())); - } - - newCharacterObject->setSceneIdOnThisAndContents(createMessage->getPlanetName()); - - // ---------------------------------------------------------------------- - // Tell DB Process we're about to send it a character, then send it - AddCharacterMessage const acm(createMessage->getStationId(), newCharacterObject->getNetworkId(),getProcessId(),createMessage->getCharacterName(),createMessage->getJedi()); - sendToDatabaseServer(acm); - newCharacterObject->persist(); - - // ---------------------------------------------------------------------- - // Register player name with the global list - std::string const &firstName = Unicode::wideToNarrow(Unicode::toLower(newCharacterObject->getAssignedObjectFirstName())); - std::string const &fullName = Unicode::wideToNarrow(newCharacterObject->getAssignedObjectName()); - time_t const timeNow = Os::getRealSystemTime(); - NameManager::getInstance().addPlayer(newCharacterObject->getNetworkId(), createMessage->getStationId(), firstName, fullName, timeNow, timeNow, true); - - // ---------------------------------------------------------------------- - // Delete the new character -- will reload it from DB when player logs in - // (This is so that the player could log in to a different server, or not log in at all, and things would still work.) - ServerWorld::removeObjectFromGame(*newCharacterObject); - delete newCharacterObject; - - m_charactersPendingCreation->erase(vrn.getStationId()); - delete createMessage; - - // Destroy any existing chat avatar that may be using the new character's name - GenericValueTypeMessage const chatDestroyAvatar("ChatDestroyAvatar", firstName); - Chat::sendToChatServer(chatDestroyAvatar); -} - -//-------------------------------------------------------------------- - -void GameServer::handleVerifyAndLockNameVerification(const VerifyNameResponse &vrn) -{ - LOG("TraceCharacterCreation", ("%lu VerifyNameResponse from db for verify and lock name received, sending VerifyAndLockNameResponse(%lu, %s, %s)", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); - DEBUG_REPORT_PRINT(true, ("%lu VerifyNameResponse from db for verify and lock name received, sending VerifyAndLockResponse(%lu, %s, %s)\n", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); - - if (vrn.getCharacterId().isValid()) - { - if (vrn.getErrorMessage() != NameErrors::nameApproved) - { - std::string const errorText(std::string("@") + vrn.getErrorMessage().getCanonicalRepresentation()); - ScriptParams params; - params.addParam(errorText.c_str(), "reason"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(vrn.getCharacterId(), "renameCharacterNameValidationFail", dictionary->getSerializedData(), 0, false); - } - } - else - { - MessageToQueue::getInstance().sendMessageToJava(vrn.getCharacterId(), "renameCharacterNameValidationSuccess", std::vector(), 0, false); - } - } - else - { - VerifyAndLockNameResponse const verifyAndLockNameResponse(vrn.getStationId(), vrn.getName(), vrn.getErrorMessage()); - sendToCentralServer(verifyAndLockNameResponse); - } -} - -//-------------------------------------------------------------------- - -bool GameServer::isCreatePending(uint32 stationId) const -{ - std::map::const_iterator findPendingCreation=m_charactersPendingCreation->find(stationId); - // If there is not a creation request pending, just reply with the random name. - return findPendingCreation != m_charactersPendingCreation->end(); -} - -//-------------------------------------------------------------------- - -const StringId & GameServer::canCreateAvatar(const std::string &templateName) -{ - const ServerCreatureObjectTemplate * creatureTemplate = getServerCreatureObjectTemplate(templateName); - if (!creatureTemplate) - { - return NameErrors::nameDeclinedNotCreatureTemplate; - } - - if (!creatureTemplate->getCanCreateAvatar()) - { - creatureTemplate->releaseReference(); - return NameErrors::nameDeclinedCantCreateAvatar; - } - - creatureTemplate->releaseReference(); - return NameErrors::nameApproved; -} - -//-------------------------------------------------------------------- - -const ServerCreatureObjectTemplate * GameServer::getServerCreatureObjectTemplate(const std::string &templateName) const -{ - const ObjectTemplate * objectTemplate = ObjectTemplateList::fetch(templateName); - if (!objectTemplate) - return 0; - - const ServerCreatureObjectTemplate * creatureTemplate = dynamic_cast(objectTemplate); - - return creatureTemplate; -} -//----------------------------------------------------------------------- - -int GameServer::getNumClients() const -{ - if (m_clients) - return m_clients->size(); - return 0; -} - -//----------------------------------------------------------------------- - -void GameServer::handleTeleportMessage(TeleportMessage const &message) -{ - CreatureObject * const creature = dynamic_cast(NetworkIdManager::getObjectById(message.getActorId())); - if (creature) - { - char buf[256]; - IGNORE_RETURN(snprintf(buf, sizeof(buf)-1, "%s %g %g %g %s %g %g %g", - message.getSceneId().c_str(), - message.getPosition_w().x, - message.getPosition_w().y, - message.getPosition_w().z, - message.getContainerId().getValueString().c_str(), - message.getPosition_p().x, - message.getPosition_p().y, - message.getPosition_p().z)); - buf[sizeof(buf)-1] = '\0'; - - Command::ErrorCode status = Command::CEC_Success; - creature->forceExecuteCommand(CommandTable::getCommand(Crc::calculate("planetwarp")), NetworkId::cms_invalid, Unicode::narrowToWide(buf), status, false); - } -} - -//----------------------------------------------------------------------- - -void GameServer::handleRetrievedItemLoadMessage(RetrievedItemLoadMessage const &message) -{ - CachedNetworkId ownerId(message.getOwnerId()); - if (ownerId.getObject()) - { - CreatureObject *owner = dynamic_cast(ownerId.getObject()); - if (owner) - { - ServerObject *inventory = owner->getInventory(); - if (inventory) - { - NetworkId objectId = message.getItemId(); - if (objectId != NetworkId::cms_invalid) - { - inventory->loadContainedObjectFromDB(message.getItemId()); - } - } - } - UNREF(owner); - } -} - -//----------------------------------------------------------------------- - -void GameServer::handleReloadAdminTableMessage(ReloadAdminTableMessage const &message) -{ - AdminAccountManager::reload(); -} - -//----------------------------------------------------------------------- - -void GameServer::handleReloadCommandTableMessage(ReloadCommandTableMessage const &message) -{ - ServerCommandTable::load(); -} - -//----------------------------------------------------------------------- - -void GameServer::handleReloadDatatableMessage(ReloadDatatableMessage const &message) -{ - DataTableManager::reload(message.getTable()); -} - -//----------------------------------------------------------------------- - -void GameServer::handleReloadScriptMessage(ReloadScriptMessage const &message) -{ - GameScriptObject::reloadScript(message.getScript()); -} - -//----------------------------------------------------------------------- - -void GameServer::handleReloadTemplateMessage(ReloadTemplateMessage const &message) -{ - Iff templateFile; - if (templateFile.open(message.getTemplate().c_str(), true)) - { - ObjectTemplateList::reload(templateFile); - } -} - -//----------------------------------------------------------------------- - -void GameServer::handleEnableNewJediTrackingMessage(EnableNewJediTrackingMessage const &message) -{ - GameScriptObject::enableNewJediTracking(message.getEnableTracking()); -} - -//----------------------------------------------------------------------- - -void GameServer::checkIdleClients(float time) -{ - static float s_idleTimePassed; - - s_idleTimePassed += time; - - if (s_idleTimePassed > IDLE_CLIENTS_CHECK_TIME_SEC) - { - s_idleTimePassed = 0.0f; - - std::vector idleClients; - - for (ClientMap::iterator i = m_clients->begin(); i != m_clients->end(); ++i) - { - if ((*i).second->idledTooLong()) - { - PlayerObject const * playerObject = PlayerCreatureController::getPlayerObject(safe_cast((*i).second->getCharacterObject())); - if (!playerObject || (playerObject->getSessionLastActiveTime() == 0)) - { - idleClients.push_back((*i).second); - } - } - } - - for (std::vector::iterator j = idleClients.begin(); j != idleClients.end(); ++j) - (*j)->handleIdleDisconnect(); - } -} - -// ---------------------------------------------------------------------- - -void GameServer::getObjectsWithClients(std::vector &objects) const -{ - objects.clear(); - for (ClientMap::const_iterator i = m_clients->begin(); i != m_clients->end(); ++i) - if ((*i).second->getCharacterObject()) - objects.push_back((*i).second->getCharacterObject()); -} - -// ---------------------------------------------------------------------- - -void GameServer::setDone(char const *reasonfmt, ...) -{ - if (!m_done) - { - char reason[1024]; - va_list ap; - va_start(ap, reasonfmt); - _vsnprintf(reason, sizeof(reason), reasonfmt, ap); - reason[sizeof(reason)-1] = '\0'; - - LOG( - "ServerShutdown", - ( - "GameServer %d (pid %d) shutdown, reason: %s", - static_cast(getProcessId()), - static_cast(Os::getProcessId()), - reason)); - - REPORT_LOG( - true, - ( - "GameServer %d (pid %d) shutdown, reason: %s\n", - static_cast(getProcessId()), - static_cast(Os::getProcessId()), - reason)); - - va_end(ap); - m_done = true; - } -} - -// ---------------------------------------------------------------------- - -void GameServer::setDatabaseProcessConnection(DatabaseProcessConnection *newDatabaseProcessConnection) -{ - if (newDatabaseProcessConnection) - { - FATAL(newDatabaseProcessConnection != m_pendingDatabaseProcessConnection, ("Database process connection established but does not match pending?")); - m_databaseProcessConnection = newDatabaseProcessConnection; - m_pendingDatabaseProcessConnection = 0; - m_databaseProcessId = newDatabaseProcessConnection->getPid(); - - onDatabaseProcessConnectionEstablished(); - } - else - { - m_databaseProcessConnection = 0; - m_pendingDatabaseProcessConnection = 0; - } -} - -// ---------------------------------------------------------------------- - -uint32 GameServer::getDatabaseProcessId() const -{ - return m_databaseProcessId; -} - -// ---------------------------------------------------------------------- - -void GameServer::handleCSRequest( GameServerCSRequestMessage & message ) -{ - DEBUG_REPORT_LOG( true, ( "HandleCSRequest:GameServer\n" ) ); -} - -// ---------------------------------------------------------------------- - -bool GameServer::addPendingLoadRequest(NetworkId const & id) -{ - if (isAtPendingLoadRequestLimit()) - return false; - - if (s_pendingLoadRequests.find(id) != s_pendingLoadRequests.end()) - return false; - - s_pendingLoadRequests[id] = (unsigned int)::time(NULL); - - return true; -} - -// ---------------------------------------------------------------------- - -void GameServer::removePendingLoadRequest(NetworkId const & id) -{ - s_pendingLoadRequests.erase(id); -} - -// ---------------------------------------------------------------------- - -bool GameServer::isAtPendingLoadRequestLimit() -{ - return s_pendingLoadRequests.size() >= static_cast(getPendingLoadRequestLimit()); -} - -// ---------------------------------------------------------------------- - -int GameServer::getPendingLoadRequestLimit() -{ - static int pendingLoadRequestLimit = -1; - - if (pendingLoadRequestLimit == -1) - { - pendingLoadRequestLimit = ConfigServerGame::getPendingLoadRequestLimit(); - - // see if there's a pending load limit set for this particular game server - char key[128]; - snprintf(key, sizeof(key)-1, "pendingLoadRequestLimit_%s.%lu", ServerWorld::getSceneId().c_str(), GameServer::getInstance().getPreloadAreaId()); - key[sizeof(key)-1] = '\0'; - - if (GameServerNamespace::getConfigSetting("GameServer", key, pendingLoadRequestLimit)) - return pendingLoadRequestLimit; - - // see if there's a pending load limit set for this particular planet - snprintf(key, sizeof(key)-1, "pendingLoadRequestLimit_%s", ServerWorld::getSceneId().c_str()); - key[sizeof(key)-1] = '\0'; - - if (GameServerNamespace::getConfigSetting("GameServer", key, pendingLoadRequestLimit)) - return pendingLoadRequestLimit; - - // use default server pending load limit - pendingLoadRequestLimit = ConfigServerGame::getPendingLoadRequestLimit(); - } - - return pendingLoadRequestLimit; -} - -// ---------------------------------------------------------------------- - -int GameServer::getNumberOfPendingLoadRequests() -{ - return s_pendingLoadRequests.size(); -} - -// ---------------------------------------------------------------------- - -unsigned long GameServer::getOldestPendingLoadRequestTime(NetworkId & id) -{ - unsigned long oldestTime = std::numeric_limits::max(); - - std::map::const_iterator i = s_pendingLoadRequests.begin(); - for (; i != s_pendingLoadRequests.end(); ++i) - if (i->second < oldestTime) - { - id = i->first; - oldestTime = i->second; - } - - return oldestTime; -} - -// ---------------------------------------------------------------------- - -ShipObject *GameServerNamespace::getAttachedShip(CreatureObject *creature) -{ - // The "attached" ship is the ship which must move along with the creature. - // This means if the creature is piloting, the ship is is piloting, - // or the containing ship if the creature is the ship's owner. - ShipObject * const ship = ShipObject::getContainingShipObject(creature); - if ( ship - && ( ship->getOwnerId() == creature->getNetworkId() - || creature->getPilotedShip() == ship)) - return ship; - return 0; -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::loadRetroactiveCtsHistory() -{ - FATAL(GameServer::getInstance().getClusterName().empty(), ("cannot load retroactive CTS history until the cluster has received its cluster name")); - - static bool alreadyDone = false; - if (alreadyDone) - return; - - alreadyDone = true; - - // set up data to retroactive CTS history - std::string const retroactiveCtsHistoryFilename = ConfigServerGame::getRetroactiveCtsHistoryFilename(); - if (!retroactiveCtsHistoryFilename.empty()) - { - DataTable * table = DataTableManager::getTable(retroactiveCtsHistoryFilename, true); - if (table) - { - int const columnTransferTime = table->findColumnNumber("transfer time epoch"); - - int const columnSourceCluster = table->findColumnNumber("source cluster"); - int const columnSourceCharacterId = table->findColumnNumber("source character id"); - int const columnSourceCharacterName = table->findColumnNumber("source character name"); - int const columnSourceCharacterBornDate = table->findColumnNumber("source character born date"); - - int const columnTargetCluster = table->findColumnNumber("target cluster"); - int const columnTargetCharacterId = table->findColumnNumber("target character id"); - - FATAL((columnTransferTime < 0), ("column \"transfer time epoch\" not found in %s", retroactiveCtsHistoryFilename.c_str())); - - FATAL((columnSourceCluster < 0), ("column \"source cluster\" not found in %s", retroactiveCtsHistoryFilename.c_str())); - FATAL((columnSourceCharacterId < 0), ("column \"source character id\" not found in %s", retroactiveCtsHistoryFilename.c_str())); - FATAL((columnSourceCharacterName < 0), ("column \"source character name\" not found in %s", retroactiveCtsHistoryFilename.c_str())); - FATAL((columnSourceCharacterBornDate < 0), ("column \"source character born date\" not found in %s", retroactiveCtsHistoryFilename.c_str())); - - FATAL((columnTargetCluster < 0), ("column \"target cluster\" not found in %s", retroactiveCtsHistoryFilename.c_str())); - FATAL((columnTargetCharacterId < 0), ("column \"target character id\" not found in %s", retroactiveCtsHistoryFilename.c_str())); - - // read in retroactive objvars; these are stored in a variable number of - // colunms that are named in ascending order, so search for all such columns - std::vector columnsObjvarName; - std::vector columnsObjvarType; - std::vector columnsObjvarValue; - - char buffer[128]; - int columnNumber; - for (int i = 1; i <= 1000000000; ++i) - { - snprintf(buffer, sizeof(buffer)-1, "objvar name %d", i); - buffer[sizeof(buffer)-1] = '\0'; - - columnNumber = table->findColumnNumber(buffer); - if (columnNumber < 0) - break; - - columnsObjvarName.push_back(columnNumber); - - snprintf(buffer, sizeof(buffer)-1, "objvar type %d", i); - buffer[sizeof(buffer)-1] = '\0'; - - columnNumber = table->findColumnNumber(buffer); - FATAL((columnNumber < 0), ("column \"%s\" not found in %s", buffer, retroactiveCtsHistoryFilename.c_str())); - - columnsObjvarType.push_back(columnNumber); - - snprintf(buffer, sizeof(buffer)-1, "objvar value %d", i); - buffer[sizeof(buffer)-1] = '\0'; - - columnNumber = table->findColumnNumber(buffer); - FATAL((columnNumber < 0), ("column \"%s\" not found in %s", buffer, retroactiveCtsHistoryFilename.c_str())); - - columnsObjvarValue.push_back(columnNumber); - } - - // CTS data can also come from config file, so read that in, if any - std::list ctsDataFromConfig; - - { - int index = 0; - char const * pszCtsDataFromConfig = NULL; - do - { - pszCtsDataFromConfig = ConfigFile::getKeyString("GameServer", "retroactiveCtsHistory", index++, NULL); - if (pszCtsDataFromConfig != NULL) - { - ctsDataFromConfig.push_back(pszCtsDataFromConfig); - } - } - while (pszCtsDataFromConfig); - } - - CtsSourceCharacterInfo sourceCharacterInfo; - std::string retroactiveObjvarName; - int retroactiveObjvarType; - std::string retroactiveObjvarValue; - std::string targetCluster; - NetworkId targetCharacterId; - - // transfer time, source character info - // target cluster - // target character id - // \/ \/ \/ - std::map, CtsSourceCharacterInfo> allCtsHistoryList; - -#ifdef _DEBUG - std::set allCtsSourceCluster; -#endif - - int const currentBornDate = PlayerObject::getCurrentBornDate(); - - std::list::const_iterator iterCtsDataFromConfig = ctsDataFromConfig.begin(); - std::list::const_iterator const iterCtsDataFromConfigEnd = ctsDataFromConfig.end(); - Unicode::String const ctsDataFromConfigDelimiter(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector ctsDataFromConfigTokens; - std::string ctsDataFromConfigParsedData; - - int const numRows = table->getNumRows(); - int rowIndex = 0; - - while (true) - { - if (rowIndex < numRows) - { - sourceCharacterInfo.transferTime = static_cast(table->getIntValue(columnTransferTime, rowIndex)); - - sourceCharacterInfo.sourceCluster = table->getStringValue(columnSourceCluster, rowIndex); - sourceCharacterInfo.sourceCharacterId = NetworkId(table->getStringValue(columnSourceCharacterId, rowIndex)); - sourceCharacterInfo.sourceCharacterName = table->getStringValue(columnSourceCharacterName, rowIndex); - sourceCharacterInfo.sourceCharacterBornDate = table->getIntValue(columnSourceCharacterBornDate, rowIndex); - - targetCluster = table->getStringValue(columnTargetCluster, rowIndex); - targetCharacterId = NetworkId(table->getStringValue(columnTargetCharacterId, rowIndex)); - - // read retroactive objvars - { - sourceCharacterInfo.sourceCharacterRetroactiveObjvars.clear(); - - for (size_t i = 0, size = columnsObjvarName.size(); i < size; ++i) - { - retroactiveObjvarName = table->getStringValue(columnsObjvarName[i], rowIndex); - retroactiveObjvarType = table->getIntValue(columnsObjvarType[i], rowIndex); - retroactiveObjvarValue = table->getStringValue(columnsObjvarValue[i], rowIndex); - - if (!retroactiveObjvarName.empty() && !retroactiveObjvarValue.empty()) - { - // can only handle INT (type 0) and INT_ARRAY (type 1) objvar type at this time - FATAL(((retroactiveObjvarType != static_cast(DynamicVariable::INT)) && (retroactiveObjvarType != static_cast(DynamicVariable::INT_ARRAY))), ("invalid or unsupported objvar type %d in %s, row %d", retroactiveObjvarType, retroactiveCtsHistoryFilename.c_str(), (rowIndex+3))); - sourceCharacterInfo.sourceCharacterRetroactiveObjvars.push_back(std::make_pair(retroactiveObjvarName, DynamicVariable())); - sourceCharacterInfo.sourceCharacterRetroactiveObjvars[sourceCharacterInfo.sourceCharacterRetroactiveObjvars.size() - 1].second.load(-1, retroactiveObjvarType, Unicode::narrowToWide(retroactiveObjvarValue)); - } - } - } - - ++rowIndex; - } - else if (iterCtsDataFromConfig == iterCtsDataFromConfigEnd) - { - break; - } - else - { - ctsDataFromConfigTokens.clear(); - if ((Unicode::tokenize(Unicode::narrowToWide(*iterCtsDataFromConfig), ctsDataFromConfigTokens, &ctsDataFromConfigDelimiter, NULL)) && (ctsDataFromConfigTokens.size() == 7)) - { - // sanity check - ctsDataFromConfigParsedData = FormattedString<2048>().sprintf("%s|%s|%s|%s|%s|%s|%s", Unicode::wideToNarrow(ctsDataFromConfigTokens[0]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[1]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[2]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[3]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[4]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[5]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[6]).c_str()); - FATAL((ctsDataFromConfigParsedData != *iterCtsDataFromConfig), ("parsed CTS data (%s) does not equal read CTS data (%s)", ctsDataFromConfigParsedData.c_str(), iterCtsDataFromConfig->c_str())); - - sourceCharacterInfo.transferTime = static_cast(::atol(Unicode::wideToNarrow(ctsDataFromConfigTokens[0]).c_str())); - - sourceCharacterInfo.sourceCluster = Unicode::wideToNarrow(ctsDataFromConfigTokens[1]); - sourceCharacterInfo.sourceCharacterId = NetworkId(Unicode::wideToNarrow(ctsDataFromConfigTokens[2])); - sourceCharacterInfo.sourceCharacterName = Unicode::wideToNarrow(ctsDataFromConfigTokens[3]); - sourceCharacterInfo.sourceCharacterBornDate = ::atoi(Unicode::wideToNarrow(ctsDataFromConfigTokens[4]).c_str()); - - targetCluster = Unicode::wideToNarrow(ctsDataFromConfigTokens[5]); - targetCharacterId = NetworkId(Unicode::wideToNarrow(ctsDataFromConfigTokens[6])); - - sourceCharacterInfo.sourceCharacterRetroactiveObjvars.clear(); - } - else - { - FATAL(true, ("cannot parse CTS data (%s) read from config file", iterCtsDataFromConfig->c_str())); - } - - ++iterCtsDataFromConfig; - } - - FATAL(((sourceCharacterInfo.sourceCharacterBornDate > 0) && (sourceCharacterInfo.sourceCharacterBornDate < 907)), ("source character (%s, %s) has born date (%d) < 907", sourceCharacterInfo.sourceCluster.c_str(), sourceCharacterInfo.sourceCharacterId.getValueString().c_str(), sourceCharacterInfo.sourceCharacterBornDate)); - FATAL((sourceCharacterInfo.sourceCharacterBornDate > currentBornDate), ("source character (%s, %s) has born date (%d) > current born date (%d)", sourceCharacterInfo.sourceCluster.c_str(), sourceCharacterInfo.sourceCharacterId.getValueString().c_str(), sourceCharacterInfo.sourceCharacterBornDate, currentBornDate)); - - std::map > * clusterCtsHistory = NULL; -#ifdef _DEBUG - IGNORE_RETURN(allCtsSourceCluster.insert(sourceCharacterInfo.sourceCluster)); - clusterCtsHistory = &(s_retroactiveCtsHistoryList[targetCluster]); -#else - // for release build, we only care about transfers into our cluster; - // for debug build, read them all so we can test out the logic to - // make sure it works for all clusters - if (targetCluster == GameServer::getInstance().getClusterName()) - clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; -#endif - if (clusterCtsHistory) - { - if (clusterCtsHistory->count(targetCharacterId) <= 0) - { - (*clusterCtsHistory)[targetCharacterId].push_back(sourceCharacterInfo); - } - } - - std::map, CtsSourceCharacterInfo>::const_iterator const iterFindCtsHistory = allCtsHistoryList.find(std::make_pair(targetCharacterId, targetCluster)); - if (iterFindCtsHistory == allCtsHistoryList.end()) - { - allCtsHistoryList[std::make_pair(targetCharacterId, targetCluster)] = sourceCharacterInfo; - } - else - { - FATAL(((iterFindCtsHistory->second.sourceCharacterId != sourceCharacterInfo.sourceCharacterId) || (iterFindCtsHistory->second.sourceCluster != sourceCharacterInfo.sourceCluster)), ("character (%s, %s) has 2 transfers from different source characters (%s, %s, %s, %ld, %s) and (%s, %s, %s, %ld, %s)", targetCluster.c_str(), targetCharacterId.getValueString().c_str(), iterFindCtsHistory->second.sourceCluster.c_str(), iterFindCtsHistory->second.sourceCharacterId.getValueString().c_str(), iterFindCtsHistory->second.sourceCharacterName.c_str(), iterFindCtsHistory->second.transferTime, CalendarTime::convertEpochToTimeStringLocal(iterFindCtsHistory->second.transferTime).c_str(), sourceCharacterInfo.sourceCluster.c_str(), sourceCharacterInfo.sourceCharacterId.getValueString().c_str(), sourceCharacterInfo.sourceCharacterName.c_str(), sourceCharacterInfo.transferTime, CalendarTime::convertEpochToTimeStringLocal(sourceCharacterInfo.transferTime).c_str())); - } - } - - DataTableManager::close(retroactiveCtsHistoryFilename); - -#ifdef _DEBUG - { - // make sure there are collection slots defined for CTS titles - for (std::set::const_iterator iter = allCtsSourceCluster.begin(); iter != allCtsSourceCluster.end(); ++iter) - { - std::string collectionSlotName = std::string("cts_from_") + Unicode::toLower(*iter); - - std::string::size_type pos = collectionSlotName.find('-'); - while (pos != std::string::npos) - { - collectionSlotName.replace(pos, 1, 1, '_'); - pos = collectionSlotName.find('-'); - } - - DEBUG_WARNING(!CollectionsDataTable::getSlotByName(collectionSlotName), ("no collection slot defined for CTS title (%s)", collectionSlotName.c_str())); - } - } -#endif - - // build CTS history for characters who have transferred multiple times - - // source cluster - // source character id - // \/ \/ - std::set > ctsHistorySourceCharacters; - -#ifdef _DEBUG - for (std::map > >::iterator iterCtsHistoryCluster = s_retroactiveCtsHistoryList.begin(); iterCtsHistoryCluster != s_retroactiveCtsHistoryList.end(); ++iterCtsHistoryCluster) - { - std::string const & ctsHistoryClusterName = iterCtsHistoryCluster->first; - std::map > & ctsHistoryCluster = iterCtsHistoryCluster->second; - -#else - { - std::string const & ctsHistoryClusterName = GameServer::getInstance().getClusterName(); - std::map > & ctsHistoryCluster = s_retroactiveCtsHistoryListThisCluster; -#endif - for (std::map >::iterator iterCtsHistoryCharacter = ctsHistoryCluster.begin(); iterCtsHistoryCharacter != ctsHistoryCluster.end(); ++iterCtsHistoryCharacter) - { - FATAL((iterCtsHistoryCharacter->second.size() != 1), ("character (%s, %s) should have exactly 1 CTS history at this point in the parsing", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str())); - CtsSourceCharacterInfo const & ctsHistoryLastSourceCharacter = iterCtsHistoryCharacter->second[0]; - - ctsHistorySourceCharacters.clear(); - IGNORE_RETURN(ctsHistorySourceCharacters.insert(std::make_pair(ctsHistoryLastSourceCharacter.sourceCharacterId, ctsHistoryLastSourceCharacter.sourceCluster))); - - std::map, CtsSourceCharacterInfo>::const_iterator iterFindCharacterCtsHistory = allCtsHistoryList.find(std::make_pair(ctsHistoryLastSourceCharacter.sourceCharacterId, ctsHistoryLastSourceCharacter.sourceCluster)); - while (iterFindCharacterCtsHistory != allCtsHistoryList.end()) - { - FATAL((ctsHistorySourceCharacters.count(std::make_pair(iterFindCharacterCtsHistory->second.sourceCharacterId, iterFindCharacterCtsHistory->second.sourceCluster)) > 0), ("character (%s, %s) has multiple CTS history for the same source character (%s, %s, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), iterFindCharacterCtsHistory->second.sourceCluster.c_str(), iterFindCharacterCtsHistory->second.sourceCharacterId.getValueString().c_str(), iterFindCharacterCtsHistory->second.sourceCharacterName.c_str())); - IGNORE_RETURN(ctsHistorySourceCharacters.insert(std::make_pair(iterFindCharacterCtsHistory->second.sourceCharacterId, iterFindCharacterCtsHistory->second.sourceCluster))); - - FATAL((iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].transferTime <= iterFindCharacterCtsHistory->second.transferTime), ("character (%s, %s) has out of order CTS history for source characters (%s, %s, %s, %ld, %s) and (%s, %s, %s, %ld, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].sourceCluster.c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].sourceCharacterId.getValueString().c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].sourceCharacterName.c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].transferTime, CalendarTime::convertEpochToTimeStringLocal(iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].transferTime).c_str(), iterFindCharacterCtsHistory->second.sourceCluster.c_str(), iterFindCharacterCtsHistory->second.sourceCharacterId.getValueString().c_str(), iterFindCharacterCtsHistory->second.sourceCharacterName.c_str(), iterFindCharacterCtsHistory->second.transferTime, CalendarTime::convertEpochToTimeStringLocal(iterFindCharacterCtsHistory->second.transferTime).c_str())); - iterCtsHistoryCharacter->second.push_back(iterFindCharacterCtsHistory->second); - - iterFindCharacterCtsHistory = allCtsHistoryList.find(std::make_pair(iterFindCharacterCtsHistory->second.sourceCharacterId, iterFindCharacterCtsHistory->second.sourceCluster)); - } - } - } - -#ifdef _DEBUG - { - // make sure that we have the born date of the "root" source character for each transfer - for (std::map > >::const_iterator iterCtsHistoryCluster = s_retroactiveCtsHistoryList.begin(); iterCtsHistoryCluster != s_retroactiveCtsHistoryList.end(); ++iterCtsHistoryCluster) - { - std::string const & ctsHistoryClusterName = iterCtsHistoryCluster->first; - std::map > const & ctsHistoryCluster = iterCtsHistoryCluster->second; - - for (std::map >::const_iterator iterCtsHistoryCharacter = ctsHistoryCluster.begin(); iterCtsHistoryCharacter != ctsHistoryCluster.end(); ++iterCtsHistoryCharacter) - { - FATAL(iterCtsHistoryCharacter->second.empty(), ("character (%s, %s) has empty CTS history list", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str())); - - // we only care about missing born date for transfers on or before - // Wed Nov 19 23:21:11 2008 Pacific Standard Time (epoch 1227165671) - // since transfers after that should correctly transfer the born date - FATAL((((iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).sourceCharacterBornDate <= 0) && ((iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).transferTime <= 1227165671)), ("character (%s, %s) has no born date for the \"root\" source character (%s, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), (iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).sourceCluster.c_str(), (iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).sourceCharacterId.getValueString().c_str())); - - // if the character has transferred multiple times, make sure that only the "root" source character has a born date - if (iterCtsHistoryCharacter->second.size() > 1) - { - for (size_t i = 0, sizeExcludingLastElement = (iterCtsHistoryCharacter->second.size() - 1); i < sizeExcludingLastElement; ++i) - { - FATAL(((iterCtsHistoryCharacter->second[i]).sourceCharacterBornDate > 0), ("character (%s, %s) has born date (%d) for a \"non root\" source character (%s, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), (iterCtsHistoryCharacter->second[i]).sourceCharacterBornDate, (iterCtsHistoryCharacter->second[i]).sourceCluster.c_str(), (iterCtsHistoryCharacter->second[i]).sourceCharacterId.getValueString().c_str())); - } - } - } - } - } -#endif - } - } -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::loadRetroactivePlayerCityCreationTime() -{ - FATAL(GameServer::getInstance().getClusterName().empty(), ("cannot load retroactive player city creation time until the cluster has received its cluster name")); - - static bool alreadyDone = false; - if (alreadyDone) - return; - - alreadyDone = true; - - // set up data to player city creation time - std::string const retroactivePlayerCityCreationTimeFilename = ConfigServerGame::getRetroactivePlayerCityCreationTimeFilename(); - if (!retroactivePlayerCityCreationTimeFilename.empty()) - { - DataTable * table = DataTableManager::getTable(retroactivePlayerCityCreationTimeFilename, true); - if (table) - { - int const columnCreationTime = table->findColumnNumber("creation time epoch"); - int const columnCluster = table->findColumnNumber("cluster"); - int const columnCityId = table->findColumnNumber("city id"); - - FATAL((columnCreationTime < 0), ("column \"creation time epoch\" not found in %s", retroactivePlayerCityCreationTimeFilename.c_str())); - FATAL((columnCluster < 0), ("column \"cluster\" not found in %s", retroactivePlayerCityCreationTimeFilename.c_str())); - FATAL((columnCityId < 0), ("column \"city id\" not found in %s", retroactivePlayerCityCreationTimeFilename.c_str())); - - // player city creation time data can also come from config file, so read that in, if any - std::list playerCityCreationTimeDataFromConfig; - - { - int index = 0; - char const * pszPlayerCityCreationTimeDataFromConfig = NULL; - do - { - pszPlayerCityCreationTimeDataFromConfig = ConfigFile::getKeyString("GameServer", "retroactivePlayerCityCreationTime", index++, NULL); - if (pszPlayerCityCreationTimeDataFromConfig != NULL) - { - playerCityCreationTimeDataFromConfig.push_back(pszPlayerCityCreationTimeDataFromConfig); - } - } - while (pszPlayerCityCreationTimeDataFromConfig); - } - - std::list::const_iterator iterPlayerCityCreationTimeDataFromConfig = playerCityCreationTimeDataFromConfig.begin(); - std::list::const_iterator const iterPlayerCityCreationTimeDataFromConfigEnd = playerCityCreationTimeDataFromConfig.end(); - Unicode::String const playerCityCreationTimeDataFromConfigDelimiter(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector playerCityCreationTimeDataFromConfigTokens; - std::string playerCityCreationTimeDataFromConfigParsedData; - - time_t creationTime = 0; - std::string cluster; - int cityId = 0; - - int const numRows = table->getNumRows(); - int rowIndex = 0; - - while (true) - { - if (rowIndex < numRows) - { - creationTime = static_cast(table->getIntValue(columnCreationTime, rowIndex)); - cluster = table->getStringValue(columnCluster, rowIndex); - cityId = table->getIntValue(columnCityId, rowIndex); - - FATAL((cluster.empty()), ("cluster name is empty in %s, row %d", retroactivePlayerCityCreationTimeFilename.c_str(), (rowIndex+3))); - FATAL((cityId <= 0), ("city id for player city (%s, %d) is <= 0 in %s, row %d", cluster.c_str(), cityId, retroactivePlayerCityCreationTimeFilename.c_str(), (rowIndex+3))); - FATAL((creationTime <= 0), ("creation time (%d) for player city (%s, %d) is <= 0 in %s, row %d", creationTime, cluster.c_str(), cityId, retroactivePlayerCityCreationTimeFilename.c_str(), (rowIndex+3))); - - ++rowIndex; - } - else if (iterPlayerCityCreationTimeDataFromConfig == iterPlayerCityCreationTimeDataFromConfigEnd) - { - break; - } - else - { - playerCityCreationTimeDataFromConfigTokens.clear(); - if ((Unicode::tokenize(Unicode::narrowToWide(*iterPlayerCityCreationTimeDataFromConfig), playerCityCreationTimeDataFromConfigTokens, &playerCityCreationTimeDataFromConfigDelimiter, NULL)) && (playerCityCreationTimeDataFromConfigTokens.size() == 3)) - { - // sanity check - playerCityCreationTimeDataFromConfigParsedData = FormattedString<2048>().sprintf("%s|%s|%s", Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[0]).c_str(), Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[1]).c_str(), Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[2]).c_str()); - FATAL((playerCityCreationTimeDataFromConfigParsedData != *iterPlayerCityCreationTimeDataFromConfig), ("parsed player city creation time data (%s) does not equal read player city creation time data (%s)", playerCityCreationTimeDataFromConfigParsedData.c_str(), iterPlayerCityCreationTimeDataFromConfig->c_str())); - - creationTime = static_cast(::atol(Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[0]).c_str())); - cluster = Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[1]); - cityId = ::atoi(Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[2]).c_str()); - - FATAL((cluster.empty()), ("cluster name is empty in config option (%s)", iterPlayerCityCreationTimeDataFromConfig->c_str())); - FATAL((cityId <= 0), ("city id for player city (%s, %d) is <= 0 in config option (%s)", cluster.c_str(), cityId, iterPlayerCityCreationTimeDataFromConfig->c_str())); - FATAL((creationTime <= 0), ("creation time (%d) for player city (%s, %d) is <= 0 in config option (%s)", creationTime, cluster.c_str(), cityId, iterPlayerCityCreationTimeDataFromConfig->c_str())); - } - else - { - FATAL(true, ("cannot parse player city creation time data (%s) read from config file", iterPlayerCityCreationTimeDataFromConfig->c_str())); - } - - ++iterPlayerCityCreationTimeDataFromConfig; - } - - std::map * clusterPlayerCityCreationTimeHistory = NULL; -#ifdef _DEBUG - clusterPlayerCityCreationTimeHistory = &(s_retroactivePlayerCityCreationTime[cluster]); -#else - // for release build, we only care about player cities created - // on our cluster cluster; for debug build, read them all so we - // can test out the logic to make sure it works for all clusters - if (cluster == GameServer::getInstance().getClusterName()) - clusterPlayerCityCreationTimeHistory = &s_retroactivePlayerCityCreationTimeThisCluster; -#endif - if (clusterPlayerCityCreationTimeHistory) - { - FATAL((clusterPlayerCityCreationTimeHistory->count(cityId) > 0), ("multiple entries found for player city (%s, %d)", cluster.c_str(), cityId)); - (*clusterPlayerCityCreationTimeHistory)[cityId] = creationTime; - } - } - - DataTableManager::close(retroactivePlayerCityCreationTimeFilename); - } - } -} - -// ---------------------------------------------------------------------- - -bool GameServerNamespace::checkAndSetOutstandingRequestSceneTransfer(ServerObject & object) -{ - int const timeNow = static_cast(::time(NULL)); - - // don't send multiple RequestSceneTransfer message - if (object.getObjVars().hasItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER) && (object.getObjVars().getType(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER) == DynamicVariable::INT)) - { - int requestTimeOut = 0; - if (object.getObjVars().getItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER, requestTimeOut)) - { - if (timeNow <= requestTimeOut) - { - LOG("RequestSceneWarp", ("%s already has an outstanding RequestSceneTransfer that will expire in %d seconds", PlayerObject::getAccountDescription(&object).c_str(), (requestTimeOut - timeNow))); - return true; - } - else - { - LOG("RequestSceneWarp", ("%s has an expired RequestSceneTransfer, so we are allowing a new RequestSceneTransfer", PlayerObject::getAccountDescription(&object).c_str())); - } - } - } - - IGNORE_RETURN(object.setObjVarItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER, (timeNow + ConfigServerGame::getRequestSceneWarpTimeoutSeconds()))); - - return false; -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::handleFactionalSystemMessage(FactionalSystemMessage const & msg) -{ - // is it a ranged message? - if (msg.getRadius() >= 0.0f) - { - TangibleObject * to; - std::vector playersInRange; - ServerWorld::findPlayerCreaturesInRange(msg.getLocation(), msg.getRadius(), playersInRange); - for (std::vector::const_iterator i = playersInRange.begin(); i != playersInRange.end(); ++i) - { - if ((*i)->isAuthoritative() && (*i)->getClient()) - { - to = (*i)->asTangibleObject(); - if (to && - ((msg.getNotifyImperial() && PvpData::isImperialFactionId(to->getPvpFaction())) || - (msg.getNotifyRebel() && PvpData::isRebelFactionId(to->getPvpFaction())) - ) - ) - { - Chat::sendSystemMessage(**i, Unicode::String(), msg.getProsePackage()); - } - } - } - } - else - { - // not a ranged message, everyone gets it - std::set const &players = PlayerObject::getAllPlayerObjects(); - if (!players.empty()) - { - CreatureObject const * creatureObject; - for (std::set::const_iterator i = players.begin(); i != players.end(); ++i) - { - creatureObject = (*i)->getCreatureObject(); - if (creatureObject && creatureObject->isAuthoritative() && creatureObject->getClient()) - { - if ((msg.getNotifyImperial() && PvpData::isImperialFactionId(creatureObject->getPvpFaction())) || - (msg.getNotifyRebel() && PvpData::isRebelFactionId(creatureObject->getPvpFaction())) - ) - { - Chat::sendSystemMessage(*creatureObject, Unicode::String(), msg.getProsePackage()); - } - } - } - } - } -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::handleMessageToPlayersOnPlanet(std::string const & methodName, std::vector const & params, float const delay, Vector const & loc, float const radius, bool const includeDisconnectedPlayers) -{ - // we cannot use ServerWorld::findPlayerCreaturesInRange() because that only looks at creatures - // that are in the world, and disconnected players creatures are removed from the world - std::set const &players = PlayerObject::getAllPlayerObjects(); - if (!players.empty()) - { - float const radiusSquared = sqr(radius); - CreatureObject const * creatureObject; - for (std::set::const_iterator i = players.begin(); i != players.end(); ++i) - { - creatureObject = (*i)->getCreatureObject(); - if (creatureObject && creatureObject->isAuthoritative() && (includeDisconnectedPlayers || creatureObject->getClient())) - { - // check range, if necessary - if ((radius < 0.0f) || (loc.magnitudeBetweenSquared(creatureObject->getPosition_w()) < radiusSquared)) - { - MessageToQueue::getInstance().sendMessageToJava(creatureObject->getNetworkId(), methodName, params, static_cast(delay), false); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::handleMessageLocateStructureByOwnerIdReq(GameServer & gsInstance, uint32 responsePid, bool isGod, NetworkId const & ownerId, NetworkId const & ownerResidenceId, NetworkId const & responseId) -{ - static std::string const planetName(ServerWorld::getSceneId()); - static std::string const displayPlanetName(Unicode::wideToNarrow(StringId("planet_n", planetName).localize())); - std::vector response; - - // buildings - { - BuildingObject::AllBuildingsSet const & allBuildings = BuildingObject::getAllBuildings(); - for (BuildingObject::AllBuildingsSet::const_iterator iterBuilding = allBuildings.begin(); iterBuilding != allBuildings.end(); ++iterBuilding) - { - if ((*iterBuilding)->isAuthoritative() && ((*iterBuilding)->getOwnerId() == ownerId) && (*iterBuilding)->isInWorldCell()) - { - // player assigned name - std::string name = Unicode::wideToNarrow((*iterBuilding)->getAssignedObjectName()); - - // buildings have their name in the sign - if (name.empty() && (*iterBuilding)->getObjVars().hasItem("player_structure.sign.name") && ((*iterBuilding)->getObjVars().getType("player_structure.sign.name") == DynamicVariable::STRING)) - IGNORE_RETURN((*iterBuilding)->getObjVars().getItem("player_structure.sign.name", name)); - - // default/type name - Unicode::String nameTypeWide; - std::string nameTypeNarrow = "Building"; - if ((*iterBuilding)->getObjectNameStringId().localize(nameTypeWide)) - nameTypeNarrow = Unicode::wideToNarrow(nameTypeWide); - - if (!name.empty()) - { - if (name != nameTypeNarrow) - { - name += " ("; - name += nameTypeNarrow; - name += ")"; - } - } - else - { - name = nameTypeNarrow; - } - - // check for residence building - NetworkId residenceOf; - if ((*iterBuilding)->getObjVars().getItem("player_structure.residence.building", residenceOf) && (residenceOf == ownerId)) - { - if (ownerId == responseId) - { - if (ownerResidenceId == (*iterBuilding)->getNetworkId()) - { - name += " (residence)"; - } - else - { - // house thinks it's the residence of the owner, but owner doesn't think so, - // so fix up house so it no longer thinks it's the residence of the owner - (const_cast(*iterBuilding))->removeObjVarItem("player_structure.residence.building"); - } - } - else - { - name += " (residence)"; - } - } - - Vector const loc = (*iterBuilding)->findPosition_w(); - std::string cityAndPlanetName; - int const cityId = CityInterface::getCityAtLocation(planetName, static_cast(loc.x), static_cast(loc.z), 0); - if (cityId > 0) - cityAndPlanetName = CityInterface::getCityInfo(cityId).getCityName(); - - if (!cityAndPlanetName.empty()) - cityAndPlanetName += ", "; - - cityAndPlanetName += displayPlanetName; - - Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(planetName, loc.x, loc.z); - if (region) - { - cityAndPlanetName += ":"; - cityAndPlanetName += Unicode::wideToNarrow(StringId::decodeString(region->getName())); - } - - if (!isGod) - response.push_back(FormattedString<1024>().sprintf("%s at %s (%d, %d)", name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); - else - response.push_back(FormattedString<1024>().sprintf("%s, %s at %s (%d, %d)", (*iterBuilding)->getNetworkId().getValueString().c_str(), name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); - } - } - } - - // installations, including harvesters and factories - { - InstallationObject::AllInstallationsSet const & allInstallations = InstallationObject::getAllInstallations(); - for (ManufactureInstallationObject::AllInstallationsSet::const_iterator iterInstallation = allInstallations.begin(); iterInstallation != allInstallations.end(); ++iterInstallation) - { - if ((*iterInstallation)->isAuthoritative() && ((*iterInstallation)->getOwnerId() == ownerId) && (*iterInstallation)->isInWorldCell()) - { - // player assigned name - std::string name = Unicode::wideToNarrow((*iterInstallation)->getAssignedObjectName()); - - // default/type name - Unicode::String nameTypeWide; - std::string nameTypeNarrow; - if ((*iterInstallation)->getObjectNameStringId().localize(nameTypeWide)) - nameTypeNarrow = Unicode::wideToNarrow(nameTypeWide); - else if (dynamic_cast(*iterInstallation)) - nameTypeNarrow = "Harvester"; - else if (dynamic_cast(*iterInstallation)) - nameTypeNarrow = "Factory"; - else - nameTypeNarrow = "Installation"; - - if (!name.empty()) - { - if (name != nameTypeNarrow) - { - name += " ("; - name += nameTypeNarrow; - name += ")"; - } - } - else - { - name = nameTypeNarrow; - } - - Vector const loc = (*iterInstallation)->findPosition_w(); - std::string cityAndPlanetName; - int const cityId = CityInterface::getCityAtLocation(planetName, static_cast(loc.x), static_cast(loc.z), 0); - if (cityId > 0) - cityAndPlanetName = CityInterface::getCityInfo(cityId).getCityName(); - - if (!cityAndPlanetName.empty()) - cityAndPlanetName += ", "; - - cityAndPlanetName += displayPlanetName; - - Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(planetName, loc.x, loc.z); - if (region) - { - cityAndPlanetName += ":"; - cityAndPlanetName += Unicode::wideToNarrow(StringId::decodeString(region->getName())); - } - - if (!isGod) - response.push_back(FormattedString<1024>().sprintf("%s at %s (%d, %d)", name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); - else - response.push_back(FormattedString<1024>().sprintf("%s, %s at %s (%d, %d)", (*iterInstallation)->getNetworkId().getValueString().c_str(), name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); - } - } - } - - // if there are any matches, send reply - if (!response.empty()) - { - GenericValueTypeMessage, std::vector > > locateStructureByOwnerIdRsp("LSBOIRsp", std::make_pair(std::make_pair(responsePid, responseId), response)); - gsInstance.sendToCentralServer(locateStructureByOwnerIdRsp); - } -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::handleMessageLocateStructureByOwnerIdRsp(NetworkId const & responseId, std::vector const & response) -{ - if (response.empty()) - return; - - ServerObject const * const object = ServerWorld::findObjectByNetworkId(responseId); - if (!object) - return; - - Client * const clientObj = object->getClient(); - if (!clientObj) - return; - - for (std::vector::const_iterator iter = response.begin(); iter != response.end(); ++iter) - ConsoleMgr::broadcastString(*iter, clientObj); -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::handleAdjustAccountFeatureIdResponse(AdjustAccountFeatureIdResponse const & msg) -{ - Archive::ByteStream bs; - msg.pack(bs); - - if (msg.getRequestingPlayer().isValid()) - { - MessageToQueue::getInstance().sendMessageToC(msg.getRequestingPlayer(), - "C++AdjustAccountFeatureIdResponse", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } - - if (msg.getTargetPlayer().isValid() && (msg.getTargetPlayer() != msg.getRequestingPlayer())) - { - MessageToQueue::getInstance().sendMessageToC(msg.getTargetPlayer(), - "C++AdjustAccountFeatureIdResponse", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } - - if (msg.getTargetItem().isValid() && (msg.getTargetItem() != msg.getRequestingPlayer()) && (msg.getTargetItem() != msg.getTargetPlayer())) - { - MessageToQueue::getInstance().sendMessageToC(msg.getTargetItem(), - "C++AdjustAccountFeatureIdResponse", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } -} - -// ---------------------------------------------------------------------- - -void GameServerNamespace::handleAccountFeatureIdResponse(AccountFeatureIdResponse const & msg) -{ - // this message may arrive before the Client object has been attached - // to the character object, or even before we have loaded the character - // object into the game, so we'll just directly search for the Client - // object associated with the character object and update the information - bool needToNotifyRequester = (((msg.getRequestReason() == AccountFeatureIdRequest::RR_ConsoleCommandReloadRequest) || (msg.getRequestReason() == AccountFeatureIdRequest::RR_ReloadRewardCheck)) && msg.getRequester().isValid()); - - if (msg.getResultCode() == RESULT_SUCCESS) - { - Client * client = GameServer::getInstance().getClient(msg.getTarget()); - if (client) - { - if (msg.getGameCode() == PlatformGameCode::SWG) - client->setAccountFeatureIds(msg.getFeatureIds()); - } - else - { - // character object may have moved to a different game server, - // so forward the message to the character object for handling - Archive::ByteStream bs; - msg.pack(bs); - - MessageToQueue::getInstance().sendMessageToC(msg.getTarget(), - "C++AccountFeatureIdResponse", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - - // don't need to send another messageTo to the requester - if (needToNotifyRequester && (msg.getRequester() == msg.getTarget())) - needToNotifyRequester = false; - } - } - - if (needToNotifyRequester) - { - Archive::ByteStream bs; - msg.pack(bs); - - MessageToQueue::getInstance().sendMessageToC(msg.getRequester(), - "C++AccountFeatureIdResponse", - std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), - 0, - false); - } -} - -// ---------------------------------------------------------------------- - -std::string GameServer::getRetroactiveCtsHistory(std::string const & clusterName, NetworkId const & characterId) -{ - std::string result; - std::map > const * clusterCtsHistory = NULL; - -#ifdef _DEBUG - std::map > >::const_iterator const iterFindCluster = s_retroactiveCtsHistoryList.find(clusterName); - if (iterFindCluster != s_retroactiveCtsHistoryList.end()) - clusterCtsHistory = &(iterFindCluster->second); -#else - if (clusterName == GameServer::getInstance().getClusterName()) - clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; -#endif - - if (!clusterCtsHistory) - return result; - - std::map >::const_iterator const iterFindCharacter = clusterCtsHistory->find(characterId); - if (iterFindCharacter == clusterCtsHistory->end()) - return result; - - int count = 0; - for (std::vector::const_reverse_iterator iterCtsHistory = iterFindCharacter->second.rbegin(); iterCtsHistory != iterFindCharacter->second.rend(); ++iterCtsHistory) - { - if (!result.empty()) - result += "\n"; - - ++count; - - if (iterCtsHistory->sourceCharacterBornDate <= 0) - result += FormattedString<1024>().sprintf("%2d) transferred from (%s, %s, %s) on (%ld, %s)", count, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterName.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->transferTime, CalendarTime::convertEpochToTimeStringLocal(iterCtsHistory->transferTime).c_str()); - else - result += FormattedString<1024>().sprintf("%2d) transferred from (%s, %s, %s, born date=%d, %s) on (%ld, %s)", count, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterName.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->sourceCharacterBornDate, CalendarTime::getCharacerBirthDateString(iterCtsHistory->sourceCharacterBornDate).c_str(), iterCtsHistory->transferTime, CalendarTime::convertEpochToTimeStringLocal(iterCtsHistory->transferTime).c_str()); - - for (std::vector >::const_iterator iterRetroactiveObjvar = iterCtsHistory->sourceCharacterRetroactiveObjvars.begin(); iterRetroactiveObjvar != iterCtsHistory->sourceCharacterRetroactiveObjvars.end(); ++iterRetroactiveObjvar) - result += FormattedString<1024>().sprintf("\n\t(%s, %s)", iterRetroactiveObjvar->first.c_str(), Unicode::wideToNarrow(iterRetroactiveObjvar->second.getPackedValueString()).c_str()); - } - - return result; -} - -// ---------------------------------------------------------------------- - -void GameServer::setRetroactiveCtsHistory(CreatureObject & player) -{ - if (!player.isAuthoritative()) - return; - - if (player.getObjVars().hasItem("ctsHistory")) - return; - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(&player); - if (!playerObject) - return; - - if (!playerObject->isAuthoritative()) - return; - - std::map > const * clusterCtsHistory = NULL; - -#ifdef _DEBUG - std::map > >::const_iterator const iterFindCluster = s_retroactiveCtsHistoryList.find(GameServer::getInstance().getClusterName()); - if (iterFindCluster != s_retroactiveCtsHistoryList.end()) - clusterCtsHistory = &(iterFindCluster->second); -#else - clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; -#endif - - if (!clusterCtsHistory) - return; - - std::map >::const_iterator const iterFindCharacter = clusterCtsHistory->find(player.getNetworkId()); - if (iterFindCharacter == clusterCtsHistory->end()) - return; - - int count = 0; - int rootSourceCharacterBornDate = 0; - std::vector ctsSourceGalaxies; - for (std::vector::const_reverse_iterator iterCtsHistory = iterFindCharacter->second.rbegin(); iterCtsHistory != iterFindCharacter->second.rend(); ++iterCtsHistory) - { - ++count; - LOG("CustomerService", ("CharacterTransferRetroactiveHistory: %s, setting objvar ctsHistory.%d = \"%ld %s %s %s\", transfer time (%s)", playerObject->getAccountDescription().c_str(), count, iterCtsHistory->transferTime, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->sourceCharacterName.c_str(), CalendarTime::convertEpochToTimeStringLocal(iterCtsHistory->transferTime).c_str())); - IGNORE_RETURN(player.setObjVarItem(FormattedString<1024>().sprintf("ctsHistory.%d", count), FormattedString<1024>().sprintf("%ld %s %s %s", iterCtsHistory->transferTime, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->sourceCharacterName.c_str()))); - - if (iterCtsHistory->sourceCharacterBornDate > 0) - { - if ((rootSourceCharacterBornDate == 0) || (iterCtsHistory->sourceCharacterBornDate < rootSourceCharacterBornDate)) - rootSourceCharacterBornDate = iterCtsHistory->sourceCharacterBornDate; - } - - ctsSourceGalaxies.push_back(iterCtsHistory->sourceCluster); - } - - if (rootSourceCharacterBornDate > 0) - { - // initialize the character's born date, if necessary - playerObject->setBornDate(); - - // fix up the character's born date, but only if the "fixup" date is earlier than the current date - int const characterBornDate = playerObject->getBornDate(); - if (rootSourceCharacterBornDate < characterBornDate) - { - playerObject->adjustBornDate(rootSourceCharacterBornDate - characterBornDate); - LOG("CustomerService", ("CharacterTransferRetroactiveHistory: %s, fixing born date from (%d, %s) to (%d, %s)", playerObject->getAccountDescription().c_str(), characterBornDate, CalendarTime::getCharacerBirthDateString(characterBornDate).c_str(), rootSourceCharacterBornDate, CalendarTime::getCharacerBirthDateString(rootSourceCharacterBornDate).c_str())); - - // send mail to player notifying of born date change - Chat::sendPersistentMessage("system", Unicode::wideToNarrow(Unicode::toLower(player.getAssignedObjectFirstName())), Unicode::narrowToWide("Birth Date Fixup"), Unicode::narrowToWide(FormattedString<1024>().sprintf("This character's birth date has been adjusted from %s to %s.", CalendarTime::getCharacerBirthDateString(characterBornDate).c_str(), CalendarTime::getCharacerBirthDateString(rootSourceCharacterBornDate).c_str())), Unicode::emptyString); - } - } - - // grant CTS titles for transfers that occurred between different galaxies - if (!ctsSourceGalaxies.empty()) - { - ctsSourceGalaxies.push_back(GameServer::getInstance().getClusterName()); - for (size_t i = 0, stopIndex = (ctsSourceGalaxies.size() - 2); i <= stopIndex; ++i) - { - if (ctsSourceGalaxies[i] != ctsSourceGalaxies[i+1]) - { - // lower case source cluster name and replace - // - with _ for use to grant CTS title - std::string collectionSlotName = std::string("cts_from_") + Unicode::toLower(ctsSourceGalaxies[i]); - - std::string::size_type pos = collectionSlotName.find('-'); - while (pos != std::string::npos) - { - collectionSlotName.replace(pos, 1, 1, '_'); - pos = collectionSlotName.find('-'); - } - - CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(collectionSlotName); - if (collectionSlot && !playerObject->hasCompletedCollectionSlot(*collectionSlot)) - { - LOG("CustomerService", ("CharacterTransferRetroactiveHistory: %s, granting CTS title %s", playerObject->getAccountDescription().c_str(), collectionSlotName.c_str())); - IGNORE_RETURN(playerObject->modifyCollectionSlotValue(collectionSlotName, 1ll)); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -std::vector > const *> const & GameServer::getRetroactiveCtsHistoryObjvars(NetworkId const & characterId) -{ - static std::vector > const *> returnValue; - returnValue.clear(); - - std::map > const * clusterCtsHistory = NULL; - -#ifdef _DEBUG - std::map > >::const_iterator const iterFindCluster = s_retroactiveCtsHistoryList.find(GameServer::getInstance().getClusterName()); - if (iterFindCluster != s_retroactiveCtsHistoryList.end()) - clusterCtsHistory = &(iterFindCluster->second); -#else - clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; -#endif - - if (!clusterCtsHistory) - return returnValue; - - std::map >::const_iterator const iterFindCharacter = clusterCtsHistory->find(characterId); - if (iterFindCharacter == clusterCtsHistory->end()) - return returnValue; - - int numberOfNonEmptyVectorsReturned = 0; - for (std::vector::const_reverse_iterator iterCtsHistory = iterFindCharacter->second.rbegin(); iterCtsHistory != iterFindCharacter->second.rend(); ++iterCtsHistory) - { - returnValue.push_back(&(iterCtsHistory->sourceCharacterRetroactiveObjvars)); - - if (!iterCtsHistory->sourceCharacterRetroactiveObjvars.empty()) - { - ++numberOfNonEmptyVectorsReturned; - } - } - - if (numberOfNonEmptyVectorsReturned == 0) - returnValue.clear(); - - return returnValue; -} - -// ---------------------------------------------------------------------- - -time_t GameServer::getRetroactivePlayerCityCreationTime(std::string const & clusterName, int cityId) -{ - std::map const * clusterPlayerCityCreationTimeHistory = NULL; - -#ifdef _DEBUG - std::map >::const_iterator const iterFindCluster = s_retroactivePlayerCityCreationTime.find(clusterName); - if (iterFindCluster != s_retroactivePlayerCityCreationTime.end()) - clusterPlayerCityCreationTimeHistory = &(iterFindCluster->second); -#else - if (clusterName == GameServer::getInstance().getClusterName()) - clusterPlayerCityCreationTimeHistory = &s_retroactivePlayerCityCreationTimeThisCluster; -#endif - - if (!clusterPlayerCityCreationTimeHistory) - return -1; - - std::map::const_iterator const iterFindCity = clusterPlayerCityCreationTimeHistory->find(cityId); - if (iterFindCity != clusterPlayerCityCreationTimeHistory->end()) - return iterFindCity->second; - - return -1; -} - -// ---------------------------------------------------------------------- - -int GameServer::getServerSpawnLimit() -{ - static int serverSpawnLimit = -1; - - if (GameServer::getInstance().getPreloadAreaId() == 0) - { - return ConfigServerGame::getServerSpawnLimit(); - } - - if (serverSpawnLimit == -1) - { - serverSpawnLimit = ConfigServerGame::getServerSpawnLimit(); - - // see if there's a spawn limit set for this particular game server - char key[128]; - snprintf(key, sizeof(key)-1, "serverSpawnLimit_%s.%lu", ServerWorld::getSceneId().c_str(), GameServer::getInstance().getPreloadAreaId()); - key[sizeof(key)-1] = '\0'; - - if (getConfigSetting("GameServer", key, serverSpawnLimit)) - return serverSpawnLimit; - - // see if there's a spawn limit set for this particular planet - snprintf(key, sizeof(key)-1, "serverSpawnLimit_%s", ServerWorld::getSceneId().c_str()); - key[sizeof(key)-1] = '\0'; - - if (getConfigSetting("GameServer", key, serverSpawnLimit)) - return serverSpawnLimit; - - // use default server spawn limit - serverSpawnLimit = ConfigServerGame::getServerSpawnLimit(); - } - - return serverSpawnLimit; -} - -// ---------------------------------------------------------------------- - -#ifdef _DEBUG -void GameServer::setExtraDelayPerFrameMs(int ms) // to emulate long loop time -{ - s_extraDelayPerFrameMs = ms; -} -#endif - -// ====================================================================== +// GameServer.cpp +// copyright 2000 Verant Interactive +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "serverGame/FirstServerGame.h" +#include "serverGame/GameServer.h" + +#include "serverGame/AiMovementBase.h" +#include "serverGame/AiCreatureController.h" +#include "serverGame/AiShipController.h" +#include "serverGame/AttribModNameManager.h" +#include "serverGame/AuthTransferTracker.h" +#include "serverGame/BiographyManager.h" +#include "serverGame/BuildingObject.h" +#include "serverGame/CellObject.h" +#include "serverGame/CentralConnection.h" +#include "serverGame/CharacterMatchManager.h" +#include "serverGame/Chat.h" +#include "serverGame/ChatServerConnection.h" +#include "serverGame/CitizenInfo.h" +#include "serverGame/CityInfo.h" +#include "serverGame/CityInterface.h" +#include "serverGame/CityObject.h" +#include "serverGame/Client.h" +#include "serverGame/ClusterWideDataClient.h" +#include "serverGame/CombatTracker.h" +#include "serverGame/CommandCppFuncs.h" +#include "serverGame/CommoditiesMarket.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ConnectionServerConnection.h" +#include "serverGame/ConsoleManager.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/CustomerServiceServerConnection.h" +#include "serverGame/DatabaseProcessConnection.h" +#include "serverGame/GameServerMetricsData.h" +#include "serverGame/GuildInterface.h" +#include "serverGame/GuildObject.h" +#include "serverGame/HarvesterInstallationObject.h" +#include "serverGame/LogoutTracker.h" +#include "serverGame/ManufactureInstallationObject.h" +#include "serverGame/MessageToQueue.h" +#include "serverGame/MissileManager.h" +#include "serverGame/NameManager.h" +#include "serverGame/NewbieTutorial.h" +#include "serverGame/NonCriticalTaskQueue.h" +#include "serverGame/ObjectIdManager.h" +#include "serverGame/ObjectTracker.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/PlanetServerConnection.h" +#include "serverGame/PlayerCreationManagerServer.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/PlayerSanityChecker.h" +#include "serverGame/PlayerShipController.h" +#include "serverGame/PositionUpdateTracker.h" +#include "serverGame/PurgeManager.h" +#include "serverGame/Region.h" +#include "serverGame/RegionMaster.h" +#include "serverGame/ResourceTypeObject.h" +#include "serverGame/ServerAsteroidManager.h" +#include "serverGame/SceneGlobalData.h" +#include "serverGame/ServerBuildoutManager.h" +#include "serverGame/ServerCommandPermissionManager.h" +#include "serverGame/ServerCommandTable.h" +#include "serverGame/ServerController.h" +#include "serverGame/ServerCreatureObjectTemplate.h" +#include "serverGame/ServerImageDesignerManager.h" +#include "serverGame/ServerMessageForwarding.h" +#include "serverGame/ServerObjectTerrainModificationNotification.h" +#include "serverGame/ServerUIManager.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/ShipAiReactionManager.h" +#include "serverGame/ShipClientUpdateTracker.h" +#include "serverGame/ShipObject.h" +#include "serverGame/StationPlayersCollectorAPI.h" +#include "serverGame/SurveySystem.h" +#include "serverGame/TangibleObject.h" +#include "serverGame/TaskManagerConnection.h" +#include "serverGame/VeteranRewardManager.h" +#include "serverMetrics/MetricsManager.h" +#include "serverNetworkMessages/AccountFeatureIdRequest.h" +#include "serverNetworkMessages/AccountFeatureIdResponse.h" +#include "serverNetworkMessages/AddCharacterMessage.h" +#include "serverNetworkMessages/AddResourceTypeMessage.h" +#include "serverNetworkMessages/AdjustAccountFeatureIdResponse.h" +#include "serverNetworkMessages/AiMovementMessage.h" +#include "serverNetworkMessages/AiCreatureStateMessage.h" +#include "serverNetworkMessages/AuthTransferClientMessage.h" +#include "serverNetworkMessages/BiographyMessage.h" +#include "serverNetworkMessages/CentralGameServerMessages.h" +#include "serverNetworkMessages/CentralPingMessage.h" +#include "serverNetworkMessages/CharacterNamesMessage.h" +#include "serverNetworkMessages/ChatServerOnline.h" +#include "serverNetworkMessages/ChunkCompleteMessage.h" +#include "serverNetworkMessages/ClaimRewardsReplyMessage.h" +#include "serverNetworkMessages/CreateDynamicRegionCircleMessage.h" +#include "serverNetworkMessages/CreateDynamicRegionRectangleMessage.h" +#include "serverNetworkMessages/CreateDynamicSpawnRegionCircleMessage.h" +#include "serverNetworkMessages/CreateGroupMessage.h" +#include "serverNetworkMessages/CreateObjectMessage.h" +#include "serverNetworkMessages/CreateSyncUiMessage.h" +#include "serverNetworkMessages/EnableNewJediTrackingMessage.h" +#include "serverNetworkMessages/EndBaselinesMessage.h" +#include "serverNetworkMessages/ExcommunicateGameServerMessage.h" +#include "serverNetworkMessages/FactionalSystemMessage.h" +#include "serverNetworkMessages/FailedToLoadObjectMessage.h" +#include "serverNetworkMessages/FeatureIdTransactionResponse.h" +#include "serverNetworkMessages/FirstPlanetGameServerIdMessage.h" +#include "serverNetworkMessages/GameConnectionServerMessages.h" +#include "serverNetworkMessages/GameGameServerMessages.h" +#include "serverNetworkMessages/GameServerConnectAck.h" +#include "serverNetworkMessages/GameServerReadyMessage.h" +#include "serverNetworkMessages/GameServerUniverseLoadedMessage.h" +#include "serverNetworkMessages/GameTaskManagerMessages.h" +#include "serverNetworkMessages/GetMoneyFromOfflineObjectMessage.h" +#include "serverNetworkMessages/LoadContainedObjectMessage.h" +#include "serverNetworkMessages/LoadContentsMessage.h" +#include "serverNetworkMessages/LocateObjectResponseMessage.h" +#include "serverNetworkMessages/LocatePlayerResponseMessage.h" +#include "serverNetworkMessages/LoadObjectMessage.h" +#include "serverNetworkMessages/LoadStructureMessage.h" +#include "serverNetworkMessages/LoadUniverseMessage.h" +#include "serverNetworkMessages/LocateStructureMessage.h" +#include "serverNetworkMessages/LocationResponse.h" +#include "serverNetworkMessages/MessageToAckMessage.h" +#include "serverNetworkMessages/NewClient.h" +#include "serverNetworkMessages/PersistedPlayerMessage.h" +#include "serverNetworkMessages/PlayedTimeAccumMessage.h" +#include "serverNetworkMessages/PopulationListMessage.h" +#include "serverNetworkMessages/PreloadRequestCompleteMessage.h" +#include "serverNetworkMessages/ProfilerOperationMessage.h" +#include "serverNetworkMessages/RandomName.h" +#include "serverNetworkMessages/ReloadAdminTableMessage.h" +#include "serverNetworkMessages/ReloadCommandTableMessage.h" +#include "serverNetworkMessages/ReloadDatatableMessage.h" +#include "serverNetworkMessages/ReloadScriptMessage.h" +#include "serverNetworkMessages/ReloadTemplateMessage.h" +#include "serverNetworkMessages/RenameCharacterMessage.h" +#include "serverNetworkMessages/RetrievedItemLoadMessage.h" +#include "serverNetworkMessages/SceneTransferMessages.h" +#include "serverNetworkMessages/SetAuthoritativeMessage.h" +#include "serverNetworkMessages/SetPlanetServerMessage.h" +#include "serverNetworkMessages/SetUniverseAuthoritativeMessage.h" +#include "serverNetworkMessages/StructuresForPurgeMessage.h" +#include "serverNetworkMessages/SynchronizeScriptVarDeltasMessage.h" +#include "serverNetworkMessages/SynchronizeScriptVarsMessage.h" +#include "serverNetworkMessages/TeleportMessage.h" +#include "serverNetworkMessages/TeleportToMessage.h" +#include "serverNetworkMessages/TransferCharacterData.h" +#include "serverNetworkMessages/TransferCharacterDataArchive.h" +#include "serverNetworkMessages/TransferReplyMoveValidation.h" +#include "serverNetworkMessages/UnloadObjectMessage.h" +#include "serverNetworkMessages/UnloadProxyMessage.h" +#include "serverNetworkMessages/UpdateObjectPositionMessage.h" +#include "serverNetworkMessages/UploadCharacterMessage.h" +#include "serverNetworkMessages/VerifyAndLockName.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptDictionary.h" +#include "serverScript/ScriptParameters.h" +#include "serverUtility/AdminAccountManager.h" +#include "serverUtility/ServerClock.h" +#include "Session/CommonAPI/CommonAPI.h" +#include "sharedCollision/CollisionProperty.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/DebugMonitor.h" +#include "sharedDebug/Profiler.h" +#include "sharedFile/Iff.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedFoundation/Os.h" +#include "sharedGame/AppearanceManager.h" +#include "sharedGame/CombatDataTable.h" +#include "sharedGame/CommandTable.h" +#include "sharedGame/OutOfBandPackager.h" +#include "sharedGame/PlatformFeatureBits.h" +#include "sharedGame/ProsePackage.h" +#include "sharedGame/PvpData.h" +#include "sharedGame/QuestManager.h" +#include "sharedLog/FileLogObserver.h" +#include "sharedLog/Log.h" +#include "sharedMessageDispatch/MessageManager.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedNetwork/Service.h" +#include "sharedNetworkMessages/BaselinesMessage.h" +#include "sharedNetworkMessages/BatchBaselinesMessage.h" +#include "sharedNetworkMessages/ConsoleChannelMessages.h" +#include "sharedNetworkMessages/DeltasMessage.h" +#include "sharedNetworkMessages/FrameEndMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/HyperspaceMessage.h" +#include "sharedNetworkMessages/MessageQueueGenericValueType.h" +#include "sharedNetworkMessages/NameErrors.h" +#include "sharedNetworkMessages/ObjectChannelMessages.h" +#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" +#include "sharedNetworkMessages/SlowDownEffectMessage.h" +#include "sharedNetworkMessages/UpdateContainmentMessage.h" +#include "sharedObject/AlterScheduler.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Container.h" +#include "sharedObject/NetworkController.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectList.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/PortalProperty.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedPathfinding/Pathfinding.h" +#include "sharedSkillSystem/SkillManager.h" +#include "sharedSkillSystem/SkillObject.h" +#include "sharedTerrain/ProceduralTerrainAppearance.h" +#include "sharedTerrain/TerrainObject.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" +#include "swgSharedUtility/SpeciesRestrictions.h" +#include "unicodeArchive/UnicodeArchive.h" + +#include + +//----------------------------------------------------------------------- + +//#undef PROFILE_INDIVIDUAL_MESSAGES +#define PROFILE_INDIVIDUAL_MESSAGES 1 + +#ifdef PROFILE_INDIVIDUAL_MESSAGES + #define MESSAGE_PROFILER_BLOCK(a) PROFILER_AUTO_BLOCK_DEFINE(a) +#else + #define MESSAGE_PROFILER_BLOCK(a) NOP +#endif + +//----------------------------------------------------------------------- + +namespace GameServerNamespace +{ + bool gs_gameServerReady = false; + const float IDLE_CLIENTS_CHECK_TIME_SEC = 30.0f; + ServerCommandPermissionManager * s_permissionManager = 0; + + unsigned long s_frameTime; + uint64 s_totalObjectCreateMessagesReceived; + uint64 s_totalObjectCreateMessagesSent; + bool s_metricsManagerInstalled = false; + uint32 s_lastTaskKeepaliveTime = 0; + +#ifdef _DEBUG + int s_extraDelayPerFrameMs = 0; // to emulate long loop time +#endif + + std::set s_clusterStartupResidenceStructureListResponse; + std::map > s_clusterStartupResidenceStructureListByStructure; + + unsigned long getFrameRateLimit(); + void broadCastHyperspaceOnWarp(ServerObject const * owner); + ShipObject *getAttachedShip(CreatureObject *creature); + + std::map s_pendingLoadRequests; + + struct CtsSourceCharacterInfo + { + time_t transferTime; + std::string sourceCluster; + NetworkId sourceCharacterId; + std::string sourceCharacterName; + int sourceCharacterBornDate; + std::vector > sourceCharacterRetroactiveObjvars; + }; + + // any particular target character may have gone through multiple transfers + // so we want to keep a list (ordered by transfer time) of all the transfers + // the character has gone through + // + // for release build, we only care about transfers into our cluster; + // for debug build, read them all so we can test out the logic to + // make sure it works for all clusters + // + // transfer time, source character info + // target character id + // target cluster + // \/ \/ \/ +#ifdef _DEBUG + std::map > > s_retroactiveCtsHistoryList; +#else + std::map > s_retroactiveCtsHistoryListThisCluster; +#endif + + void loadRetroactiveCtsHistory(); + + // retroactive player city creation time + // + // city creation time + // city id + // cluster + // \/ \/ \/ +#ifdef _DEBUG + std::map > s_retroactivePlayerCityCreationTime; +#else + std::map s_retroactivePlayerCityCreationTimeThisCluster; +#endif + + void loadRetroactivePlayerCityCreationTime(); + + bool getConfigSetting(const char *section, const char *key, int & value) + { + const ConfigFile::Section * sec = ConfigFile::getSection(section); + if (sec == NULL) + return false; + + const ConfigFile::Key * ky = sec->findKey(key); + if (ky == NULL) + return false; + + value = ky->getAsInt(ky->getCount()-1, value); + return true; + } + + const std::string OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER("hasOutstandingRequestSceneTransfer"); + bool checkAndSetOutstandingRequestSceneTransfer(ServerObject & object); + + void handleFactionalSystemMessage(FactionalSystemMessage const & msg); + void handleMessageToPlayersOnPlanet(std::string const & methodName, std::vector const & params, float delay, Vector const & loc, float radius, bool includeDisconnectedPlayers); + void handleMessageLocateStructureByOwnerIdReq(GameServer & gsInstance, uint32 responsePid, bool isGod, NetworkId const & ownerId, NetworkId const & ownerResidenceId, NetworkId const & responseId); + void handleMessageLocateStructureByOwnerIdRsp(NetworkId const & responseId, std::vector const & response); + void handleAdjustAccountFeatureIdResponse(AdjustAccountFeatureIdResponse const & msg); + void handleAccountFeatureIdResponse(AccountFeatureIdResponse const & msg); + + namespace SlotNames + { + static const ConstCharCrcLowerString appearance ("appearance_inventory"); + } + + const char* s_appearanceTemplate = "object/tangible/inventory/appearance_inventory.iff"; + +} + +using namespace GameServerNamespace; + +//---------------------------------------------------------------------- + +GameServer * GameServer::ms_instance = 0; + +//----------------------------------------------------------------------- + +GameServer::GameServer() : +MessageDispatch::Receiver(), +m_done (false), +m_processId (0), +m_preloadAreaId (0), +m_databaseProcessId (0), +m_gameServerPids (), +m_centralService (), +m_centralServerConnection (0), +m_customerServiceServerConnection (0), +m_connectionServerVector (new ConnectionServerVector), +m_planetServerConnection (0), +m_databaseProcessConnection (0), +m_pendingDatabaseProcessConnection (0), +m_taskManagerConnection (), +m_clients (new ClientMap), +m_clientService (), +m_clusterName (), +m_clusterId (0), +m_firstGameServerForPlanet (0), +m_pendingContainedObjects (new PendingContainedObjectsMap), +m_charactersPendingCreation (new CharactersPendingCreationMap), +m_metricsData (0), +m_gameServerReadyObjectIds (false), +m_gameServerReadyDatabaseConnected (false), +m_gameServerReadyPlanetConnected (false), +m_connectionTimeout (false), +m_chatServerConnection (0) +{ + IGNORE_RETURN(SkillManager::getInstance().getRoot ()); + + ObjectIdManager::getInstance(); + // set up central server connection + m_centralService = new CentralServerConnection(ConfigServerGame::getCentralServerAddress(), ConfigServerGame::getCentralServerPort()); + connectToMessage("CentralConnectionOpened"); + connectToMessage("CentralConnectionClosed"); + + //Add connection server messages + connectToMessage("ConnectionServerAddress"); + connectToMessage("ConnectionServerClosed"); + connectToMessage("NewClient"); + + connectToMessage("TaskConnectionClosed"); + + // set up Commodity server connection + connectToMessage("CommoditiesServerConnectionClosed"); + + // application messages + connectToMessage("BaselinesMessage"); + connectToMessage("BatchBaselinesMessage"); + connectToMessage("DeltasMessage"); + connectToMessage("ChunkCompleteMessage"); + connectToMessage("CentralGameServerSetProcessId"); + connectToMessage("GameServerSetupMessage"); + connectToMessage("LoadUniverseMessage"); + connectToMessage("PlanetConnectionClosed"); + connectToMessage("PlanetConnectionOpened"); + connectToMessage("SetPlanetServerMessage"); + connectToMessage("SetUniverseAuthoritativeMessage"); + connectToMessage("CentralCreateCharacter"); + connectToMessage("CreateDynamicSpawnRegionCircle"); + connectToMessage("CreateDynamicRegionCircleMessage"); + connectToMessage("CreateDynamicRegionRectangleMessage"); + connectToMessage("CreateGroupMessage"); + connectToMessage("CreateObjectByCrcMessage"); + connectToMessage("CreateSyncUiMessage"); + connectToMessage("DropClient"); + connectToMessage("EnableNewJediTrackingMessage"); + connectToMessage("EndBaselinesMessage"); + connectToMessage("GameSetProcessId"); + connectToMessage("GameServerConnectAck"); + connectToMessage("LoadObjectMessage"); + connectToMessage("ObjControllerMessage"); + connectToMessage("ProfilerOperationMessage"); + connectToMessage("SetAuthoritativeMessage"); + connectToMessage("SynchronizationMessage"); + connectToMessage("TaskShutdownGameServer"); + connectToMessage("UniverseCompleteMessage"); + connectToMessage("GameServerUniverseLoadedMessage"); + connectToMessage("AddResourceTypeMessage"); + connectToMessage("AddImportedResourceType"); + connectToMessage("PreloadRequestCompleteMessage"); + connectToMessage("UnloadObjectMessage"); + connectToMessage("VerifyNameResponse"); + connectToMessage("SceneTransferMessage"); + connectToMessage("RandomNameRequest"); // from connection server + connectToMessage("VerifyAndLockNameRequest"); // from connection server + + connectToMessage("ChatServerOnline"); + connectToMessage("ChatServerConnectionClosed"); + connectToMessage("TeleportMessage"); + connectToMessage("TeleportToMessage"); + connectToMessage("RetrievedItemLoadMessage"); + connectToMessage("UnloadProxyMessage"); + connectToMessage("BiographyMessage"); + connectToMessage("LoadContainedObjectMessage"); + connectToMessage("LoadContentsMessage"); + connectToMessage("FirstPlanetGameServerIdMessage"); + connectToMessage("ReloadAdminTableMessage"); + connectToMessage("ReloadCommandTableMessage"); + connectToMessage(ReloadDatatableMessage::ms_messageName); + connectToMessage("ReloadScriptMessage"); + connectToMessage("ReloadTemplateMessage"); + connectToMessage("AuthTransferConfirmMessage"); + connectToMessage("ConnectionServerConnectionDestroyed"); + connectToMessage("PersistedPlayerMessage"); + connectToMessage("RenameCharacterMessageEx"); + connectToMessage("PopulationListMessage"); + connectToMessage("UpdateObjectPositionMessage"); + connectToMessage("UpdateContainmentMessage"); + connectToMessage("SynchronizeScriptVarsMessage"); + connectToMessage("SynchronizeScriptVarDeltasMessage"); + connectToMessage("CentralPingMessage"); + connectToMessage("AddGameServer"); + connectToMessage("ExcommunicateGameServerMessage"); + connectToMessage("LocateObject"); + connectToMessage("LocateObjectByTemplateName"); + connectToMessage("LocatePlayerByPartialName"); + connectToMessage("LocateWarden"); + connectToMessage("LocateCreatureByCreatureName"); + connectToMessage("LSBOIReq"); + connectToMessage("LSBOIRsp"); + connectToMessage("LocateStructureMessage"); + connectToMessage("LoadStructureMessage"); + connectToMessage("LocateObjectResponseMessage"); + connectToMessage("LocatePlayerResponseMessage"); + connectToMessage("PlayerSanityCheck"); + connectToMessage("PlayerSanityCheckSuccess"); + connectToMessage("PlayerSanityCheckProxy"); + connectToMessage("PlayerSanityCheckProxyFail"); + connectToMessage("EnablePlayerSanityCheckerMessage"); + connectToMessage("StartSaveReplyMessage"); + connectToMessage("DatabaseConsoleReplyMessage"); + connectToMessage("FindAuthObject"); + connectToMessage("CharacterNamesMessage"); + connectToMessage("DownloadCharacterMessage"); + connectToMessage("UploadCharacterMessage"); + connectToMessage("LocationResponse"); + connectToMessage("ReleaseCharacterNameByIdMessage"); + connectToMessage("AddAttribModName"); + connectToMessage("AddAttribModNamesList"); + connectToMessage("CustomerServiceServerGameServerServiceAddress"); + connectToMessage("AiCreatureStateMessage"); + connectToMessage("UnloadPersistedCharacter"); + connectToMessage("AboutToLoadCharacterFromDB"); + connectToMessage("AuthTransferClientMessage"); + connectToMessage("ClearTheaterMessage"); + connectToMessage("SetTheaterMessage"); + connectToMessage("PageChangeAuthority"); + connectToMessage("ManualDepleteResourceMessage"); + connectToMessage("GetMoneyFromOfflineObjectMessage"); + connectToMessage("ClaimRewardsReplyMessage"); + connectToMessage("SetOverrideAccountAgeMessage"); + connectToMessage("StructuresForPurgeMessage"); + connectToMessage(SlowDownEffectMessage::MessageType); + connectToMessage("PlayedTimeAccumMessage"); + connectToMessage("RequestLoadAckMessage"); + connectToMessage("FactionalSystemMessage"); + connectToMessage("MessageToPlayersOnPlanet"); + connectToMessage("ReportSystemClockTime"); + connectToMessage("ReportSystemClockTimeResponse"); + connectToMessage("ReportPlanetaryTime"); + connectToMessage("ReportPlanetaryTimeResponse"); + connectToMessage("ClusterStartComplete"); + connectToMessage("CSRSLReq"); + connectToMessage("CSRSLRsp"); + connectToMessage("PopStatReq"); + connectToMessage("GcwScoreStatReq"); + connectToMessage("GcwScoreStatRaw"); + connectToMessage("GcwScoreStatPct"); + connectToMessage("LLTStatReq"); + connectToMessage("LfgStatReq"); + connectToMessage("ClusterId"); + connectToMessage("OccupyUnlockedSlotRsp"); + connectToMessage("VacateUnlockedSlotRsp"); + connectToMessage("SwapUnlockedSlotRsp"); + connectToMessage("AdjustAccountFeatureIdResponse"); + connectToMessage("AccountFeatureIdResponse"); + connectToMessage("FeatureIdTransactionResponse"); + connectToMessage("TransferReplyMoveValidation"); + connectToMessage("TransferReplyNameValidation"); + + // Cluster wide data client + ClusterWideDataClient::install(); + ClusterWideDataClient::registerMessage(*this); + + m_taskManagerConnection = new TaskManagerConnection("127.0.0.1", ConfigServerGame::getTaskManagerPort()); +} + +//----------------------------------------------------------------------- + +GameServer::~GameServer() +{ + m_chatServerConnection = 0; + delete m_clients; + m_clients = 0; + delete m_connectionServerVector; + m_connectionServerVector = 0; + + delete m_pendingContainedObjects; + m_pendingContainedObjects = 0; + delete m_charactersPendingCreation; + m_charactersPendingCreation = 0; +} + +//---------------------------------------------------------------------- + +void GameServer::install () +{ + DEBUG_FATAL (ms_instance, ("already installed")); + ms_instance = new GameServer; +} + +//---------------------------------------------------------------------- + +void GameServer::remove () +{ + // ok to remove an uninstalled GameServer singleton. + delete ms_instance; + ms_instance = 0; +} + +//----------------------------------------------------------------------- + +uint64 GameServer::getTotalObjectCreatesReceived() // static +{ + return s_totalObjectCreateMessagesReceived; +} + +//----------------------------------------------------------------------- + +uint64 GameServer::getTotalObjectCreatesSent() // static + { + return s_totalObjectCreateMessagesSent; +} + +//----------------------------------------------------------------------- + +void GameServer::incrementTotalObjectCreatesSent() // static + { + ++s_totalObjectCreateMessagesSent; +} + +//----------------------------------------------------------------------- +void GameServer::reportClusterStartupResidenceStructure(int cityId, const NetworkId & structureId, const NetworkId & ownerId) // static +{ + s_clusterStartupResidenceStructureListByStructure[structureId] = std::make_pair(cityId, ownerId); +} + +//----------------------------------------------------------------------- + +void GameServer::reportBuildingObjectDestroyed(const NetworkId & structureId) +{ + if (!s_clusterStartupResidenceStructureListByStructure.empty()) + IGNORE_RETURN(s_clusterStartupResidenceStructureListByStructure.erase(structureId)); +} + +//----------------------------------------------------------------------- + +/** + * Establish a connection to a game server (if not already connected). + */ +void GameServer::connectToDatabaseProcess(std::string const &address, uint16 port, uint32 pid) +{ + FATAL(m_pendingDatabaseProcessConnection, ("Tried to connect to database process with connection still pending?")); + FATAL(m_databaseProcessConnection, ("Tried to connect to database process when alrady connected?")); + + m_pendingDatabaseProcessConnection = new DatabaseProcessConnection(address, port, pid); + + LOG("GameGameConnect", ("Game Server %lu is connecting to database process, pid %lu, addr %s port %d", m_processId, pid, address.c_str(), static_cast(port))); +} + +//------------------------------------------------------------------- + +/** + * Create a proxy for an object we own on another server. + * + * If address is specified, it will establish a connection and queue + * the task to be done later, if necessary. Otherwise, it will FATAL + * if not connected. + * @see GameServerConnectionHandler::addGameServer + */ + +void GameServer::createRemoteProxy(uint32 remoteProcessId, ServerObject *object) +{ + + WARNING_STRICT_FATAL(!object, ("Told to create an object on %d we know nothing about!\n", remoteProcessId)); + NetworkId objectId = object->getNetworkId(); + + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(),("createRemoteProxy(%lu,%s)\n",remoteProcessId, objectId.getValueString().c_str())); + + if (remoteProcessId == 0) + { + DEBUG_FATAL(true, ("Invalid ProcessId in GameServer::CreateRemoteProxy()\n")); + return; + } + + + //If we have the object in the world and we are auth for it, create it. + if (object) + { + if (object->isAuthoritative()) + { + if(GameServer::getProcessId() != remoteProcessId) + { + object->addServerToProxyList(remoteProcessId); + } + } + else + { + //Can't create an object if we're not authoritative. + // Forward the message to the auth server. + + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(),("Forwarding proxy request for %s to authoritative server\n",objectId.getValueString().c_str())); + + ServerMessageForwarding::begin(object->getAuthServerProcessId()); + + LoadObjectMessage const loadObjectMessage(objectId, remoteProcessId); + ServerMessageForwarding::send(loadObjectMessage); + + ServerMessageForwarding::end(); + } + } +} + +// ---------------------------------------------------------------------- + +void GameServer::createProxyOnAllServers(ServerObject *object) +{ + for (std::vector::const_iterator i = m_gameServerPids.begin(); i != m_gameServerPids.end(); ++i) + createRemoteProxy(*i, object); +} + +// ---------------------------------------------------------------------- + +void GameServer::debugIO (void) +{ +#ifdef _DEBUG +// DebugMonitor::flushOutput(); +// DebugMonitor::clearScreen(); + DebugFlags::callReportRoutines(); +#endif +} + +//----------------------------------------------------------------------- + +void GameServer::deliverMessageToClientObject(const NetworkId &oid, const Archive::ByteStream & source) +{ + const ClientMap::iterator i = m_clients->find(oid); + if(i != m_clients->end()) + { + Archive::ReadIterator ri = source.begin(); + GameNetworkMessage const msg(ri); + (*i).second->receiveClientMessage(msg); + } + else + { + DEBUG_REPORT_LOG(true, ("Received message for unknown client %s\n", oid.getValueString().c_str())); + } +} + +//----------------------------------------------------------------------- + +void GameServer::dropClient(const NetworkId& oid) +{ + dropClient(oid, false); +} +//----------------------------------------------------------------------- + +void GameServer::dropClient(const NetworkId& oid, const bool immediate) +{ + DEBUG_REPORT_LOG(true,("Dropping client %s\n",oid.getValueString().c_str())); + + const ClientMap::iterator i = m_clients->find(oid); + if(i != m_clients->end()) + { + Client* client = const_cast((*i).second); + m_clients->erase(i); + client->selfDestruct(immediate); + } +} + +//----------------------------------------------------------------------- + +unsigned long GameServer::getFrameTime() const +{ + return s_frameTime; +} + +//----------------------------------------------------------------------- + +Client * GameServer::getClient(const NetworkId& networkId) +{ + ClientMap::iterator i = m_clients->find(networkId); + if (i != m_clients->end()) + { + return i->second; + } + return NULL; +} + +//----------------------------------------------------------------------- +const Service * GameServer::getClientService() const +{ + return m_clientService; +} + +// ---------------------------------------------------------------------- + +bool GameServer::isGameServerConnected(uint32 processId) const +{ + return std::binary_search(m_gameServerPids.begin(), m_gameServerPids.end(), processId); +} + +//----------------------------------------------------------------------- + +ConnectionServerConnection * GameServer::getConnectionServerConnection(const std::string & connectionServerIp, const uint16 connectionServerPort) +{ + ConnectionServerConnection * result = 0; + + if (m_connectionServerVector) + { + for (ConnectionServerVector::iterator i = m_connectionServerVector->begin(); i != m_connectionServerVector->end(); ++i) + { + if (((*i)->getRemoteAddress() == connectionServerIp) && ((*i)->getRemotePort() == connectionServerPort)) + { + result = *i; + break; + } + } + } + + return result; +} + +//----------------------------------------------------------------------- + +void GameServer::initialize() +{ + //@todo, this function seems wrong to me. This should happen in install or in the constructor. + //Right now this gets called at the beginning of ::run + + ServerCommandTable::load(); + loadTerrain (); + + ShipObject::install(); + AiShipController::install(); + AICreatureController::install(); + ShipAiReactionManager::install(); + PlayerShipController::install(); + MissileManager::install(); + ShipClientUpdateTracker::install(); + ServerAsteroidManager::install(); + QuestManager::install(); + VeteranRewardManager::install(); + SceneGlobalData::install(); + StationPlayersCollectorAPI::install(); + ServerObject::install(); + TangibleObject::install(); + Client::install(); + + m_metricsData = new GameServerMetricsData; + s_permissionManager = new ServerCommandPermissionManager(); +} + +// ---------------------------------------------------------------------- + +void GameServer::loadTerrain () +{ + if (TerrainObject::getInstance ()) + { + TerrainObject::getInstance ()->removeFromWorld (); + delete TerrainObject::getInstance (); + } + + char const * const terrainFileName = ConfigServerGame::getGroundScene(); + FATAL(!terrainFileName || !TreeFile::exists(terrainFileName), ("%s is not a valid terrain file", terrainFileName)); + + TerrainObject * const terrainObject = new TerrainObject(ServerWorld::getTerrainObjectNotification()); + terrainObject->setDebugName("terrain"); + Appearance * const appearance = AppearanceTemplateList::createAppearance(terrainFileName); + terrainObject->setAppearance(appearance); + + ProceduralTerrainAppearance * const proceduralTerrainAppearance = dynamic_cast(appearance); + if (proceduralTerrainAppearance) + ServerObjectTerrainModificationNotification::setTerrainAppearance(proceduralTerrainAppearance); + + terrainObject->addToWorld(); +} + +// ---------------------------------------------------------------------- + +void GameServer::shutdown() +{ + delete s_permissionManager; + s_permissionManager = 0; + if(s_metricsManagerInstalled) + MetricsManager::remove(); + delete m_metricsData; + m_metricsData = 0; + + m_centralService = 0; + m_planetServerConnection = 0; + + if (m_customerServiceServerConnection != NULL) + { + m_customerServiceServerConnection->disconnect(); + } +} + +// ---------------------------------------------------------------------- + +void GameServer::receiveMessage(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) +{ + static Archive::ReadIterator ri; + static Archive::ByteStream bs; + + PROFILER_AUTO_BLOCK_DEFINE("GameServer::receiveMessage"); + + // advise the TaskManager that the gameserver isn't dead in cases where + // the server is handling a LOT of LoadObjectMessages and creating + // proxies. + if(getInstance().m_taskManagerConnection) + { + if(Clock::timeMs() - s_lastTaskKeepaliveTime > 60000) + { + static const GenericValueTypeMessage gameServerTaskManagerKeepAlive("GameServerTaskManagerKeepAlive", Os::getProcessId()); + getInstance().m_taskManagerConnection->send(gameServerTaskManagerKeepAlive, true); + s_lastTaskKeepaliveTime = Clock::timeMs(); + } + } + + ServerConnection * const serverConnection = const_cast(dynamic_cast(&source)); + + if(message.isType("CentralConnectionOpened")) + { + MESSAGE_PROFILER_BLOCK("CentralConnectionOpened"); + if (!m_centralServerConnection) + m_centralServerConnection = const_cast(static_cast(&source)); + } + else if (message.isType("CustomerServiceServerGameServerServiceAddress")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const address(ri); + + DEBUG_REPORT_LOG(true, ("GameServer: Creating customer service server connection @ (%s:%d)\n", address.getValue().first.c_str(), address.getValue().second)); + + if (m_customerServiceServerConnection != NULL) + { + m_customerServiceServerConnection->disconnect(); + } + + m_customerServiceServerConnection = new CustomerServiceServerConnection(address.getValue().first, address.getValue().second); + } + else if(message.isType("BaselinesMessage")) + { + MESSAGE_PROFILER_BLOCK("BaselinesMessage"); + ri = static_cast(message).getByteStream().begin(); + BaselinesMessage const m(ri); + ServerObject *so = ServerWorld::findUninitializedObjectByNetworkId(m.getTarget()); + if (so) + { + so->applyBaselines(m); + } + else + { + // find any object + so = safe_cast(NetworkIdManager::getObjectById(m.getTarget())); + if (so) + { + DEBUG_WARNING(true, ("Applied baselines on object %s which is already initialized.", m.getTarget().getValueString().c_str())); + so->applyBaselines(m); + } + else + { + DEBUG_WARNING(true, ("Got baselines on object %s which could not be found.", m.getTarget().getValueString().c_str())); + } + } + } + else if(message.isType("BatchBaselinesMessage")) + { + MESSAGE_PROFILER_BLOCK("BaselinesMessage"); + ri = static_cast(message).getByteStream().begin(); + BatchBaselinesMessage const m(ri); + + std::vector const & baselines = m.getData(); + + ServerObject * lastObject = NULL; + + for (std::vector::const_iterator i=baselines.begin(); i!=baselines.end(); ++i) + { + // There's a good chance the baselines for an object will come together, so remember the previous object + // and don't look it up again if the network id hasn't changed. + if (!lastObject || lastObject->getNetworkId() != i->m_networkId) + { + lastObject = ServerWorld::findUninitializedObjectByNetworkId(i->m_networkId); + + if (!lastObject) + { + lastObject = safe_cast(NetworkIdManager::getObjectById(i->m_networkId)); + if (lastObject) + { + WARNING(true, ("Applied baselines on object %s which is already initialized.", i->m_networkId.getValueString().c_str())); + + } + else + { + WARNING(true, ("Got baselines on object %s which could not be found.", i->m_networkId.getValueString().c_str())); + } + } + } + if (lastObject) + { + lastObject->applyBaselines(i->m_packageId, i->m_package); + } + } + } + else if(message.isType("DeltasMessage")) + { + MESSAGE_PROFILER_BLOCK("DeltasMessage"); + ri = static_cast(message).getByteStream().begin(); + DeltasMessage const m(ri); + ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(m.getTarget())); + if (so) + so->applyDeltas(m); + else + DEBUG_WARNING(true, ("Got DeltasMessage on object %s, which could not be found.", m.getTarget().getValueString().c_str())); + } + + else if(message.isType("ChunkCompleteMessage")) + { + MESSAGE_PROFILER_BLOCK("ChunkCompleteMessage"); + ri = static_cast(message).getByteStream().begin(); + ChunkCompleteMessage const m(ri); + GameServer::getInstance().sendToPlanetServer(m); + + std::vector > const & chunks = m.getChunks(); + for (std::vector >::const_iterator i=chunks.begin(); i!=chunks.end(); ++i) + ServerBuildoutManager::onChunkComplete(i->first, i->second); + } + + else if(message.isType("CentralConnectionClosed")) + { + MESSAGE_PROFILER_BLOCK("CentralConnectionClosed"); + // @ todo : shutdown gracefully + DEBUG_REPORT_LOG(true, ("The connection to the central server has been closed\n")); + setDone("CentralConnectionClosed : %s", serverConnection->getDisconnectReason().c_str()); + m_centralServerConnection = 0; + } + else if(message.isType("TaskConnectionOpened")) + { + MESSAGE_PROFILER_BLOCK("TaskConnectionOpened"); + DEBUG_REPORT_LOG(true, ("The connection with the task manager has been established\n")); + } + else if(message.isType("TaskConnectionClosed")) + { + MESSAGE_PROFILER_BLOCK("TaskConnectionClosed"); + DEBUG_REPORT_LOG(true, ("The connection to the task manager has closed\n")); + m_taskManagerConnection = 0; + } + else if (message.isType("AddGameServer")) + { + MESSAGE_PROFILER_BLOCK("AddGameServer"); + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const addGameServerMessage(ri); + + uint32 const pid = addGameServerMessage.getValue(); + + DEBUG_REPORT_LOG(true, ("Received AddGameServer for server %lu.\n", pid)); + + FATAL(std::find(m_gameServerPids.begin(), m_gameServerPids.end(), pid) != m_gameServerPids.end(), ("Got AddGameServer for server %lu which we thought was already running?", pid)); + + m_gameServerPids.push_back(pid); + std::sort(m_gameServerPids.begin(), m_gameServerPids.end()); + } + else if (message.isType("ExcommunicateGameServerMessage")) + { + MESSAGE_PROFILER_BLOCK("ExcommunicateGameServerMessage"); + ri = static_cast(message).getByteStream().begin(); + ExcommunicateGameServerMessage msg(ri); + + uint32 const pid = msg.getServerId(); + + DEBUG_REPORT_LOG(true, ("Received ExcommunicateGameServer for server %lu.\n", pid)); + LOG("GameGameConnect", ("Server %lu was told that server %lu has gone away by Central", getProcessId(), pid)); + + FATAL(pid == getProcessId(), ("Crashing because Central told us to (probably indicates we weren't responding to pings)")); + + std::vector::iterator i = std::find(m_gameServerPids.begin(), m_gameServerPids.end(), pid); + if (i != m_gameServerPids.end()) + { + m_gameServerPids.erase(i); + + MessageToQueue::getInstance().onGameServerDisconnect(pid); + ServerUniverse::getInstance().onServerConnectionClosed(pid); + AuthTransferTracker::handleGameServerDisconnect(pid); + } + } + else if(message.isType("CommoditiesServerConnectionClosed")) + { + DEBUG_REPORT_LOG(true, ("CommoditiesServer connection closed\n")); + CommoditiesMarket::closeCommoditiesServerConnection(); + } + else if (message.isType("ConnectionServerAddress")) + { + MESSAGE_PROFILER_BLOCK("ConnectionServerAddress"); + // Central is telling us about a new connection server. + ri = static_cast(message).getByteStream().begin(); + ConnectionServerAddress const msg(ri); + ConnectionServerConnection * const newConn = new ConnectionServerConnection(msg.getGameServiceAddress(), msg.getGameServicePort()); + m_connectionServerVector->push_back(newConn); + } + else if (message.isType("ConnectionServerConnectionClosed") || message.isType("ConnectionServerConnectionDestroyed")) + { + MESSAGE_PROFILER_BLOCK("ConnectionServerConnectionClosed"); + ConnectionServerConnection const * const c = dynamic_cast(&source); + ConnectionServerVector::iterator i = std::find(m_connectionServerVector->begin(), m_connectionServerVector->end(), c); + if (i != m_connectionServerVector->end()) + { + m_connectionServerVector->erase(i); + } + } + else if(message.isType("NewClient")) + { + MESSAGE_PROFILER_BLOCK("NewClient"); + static std::string const loginTrace("TRACE_LOGIN"); + ri = static_cast(message).getByteStream().begin(); + NewClient const msg(ri); + LOG(loginTrace, ("NewClient(%s)", msg.getNetworkId().getValueString().c_str())); + + //@todo make sure this holds up with non players (like vehicles) + //because right not, we construct a new client object for EACH object + //even ones that could be controlled by the same client. + //Also is it possible to receive this message for an object we already control? + + if (m_clients->find(msg.getNetworkId()) != m_clients->end()) + { + // inconsistant state, drop the client + LOG(loginTrace, ("NewClient(%s) : Error! Getting a NewClient message for a client that already exists", msg.getNetworkId().getValueString().c_str())); + + KickPlayer const kickMessage(msg.getNetworkId(), "Duplicate Client"); + sendToConnectionServers(kickMessage); + dropClient(msg.getNetworkId()); + return; + } + + // don't allow login if the character is in the middle of CTS or has been successfully CTS(ed) + ServerObject * const obj = ServerWorld::findObjectByNetworkId(msg.getNetworkId()); + if (obj) + { + bool kickRequested = false; + + DynamicVariableList const & objVars = obj->getObjVars(); + int timeOut; + if (objVars.getItem("disableLoginCtsInProgress", timeOut)) + { + if (timeOut > static_cast(ServerClock::getInstance().getGameTimeSeconds())) + { + MessageToQueue::getInstance().sendMessageToC(obj->getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); + kickRequested = true; + } + else + { + obj->removeObjVarItem("disableLoginCtsInProgress"); + } + } + + int transferredTime; + if (!kickRequested && objVars.getItem("disableLoginCtsCompleted", transferredTime) && !msg.getUsingAdminLogin()) + { + MessageToQueue::getInstance().sendMessageToC(obj->getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); + kickRequested = true; + } + } + + LOG(loginTrace, ("NewClient(%s) : A new client is being created from connection server", msg.getNetworkId().getValueString().c_str())); + std::set const observedObjectSet(msg.getObservedObjects().begin(), msg.getObservedObjects().end()); + Client * const c = new Client( + const_cast(static_cast(source)), + msg.getNetworkId(), + msg.getAccountName(), + msg.getIpAddress(), + msg.getIsSecure(), + msg.getIsSkipLoadScreen(), + msg.getStationId(), + observedObjectSet, + msg.getGameFeatures(), + msg.getSubscriptionFeatures(), + Client::AccountFeatureIdList(), + msg.getEntitlementTotalTime(), + msg.getEntitlementEntitledTime(), + msg.getEntitlementTotalTimeSinceLastLogin(), + msg.getEntitlementEntitledTimeSinceLastLogin(), + msg.getBuddyPoints(), + msg.getConsumedRewardEvents(), + msg.getClaimedRewardItems(), + msg.getUsingAdminLogin(), + CombatDataTable::CSFT_All, + 128, + 90, + false, + false, + msg.getSendToStarport() ); + + ClientMap::iterator f = m_clients->find(msg.getNetworkId()); + + if(f != m_clients->end()) + m_clients->erase(msg.getNetworkId()); + + m_clients->insert(std::make_pair(msg.getNetworkId(), c)); + + if (!msg.getUsingAdminLogin()) + { + AccountFeatureIdRequest const req(NetworkId::cms_invalid, GameServer::getInstance().getProcessId(), msg.getNetworkId(), static_cast(msg.getStationId()), PlatformGameCode::SWG, AccountFeatureIdRequest::RR_Reload); + c->sendToConnectionServer(req); + } + } + else if(message.isType("AuthTransferClientMessage")) + { + MESSAGE_PROFILER_BLOCK("AuthTransferClientMessage"); + static const std::string loginTrace("TRACE_LOGIN"); + ri = static_cast(message).getByteStream().begin(); + AuthTransferClientMessage const msg(ri); + LOG(loginTrace, ("AuthTransferClientMessage(%s)", msg.getNetworkId().getValueString().c_str())); + + //@todo make sure this holds up with non players (like vehicles) + //because right not, we construct a new client object for EACH object + //even ones that could be controlled by the same client. + //Also is it possible to receive this message for an object we already control? + + if (m_clients->find(msg.getNetworkId()) != m_clients->end()) + { + // inconsistant state, drop the client + LOG(loginTrace, ("AuthTransferClientMessage(%s) : Error! Getting a AuthTransferClientMessage message for a client that already exists", msg.getNetworkId().getValueString().c_str())); + KickPlayer const kickMessage(msg.getNetworkId(), "Duplicate Client"); + sendToConnectionServers(kickMessage); + dropClient(msg.getNetworkId()); + return; + } + + // locate the connection server for the client + ConnectionServerConnection * const connectionServer = getConnectionServerConnection(msg.getConnectionServerIp(), msg.getConnectionServerPort()); + + if (!connectionServer) + { + // inconsistant state, drop the client + LOG(loginTrace, ("AuthTransferClientMessage(%s) : Error! Getting a AuthTransferClientMessage message for a client but could not locate connection server (%s:%hu)", msg.getNetworkId().getValueString().c_str(), msg.getConnectionServerIp().c_str(), msg.getConnectionServerPort())); + KickPlayer const kickMessage(msg.getNetworkId(), "Invalid Connection Server"); + sendToConnectionServers(kickMessage); + dropClient(msg.getNetworkId()); + return; + } + + LOG(loginTrace, ("AuthTransferClientMessage(%s) : A new client is being created from game server %lu", msg.getNetworkId().getValueString().c_str(), msg.getSourceServerPid())); + + std::set observedObjectSet(msg.getObservedObjects().begin(), msg.getObservedObjects().end()); + Client * c = new Client(*connectionServer, msg.getNetworkId(), msg.getAccount(), msg.getIpAddress(), msg.getSecure(), msg.getSkipLoadScreen(), msg.getStationId(), observedObjectSet, msg.getGameFeatures(), msg.getSubscriptionFeatures(), msg.getAccountFeatureIds(), msg.getEntitlementTotalTime(), msg.getEntitlementEntitledTime(), msg.getEntitlementTotalTimeSinceLastLogin(), msg.getEntitlementEntitledTimeSinceLastLogin(), msg.getBuddyPoints(), msg.getConsumedRewardEvents(), msg.getClaimedRewardItems(), msg.getUsingAdminLogin(), static_cast(msg.getCombatSpamFilter()), msg.getCombatSpamRangeSquaredFilter(), msg.getFurnitureRotationDegree(), msg.getHasUnoccupiedJediSlot(), msg.getIsJediSlotCharacter()); + ClientMap::iterator f = m_clients->find(msg.getNetworkId()); + + if(f != m_clients->end()) + m_clients->erase(msg.getNetworkId()); + + m_clients->insert(std::make_pair(msg.getNetworkId(), c)); + } + + //--- + // application messages + else if(message.isType("CentralGameServerSetProcessId")) + { + MESSAGE_PROFILER_BLOCK("CentralGameServerSetProcessId"); + ri = static_cast(message).getByteStream().begin(); + CentralGameServerSetProcessId const m(ri); + + m_processId = m.getProcessId(); + LOG("GameServer", ("I am process %d", m_processId)); + LOG("GameGameConnect", ("Received CentralGameServerSetProcessId message for pid %d", m_processId)); + DEBUG_FATAL(m.getClockSubtractInterval()==0,("Got 0 for the clock subtract interval (probably indicates we connected to Central too early).\n")); + ServerClock::getInstance().setSubtractInterval(m.getClockSubtractInterval()); + m_clusterName = m.getClusterName(); + + ScriptParams s; + s.addParam(m_clusterName.c_str()); + GameScriptObject::runOneScript("base_class", "setGalaxyName", "s", s); + Chat::createSystemRooms(m_clusterName, ServerWorld::getSceneId()); + + if (!m_centralServerConnection) + { + m_centralServerConnection = const_cast(static_cast(&source)); + DEBUG_FATAL(true, ("m_centralServerConnection should have already been set when receiving CentralConnectionOpened.")); + } + + CentralGameServerConnect const connectMessage( + ConfigServerGame::getSceneID(), + "", + 0, + "", + 0); + + m_centralServerConnection->send(connectMessage, true); + + loadRetroactiveCtsHistory(); + loadRetroactivePlayerCityCreationTime(); + } + else if (message.isType("SetAuthoritativeMessage")) + { + MESSAGE_PROFILER_BLOCK("SetAuthoritativeMessage"); + ri = static_cast(message).getByteStream().begin(); + SetAuthoritativeMessage const t(ri); + + ServerObject * const object = ServerWorld::findObjectByNetworkId(t.getId()); + if (object) + { + bool allowed = true; + + // if the PlanetServer is asking us to transfer authority for an object that + // is contained, reject it, because contained object must have the same authority + // as its container; this can happen in a race condition where authority transfer + // is requested, and while the request is happening, the object moves into a container + if ((&source == m_planetServerConnection) && !t.getSceneChange() && object->isAuthoritative()) + { + Object const * const topmostContainer = ContainerInterface::getTopmostContainer(*object); + + if (topmostContainer != object) + { + WARNING(true, ("Denying authority transfer for (%s) from game server (%lu) to game server (%lu) because it is contained by (%s)", object->getDebugInformation().c_str(), GameServer::getInstance().getProcessId(), t.getProcess(), (topmostContainer ? topmostContainer->getDebugInformation().c_str() : "NULL"))); + + allowed = false; + + GenericValueTypeMessage > const denyMessage( + "DenySetAuthoritativeMessage", + std::make_pair(t.getId(), GameServer::getInstance().getProcessId())); + + sendToPlanetServer(denyMessage); + + object->updatePositionOnPlanetServer(true); + } + } + + if (allowed) + { + if (t.getGoalIsValid()) + object->transferAuthority(t.getProcess(), !t.getSceneChange(), t.getHandlingCrash(), t.getGoalCell(), t.getGoalTransform(), false); + else + object->transferAuthority(t.getProcess(), !t.getSceneChange(), t.getHandlingCrash(), false); + } + } + } + else if(message.isType("LoadObjectMessage")) + { + MESSAGE_PROFILER_BLOCK("LoadObjectMessage"); + + ri = static_cast(message).getByteStream().begin(); + LoadObjectMessage const t(ri); + + ServerObject * const target = ServerWorld::findObjectByNetworkId(t.getId()); + if (target) + createRemoteProxy(t.getProcess(), target); + else + WARNING(true, ("Told to create object %s on %d we know nothing about (received LoadObjectMessage for an object not on this server, PlanetServer is probably confused)", t.getId().getValueString().c_str(), t.getProcess())); + } + else if(message.isType("UnloadObjectMessage")) + { + MESSAGE_PROFILER_BLOCK("UnloadObjectMessage"); + ri = static_cast(message).getByteStream().begin(); + UnloadObjectMessage const t(ri); + + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Got unload object message for %s\n", t.getId().getValueString().c_str())); + + ServerObject * const object = ServerWorld::findObjectByNetworkId(t.getId()); + if (object) + object->unload(); + DEBUG_WARNING(! object, ("Handling unload object message but the object does not exist\n")); + } + else if(message.isType("UnloadProxyMessage")) + { + MESSAGE_PROFILER_BLOCK("UnloadProxyMessage"); + ri = static_cast(message).getByteStream().begin(); + UnloadProxyMessage const unloadProxyMessage(ri); + + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Received UnloadProxyMessage for object %s server %lu\n", unloadProxyMessage.getObjectId().getValueString().c_str(), unloadProxyMessage.getProxyGameServerId())); + + ServerObject * const object = ServerWorld::findObjectByNetworkId(unloadProxyMessage.getObjectId()); + if(object) + { + if(object->isAuthoritative()) + { + if (unloadProxyMessage.getProxyGameServerId() != getProcessId()) + object->removeServerFromProxyList(unloadProxyMessage.getProxyGameServerId()); + else + DEBUG_WARNING(true,("Can't unproxy object %s from this server because this server is authoritative.", unloadProxyMessage.getObjectId().getValueString().c_str())); + } + else + { + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(),("Forwarding UnloadProxyMessage for %s to authoritative server\n", unloadProxyMessage.getObjectId().getValueString().c_str())); + + ServerMessageForwarding::begin(object->getAuthServerProcessId()); + + ServerMessageForwarding::send(unloadProxyMessage); + + ServerMessageForwarding::end(); + } + } + else + DEBUG_WARNING(true, ("Received UnloadProxyMessage for object %s server %lu, but the object could not be found", unloadProxyMessage.getObjectId().getValueString().c_str(), unloadProxyMessage.getProxyGameServerId())); + } + else if(message.isType("ProfilerOperationMessage")) + { + MESSAGE_PROFILER_BLOCK("ProfilerOperationMessage"); + ri = static_cast(message).getByteStream().begin(); + ProfilerOperationMessage const m(ri); + uint32 const processId = m.getProcessId(); + if (processId == 0 || processId == getProcessId()) + Profiler::handleOperation(m.getOperation().c_str()); + } + else if(message.isType("CentralCreateCharacter")) + { + MESSAGE_PROFILER_BLOCK("CentralCreateCharacter"); + ri = static_cast(message).getByteStream().begin(); + handleCreateCharacter(new CentralCreateCharacter(ri)); + } + else if (message.isType("VerifyNameResponse")) + { + MESSAGE_PROFILER_BLOCK("VerifyNameResponse"); + ri = static_cast(message).getByteStream().begin(); + VerifyNameResponse vrn(ri); + + if (isCreatePending(vrn.getStationId())) + { + handleCharacterCreateNameVerification(vrn); + } + else + { + handleVerifyAndLockNameVerification(vrn); + } + } + else if (message.isType("RandomNameRequest")) + { + MESSAGE_PROFILER_BLOCK("RandomNameRequest"); + ri = static_cast(message).getByteStream().begin(); + RandomNameRequest const crnr(ri); + handleNameRequest(crnr); + } + else if (message.isType("VerifyAndLockNameRequest")) + { + MESSAGE_PROFILER_BLOCK("VerifyAndLockNameRequest"); + ri = static_cast(message).getByteStream().begin(); + VerifyAndLockNameRequest const valnr(ri); + handleVerifyAndLockNameRequest(valnr, true, true); + } + else if(message.isType("ObjControllerMessage")) + { + MESSAGE_PROFILER_BLOCK("ObjControllerMessage"); + + ri = static_cast(message).getByteStream().begin(); + ObjControllerMessage c(ri); + + // Could be in baselines so it may be initialized or it may not. Since we don't know we have to use NetworkIdManager to get it. + // The object could also have been destroyed due to an auth transfer, so if it has been and not all servers have confirmed it, + // we need to forward the message. + + bool appended = false; + + ServerObject * const target = safe_cast(NetworkIdManager::getObjectById(c.getNetworkId())); + if (target != NULL) + { + // valid target, get its controller + ServerController * const controller = safe_cast(target->getController()); + if (controller != NULL) + { + uint32 flags = c.getFlags(); + if(flags & GameControllerMessageFlags::DEST_AUTH_SERVER) + { + if(ConfigServerGame::getEnableDebugControllerMessageSpam()) + { + WARNING(! target->isAuthoritative(), ("Received a controller message (%d) destined for the authoritative object (%s:%s) on this server, but the object is NOT authoritative on this server", c.getMessage(), target->getObjectTemplateName(), target->getNetworkId().getValueString().c_str() )); + } + } + flags |= GameControllerMessageFlags::SOURCE_REMOTE_SERVER; + controller->appendMessage(c.getMessage(), c.getValue(), c.getData(), flags); + appended = true; + } + } + else + { + uint32 const destServer = AuthTransferTracker::getAuthTransferDest(c.getNetworkId()); + if (destServer) + { + if(ConfigServerGame::getEnableDebugControllerMessageSpam()) + { + WARNING(true, ("ObjControllerMessage %d for object %s arrived, but the object has transferred authority to server %d", c.getMessage(), c.getNetworkId().getValueString().c_str(), destServer)); + } + + ServerMessageForwarding::begin(destServer); + + ServerMessageForwarding::send(c); + + ServerMessageForwarding::end(); + } + else + DEBUG_WARNING(true, ("Got ObjControllerMessage for object %s, which could not be found.", c.getNetworkId().getValueString().c_str())); + } + + if (!appended) + delete c.getData(); + } + else if(message.isType("EndBaselinesMessage")) + { + MESSAGE_PROFILER_BLOCK("EndBaselinesMessage"); + ri = static_cast(message).getByteStream().begin(); + EndBaselinesMessage const t(ri); + ServerObject * const object = ServerWorld::findUninitializedObjectByNetworkId(t.getId()); + if (object != NULL) + { + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Received EndBaselinesMessage for %s\n", t.getId().getValueString().c_str())); + ServerController * const controller = dynamic_cast(object->getController()); + NOT_NULL(controller); + + bool const fromDbServer = serverConnection && serverConnection == m_databaseProcessConnection; + object->serverObjectEndBaselines(fromDbServer); + } + else + { + ServerObject * const badObject = ServerWorld::findObjectByNetworkId(t.getId()); + WARNING(!badObject, ("Got EndBaeslinesMessage on object (%s) that doesn't exist!", t.getId().getValueString().c_str())); + WARNING(badObject, ("Got EndBaselinesMessage on object (%s : %s) which has already been created and placed in the world!", badObject->getTemplateName(), badObject->getNetworkId().getValueString().c_str())); + } + } + else if(message.isType("TaskShutdownGameServer")) + { + MESSAGE_PROFILER_BLOCK("TaskShutdownGameServer"); + setDone("TaskShutdownGameServer"); + } + else if (message.isType("CreateObjectByCrcMessage")) + { + s_totalObjectCreateMessagesReceived ++; + + MESSAGE_PROFILER_BLOCK("CreateObjectByCrcMessage"); + ri = static_cast(message).getByteStream().begin(); + + NetworkId networkId; + uint32 templateCrc; + bool createAuthoritative; + + CreateObjectByCrcMessage const t(ri); + networkId = t.getId(); + templateCrc = t.getCrc(); + createAuthoritative = t.getCreateAuthoritative(); + + NOT_NULL(serverConnection); + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("CreateObjectMessageByName %s:%s\n", ObjectTemplateList::lookUp(templateCrc).getString(), networkId.getValueString().c_str())); + + Object * const object = NetworkIdManager::getObjectById(networkId); + bool okToCreate = true; + if (object) + { + DEBUG_REPORT_LOG(true, ("WARNING: GOT create message for object %s that already exists!\n", networkId.getValueString().c_str())); + if (object->getKill()) + { + delete object; + okToCreate = true; + } + else + { + WARNING_STRICT_FATAL(true, ("Hey, Got create message for object %s That isn't being deleted!", networkId.getValueString().c_str())); + okToCreate = false; + } + } + + if (okToCreate) + { + //-- Since space is single-server, we will never have proxied space objects and we can ignore the hyperspace variable in the CreateObjectBy*Message message. + ServerWorld::createProxyObject(templateCrc, networkId, createAuthoritative); + } + } + else if(message.isType("CreateSyncUiMessage")) + { + MESSAGE_PROFILER_BLOCK("CreateSyncUiMessage"); + ri = static_cast(message).getByteStream().begin(); + CreateSyncUiMessage const msg(ri); + ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(msg.getId())); + if (so) + so->addSynchronizedUi(msg.getClients()); + } + else if(message.isType("SynchronizeScriptVarsMessage")) + { + MESSAGE_PROFILER_BLOCK("SynchronizeScriptVarsMessage"); + ri = static_cast(message).getByteStream().begin(); + SynchronizeScriptVarsMessage const msg(ri); + ServerObject *so = ServerWorld::findUninitializedObjectByNetworkId(msg.getNetworkId()); + if (so) + { + GameScriptObject const * const script = so->getScriptObject(); + if (script) + script->unpackScriptVars(msg.getData()); + } + else + { + so = safe_cast(NetworkIdManager::getObjectById(msg.getNetworkId())); + DEBUG_WARNING(so, ("Got SynchronizeScriptVarsMessage for initialized object")); + } + } + else if (message.isType("SynchronizeScriptVarDeltasMessage")) + { + MESSAGE_PROFILER_BLOCK("SynchronizeScriptVarDeltasMessage"); + ri = static_cast(message).getByteStream().begin(); + SynchronizeScriptVarDeltasMessage const msg(ri); + ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(msg.getNetworkId())); + if (so) + { + GameScriptObject const * const script = so->getScriptObject(); + if (script) + script->unpackDeltaScriptVars(msg.getData()); + } + else + DEBUG_WARNING(true,("Got SynchronizeScriptVarDeltasMessage on object %s, which could not be found.", msg.getNetworkId().getValueString().c_str())); + } + else if(message.isType("UpdateObjectPositionMessage")) + { + MESSAGE_PROFILER_BLOCK("UpdateObjectPositionMessage"); + ri = static_cast(message).getByteStream().begin(); + UpdateObjectPositionMessage const msg(ri); + ServerObject * const so = ServerWorld::findUninitializedObjectByNetworkId(msg.getNetworkId()); + if (so) + so->applyObjectPositionUpdate(msg); + } + else if(message.isType("UpdateContainmentMessage")) + { + MESSAGE_PROFILER_BLOCK("UpdateContainmentMessage"); + ri = static_cast(message).getByteStream().begin(); + UpdateContainmentMessage const msg(ri); + ServerObject * const so = safe_cast(NetworkIdManager::getObjectById(msg.getNetworkId())); + if (so) + { + // Handle the containment update. + so->updateContainment(msg.getContainerId(), msg.getSlotArrangement()); + } + } + else if(message.isType("DropClient")) + { + MESSAGE_PROFILER_BLOCK("DropClient"); + ri = static_cast(message).getByteStream().begin(); + DropClient const msg(ri); + dropClient(msg.getNetworkId(), msg.getImmediate()); + } + else if(message.isType("SetPlanetServerMessage")) + { + MESSAGE_PROFILER_BLOCK("SetPlanetServerMessage"); + DEBUG_REPORT_LOG(true,("Received SetPlanetServerMessage\n")); + ri = static_cast(message).getByteStream().begin(); + SetPlanetServerMessage const m(ri); + m_planetServerConnection = new PlanetServerConnection(m.getAddress(),m.getPort()); + } + else if (message.isType("PlanetConnectionOpened")) + { + MESSAGE_PROFILER_BLOCK("PlanetConnectionOpened"); + m_planetServerConnection = const_cast(static_cast(&source)); + DEBUG_REPORT_LOG(true, ("Connection with the Planet server has been established\n")); + onPlanetServerConnectionEstablished(); + } + else if (message.isType("PlanetConnectionClosed")) + { + MESSAGE_PROFILER_BLOCK("PlanetConnectionClosed"); + if (m_planetServerConnection) + { + m_planetServerConnection->setDisconnectReason("received PlanetConnectionClosed"); + m_planetServerConnection->disconnect(); + } + m_planetServerConnection = 0; + setDone("PlanetConnectionClosed : %s", serverConnection->getDisconnectReason().c_str()); + } + else if (message.isType("GameServerSetupMessage")) + { + MESSAGE_PROFILER_BLOCK("GameServerSetupMessage"); + LOG("GameGameConnect", ("Game Server %d Received GameServerSetupMessage.", m_processId)); + + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > > const m(ri); + + m_gameServerPids = m.getValue().first; + std::sort(m_gameServerPids.begin(), m_gameServerPids.end()); + + ServerMessageForwarding::beginBroadcast(); + + GenericValueTypeMessage const addGameServerMessage("AddGameServer", getProcessId()); + ServerMessageForwarding::send(addGameServerMessage); + + ServerMessageForwarding::end(); + + uint32 const databaseProcessId = m.getValue().second.first; + std::string const &databaseProcessAddress = m.getValue().second.second.first; + uint16 const databaseProcessPort = m.getValue().second.second.second; + + connectToDatabaseProcess(databaseProcessAddress, databaseProcessPort, databaseProcessId); + + m_connectionTimeout = Clock::timeMs() + ConfigServerGame::getConnectToAllGameServersTimeout() * 1000; + } + else if (message.isType("LoadUniverseMessage")) + { + MESSAGE_PROFILER_BLOCK("LoadUniverseMessage"); + ri = static_cast(message).getByteStream().begin(); + LoadUniverseMessage const msg(ri); + + DEBUG_REPORT_LOG(true,("Got LoadUniverseMessage\n")); + ServerUniverse::getInstance().requestCreateProxiesOnServer(msg.getProcess()); + } + else if (message.isType("SetUniverseAuthoritativeMessage")) + { + MESSAGE_PROFILER_BLOCK("SetUniverseAuthoritativeMessage"); + ri = static_cast(message).getByteStream().begin(); + SetUniverseAuthoritativeMessage const m(ri); + ServerUniverse::getInstance().setUniverseProcess(m.getProcess()); + } + else if (message.isType("AddResourceTypeMessage")) + { + ri = static_cast(message).getByteStream().begin(); + AddResourceTypeMessage const msg(ri); + ServerUniverse::getInstance().handleAddResourceTypeMessage(msg); + } + else if (message.isType("AddImportedResourceType")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + if (!ServerUniverse::getInstance().getImportedResourceTypeById(msg.getValue().first)) + IGNORE_RETURN(ResourceTypeObject::addImportedResourceType(msg.getValue().second)); + } + else if (message.isType("UniverseCompleteMessage")) + { + MESSAGE_PROFILER_BLOCK("UniverseCompleteMessage"); + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + ServerUniverse::getInstance().universeComplete(msg.getValue()); + GameServerUniverseLoadedMessage const reply(getProcessId(), msg.getValue()); + GameServer::getInstance().sendToCentralServer(reply); + GameServer::getInstance().sendToPlanetServer(reply); + gs_gameServerReady = true; + } + else if (message.isType("GameServerUniverseLoadedMessage")) + { + MESSAGE_PROFILER_BLOCK("GameServerUniverseLoadedMessage"); + ri = static_cast(message).getByteStream().begin(); + GameServerUniverseLoadedMessage const msg(ri); + + ServerUniverse::getInstance().universeLoadedAck(msg.getProcessId()); + } + else if (message.isType("PreloadRequestCompleteMessage")) + { + MESSAGE_PROFILER_BLOCK("PreloadRequestCompleteMessage"); + LOG("Preload", ("Game Server %d received preloadRequestCompleteMessage from database", getInstance().m_processId)); + ri = static_cast(message).getByteStream().begin(); + PreloadRequestCompleteMessage const msg(ri); + + DEBUG_REPORT_LOG(true,("Got PreloadRequestCompleteMessage. We are server %lu in the preload list\n",msg.getPreloadAreaId())); + + m_preloadAreaId = msg.getPreloadAreaId(); + MetricsManager::install(m_metricsData, true, "GameServer", ServerWorld::getSceneId(), msg.getPreloadAreaId()); + s_metricsManagerInstalled = true; + GameServer::getInstance().sendToPlanetServer(msg); + + // Our assigned preload number should be the same as the preload number we were started with; + // The cluster will still work but the restartgameserver.pl script may end up restarting the wrong + // game server because of the mismatch; it's worth putting out a log to look into what went wrong +#ifndef _DEBUG + if (static_cast(msg.getPreloadAreaId()) != ConfigServerGame::getPreloadNumber()) + LOG("Preload", ("Game Server %d got assigned preload number %lu but was launched with preload number %d", getInstance().m_processId, msg.getPreloadAreaId(), ConfigServerGame::getPreloadNumber())); +#endif + + // Notify ServerWorld that preloading is complete, so it can trigger scripts as appropriate + ServerWorld::onPreloadComplete(); + } + else if (message.isType("SceneTransferMessage")) + { + MESSAGE_PROFILER_BLOCK("SceneTransferMessage"); + ri = static_cast(message).getByteStream().begin(); + SceneTransferMessage const msg(ri); + + ServerObject * obj = ServerWorld::findObjectByNetworkId(msg.getNetworkId()); + if (obj) + obj->removeObjVarItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER); + + if (obj && obj->isAuthoritative() && isGameServerConnected(msg.getDestinationGameServer()) && (!obj->isPlayerControlled() || obj->getClient())) + { + if (obj->getSceneId() == msg.getSceneName()) + { + WARNING_STRICT_FATAL(true, ("Same scene planetwarps are no longer supported!")); + if (obj->getClient()) + dropClient(obj->getNetworkId()); + obj->unload(); + } + else + { + // Mounts: if it is a rider that is trying to planet warp, change the planet warp object + // to be the mount. + CreatureObject *const objAsCreature = obj->asCreatureObject(); + if (objAsCreature) + { + if (objAsCreature->getState(States::RidingMount)) + { + // The obj instance is a mounted rider. Replace obj with the mount. + CreatureObject *const mountObject = objAsCreature->getMountedCreature(); + if (mountObject) + { + // Set the proper position for the rider to that for the + // scene transfer. Failure to take this step causes the + // ServerObject::setClient() call on the destination server + // to have the wrong position for the player, thus setting + // up location-based containment improperly, screwing up + // the client's view of the world. + obj->setPosition_p(msg.getPosition_w()); + + // Replace obj with mount. + obj = mountObject; + } + else + { + LOG("mounts-bug", ("GS::SceneTransferMessage: server id=[%d],rider id=[%s] has RidingMount state but getMountedCreature() returns NULL.", static_cast(getProcessId()), obj->getNetworkId().getValueString().c_str())); + objAsCreature->emergencyDismountForRider(); + } + } + else + { + ShipObject * const ship = getAttachedShip(objAsCreature); + if (ship) + { + // Set the proper position for the rider to that for the + // scene transfer. Failure to take this step causes the + // ServerObject::setClient() call on the destination server + // to have the wrong position for the player, thus setting + // up location-based containment improperly, screwing up + // the client's view of the world. + obj->setPosition_w(msg.getPosition_w()); + + obj = ship; + } + } + } + + // Proceed with scene transfer on the transfer focus object. + bool doSceneChange = false; + + if (ContainerInterface::getTopmostContainer(*obj) == obj) + doSceneChange = true; + else + { + Transform tr(obj->getTransform_o2w()); + if (tr.isNaN()) + { + WARNING(true, ("Scene change for %s with nan in transform (i=%g,%g,%g j=%g,%g,%g k=%g,%g,%g, p=%g,%g,%g)", + obj->getDebugInformation().c_str(), + tr.getLocalFrameI_p().x, tr.getLocalFrameI_p().y, tr.getLocalFrameI_p().z, + tr.getLocalFrameJ_p().x, tr.getLocalFrameJ_p().y, tr.getLocalFrameJ_p().z, + tr.getLocalFrameK_p().x, tr.getLocalFrameK_p().y, tr.getLocalFrameK_p().z, + tr.getPosition_p().x, tr.getPosition_p().y, tr.getPosition_p().z)); + tr.resetRotate_l2p(); + } + Container::ContainerErrorCode err = Container::CEC_Success; + doSceneChange = ContainerInterface::transferItemToWorld(*obj, tr, 0, err); + } + + if (doSceneChange) + { + obj->setSceneIdOnThisAndContents(msg.getSceneName()); + + //-- As soon as we change the scene id on the object, tell central about the + // scene change. This fixes a bug that can occur if the authority transfer + // never completes where Central is left thinking we're still on this gameserver's + // scene (the source scene) but the object's data says we're on the destination + // due to the scene set above. + GenericValueTypeMessage > > const setSceneMsg("SetSceneForPlayer", std::make_pair(msg.getNetworkId(), std::make_pair(msg.getSceneName(), false))); + GameServer::getInstance().sendToCentralServer(setSceneMsg); + + if (!msg.getSceneName().empty()) + { + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(msg.getNetworkId()); + if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.locationPlanet != msg.getSceneName())) + ServerUniverse::setConnectedCharacterPlanetData(msg.getNetworkId(), msg.getSceneName()); + } + + obj->getContainedByProperty()->setContainedBy(NetworkId::cms_invalid); + obj->setPosition_p(msg.getPosition_w()); + if (msg.getContainerId() != NetworkId::cms_invalid) + obj->setInteriorTeleportDestination(msg.getContainerId(), msg.getContainerName(), msg.getPosition_p()); + if (!msg.getScriptCallback().empty()) + obj->setTeleportScriptCallback(msg.getScriptCallback()); + obj->transferAuthority(msg.getDestinationGameServer(), false, false, false); + obj->clearProxyList(); + } + } + } + } + else if (message.isType("ChatServerOnline")) + { + MESSAGE_PROFILER_BLOCK("ChatServerOnline"); + // a chat server advised the central server that it is online and + // is ready for game servers to connect to it. + ri = static_cast(message).getByteStream().begin(); + ChatServerOnline const cso(ri); + + if (m_chatServerConnection) + { + //we shouldn't have one already, but if we do then close it and + //accept the new one. + WARNING(true, ("We got notification of a new chat server coming online while we still had connection to an existing. We're going to disconnect from the old one and connect to the new one. This shouldn't cause any real problems, but we shouldn't have lingering chat connections laying around.")); + m_chatServerConnection->setDisconnectReason("got ChatServerOnline message"); + m_chatServerConnection->disconnect(); + m_chatServerConnection = 0; + Chat::setChatServer(m_chatServerConnection); + } + + if(! m_chatServerConnection) + { + REPORT_LOG(true, ("New chat server connection active\n")); + m_chatServerConnection = new ChatServerConnection(cso.getAddress(), cso.getPort()); + Chat::setChatServer(m_chatServerConnection); + if(! m_clusterName.empty()) + { + Chat::createSystemRooms(m_clusterName, ServerWorld::getSceneId()); + } + } + } + else if(message.isType("ChatServerConnectionClosed")) + { + MESSAGE_PROFILER_BLOCK("ChatServerConnectionClosed"); + REPORT_LOG(true, ("GameServer: Chat Server connection closed\n")); + if (m_chatServerConnection) + { + m_chatServerConnection->setDisconnectReason("got ChatServerConnectionClosed message"); + m_chatServerConnection->disconnect(); + + // if there is an interruption of service on the network + // between the GameServer and ChatServer, but the ChatServer + // is still running, the game server might never reconnect. Advise + // Central that the GameServer has lost a connection with the chat + // server + GameNetworkMessage const chatClosed("ChatClosedConnectionWithGameServer"); + sendToCentralServer(chatClosed); + } + m_chatServerConnection = 0; + } + else if(message.isType("TeleportMessage")) + { + MESSAGE_PROFILER_BLOCK("TeleportMessage"); + ri = static_cast(message).getByteStream().begin(); + TeleportMessage const msg(ri); + handleTeleportMessage(msg); + } + else if (message.isType("TeleportToMessage")) + { + MESSAGE_PROFILER_BLOCK("TeleportToMessage"); + ri = static_cast(message).getByteStream().begin(); + TeleportToMessage const msg(ri); + ServerObject * const serverObj = safe_cast(NetworkIdManager::getObjectById(msg.getTargetId())); + if (serverObj && serverObj->isAuthoritative()) + { + + // send teleport message + Object const * const firstParent = ContainerInterface::getFirstParentInWorld(*serverObj); + if (firstParent) + { + ServerMessageForwarding::begin(msg.getProcessId()); + + TeleportMessage const teleportMessage( + msg.getActorId(), + serverObj->getSceneId(), + firstParent->getPosition_w(), + firstParent->getAttachedTo() ? firstParent->getAttachedTo()->getNetworkId() : NetworkId::cms_invalid, + firstParent->getPosition_p()); + ServerMessageForwarding::send(teleportMessage); + + ServerMessageForwarding::end(); + } + } + } + else if(message.isType("RetrievedItemLoadMessage")) + { + MESSAGE_PROFILER_BLOCK("RetrievedItemLoadMessage"); + ri = static_cast(message).getByteStream().begin(); + RetrievedItemLoadMessage const msg(ri); + handleRetrievedItemLoadMessage(msg); + } + else if(message.isType("BiographyMessage")) + { + MESSAGE_PROFILER_BLOCK("BiographyMessage"); + ri = static_cast(message).getByteStream().begin(); + BiographyMessage const msg(ri); + BiographyManager::onBiographyRetrieved(msg.getOwner(),msg.getBio()); + } + else if(message.isType("LoadContainedObjectMessage")) + { + MESSAGE_PROFILER_BLOCK("LoadContainedObjectMessage"); + ri = static_cast(message).getByteStream().begin(); + LoadContainedObjectMessage const m(ri); + ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(m.getContainerId())); + if (obj) + { + WARNING(!obj->isAuthoritative(), ("Got LoadContainedObjectMessage, but the container is not authoritative. Container is %s, Object id %s", + obj->getDebugInformation().c_str(), m.getObjectId().getValueString().c_str())); + + obj->onContainedObjectLoaded(m.getObjectId()); + } + else + { + WARNING(true, ("Got LoadContainedObjectMessage, but could not find the container. Container id %s, Object id %s", + m.getContainerId().getValueString().c_str(), m.getObjectId().getValueString().c_str())); + } + } + else if(message.isType("LoadContentsMessage")) + { + MESSAGE_PROFILER_BLOCK("LoadContentsMessage"); + ri = static_cast(message).getByteStream().begin(); + LoadContentsMessage const m(ri); + ServerObject * const obj = safe_cast(NetworkIdManager::getObjectById(m.getContainerId())); + if (obj) + { + WARNING(!obj->isAuthoritative(),("Got LoadContentsMessage, but the container is not authoritative. Container is %s", + obj->getDebugInformation().c_str())); + + obj->onAllContentsLoaded(); + } + else + { + WARNING(true,("Got LoadContentsMessage, but could not find the container. Container id %s", + m.getContainerId().getValueString().c_str())); + } + } + else if(message.isType("FirstPlanetGameServerIdMessage")) + { + MESSAGE_PROFILER_BLOCK("FirstPlanetGameServerIdMessage"); + ri = static_cast(message).getByteStream().begin(); + FirstPlanetGameServerIdMessage const msg(ri); + m_firstGameServerForPlanet = msg.getGameServerId(); + DEBUG_REPORT_LOG(true,("First game server for %s is %lu\n",ServerWorld::getSceneId().c_str(),m_firstGameServerForPlanet)); + } + else if(message.isType("CreateDynamicRegionCircleMessage")) + { + MESSAGE_PROFILER_BLOCK("CreateDynamicRegionCircleMessage"); + ri = static_cast(message).getByteStream().begin(); + CreateDynamicRegionCircleMessage const msg(ri); + RegionMaster::createNewDynamicRegion(msg.getCenterX(), msg.getCenterZ(), msg.getRadius(), msg.getName(), msg.getPlanet(), msg.getPvp(), msg.getBuildable(), msg.getMunicipal(), msg.getGeography(), msg.getMinDifficulty(), msg.getMaxDifficulty(), msg.getSpawnable(), msg.getMission(), msg.getVisible(), msg.getNotify()); + } + else if(message.isType("CreateDynamicRegionRectangleMessage")) + { + MESSAGE_PROFILER_BLOCK("CreateDynamicRegionRectangleMessage"); + ri = static_cast(message).getByteStream().begin(); + CreateDynamicRegionRectangleMessage const msg(ri); + RegionMaster::createNewDynamicRegion(msg.getMinX(), msg.getMinZ(), msg.getMaxX(), msg.getMaxZ(), msg.getName(), msg.getPlanet(), msg.getPvp(), msg.getBuildable(), msg.getMunicipal(), msg.getGeography(), msg.getMinDifficulty(), msg.getMaxDifficulty(), msg.getSpawnable(), msg.getMission(), msg.getVisible(), msg.getNotify()); + } + else if(message.isType("CreateGroupMessage")) + { + MESSAGE_PROFILER_BLOCK("CreateGroupMessage"); + ri = static_cast(message).getByteStream().begin(); + CreateGroupMessage const msg(ri); + ServerUniverse::getInstance().createGroup(msg.getLeader(), msg.getMembers()); + } + else if(message.isType("ReloadAdminTableMessage")) + { + MESSAGE_PROFILER_BLOCK("ReloadAdminTableMessage"); + ri = static_cast(message).getByteStream().begin(); + ReloadAdminTableMessage const msg(ri); + handleReloadAdminTableMessage(msg); + } + else if(message.isType("ReloadCommandTableMessage")) + { + MESSAGE_PROFILER_BLOCK("ReloadCommandTableMessage"); + ri = static_cast(message).getByteStream().begin(); + ReloadCommandTableMessage const msg(ri); + handleReloadCommandTableMessage(msg); + } + else if (message.isType(ReloadDatatableMessage::ms_messageName)) + { + MESSAGE_PROFILER_BLOCK(ReloadDatatableMessage::ms_messageName); + ri = static_cast(message).getByteStream().begin(); + ReloadDatatableMessage const msg(ri); + handleReloadDatatableMessage(msg); + } + else if(message.isType("ReloadScriptMessage")) + { + MESSAGE_PROFILER_BLOCK("ReloadScriptMessage"); + ri = static_cast(message).getByteStream().begin(); + ReloadScriptMessage const msg(ri); + handleReloadScriptMessage(msg); + } + else if(message.isType("ReloadTemplateMessage")) + { + MESSAGE_PROFILER_BLOCK("ReloadTemplateMessage"); + ri = static_cast(message).getByteStream().begin(); + ReloadTemplateMessage const msg(ri); + handleReloadTemplateMessage(msg); + } + else if(message.isType("EnableNewJediTrackingMessage")) + { + MESSAGE_PROFILER_BLOCK("EnableNewJediTrackingMessage"); + ri = static_cast(message).getByteStream().begin(); + EnableNewJediTrackingMessage const msg(ri); + handleEnableNewJediTrackingMessage(msg); + } + else + { + // GameServer::receiveMessage() is getting too big for the compiler to handle + // so some of the message handling is done in the private helper receiveMessage2() + receiveMessage2(source, message); + } +} + +// ---------------------------------------------------------------------- +// GameServer::receiveMessage() is getting too big for the compiler to handle +// so some of the message handling is done in this private helper receiveMessage2() + +void GameServer::receiveMessage2(const MessageDispatch::Emitter & source, const MessageDispatch::MessageBase & message) +{ + static Archive::ReadIterator ri; + static Archive::ByteStream bs; + + PROFILER_AUTO_BLOCK_DEFINE("GameServer::receiveMessage2"); + + if(message.isType("AuthTransferConfirmMessage")) + { + MESSAGE_PROFILER_BLOCK("AuthTransferConfirmMessage"); + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + AuthTransferTracker::handleConfirmAuthTransfer(msg.getValue().first, msg.getValue().second); + } + else if(message.isType("PersistedPlayerMessage")) + { + MESSAGE_PROFILER_BLOCK("PersistedPlayerMessage"); + ri = static_cast(message).getByteStream().begin(); + PersistedPlayerMessage const msg(ri); + LogoutTracker::onPersisted(msg.getPlayerId()); + sendToPlanetServer(msg); + } + else if(message.isType("RenameCharacterMessageEx")) + { + MESSAGE_PROFILER_BLOCK("RenameCharacterMessageEx"); + ri = static_cast(message).getByteStream().begin(); + RenameCharacterMessageEx msg(ri); + NameManager::getInstance().renamePlayer(msg.getCharacterId(), msg.getNewName(), msg.getNewName()); + + // update the character's name in the citizen and guild listing + if (ServerUniverse::getInstance().isAuthoritative()) + { + std::string const newName(Unicode::wideToNarrow(msg.getNewName())); + GuildInterface::verifyGuildMemberName(msg.getCharacterId(), newName); + CityInterface::verifyCitizenName(msg.getCharacterId(), newName); + CityInterface::verifyPgcChroniclerName(msg.getCharacterId(), newName); + } + } + else if(message.isType("PopulationListMessage")) + { + MESSAGE_PROFILER_BLOCK("PopulationListMessage"); + ri = static_cast(message).getByteStream().begin(); + PopulationListMessage const msg(ri); + ServerUniverse::getInstance().updatePopulationList(msg.getList()); + } + else if (message.isType("CentralPingMessage")) + { + MESSAGE_PROFILER_BLOCK("CentralPingMessage"); + CentralPingMessage const reply; + sendToCentralServer(reply); + } + else if (message.isType("LocateObject")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > const msg(ri); + + uint32 const responsePid = msg.getValue().first; + NetworkId const &targetId = msg.getValue().second.first; + NetworkId const &responseId = msg.getValue().second.second; + + ServerObject const * const targetObj = safe_cast(NetworkIdManager::getObjectById(targetId)); + if (targetObj) + { + std::vector containers; + for (Object const *o = ContainerInterface::getContainedByObject(*targetObj); o; o = ContainerInterface::getContainedByObject(*o)) + containers.push_back(o->getNetworkId()); + + NetworkId residenceOf; + if (!targetObj->getObjVars().getItem("player_structure.residence.building", residenceOf)) + residenceOf = NetworkId::cms_invalid; + + LocateObjectResponseMessage const msg( + targetId, + responseId, + responsePid, + targetObj->findPosition_w(), + ConfigServerGame::getSceneID(), + targetObj->getObjectTemplateName(), + getProcessId(), + containers, + targetObj->isAuthoritative(), + residenceOf); + + sendToCentralServer(msg); + } + } + else if (message.isType("LocateObjectByTemplateName")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > const msg(ri); + + uint32 const responsePid = msg.getValue().first; + uint32 const templateCrc = msg.getValue().second.first; + NetworkId const & responseId = msg.getValue().second.second; + + NetworkIdManager::NetworkIdObjectHashMap const & allObjects = NetworkIdManager::getAllObjects(); + for (NetworkIdManager::NetworkIdObjectHashMap::const_iterator iter = allObjects.begin(); iter != allObjects.end(); ++iter) + { + if (!iter->second->isAuthoritative()) + { + continue; + } + + ObjectTemplate const * const objectTemplate = iter->second->getObjectTemplate(); + if (objectTemplate && (objectTemplate->getCrcName().getCrc() == templateCrc)) + { + std::vector containers; + for (Object const *o = ContainerInterface::getContainedByObject(*(iter->second)); o; o = ContainerInterface::getContainedByObject(*o)) + containers.push_back(o->getNetworkId()); + + LocateObjectResponseMessage const msg( + iter->second->getNetworkId(), + responseId, + responsePid, + iter->second->findPosition_w(), + ConfigServerGame::getSceneID(), + objectTemplate->getName(), + getProcessId(), + containers, + true, + NetworkId::cms_invalid); + + sendToCentralServer(msg); + } + } + } + else if (message.isType("LocatePlayerByPartialName")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > const msg(ri); + + uint32 const responsePid = msg.getValue().first; + std::string const & partialName = msg.getValue().second.first; + NetworkId const & responseId = msg.getValue().second.second; + + // Try to find player objects with matching names + std::set const &players = PlayerObject::getAllPlayerObjects(); + if (!players.empty()) + { + // Convert the player name to wide character string + Unicode::String const widePartialName = Unicode::toLower(Unicode::utf8ToWide(partialName)); + + // See if a player object has a "matching" first name + std::set::const_iterator i; + for (i = players.begin(); i != players.end(); ++i) + { + PlayerObject const * const playerObject = *i; + CreatureObject const * const creatureObject = playerObject->getCreatureObject(); + + // don't include logged out players waiting to be saved or not initialized + if (!creatureObject || !creatureObject->isInWorld() || !creatureObject->isAuthoritative() || !creatureObject->getClient()) + continue; + + // Lower case the first name of the player for the comparison + Unicode::String lowerCasePlayerName = Unicode::toLower(creatureObject->getAssignedObjectFirstName()); + + // Try to find the partial name somewhere within the player name + if (partialName == "*" || lowerCasePlayerName.find(widePartialName) != Unicode::String::npos) + { + LocatePlayerResponseMessage const msg( + creatureObject->getNetworkId(), + responseId, + responsePid, + ConfigServerGame::getSceneID(), + creatureObject->findPosition_w(), + getProcessId()); + + sendToCentralServer(msg); + } + } + } + } + else if (message.isType("LocateWarden")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + uint32 const responsePid = msg.getValue().first; + NetworkId const & responseId = msg.getValue().second; + + // Try to find warden player objects + std::set const &players = PlayerObject::getAllPlayerObjects(); + if (!players.empty()) + { + std::set::const_iterator i; + for (i = players.begin(); i != players.end(); ++i) + { + PlayerObject const * const playerObject = *i; + CreatureObject const * const creatureObject = playerObject->getCreatureObject(); + + // don't include logged out players waiting to be saved or not initialized + if (!creatureObject || !creatureObject->isInWorld() || !creatureObject->isAuthoritative() || !creatureObject->getClient()) + continue; + + if (playerObject->isWarden()) + { + LocatePlayerResponseMessage const msg( + creatureObject->getNetworkId(), + responseId, + responsePid, + ConfigServerGame::getSceneID(), + creatureObject->findPosition_w(), + getProcessId()); + + sendToCentralServer(msg); + } + } + } + } + else if (message.isType("LocateCreatureByCreatureName")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > const msg(ri); + + uint32 const responsePid = msg.getValue().first; + std::string const & creatureName = msg.getValue().second.first; + NetworkId const & responseId = msg.getValue().second.second; + + CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures(); + for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i) + { + CreatureObject const * const creatureObj = *i; + if (creatureObj->isAuthoritative()) + { + AICreatureController const * const aiCreatureController = AICreatureController::asAiCreatureController(creatureObj->getController()); + if (aiCreatureController == NULL) + { + continue; + } + + PersistentCrcString const & pcsCreatureName = aiCreatureController->getCreatureName(); + if (pcsCreatureName.isEmpty()) + { + continue; + } + + if (creatureName != pcsCreatureName.getString()) + { + continue; + } + + std::vector containers; + for (Object const *o = ContainerInterface::getContainedByObject(*creatureObj); o; o = ContainerInterface::getContainedByObject(*o)) + containers.push_back(o->getNetworkId()); + + LocateObjectResponseMessage const msg( + creatureObj->getNetworkId(), + responseId, + responsePid, + creatureObj->findPosition_w(), + ConfigServerGame::getSceneID(), + creatureObj->getObjectTemplateName(), + getProcessId(), + containers, + true, + NetworkId::cms_invalid); + + sendToCentralServer(msg); + } + } + } + else if (message.isType("LSBOIReq")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair, NetworkId> > > const locateStructureByOwnerIdReq(ri); + + handleMessageLocateStructureByOwnerIdReq(*this, locateStructureByOwnerIdReq.getValue().first.first, locateStructureByOwnerIdReq.getValue().first.second, locateStructureByOwnerIdReq.getValue().second.first.first, locateStructureByOwnerIdReq.getValue().second.first.second, locateStructureByOwnerIdReq.getValue().second.second); + } + else if (message.isType("LSBOIRsp")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::vector > > const locateStructureByOwnerIdRsp(ri); + + handleMessageLocateStructureByOwnerIdRsp(locateStructureByOwnerIdRsp.getValue().first.second, locateStructureByOwnerIdRsp.getValue().second); + } + else if (message.isType("ReportSystemClockTime")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + +#ifdef WIN32 + std::string hostName = NetworkHandler::getHostName(); +#else + std::string hostName = NetworkHandler::getHumanReadableHostName(); +#endif + + std::string time = FormattedString<1024>().sprintf("(%3d,%5dms) %30s.%-2lu (%3lu) on %35s:%-7d (%lu) ", ObjectTracker::getNumPlayers(), static_cast(Clock::frameTime()*1000), ServerWorld::getSceneId().c_str(), m_preloadAreaId, m_processId, hostName.c_str(), Os::getProcessId(), ServerClock::getInstance().getGameTimeSeconds()); + time += CalendarTime::convertEpochToTimeStringGMT(::time(NULL)); + + GenericValueTypeMessage > > rsctr( + "ReportSystemClockTimeResponse", std::make_pair(msg.getValue().first, std::make_pair(time, msg.getValue().second))); + + sendToCentralServer(rsctr); + } + else if (message.isType("ReportSystemClockTimeResponse")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > const msg(ri); + + ConsoleMgr::broadcastString(msg.getValue().second.first, msg.getValue().second.second); + } + else if (message.isType("ReportPlanetaryTime")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + time_t const timeNow = ::time(NULL); + std::string time = FormattedString<1024>().sprintf("%30s.%-2lu (%3lu) (%lu) (%ld, ", ServerWorld::getSceneId().c_str(), m_preloadAreaId, m_processId, ServerClock::getInstance().getGameTimeSeconds(), timeNow); + time += CalendarTime::convertEpochToTimeStringGMT(timeNow); + time += ")"; + + const TerrainObject* const terrainObject = TerrainObject::getInstance(); + if (terrainObject) + { + const float environmentCycleTime = terrainObject->getEnvironmentCycleTime(); + if (environmentCycleTime > 0.f) + { + const float day = fmodf(static_cast(ServerClock::getInstance().getGameTimeSeconds()), environmentCycleTime) / environmentCycleTime; + int hour = 6 + static_cast(day * 24.f * 60.f) / 60; + if (hour >= 24) + hour -= 24; + const int minute = static_cast(fmodf(day * 24.f * 60.f, 60.f)); + + time += FormattedString<1024>().sprintf(" (%g, %02d:%02d, %f)", environmentCycleTime, hour, minute, day); + } + else + { + time += FormattedString<1024>().sprintf(" (environmentCycleTime %g is <= 0.f)", environmentCycleTime); + } + } + else + { + time += " (terrainObject is NULL)"; + } + + GenericValueTypeMessage > > rptr( + "ReportPlanetaryTimeResponse", std::make_pair(msg.getValue().first, std::make_pair(time, msg.getValue().second))); + + sendToCentralServer(rptr); + } + else if (message.isType("ReportPlanetaryTimeResponse")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > const msg(ri); + + ConsoleMgr::broadcastString(msg.getValue().second.first, msg.getValue().second.second); + } + else if (message.isType("ClusterStartComplete")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + if (msg.getValue()) + { + // cluster initial start has completed + if (ServerUniverse::getInstance().isAuthoritative()) + { + // add player city travel points + std::map const & allCities = CityInterface::getAllCityInfo(); + for (std::map::const_iterator iter = allCities.begin(); iter != allCities.end(); ++iter) + { + CityInfo const & ci = iter->second; + if (ci.getCityName().empty()) + continue; + + if ((ci.getRadius() >= 400) && (ci.getTravelCost() > 0)) + { + PlanetObject *planet = ServerUniverse::getInstance().getPlanetByName(ci.getPlanet()); + if (planet) + { + planet->addTravelPoint( + ci.getCityName(), + ci.getTravelLoc(), + ci.getTravelCost(), + ci.getTravelInterplanetary(), + TravelPoint::TPT_PC_Shuttleport); + } + } + } + + // do some sanity check of GCW score + GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); + CityObject const * const co = ServerUniverse::getInstance().getMasterCityObject(); + if (go && go->isAuthoritative() && co && co->isAuthoritative()) + { + // depersist GCW score, if it hasn't already been done + std::map const & gcwImperialScorePercentile = go->getGcwImperialScorePercentile(); + if (gcwImperialScorePercentile.empty()) + { + // this will also calculate the GCW Region Defender Bonus + go->depersistGcwImperialScorePercentile(); + } + else + { + // for sanity's sake, (re)calculate the GCW Region Defender Bonus + for (std::map::const_iterator iter = gcwImperialScorePercentile.begin(); iter != gcwImperialScorePercentile.end(); ++iter) + go->updateGcwRegionDefenderBonus(iter->first); + } + } + } + + if (ConfigServerGame::getEnableCityCitizenshipFixup() && ServerUniverse::getInstance().isAuthoritative()) + { + std::vector const & allGameServerPids = getAllGameServerPids(); + if (!allGameServerPids.empty()) + { + ServerMessageForwarding::beginBroadcast(); + GenericValueTypeMessage clusterStartupResidenceStructureListRequest("CSRSLReq", getProcessId()); + ServerMessageForwarding::send(clusterStartupResidenceStructureListRequest); + ServerMessageForwarding::end(); + + s_clusterStartupResidenceStructureListResponse.clear(); + for (std::vector::const_iterator iter = allGameServerPids.begin(); iter != allGameServerPids.end(); ++iter) + IGNORE_RETURN(s_clusterStartupResidenceStructureListResponse.insert(*iter)); + } + else + { + s_clusterStartupResidenceStructureListByStructure.clear(); + s_clusterStartupResidenceStructureListResponse.clear(); + } + } + else if (!ConfigServerGame::getEnableCityCitizenshipFixup()) + { + s_clusterStartupResidenceStructureListByStructure.clear(); + s_clusterStartupResidenceStructureListResponse.clear(); + } + } + else + { + s_clusterStartupResidenceStructureListByStructure.clear(); + s_clusterStartupResidenceStructureListResponse.clear(); + } + } + else if (message.isType("CSRSLReq")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const clusterStartupResidenceStructureListRequest(ri); + + ServerMessageForwarding::begin(clusterStartupResidenceStructureListRequest.getValue()); + + std::map > clusterStartupResidenceStructureListByCity; + if (!s_clusterStartupResidenceStructureListByStructure.empty()) + { + for (std::map >::const_iterator iter = s_clusterStartupResidenceStructureListByStructure.begin(); iter != s_clusterStartupResidenceStructureListByStructure.end(); ++iter) + IGNORE_RETURN(clusterStartupResidenceStructureListByCity[iter->second.first].insert(iter->second.second)); + } + + GenericValueTypeMessage > > > clusterStartupResidenceStructureListResponse("CSRSLRsp", std::make_pair(getProcessId(), clusterStartupResidenceStructureListByCity)); + ServerMessageForwarding::send(clusterStartupResidenceStructureListResponse); + ServerMessageForwarding::end(); + + s_clusterStartupResidenceStructureListByStructure.clear(); + s_clusterStartupResidenceStructureListResponse.clear(); + } + else if (message.isType("CSRSLRsp")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > > > const clusterStartupResidenceStructureListResponse(ri); + + if (s_clusterStartupResidenceStructureListResponse.erase(clusterStartupResidenceStructureListResponse.getValue().first) != 0) + { + static std::map > s_clusterStartupResidenceStructureListByCity; + + std::map > const & residenceList = clusterStartupResidenceStructureListResponse.getValue().second; + if (!residenceList.empty()) + { + for (std::map >::const_iterator iter = residenceList.begin(); iter != residenceList.end(); ++iter) + { + if (!iter->second.empty()) + s_clusterStartupResidenceStructureListByCity[iter->first].insert(iter->second.begin(), iter->second.end()); + } + } + + if (s_clusterStartupResidenceStructureListResponse.empty()) + { + // add our own information to the list + if (!s_clusterStartupResidenceStructureListByStructure.empty()) + { + for (std::map >::const_iterator iter = s_clusterStartupResidenceStructureListByStructure.begin(); iter != s_clusterStartupResidenceStructureListByStructure.end(); ++iter) + IGNORE_RETURN(s_clusterStartupResidenceStructureListByCity[iter->second.first].insert(iter->second.second)); + } + + // we now have the complete list of every declared structure within + // city limits; besides the mayor, only owners of these structures + // can be in the citizenship list, so fix up the citizenship list + // of all cities right now + + // skip the fixup if it looks like the cluster was started + // without loading the entire planet because it means structures + // were not loaded, so we don't have the information to determine citizenship + if (!s_clusterStartupResidenceStructureListByCity.empty()) + { + // cities that have no declared structures don't have anything in + // the report, so we have to manually add in those cities + std::map > allCityMayors; + std::map const & allCities = CityInterface::getAllCityInfo(); + + for (std::map::const_iterator iterAllCities = allCities.begin(); iterAllCities != allCities.end(); ++iterAllCities) + { + if (s_clusterStartupResidenceStructureListByCity.count(iterAllCities->first) <= 0) + IGNORE_RETURN(s_clusterStartupResidenceStructureListByCity.insert(std::make_pair(iterAllCities->first, std::set()))); + + if (iterAllCities->second.getLeaderId().isValid()) + allCityMayors[iterAllCities->second.getLeaderId()] = std::make_pair(iterAllCities->first, iterAllCities->second.getCityName()); + } + + // remove citizens (except the mayor) that do not have a declared structure inside the city limits + // if necessary, add as citizen those that have a declared structure inside the city limits + std::string cityName; + std::string citizenName; + int citizenLastLoginTime = 0; + NetworkId currentCityMayor; + CitizenInfo const * currentCityMayorCitizenInfo; + std::string currentCityMayorName; + std::vector citizensToRemove; + std::string citizensToRemoveNames; + std::string citizensToRemoveDeletedNames; + std::string citizensToRemoveInactiveNames; + std::string citizensToAddNames; + bool needToAddMayorAsCitizen; + bool removeCurrentCitizen; + bool removeCurrentCitizenDeleted; + bool removeCurrentCitizenInactive; + bool hasDeclaredResidence; + int const timeNow = static_cast(::time(NULL)); + bool const citizenInactivePackupActive = (ConfigServerGame::getCityCitizenshipInactivePackupStartTimeEpoch() <= timeNow); + std::map, CitizenInfo> const & allCitizens = CityInterface::getAllCitizensInfo(); + for (std::map >::iterator iterCityId = s_clusterStartupResidenceStructureListByCity.begin(); iterCityId != s_clusterStartupResidenceStructureListByCity.end(); ++iterCityId) + { + CityInfo const & cityInfo = CityInterface::getCityInfo(iterCityId->first); + + cityName = cityInfo.getCityName(); + if (cityName.empty()) + continue; + + if (!cityInfo.getCityHallId().isValid()) + continue; + + currentCityMayor = cityInfo.getLeaderId(); + if (currentCityMayor.isValid()) + currentCityMayorCitizenInfo = CityInterface::getCitizenInfo(iterCityId->first, currentCityMayor); + else + currentCityMayorCitizenInfo = NULL; + + if (currentCityMayorCitizenInfo) + currentCityMayorName = currentCityMayorCitizenInfo->m_citizenName; + else + currentCityMayorName.clear(); + + if (currentCityMayor.isValid() && !currentCityMayorCitizenInfo) + needToAddMayorAsCitizen = true; + else + needToAddMayorAsCitizen = false; + + LOG("CityFixup", ("City %d (%s:%s, %s:%s) has %d declared structures within its city limits.", iterCityId->first, cityName.c_str(), cityInfo.getCityHallId().getValueString().c_str(), currentCityMayorName.c_str(), currentCityMayor.getValueString().c_str(), iterCityId->second.size())); + + // remove any current citizen who has not logged in for 90 days and is not marked + // as a "protected citizen" OR who no longer exists in the DB OR who does not have + // a declared structure in the city EXCEPT the mayor of the city; also remove any + // current citizen who is a mayor of another city, since mayor can only be the + // citizen of the city that they are mayor of + static const Unicode::String mailSubjectRemove = Unicode::narrowToWide("@" + StringId("city/city", "city_fixup_remove_citizens_subject").getCanonicalRepresentation()); + citizensToRemove.clear(); + citizensToRemoveNames.clear(); + citizensToRemoveDeletedNames.clear(); + citizensToRemoveInactiveNames.clear(); + for (std::map, CitizenInfo>::const_iterator iterCurrentCitizen = allCitizens.lower_bound(std::make_pair(iterCityId->first, NetworkId::cms_invalid)); iterCurrentCitizen != allCitizens.end(); ++iterCurrentCitizen) + { + if (iterCurrentCitizen->first.first != iterCityId->first) + break; + + // the erase() will tell us whether this current citizen is confirmed to have + // a declared structure in the city; what it also does for us is whoever is left + // in the list after all the erase() is done are people who have a declared + // structure in the city but are not current citizens, and will need to be added + // as citizens + citizenName = iterCurrentCitizen->second.m_citizenName; + removeCurrentCitizen = false; + removeCurrentCitizenDeleted = false; + removeCurrentCitizenInactive = false; + hasDeclaredResidence = (iterCityId->second.erase(iterCurrentCitizen->first.second) >= 1); + + // mayor never gets removed + if (iterCurrentCitizen->first.second != currentCityMayor) + { + if (!hasDeclaredResidence) + { + // remove citizen because he doesn't have a declared residence inside the city limits + removeCurrentCitizen = true; + LOG("CustomerService", ("CityFixup: removed %s (%s) (no declared residence) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); + } + else if (allCityMayors.count(iterCurrentCitizen->first.second) >= 1) + { + // remove citizen because he is already the mayor of another city + removeCurrentCitizen = true; + LOG("CustomerService", ("CityFixup: removed %s (%s) (already mayor of %d:%s) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), allCityMayors[iterCurrentCitizen->first.second].first, allCityMayors[iterCurrentCitizen->first.second].second.c_str(), iterCityId->first, cityName.c_str())); + } + else + { + citizenLastLoginTime = NameManager::getInstance().getPlayerLastLoginTime(iterCurrentCitizen->first.second); + if (citizenLastLoginTime <= 0) + { + // remove citizen because he no longer exists in the DB + removeCurrentCitizen = true; + removeCurrentCitizenDeleted = true; + LOG("CustomerService", ("CityFixup: removed %s (%s) (deleted) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); + } + else if (citizenInactivePackupActive && ((citizenLastLoginTime + ConfigServerGame::getCityCitizenshipInactivePackupInactiveTimeSeconds()) <= timeNow) && !(iterCurrentCitizen->second.m_citizenPermissions & CitizenPermissions::InactiveProtected)) + { + // remove citizen because he has not logged in for 90 days and is not marked as a "protected citizen" + removeCurrentCitizen = true; + removeCurrentCitizenInactive = true; + LOG("CustomerService", ("CityFixup: removed %s (%s) (inactive %s) as citizen of city %d (%s).", iterCurrentCitizen->first.second.getValueString().c_str(), citizenName.c_str(), CalendarTime::convertSecondsToDHMS(static_cast(timeNow - citizenLastLoginTime)).c_str(), iterCityId->first, cityName.c_str())); + } + } + } + + if (removeCurrentCitizen) + { + // build up list of citizens to remove + citizensToRemove.push_back(iterCurrentCitizen->first.second); + + // build list of citizens that gets removed to send mail to mayor + if (!currentCityMayorName.empty()) + { + if (removeCurrentCitizenDeleted) + { + if (!citizensToRemoveDeletedNames.empty()) + citizensToRemoveDeletedNames += "\r\n"; + + citizensToRemoveDeletedNames += citizenName; + + // send multiple mail if there are too many names + if (citizensToRemoveDeletedNames.size() > 2000) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_remove_deleted_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToRemoveDeletedNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); + + citizensToRemoveDeletedNames.clear(); + } + } + else if (removeCurrentCitizenInactive) + { + if (!citizensToRemoveInactiveNames.empty()) + citizensToRemoveInactiveNames += "\r\n"; + + citizensToRemoveInactiveNames += citizenName; + citizensToRemoveInactiveNames += " (offline "; + citizensToRemoveInactiveNames += CalendarTime::convertSecondsToDHMS(static_cast(timeNow - citizenLastLoginTime)); + citizensToRemoveInactiveNames += ")"; + + // send multiple mail if there are too many names + if (citizensToRemoveInactiveNames.size() > 2000) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_remove_inactive_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToRemoveInactiveNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); + + citizensToRemoveInactiveNames.clear(); + } + } + else + { + if (!citizensToRemoveNames.empty()) + citizensToRemoveNames += "\r\n"; + + citizensToRemoveNames += citizenName; + + // send multiple mail if there are too many names + if (citizensToRemoveNames.size() > 2000) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_remove_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToRemoveNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); + + citizensToRemoveNames.clear(); + } + } + } + } + } + + if (!currentCityMayorName.empty()) + { + if (!citizensToRemoveDeletedNames.empty()) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_remove_deleted_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToRemoveDeletedNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); + } + + if (!citizensToRemoveInactiveNames.empty()) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_remove_inactive_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToRemoveInactiveNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); + } + + if (!citizensToRemoveNames.empty()) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_remove_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToRemoveNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectRemove, Unicode::emptyString, oob); + } + } + + // remove citizens + for (std::vector::const_iterator iterCitizenToRemove = citizensToRemove.begin(); iterCitizenToRemove != citizensToRemove.end(); ++iterCitizenToRemove) + { + CityInterface::removeCitizen(iterCityId->first, *iterCitizenToRemove, false); + } + + // add mayor as a citizen if necessary + if (needToAddMayorAsCitizen) + IGNORE_RETURN(iterCityId->second.insert(currentCityMayor)); + + // add citizens + static const Unicode::String mailSubjectAdd = Unicode::narrowToWide("@" + StringId("city/city", "city_fixup_add_citizens_subject").getCanonicalRepresentation()); + citizensToAddNames.clear(); + for (std::set::const_iterator iterCitizenToAdd = iterCityId->second.begin(); iterCitizenToAdd != iterCityId->second.end(); ++iterCitizenToAdd) + { + // make sure it's a valid player + if (!NameManager::getInstance().isPlayer(*iterCitizenToAdd)) + continue; + + // citizens who have not logged in within the past 90 days should not be + // added as a citizen EXCEPT for the mayor who should always be a citizen + if ((*iterCitizenToAdd != currentCityMayor) && citizenInactivePackupActive) + { + citizenLastLoginTime = NameManager::getInstance().getPlayerLastLoginTime(*iterCitizenToAdd); + if ((citizenLastLoginTime <= 0) || ((citizenLastLoginTime + ConfigServerGame::getCityCitizenshipInactivePackupInactiveTimeSeconds()) <= timeNow)) + continue; + } + + // don't add someone who is already a mayor of another city, unless + // we are adding this city's mayor as a citizen of this city + if ((*iterCitizenToAdd != currentCityMayor) && (allCityMayors.count(*iterCitizenToAdd) >= 1)) + continue; + + // add the new citizen + citizenName = NameManager::getInstance().getPlayerFullName(*iterCitizenToAdd); + if (citizenName.empty()) + continue; + + // build list of citizens that gets added to send mail to mayor + if (!currentCityMayorName.empty()) + { + if (!citizensToAddNames.empty()) + citizensToAddNames += "\r\n"; + + citizensToAddNames += citizenName; + + // send multiple mail if there are too many names + if (citizensToAddNames.size() > 2000) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_add_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToAddNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectAdd, Unicode::emptyString, oob); + + citizensToAddNames.clear(); + } + } + + if (*iterCitizenToAdd == currentCityMayor) + LOG("CustomerService", ("CityFixup: added %s (%s) (is mayor) as citizen of city %d (%s).", iterCitizenToAdd->getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); + else + LOG("CustomerService", ("CityFixup: added %s (%s) (has declared residence) as citizen of city %d (%s).", iterCitizenToAdd->getValueString().c_str(), citizenName.c_str(), iterCityId->first, cityName.c_str())); + + CityInterface::setCitizenInfo(iterCityId->first, *iterCitizenToAdd, citizenName, NetworkId::cms_invalid, CitizenPermissions::Citizen); + } + + if (!citizensToAddNames.empty() && !currentCityMayorName.empty()) + { + ProsePackage pp; + pp.stringId = StringId("city/city", "city_fixup_add_citizens_body"); + pp.target.str = Unicode::narrowToWide(citizensToAddNames); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("City Hall", currentCityMayorName, mailSubjectAdd, Unicode::emptyString, oob); + } + } + } + + s_clusterStartupResidenceStructureListByCity.clear(); + s_clusterStartupResidenceStructureListByStructure.clear(); + s_clusterStartupResidenceStructureListResponse.clear(); + + CityInterface::checkForDualCitizenship(); + } + } + } + else if (message.isType("LocateStructureMessage")) + { + ri = static_cast(message).getByteStream().begin(); + LocateStructureMessage const msg(ri); + GameServer::getInstance().sendToCentralServer(msg); + } + else if (message.isType("LoadStructureMessage")) + { + ri = static_cast(message).getByteStream().begin(); + LoadStructureMessage const msg(ri); + + ServerObject * const house = ServerWorld::findObjectByNetworkId(msg.getStructureId()); + if (house) + { + //result += Unicode::narrowToWide("Error. Object already loaded."); + std::string replyMessage = "Structure " + msg.getStructureId().getValueString() + " already loaded"; + Chat::sendSystemMessage(msg.getWhoRequested(), Unicode::narrowToWide(replyMessage), Unicode::String()); + } + else + { + LoadContentsMessage const lcm(msg.getStructureId()); + GameServer::getInstance().sendToDatabaseServer(lcm); + std::string const replyMessage = "Structure " + msg.getStructureId().getValueString() + " is being loaded"; + Chat::sendSystemMessage(msg.getWhoRequested(), Unicode::narrowToWide(replyMessage), Unicode::String()); + } + } + else if (message.isType("LocateObjectResponseMessage")) + { + ri = static_cast(message).getByteStream().begin(); + LocateObjectResponseMessage const msg(ri); + + ServerObject * const responseObject = safe_cast(NetworkIdManager::getObjectById(msg.getResponseId())); + if (responseObject && responseObject->isAuthoritative()) + { + int const cityId = CityInterface::getCityAtLocation(msg.getScene(), static_cast(msg.getPosition_w().x), static_cast(msg.getPosition_w().z), 0); + std::string const cityName = CityInterface::getCityInfo(cityId).getCityName(); + + NetworkId const residenceOf = msg.getResidenceOf(); + std::string residenceOfName; + if (residenceOf.isValid()) + residenceOfName = NameManager::getInstance().getPlayerFullName(residenceOf); + + ScriptParams params; + params.addParam(msg.getTargetId(), "target"); + params.addParam(msg.getPosition_w(), "location"); + params.addParam(msg.getScene().c_str(), "scene"); + params.addParam(msg.getSharedTemplateName().c_str(), "sharedTemplateName"); + params.addParam(static_cast(msg.getTargetPid()), "pid"); + params.addParam(msg.getContainers(), "containers"); + params.addParam(msg.getIsAuthoritative(), "isAuthoritative"); + params.addParam(cityId, "cityId"); + params.addParam(cityName.c_str(), "cityName"); + params.addParam(residenceOf, "residenceOfId"); + params.addParam(residenceOfName.c_str(), "residenceOfName"); + + ScriptDictionaryPtr dictionary; + responseObject->getScriptObject()->makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(responseObject->getNetworkId(), "foundObject", dictionary->getSerializedData(), 0, false); + } + } + } + else if (message.isType("LocatePlayerResponseMessage")) + { + ri = static_cast(message).getByteStream().begin(); + LocatePlayerResponseMessage const msg(ri); + + ServerObject * const responseObject = safe_cast(NetworkIdManager::getObjectById(msg.getResponseId())); + if (responseObject && responseObject->isAuthoritative() && responseObject->getClient()) + { + std::string playerInfo = FormattedString<512>().sprintf("%s (%s) is on server %lu. %s (%.2f, %.2f, %.2f)", + msg.getTargetId().getValueString().c_str(), + NameManager::getInstance().getPlayerFullName(msg.getTargetId()).c_str(), + msg.getTargetPid(), msg.getScene().c_str(), + msg.getPosition_w().x, msg.getPosition_w().y, msg.getPosition_w().z); + + ConsoleMgr::broadcastString(playerInfo, responseObject->getClient()); + } + } + else if(message.isType("PlayerSanityCheck")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + PlayerSanityChecker::handlePlayerSanityCheck(msg.getValue().first, msg.getValue().second); + } + else if(message.isType("PlayerSanityCheckSuccess")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + PlayerSanityChecker::handlePlayerSanityCheckSuccess(msg.getValue()); + } + else if(message.isType("PlayerSanityCheckProxy")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + PlayerSanityChecker::handlePlayerSanityCheckProxy(msg.getValue().first, msg.getValue().second); + } + else if(message.isType("PlayerSanityCheckProxyFail")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + PlayerSanityChecker::handlePlayerSanityCheckProxyFail(msg.getValue().first, msg.getValue().second); + } + else if (message.isType("EnablePlayerSanityCheckerMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + PlayerSanityChecker::enable(msg.getValue()); + } + else if(message.isType("StartSaveReplyMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + ServerObject const * const requestedBy = safe_cast(NetworkIdManager::getObjectById(msg.getValue().first)); + + if (requestedBy) + { + if (msg.getValue().second) + Chat::sendSystemMessage(*requestedBy,Unicode::narrowToWide("Save has been started"),Unicode::String()); + else + Chat::sendSystemMessage(*requestedBy,Unicode::narrowToWide("Save could not be started because one was already in progress"),Unicode::String()); + } + } + else if(message.isType("DatabaseConsoleReplyMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + Chat::sendSystemMessage(msg.getValue().first,Unicode::narrowToWide(msg.getValue().second),Unicode::String()); + } + else if(message.isType("FindAuthObject")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + ServerObject const * const so = safe_cast(NetworkIdManager::getObjectById(msg.getValue().first)); + bool const found = so && so->isAuthoritative(); + + GenericValueTypeMessage, bool> > const authResponse( + "FindAuthObjectResponse", + std::make_pair(msg.getValue(), found)); + sendToPlanetServer(authResponse); + } + else if(message.isType("CharacterNamesMessage")) + { + ri = static_cast(message).getByteStream().begin(); + CharacterNamesMessage const msg(ri); + NameManager::getInstance().addPlayers(msg.getIds(), msg.getStationIds(), msg.getNames(), msg.getFullNames(), msg.getCreateTimes(), msg.getLoginTimes()); + } + else if (message.isType ("LocationResponse")) + { + Archive::ReadIterator readIterator = static_cast (message).getByteStream ().begin (); + LocationResponse const locationResponse (readIterator); + + //-- get the script object to invole the trigger on + Object * const object = NetworkIdManager::getObjectById (locationResponse.getNetworkId ()); + if (!object) + { + DEBUG_WARNING (true, ("LocationResponse: could not resolve object %s which asked for a location", locationResponse.getNetworkId ().getValueString ().c_str ())); + return; + } + + ServerObject * const scriptObject = object->asServerObject (); + if (!scriptObject) + { + DEBUG_WARNING (true, ("LocationResponse: object id=%s template=%s is not a server object", object->getNetworkId ().getValueString ().c_str (), object->getObjectTemplateName ())); + return; + } + + //-- if the location is valid, create a reservation object + Vector position_w (locationResponse.getX (), 0.f, locationResponse.getZ ()); + ServerObject * serverObject = 0; + if (locationResponse.getValid ()) + { + //-- construct the name + char objectTemplateName [512]; + snprintf (objectTemplateName, 512, "object/tangible/location/location_%i.iff", static_cast (locationResponse.getRadius ())); + + //-- get the height of the terrain + TerrainObject const * const terrainObject = TerrainObject::getConstInstance (); + if (terrainObject) + terrainObject->getHeightForceChunkCreation (position_w, position_w.y); + + //-- create the object + Transform tr; + tr.setPosition_p(position_w); + serverObject = ServerWorld::createNewObject(objectTemplateName, tr, 0, false); + DEBUG_REPORT_LOG (!serverObject, ("LocationResponse: failed to create object %s\n", objectTemplateName)); + if (serverObject) + serverObject->addToWorld (); + } + + //-- inform script of the result + ScriptParams scriptParameters; + scriptParameters.addParam (locationResponse.getLocationId ().c_str()); + scriptParameters.addParam (serverObject ? serverObject->getNetworkId () : NetworkId::cms_invalid); + scriptParameters.addParam (position_w); + scriptParameters.addParam (locationResponse.getRadius ()); + + if (scriptObject->getScriptObject ()->trigAllScripts (Scripting::TRIG_LOCATION_RECEIVED, scriptParameters) != SCRIPT_CONTINUE) + DEBUG_REPORT_LOG (true, ("LocationResponse: TRIG_LOCATION_RECEIVED: did not return SCRIPT_CONTINUE\n")); + } + else if (message.isType("ReleaseCharacterNameByIdMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + NameManager::getInstance().releasePlayerName(msg.getValue()); + } + else if (message.isType("AddAttribModName")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + AttribModNameManager::getInstance().addAttribModNameFromRemote(msg.getValue().c_str()); + } + else if (message.isType("AddAttribModNamesList")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + DEBUG_REPORT_LOG(true, ("Received attrib mod names list <%s> from remote server\n", msg.getValue().c_str())); + AttribModNameManager::getInstance().addAttribModNamesListFromRemote(msg.getValue().c_str()); + } + else if(ClusterWideDataClient::handleMessage(source, message)) + { + // nothing else to do with the message since it was + // handled by the Cluster wide data client + } + else if (message.isType("AiCreatureStateMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + NetworkId const & networkId = msg.getValue().m_networkId; + AiMovementMessage const & movement = msg.getValue().m_movement; + + CreatureObject * const creatureObject = CreatureObject::getCreatureObject(networkId); + + if (creatureObject != NULL) + { + Controller * const controller = creatureObject->getController(); + + if (controller != NULL) + { + DEBUG_LOG("debug_ai", ("GameServer::receiveMessage() Received AiCreatureStateMessage for networkId(%s) movementType(%s)", networkId.getValueString().c_str(), AiMovementBase::getMovementString(movement.getMovementType()))); + + int const flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_SERVER; + + // Movement + + controller->appendMessage(CM_aiSetMovement, 0, new AiMovementMessage(movement), flags); + } + else + { + WARNING(true, ("GameServer::receiveMessage() Received AiCreatureStateMessage for networkId(%s) movementType(%s) but the object does not have a Controller", networkId.getValueString().c_str(), AiMovementBase::getMovementString(movement.getMovementType()))); + } + } + else + { + WARNING(true, ("GameServer::receiveMessage() Received AiCreatureStateMessage for networkId(%s) movementType(%s) but could not resolve to a CreatureObject", networkId.getValueString().c_str(), AiMovementBase::getMovementString(movement.getMovementType()))); + } + } + else if (message.isType("UnloadPersistedCharacter")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const upc(ri); + + ServerObject * const object = ServerWorld::findObjectByNetworkId(upc.getValue()); + if (object) + { + WARNING(true, ("Unloaded character object (%s) which has been persisted but still exists on this game server", object->getDebugInformation().c_str())); + object->unload(); + } + } + else if (message.isType("AboutToLoadCharacterFromDB")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const atlcfdb(ri); + + ServerObject * const object = ServerWorld::findObjectByNetworkId(atlcfdb.getValue().first); + if (object) + { + WARNING(true, ("Unloaded character object (%s) because the character object is about to be loaded from the DB onto game server (%lu), I am game server (%lu)", object->getDebugInformation().c_str(), atlcfdb.getValue().second, getProcessId())); + object->unload(); + } + } + else if (message.isType("ClearTheaterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const ctm(ri); + + ServerUniverse::getInstance().remoteClearTheater(ctm.getValue()); + } + else if (message.isType("SetTheaterMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const stm(ri); + + ServerUniverse::getInstance().remoteSetTheater(stm.getValue().first, stm.getValue().second); + } + else if (message.isType("PageChangeAuthority")) + { + ServerUIManager::receiveMessage(message); + } + else if (message.isType("PlayedTimeAccumMessage")) + { + Archive::ReadIterator ri = static_cast(message).getByteStream().begin(); + PlayedTimeAccumMessage const ptam(ri); + Object * obj = NetworkIdManager::getObjectById(ptam.getNetworkId()); + if (obj != NULL && obj->asServerObject() != NULL && obj->asServerObject()->asCreatureObject() != NULL) + { + CreatureObject * target = obj->asServerObject()->asCreatureObject(); + PlayerObject *targetPlayer = target->asPlayerObject(); + if(targetPlayer) + { + targetPlayer->setPlayedTimeAccumOnly(ptam.getPlayedTimeAccum()); + } + else + { + target->setPseudoPlayedTime(ptam.getPlayedTimeAccum()); + } + } + + } + else if (message.isType("ManualDepleteResourceMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + ServerUniverse::getInstance().manualDepleteResource(msg.getValue()); + } + else if (message.isType("ClaimRewardsReplyMessage")) + { + ri = static_cast(message).getByteStream().begin(); + ClaimRewardsReplyMessage msg(ri); + VeteranRewardManager::handleClaimRewardsReply(msg.getStationId(), msg.getPlayer(), msg.getRewardEvent(), msg.getRewardItem(), msg.getAccountFeatureId(), msg.getConsumeAccountFeatureId(), msg.getPreviousAccountFeatureIdCount(), msg.getCurrentAccountFeatureIdCount(), msg.getResult(), true); + } + else if (message.isType("SetOverrideAccountAgeMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + + VeteranRewardManager::setOverrideAccountAge(msg.getValue()); + } + else if (message.isType("GetMoneyFromOfflineObjectMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GetMoneyFromOfflineObjectMessage msg(ri); + + std::string const & callback = msg.getSuccess() ? msg.getSuccessCallback() : msg.getFailCallback(); + MessageToQueue::getInstance().sendMessageToJava(msg.getReplyTo(), callback, msg.getPackedDictionary(), 0, false); + } + else if (message.isType(SlowDownEffectMessage::MessageType)) + { + ri = static_cast(message).getByteStream().begin(); + SlowDownEffectMessage msg(ri); + + // get the attacker + Object * obj = NetworkIdManager::getObjectById(msg.getSource()); + if (obj != NULL && obj->asServerObject() != NULL && obj->asServerObject()->asCreatureObject() != NULL) + { + CreatureObject * attacker = obj->asServerObject()->asCreatureObject(); + + // get the target + obj = NetworkIdManager::getObjectById(msg.getTarget()); + if (obj != NULL && obj->asServerObject() != NULL && obj->asServerObject()->asTangibleObject() != NULL) + { + TangibleObject * defender = obj->asServerObject()->asTangibleObject(); + if (attacker->isAuthoritative()) + attacker->addSlowDownEffect(*defender, msg.getConeLength(), msg.getConeAngle(), msg.getSlopeAngle(), msg.getExpireTime()); + else + attacker->addSlowDownEffectProxy(*defender, msg.getConeLength(), msg.getConeAngle(), msg.getSlopeAngle(), msg.getExpireTime()); + } + } + } + else if (message.isType("StructuresForPurgeMessage")) + { + ri = static_cast(message).getByteStream().begin(); + StructuresForPurgeMessage msg(ri); + PurgeManager::handleStructuresAndVendorsForPurge(msg.getStationId(), msg.getStructures(), msg.getVendors(), msg.getWarnOnly()); + } + else if (message.isType("RequestLoadAckMessage")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage msg(ri); + + GenericValueTypeMessage reply("LoadAckMessage",msg.getValue()); + sendToDatabaseServer(reply); + } + else if (message.isType("FactionalSystemMessage")) + { + ri = static_cast(message).getByteStream().begin(); + FactionalSystemMessage msg(ri); + handleFactionalSystemMessage(msg); + } + else if (message.isType("MessageToPlayersOnPlanet")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage >, std::pair >, std::pair > > const msg(ri); + handleMessageToPlayersOnPlanet(msg.getValue().first.first.first, msg.getValue().first.first.second, msg.getValue().first.second.first, msg.getValue().second.first, msg.getValue().second.second, msg.getValue().first.second.second); + } + else if (message.isType("PopStatReq")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const populationStatisticsRequest(ri); + UNREF(populationStatisticsRequest); + + const GenericValueTypeMessage > populationStatisticsResponse("PopStatRsp", LfgCharacterData::calculateStatistics(ServerUniverse::getConnectedCharacterLfgData())); + sendToCentralServer(populationStatisticsResponse); + } + else if (message.isType("GcwScoreStatReq")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const gcwScoreStatisticsRequest(ri); + UNREF(gcwScoreStatisticsRequest); + + static const std::map > emptyGcwScore; + PlanetObject const * const tatooine = ServerUniverse::getInstance().getTatooinePlanet(); + + static const std::map emptyGcwScorePercentile; + GuildObject const * const guildObject = ServerUniverse::getInstance().getMasterGuildObject(); + + const GenericValueTypeMessage, std::pair >, std::map > > > > gcwScoreStatisticsResponse("GcwScoreStatRsp", std::make_pair((guildObject ? guildObject->getGcwImperialScorePercentile() : emptyGcwScorePercentile), std::make_pair((tatooine ? tatooine->getGcwImperialScore() : emptyGcwScore), (tatooine ? tatooine->getGcwRebelScore() : emptyGcwScore)))); + sendToCentralServer(gcwScoreStatisticsResponse); + } + else if (message.isType("GcwScoreStatRaw")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage >, std::map > > > > const msg(ri); + if (ConfigServerGame::getReceiveGcwScoreFromOtherGalaxies() && ServerUniverse::getInstance().isAuthoritative() && _stricmp(getClusterName().c_str(), msg.getValue().first.c_str())) + { + GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); + if (go && go->isAuthoritative()) + { + go->setGcwRawScoreFromOtherGalaxy(msg.getValue().first, msg.getValue().second.first, msg.getValue().second.second); + } + } + } + else if (message.isType("GcwScoreStatPct")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::map > > > const msg(ri); + if (ConfigServerGame::getReceiveGcwScoreFromOtherGalaxies() && ServerUniverse::getInstance().isAuthoritative() && _stricmp(getClusterName().c_str(), msg.getValue().first.c_str())) + { + GuildObject * const go = ServerUniverse::getInstance().getMasterGuildObject(); + if (go && go->isAuthoritative()) + { + go->setGcwImperialScorePercentileFromOtherGalaxy(msg.getValue().first, msg.getValue().second.first, msg.getValue().second.second); + } + } + } + else if (message.isType("LLTStatReq")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const lastLoginTimeStatisticsRequest(ri); + UNREF(lastLoginTimeStatisticsRequest); + + static std::map > lastLoginTimeStatistics; + if (lastLoginTimeStatistics.empty()) + { + lastLoginTimeStatistics[(60 * 60 * 24 * 1)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day001"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 2)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day002"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 3)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day003"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 4)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day004"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 5)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day005"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 6)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day006"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 7)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day007"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 14)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day014"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 21)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day021"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 30)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day030"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 60)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day060"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 90)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day090"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 180)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day180"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 270)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Day270"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 365)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Year1"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 730)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Year2"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 1095)] = std::make_pair(std::string("totalCharacters.loginWithinPast_Year3"), 0); + lastLoginTimeStatistics[(60 * 60 * 24 * 9999)] = std::make_pair(std::string("totalCharacters"), 0); + } + + NameManager::getInstance().getPlayerWithLastLoginTimeAfterDistribution(lastLoginTimeStatistics); + + std::map >::iterator iter = lastLoginTimeStatistics.begin(); + std::map >::iterator previousIter = lastLoginTimeStatistics.begin(); + for (; iter != lastLoginTimeStatistics.end(); ++iter) + { + if (iter != previousIter) + iter->second.second += previousIter->second.second; + + previousIter = iter; + } + + static std::map > createTimeStatistics; + if (createTimeStatistics.empty()) + { + createTimeStatistics[(60 * 60 * 24 * 1)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day001"), 0); + createTimeStatistics[(60 * 60 * 24 * 2)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day002"), 0); + createTimeStatistics[(60 * 60 * 24 * 3)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day003"), 0); + createTimeStatistics[(60 * 60 * 24 * 4)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day004"), 0); + createTimeStatistics[(60 * 60 * 24 * 5)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day005"), 0); + createTimeStatistics[(60 * 60 * 24 * 6)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day006"), 0); + createTimeStatistics[(60 * 60 * 24 * 7)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day007"), 0); + createTimeStatistics[(60 * 60 * 24 * 14)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day014"), 0); + createTimeStatistics[(60 * 60 * 24 * 21)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day021"), 0); + createTimeStatistics[(60 * 60 * 24 * 30)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day030"), 0); + createTimeStatistics[(60 * 60 * 24 * 60)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day060"), 0); + createTimeStatistics[(60 * 60 * 24 * 90)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day090"), 0); + createTimeStatistics[(60 * 60 * 24 * 180)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day180"), 0); + createTimeStatistics[(60 * 60 * 24 * 270)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Day270"), 0); + createTimeStatistics[(60 * 60 * 24 * 365)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Year1"), 0); + createTimeStatistics[(60 * 60 * 24 * 730)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Year2"), 0); + createTimeStatistics[(60 * 60 * 24 * 1095)] = std::make_pair(std::string("totalCharacters.createdWithinPast_Year3"), 0); + createTimeStatistics[(60 * 60 * 24 * 9999)] = std::make_pair(std::string("totalCharacters"), 0); + } + + NameManager::getInstance().getPlayerWithCreateTimeAfterDistribution(createTimeStatistics); + + iter = createTimeStatistics.begin(); + previousIter = createTimeStatistics.begin(); + for (; iter != createTimeStatistics.end(); ++iter) + { + if (iter != previousIter) + iter->second.second += previousIter->second.second; + + previousIter = iter; + } + + const GenericValueTypeMessage >, std::map > > > lastLoginTimeStatisticsResponse("LLTStatRsp", std::make_pair(lastLoginTimeStatistics, createTimeStatistics)); + sendToCentralServer(lastLoginTimeStatisticsResponse); + } + else if (message.isType("LfgStatReq")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const characterMatchStatisticsRequest(ri); + UNREF(characterMatchStatisticsRequest); + + unsigned long numberOfCharacterMatchRequests, numberOfCharacterMatchResults, timeSpentOnCharacterMatchRequestsMs; + CharacterMatchManager::getMatchStatistics(numberOfCharacterMatchRequests, numberOfCharacterMatchResults, timeSpentOnCharacterMatchRequestsMs); + + if (numberOfCharacterMatchRequests || numberOfCharacterMatchResults || timeSpentOnCharacterMatchRequestsMs) + { + CharacterMatchManager::clearMatchStatistics(); + + const GenericValueTypeMessage > > characterMatchStatisticsResponse("LfgStatRsp", std::make_pair(numberOfCharacterMatchRequests, std::make_pair(numberOfCharacterMatchResults, timeSpentOnCharacterMatchRequestsMs))); + sendToCentralServer(characterMatchStatisticsResponse); + } + } + else if (message.isType("ClusterId")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage const msg(ri); + + if (m_clusterId == 0) + { + FATAL(((msg.getValue() < 1) || (msg.getValue() > 255)),("Cluster Id (%lu) must be between 1 and 255 inclusive", msg.getValue())); + + m_clusterId = static_cast(msg.getValue()); + } + } + else if (message.isType("OccupyUnlockedSlotRsp")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, uint32> > const occupyUnlockedSlotRsp(ri); + + char buffer[32]; + snprintf(buffer, sizeof(buffer)-1, "%d", occupyUnlockedSlotRsp.getValue().first.first); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(occupyUnlockedSlotRsp.getValue().first.second, + "C++OccupyUnlockedSlotRsp", + buffer, + 0, + false); + } + else if (message.isType("VacateUnlockedSlotRsp")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > const vacateUnlockedSlotRsp(ri); + + char buffer[32]; + snprintf(buffer, sizeof(buffer)-1, "%d", vacateUnlockedSlotRsp.getValue().first.first); + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(vacateUnlockedSlotRsp.getValue().first.second, + "C++VacateUnlockedSlotRsp", + buffer, + 0, + false); + } + else if (message.isType("SwapUnlockedSlotRsp")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage, std::pair > > > const swapUnlockedSlotRsp(ri); + + Archive::ByteStream bs; + swapUnlockedSlotRsp.pack(bs); + + MessageToQueue::getInstance().sendMessageToC(swapUnlockedSlotRsp.getValue().first.second, + "C++SwapUnlockedSlotRsp", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } + else if (message.isType("AdjustAccountFeatureIdResponse")) + { + ri = static_cast(message).getByteStream().begin(); + AdjustAccountFeatureIdResponse const msg(ri); + + handleAdjustAccountFeatureIdResponse(msg); + } + else if (message.isType("AccountFeatureIdResponse")) + { + ri = static_cast(message).getByteStream().begin(); + AccountFeatureIdResponse const msg(ri); + + handleAccountFeatureIdResponse(msg); + } + else if (message.isType("FeatureIdTransactionResponse")) + { + ri = static_cast(message).getByteStream().begin(); + FeatureIdTransactionResponse const msg(ri); + + Archive::ByteStream bs; + msg.pack(bs); + + MessageToQueue::getInstance().sendMessageToC(msg.getPlayer(), + "C++FeatureIdTransactionResponse", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } + else if (message.isType("TransferReplyMoveValidation")) + { + ri = static_cast(message).getByteStream().begin(); + TransferReplyMoveValidation const msg(ri); + + Archive::ByteStream bs; + msg.pack(bs); + + MessageToQueue::getInstance().sendMessageToC(msg.getSourceCharacterId(), + "C++TransferReplyMoveValidation", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } + else if (message.isType("TransferReplyNameValidation")) + { + ri = static_cast(message).getByteStream().begin(); + GenericValueTypeMessage > const msg(ri); + + Archive::ByteStream bs; + msg.pack(bs); + + MessageToQueue::getInstance().sendMessageToC(msg.getValue().second.getCharacterId(), + "C++TransferReplyNameValidation", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } + else if (message.isType("CreateDynamicSpawnRegionCircleMessage")) + { + ri = static_cast(message).getByteStream().begin(); + CreateDynamicSpawnRegionCircleMessage const msg(ri); + + RegionMaster::createNewDynamicRegionWithSpawn(msg.getCenterX(), msg.getCenterY(), msg.getCenterZ(), msg.getRadius(), msg.getName(), msg.getPlanet(), + msg.getPvp(), msg.getBuildable(), msg.getMunicipal(), msg.getGeography(), msg.getMinDifficulty(), msg.getMaxDifficulty(), + msg.getSpawnable(), msg.getMission(), msg.getVisible(), msg.getNotify(), msg.getSpawntable(), msg.getDuration()); + } +} + +// ---------------------------------------------------------------------- + +bool GameServer::isPlanetEnabledForCluster(std::string const &sceneName) const +{ + // look up [CentralServer] startPlanet=sceneName[:whatever] + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("CentralServer", "startPlanet", index++, 0); + // result must either match sceneName completely, or match all of sceneName and be followed by a ':' + if ( result + && ( !strcmp(result, sceneName.c_str()) + || ( !strncmp(result, sceneName.c_str(), sceneName.size()) + && result[sceneName.size()] == ':'))) + return true; + } while (result); + + return false; +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::broadCastHyperspaceOnWarp(ServerObject const * const owner) +{ + // warpingClient can be NULL if the owner is AI + Client const * const warpingClient = owner->getClient(); + + typedef std::map > DistributionList; + DistributionList distributionList; + + // Build distribution list of clients observing ship + { + typedef std::set ObserverList; + ObserverList const & observers = owner->getObservers(); + + ObserverList::const_iterator ii = observers.begin(); + ObserverList::const_iterator iiEnd = observers.end(); + for (; ii != iiEnd; ++ii) + { + Client * const client = *ii; + if (client != warpingClient) + { + distributionList[client->getConnection()].push_back(client->getCharacterObjectId()); + } + } + } + + // Send Message to distribution list + { + DistributionList::const_iterator ii = distributionList.begin(); + DistributionList::const_iterator iiEnd = distributionList.end(); + for (; ii != iiEnd; ++ii) + { + HyperspaceMessage const hyperspaceMessage(owner->getNetworkId()); + GameClientMessage const gameClientMessage(ii->second, true, hyperspaceMessage); + ii->first->send(gameClientMessage, true); + } + } +} + +/** + * Warping an object to a different scene. + */ +bool GameServer::requestSceneWarp(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newContainer, const Vector &newPosition_p, const char * scriptCallback, bool forceLoadScreen) +{ + ServerObject * const object = dynamic_cast(objectId.getObject()); + if (!object) + return false; + + if (!isPlanetEnabledForCluster(sceneName)) + { + DEBUG_WARNING(true, ("GameServer::requestSceneWarp(1) for unknown scene %s", sceneName.c_str())); + return false; + } + + Vector destPosition_w(newPosition_w); + + // clamp destination if in space + if ( !strncmp(sceneName.c_str(), "space_", 6) + && ( std::abs(newPosition_w.x) > 8000.f + || std::abs(newPosition_w.y) > 8000.f + || std::abs(newPosition_w.z) > 8000.f)) + { + WARNING(true, ("Tried to warp object %s outside of space zone boundaries (%g,%g,%g)", object->getDebugInformation().c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z)); + destPosition_w.set( + clamp(-8000.f, newPosition_w.x, 8000.f), + clamp(-8000.f, newPosition_w.y, 8000.f), + clamp(-8000.f, newPosition_w.z, 8000.f)); + } + + if (ServerWorld::getSceneId() == sceneName) + { + // if a pilot is doing a same scene warp, actually move the ship, and only allow in world coords + CreatureObject * const objAsCreature = object->asCreatureObject(); + if (objAsCreature) + { + ShipObject * const ship = getAttachedShip(objAsCreature); + if (ship) + { + broadCastHyperspaceOnWarp(ship); + ship->teleportObject(destPosition_w, NetworkId::cms_invalid, "", destPosition_w, scriptCallback ? scriptCallback : "", forceLoadScreen); + } + else + object->teleportObject(destPosition_w, newContainer, "", newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); + } + else + object->teleportObject(destPosition_w, newContainer, "", newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); + } + else + { + // don't send multiple RequestSceneTransfer message + if (!checkAndSetOutstandingRequestSceneTransfer(*object)) + { + RequestSceneTransfer const sceneTransferMessage(objectId, sceneName, getProcessId(), newPosition_p, destPosition_w, newContainer, scriptCallback); + sendToCentralServer(sceneTransferMessage); + } + } + + return true; +} + +//----------------------------------------------------------------------- + +/** + * Warping an object to a different scene. + */ +bool GameServer::requestSceneWarp(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newBuilding, const std::string &newContainerName, const Vector &newPosition_p, const char * scriptCallback, bool forceLoadScreen) +{ + ServerObject * const object = dynamic_cast(objectId.getObject()); + if (!object) + return false; + + if (!isPlanetEnabledForCluster(sceneName)) + { + DEBUG_WARNING(true, ("GameServer::requestSceneWarp(1) for unknown scene %s", sceneName.c_str())); + return false; + } + + Vector destPosition_w(newPosition_w); + + // clamp destination if in space + if ( !strncmp(sceneName.c_str(), "space_", 6) + && ( std::abs(newPosition_w.x) > 8000.f + || std::abs(newPosition_w.y) > 8000.f + || std::abs(newPosition_w.z) > 8000.f)) + { + WARNING(true, ("Tried to warp object %s outside of space zone boundaries (%g,%g,%g)", object->getDebugInformation().c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z)); + destPosition_w.set( + clamp(-8000.f, newPosition_w.x, 8000.f), + clamp(-8000.f, newPosition_w.y, 8000.f), + clamp(-8000.f, newPosition_w.z, 8000.f)); + } + + if (ServerWorld::getSceneId() == sceneName) + { + // if a pilot is doing a same scene warp, actually move the ship, and only allow in world coords + CreatureObject * const objAsCreature = object->asCreatureObject(); + if (objAsCreature) + { + ShipObject * const ship = getAttachedShip(objAsCreature); + if (ship) + { + broadCastHyperspaceOnWarp(ship); + ship->teleportObject(destPosition_w, NetworkId::cms_invalid, "", destPosition_w, scriptCallback ? scriptCallback : "", forceLoadScreen); + } + else + object->teleportObject(destPosition_w, newBuilding, newContainerName, newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); + } + else + object->teleportObject(destPosition_w, newBuilding, newContainerName, newPosition_p, scriptCallback ? scriptCallback : "", forceLoadScreen); + } + else + { + // don't send multiple RequestSceneTransfer message + if (!checkAndSetOutstandingRequestSceneTransfer(*object)) + { + RequestSceneTransfer const sceneTransferMessage(objectId, sceneName, getProcessId(), newPosition_p, destPosition_w, newBuilding, newContainerName, scriptCallback); + sendToCentralServer(sceneTransferMessage); + } + } + + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Warping an object to a different scene after a delay. + */ +bool GameServer::requestSceneWarpDelayed(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newContainer, const Vector &newPosition_p, float const delayTime, const char * scriptCallback, bool forceLoadScreen) +{ + Object * const o = objectId.getObject(); + ServerObject * const so = o ? o->asServerObject() : 0; + ShipObject * const ship = so ? so->asShipObject() : 0; + + if (!ship || !ship->isInWorld()) + return false; + + ship->setHyperspaceOnDestroy(true); + + typedef std::vector Passengers; + Passengers passengers; + + ship->findAllPassengers(passengers, true); + + Passengers::const_iterator ii = passengers.begin(); + Passengers::const_iterator iiEnd = passengers.end(); + + for (; ii != iiEnd; ++ii) + { + CreatureObject * const passenger = *ii; + Controller * const controller = passenger->getController(); + + if (controller != 0) + { + MessageQueueGenericValueType > * const data = new MessageQueueGenericValueType >(std::make_pair(sceneName, newPosition_w)); + + controller->appendMessage( + CM_aboutToHyperspace, + 0.0f, + data, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } + + char buf[1000]; + std::string callbackStr = scriptCallback; + snprintf(buf, sizeof(buf) - 1, "%s %.2f %.2f %.2f %s %.2f %.2f %.2f %s %d", sceneName.c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z, newContainer.getValueString().c_str(), newPosition_p.x, newPosition_p.y, newPosition_p.z, (!callbackStr.empty()) ? callbackStr.c_str() : "noCallback", (forceLoadScreen) ? 1 : 0); + MessageToQueue::getInstance().sendMessageToC(objectId, "C++SceneWarpDelayed", buf, static_cast(delayTime), false); + + return true; +} + +//----------------------------------------------------------------------- + +/** + * Warping an object to a different scene after a delay. + */ +bool GameServer::requestSceneWarpDelayed(const CachedNetworkId &objectId, const std::string &sceneName, const Vector &newPosition_w, const NetworkId &newBuilding, const std::string &newContainerName, const Vector &newPosition_p, float const delayTime, const char * scriptCallback, bool forceLoadScreen) +{ + Object * const o = objectId.getObject(); + ServerObject * const so = o ? o->asServerObject() : 0; + ShipObject * const ship = so ? so->asShipObject() : 0; + + if (!ship || !ship->isInWorld()) + return false; + + typedef std::vector Passengers; + Passengers passengers; + + ship->findAllPassengers(passengers, true); + + Passengers::const_iterator ii = passengers.begin(); + Passengers::const_iterator iiEnd = passengers.end(); + + for (; ii != iiEnd; ++ii) + { + CreatureObject * const passenger = *ii; + Controller * const controller = passenger->getController(); + + if (controller != 0) + { + MessageQueueGenericValueType > * const data = new MessageQueueGenericValueType >(std::make_pair(sceneName, newPosition_w)); + + controller->appendMessage( + CM_aboutToHyperspace, + 0.0f, + data, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } + + char buf[1000]; + std::string callbackStr = scriptCallback; + snprintf(buf, sizeof(buf) - 1, "%s %.2f %.2f %.2f %s %s %.2f %.2f %.2f %s %d", sceneName.c_str(), newPosition_w.x, newPosition_w.y, newPosition_w.z, newBuilding.getValueString().c_str(), newContainerName.c_str(), newPosition_p.x, newPosition_p.y, newPosition_p.z, (!callbackStr.empty()) ? callbackStr.c_str() : "none", (forceLoadScreen) ? 1 : 0); + MessageToQueue::getInstance().sendMessageToC(objectId, "C++SceneWarpDelayedContainer", buf, static_cast(delayTime), false); + + return true; +} + +// ---------------------------------------------------------------------- + +unsigned long GameServerNamespace::getFrameRateLimit() +{ + return ServerWorld::isSpaceScene() ? ConfigServerGame::getSpaceFrameRateLimit() : ConfigServerGame::getGroundFrameRateLimit(); +} + +// ---------------------------------------------------------------------- + +void GameServer::run(void) +{ + static const std::string frameLogChannel = "EndFrame:Time"; + static const std::string frameLogCount = "EndFrame:Objects"; + + getInstance().initialize(); + + unsigned long lastFrameTime = 0; + int oldFilesOpened = TreeFile::getNumberOfFilesOpenedTotal(); + int oldSizeOpened = TreeFile::getSizeOfFilesOpenedTotal(); + int newFilesOpened = 0; + int newSizeOpened = 0; + unsigned long startTime = Clock::timeMs(); + unsigned long lastFrameProcessStartTime = startTime; + + const unsigned long targetFrameTime = static_cast(1000.0f/getFrameRateLimit()); + + const GenericValueTypeMessage gameServerTaskManagerKeepAlive("GameServerTaskManagerKeepAlive", Os::getProcessId()); + + PROFILER_BLOCK_DEFINE(profileBlockMainLoop, "main loop"); + PROFILER_BLOCK_ENTER(profileBlockMainLoop); + + LOG("ServerStartup",("GameServer starting on %s", NetworkHandler::getHostName().c_str())); // no process id yet + s_frameTime = 0; + + while (!getInstance().getDone()) + { + if(getInstance().m_taskManagerConnection) + { + getInstance().m_taskManagerConnection->send(gameServerTaskManagerKeepAlive, true); + s_lastTaskKeepaliveTime = Clock::timeMs(); + } + + newFilesOpened = TreeFile::getNumberOfFilesOpenedTotal(); + newSizeOpened = TreeFile::getSizeOfFilesOpenedTotal(); + + if ( lastFrameTime > ConfigServerGame::getLoopProfileLogThresholdMs() + || (ServerWorld::isSpaceScene() && lastFrameTime > ConfigServerGame::getSpaceLoopProfileLogThresholdMs()) + || (!ServerWorld::isSpaceScene() && lastFrameTime > ConfigServerGame::getGroundLoopProfileLogThresholdMs())) + { + LOG("profile", ("Long loop (%u ms):\n%s", lastFrameTime, PROFILER_GET_LAST_FRAME_DATA())); + if (newFilesOpened > oldFilesOpened) + LOG("treefile", ("Long loop file stats: %d opened %d size", newFilesOpened - oldFilesOpened, newSizeOpened - oldSizeOpened)); + } + + oldFilesOpened = newFilesOpened; + oldSizeOpened = newSizeOpened; + + { + PROFILER_AUTO_BLOCK_DEFINE("NetFlushAllData"); + NetworkHandler::flushAndConfirmAll(); + } + + bool barrierReached = true; + + do + { + PROFILER_AUTO_BLOCK_DEFINE("BarrierWait"); + + { + PROFILER_AUTO_BLOCK_DEFINE("NetworkHandler::update"); + NetworkHandler::update(); + } + + if ((ServerWorld::isSpaceScene() && ConfigServerGame::getSpaceShouldSleep()) + || (!ServerWorld::isSpaceScene() && ConfigServerGame::getGroundShouldSleep())) + { + PROFILER_AUTO_BLOCK_DEFINE("Os::sleep"); + Os::sleep(1); + } + + if (ConfigServerGame::getCommoditiesMarketEnabled()) + { + PROFILER_AUTO_BLOCK_DEFINE("CommoditiesMarket::giveTime"); + CommoditiesMarket::giveTime(); + } + + // Note: adding 15 ms to the time passed here to adjust for minimum sleep times + barrierReached = Clock::timeMs()-lastFrameProcessStartTime+15 >= targetFrameTime; + + getInstance().debugIO(); + } while (!barrierReached && !getInstance().getDone()); + + lastFrameProcessStartTime = Clock::timeMs(); + + if (!Os::update()) + getInstance().setDone("OS condition (Parent pid change)"); + + { + PROFILER_AUTO_BLOCK_DEFINE("MetricsManager::update"); + if (s_metricsManagerInstalled) + MetricsManager::update(static_cast(lastFrameTime)); + } + + { + PROFILER_AUTO_BLOCK_DEFINE("ServerWorld::update"); + ServerWorld::update(Clock::frameTime()); + } + + { + PROFILER_AUTO_BLOCK_DEFINE("ServerUniverse::update"); + ServerUniverse::getInstance().update(Clock::frameTime()); + } + + NonCriticalTaskQueue::getInstance().update(); + { + PROFILER_AUTO_BLOCK_DEFINE("MessageToQueue::update"); + MessageToQueue::getInstance().update(Clock::frameTime()); + } + +#ifdef _DEBUG + // do an intentional sleep, to emulate long loop time + if (s_extraDelayPerFrameMs > 0) + { + PROFILER_AUTO_BLOCK_DEFINE("Os::sleep - extra"); + Os::sleep(s_extraDelayPerFrameMs); + } +#endif + + { + // Report the population at the same time on all game servers in the cluster + static bool alreadyReported(false); + if ((time(0) % ConfigServerGame::getPopulationReportTimeSeconds()) == 0) + { + if (!alreadyReported) + { + LOG("PopulationReport",("server %s:%lu population %i",ServerWorld::getSceneId().c_str(),getInstance().m_preloadAreaId,getInstance().m_clients->size())); + alreadyReported=true; + } + } + else + alreadyReported=false; + } + + unsigned long curTime = Clock::timeMs(); + lastFrameTime = curTime-startTime; + if (!getInstance().getDone()) + ServerClock::getInstance().incrementServerFrame(); + startTime = curTime; + + getInstance().checkIdleClients(Clock::frameTime()); + if (!getInstance().m_gameServerReadyDatabaseConnected && getInstance().m_connectionTimeout!=0 && (curTime > getInstance().m_connectionTimeout)) + FATAL(true,("Failed to resolve connections to all the other game servers within %i seconds",ConfigServerGame::getConnectToAllGameServersTimeout())); + + PROFILER_BLOCK_LEAVE(profileBlockMainLoop); + PROFILER_BLOCK_ENTER(profileBlockMainLoop); + if (getInstance().getDatabaseProcessId()) + { + FrameEndMessage const emptyFrameEndMessage(getInstance().getProcessId(), lastFrameTime, ""); + getInstance().sendToDatabaseServer(emptyFrameEndMessage); + if (ConfigServerGame::getSendFrameProfilerInfo()) + { + FrameEndMessage const frameEndMessage(getInstance().getProcessId(), lastFrameTime, PROFILER_GET_LAST_FRAME_DATA()); + getInstance().sendToPlanetServer(frameEndMessage); + } + else + getInstance().sendToPlanetServer(emptyFrameEndMessage); + NetworkHandler::clearBytesThisFrame(); + } + s_frameTime = curTime - lastFrameProcessStartTime; + } + + LOG("ServerStartup",("GameServer %lu exiting",getInstance().getProcessId())); + + PROFILER_BLOCK_LEAVE(profileBlockMainLoop); + + getInstance().shutdown(); + +} + +//----------------------------------------------------------------------- + +void GameServer::sendToDatabaseServer(GameNetworkMessage const &message) +{ + if (m_databaseProcessConnection) + m_databaseProcessConnection->send(message, true); + else + DEBUG_FATAL(!m_done, ("Unable to send network message to database server while not flagged for shutdown")); + } + +// ---------------------------------------------------------------------- + +std::vector const &GameServer::getAllGameServerPids() const +{ + return m_gameServerPids; +} + +// ---------------------------------------------------------------------- + +bool GameServer::hasConnectionsToOtherGameServers() const +{ + return !(m_gameServerPids.empty()); +} + +// ---------------------------------------------------------------------- + +void GameServer::sendToCentralServer(GameNetworkMessage const &message) +{ + if(m_centralServerConnection) + { + m_centralServerConnection->send(message, true); + } + else + { + DEBUG_REPORT_LOG(true,("Tried to send a message to Central Server, but it was not connected.\n")); + } +} + +// ---------------------------------------------------------------------- + +void GameServer::sendToPlanetServer(GameNetworkMessage const &message) +{ + if (m_planetServerConnection) + { + m_planetServerConnection->send(message, true); + } + else + { + DEBUG_REPORT_LOG(true,("Tried to send a message to Planet Server, but it was not connected.\n")); + } +} + +// ---------------------------------------------------------------------- + +void GameServer::sendToConnectionServers(GameNetworkMessage const &message) +{ + ConnectionServerVector v(*m_connectionServerVector); + for (ConnectionServerVector::iterator i = v.begin(); i != v.end(); ++i) + (*i)->send(message, true); +} + +// ---------------------------------------------------------------------- + +void GameServer::sendToCustomerServiceServer(GameNetworkMessage const &message) +{ + if (m_customerServiceServerConnection != NULL) + { + m_customerServiceServerConnection->send(message, true); + } + else + { + REPORT_LOG(true, ("GameServer::sendToCustomerServiceServer() ERROR: Unable to send to NULL customer service server connection\n")); + } +} + +// ---------------------------------------------------------------------- + +void GameServer::clearCustomerServiceServerConnection() +{ + if (m_customerServiceServerConnection != NULL) + { + m_customerServiceServerConnection->disconnect(); + } + + m_customerServiceServerConnection = NULL; +} + +// ---------------------------------------------------------------------- + +/** + * Call when we are connected to the database process. + * Prerequisite to gameServerReady() + */ +void GameServer::onDatabaseProcessConnectionEstablished() +{ + LOG("GameGameConnect", ("Game Server %lu is connected to database process", m_processId)); + m_gameServerReadyDatabaseConnected = true; + checkWhetherGameServerIsReady(); +} + +// ---------------------------------------------------------------------- + +/** + * Call when we have at least one block of objectId's. + * Prerequisite to gameServerReady() + */ +void GameServer::onReceivedFirstNetworkIdBlock() +{ + LOG("GameGameConnect", ("Game Server %lu has received first netId block", m_processId)); + m_gameServerReadyObjectIds = true; + checkWhetherGameServerIsReady(); +} + +// ---------------------------------------------------------------------- + +/** + * Call when we have at least one block of objectId's. + * Prerequisite to gameServerReady() + */ +void GameServer::onPlanetServerConnectionEstablished() +{ + LOG("GameGameConnect", ("Game Server %lu is connected to planet server", m_processId)); + m_gameServerReadyPlanetConnected = true; + checkWhetherGameServerIsReady(); +} + +// ---------------------------------------------------------------------- + +/** + * Call after each asynchronous step of initializing the game server. + * If all steps are completed, calls gameServerReady() + */ +void GameServer::checkWhetherGameServerIsReady() +{ + if (m_gameServerReadyDatabaseConnected && m_gameServerReadyObjectIds && m_gameServerReadyPlanetConnected) + gameServerReady(); +} + +// ---------------------------------------------------------------------- + +/** + * Call this function when we are ready to handle receiving objects. + * Notifies Central, who may tell other game servers to give + * us proxy objects now or may tell us to create new objects. + */ +void GameServer::gameServerReady() +{ + static int callCount(0); + UNREF(callCount); + DEBUG_FATAL(getProcessId()==0,("gameServerReady() was called before process ID was set.\n")); + DEBUG_FATAL((callCount++)!=0,("gameServerReady() was called more than once.\n")); + + LOG("GameGameConnect", ("Game Server %d is ready!", m_processId)); + GameServerReadyMessage const msg(static_cast(NON_NULL(TerrainObject::getInstance())->getMapWidthInMeters())); + sendToCentralServer(msg); + sendToPlanetServer(msg); +} + +// ---------------------------------------------------------------------- + +const StringId GameServer::verifyCharacterName(const std::string &templateName, const Unicode::String &name, bool forPlayer) const +{ + const ServerCreatureObjectTemplate * serverTemplate = getServerCreatureObjectTemplate(templateName); + if (!serverTemplate) + return NameErrors::nameDeclinedNotCreatureTemplate; + + const StringId & verified = verifyCharacterName(*serverTemplate, name, forPlayer); + serverTemplate->releaseReference(); + + return verified; +} + +// ---------------------------------------------------------------------- + +const StringId GameServer::verifyCharacterName(const ServerCreatureObjectTemplate &serverTemplate, const Unicode::String &name, bool forPlayer) const +{ + if (ConfigServerGame::getNameValidationAcceptAll()) + return NameErrors::nameApproved; + + if (name.empty()) + return NameErrors::nameDeclinedEmpty; + + // Check for appropriateness based on race + if (!NameManager::getInstance().isNameAppropriate(ConfigServerGame::getCharacterNameGeneratorDirectory(),serverTemplate.getNameGeneratorType(),name)) + return NameErrors::nameDeclinedRaciallyInappropriate; + + // Now match against reserved names and profanity + std::string reasonDescription; + if (NameManager::getInstance().isNameReserved(name,reasonDescription)) + return StringId(NameErrors::localizationFile,reasonDescription); + else + return NameErrors::nameApproved; +} + +//-------------------------------------------------------------------- + +void GameServer::handleCreateCharacter(const CentralCreateCharacter * createMessage) +{ + LOG("TraceCharacterCreation", ("%d received CentralCreateCharacter(%d, %s, ...)", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + if (m_charactersPendingCreation->find(createMessage->getStationId()) != m_charactersPendingCreation->end()) + { + LOG("TraceCharacterCreation", ("%d name verification for that name is still pending, sending GameCreateCharacterFailed(%d, %s, NameErrors::nameDeclinedRetry) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + DEBUG_REPORT_LOG(true, ("Received character creation request for account %li, but we are still pending a name verification for that id\n",createMessage->getStationId())); + GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedRetry, FormattedString<2048>().sprintf("%lu name verification for that name is still pending, sending GameCreateCharacterFailed(%lu, %s, NameErrors::nameDeclinedRetry) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + sendToCentralServer(characterCreateFailed); + delete createMessage; + return; + } + + const std::string & templateName = createMessage->getTemplateName(); + DEBUG_REPORT_LOG(true, ("Received character creation request for account %li (name %s, template %s)\n",createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str(), templateName.c_str())); + if(templateName.empty ()) + { + LOG("TraceCharacterCreation", ("%d sent an empty template name, sending GameCreateCharacterFailed(%d, %s, NameErrors::nameDeclinedNoTemplate) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + DEBUG_REPORT_LOG(true, ("The template was empty\n")); + // Tell central we couldn't create the character + GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedNoTemplate, FormattedString<2048>().sprintf("%lu sent an empty template name, sending GameCreateCharacterFailed(%lu, %s, NameErrors::nameDeclinedNoTemplate) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + sendToCentralServer(characterCreateFailed); + delete createMessage; + return; + } + + if (!SpeciesRestrictions::canCreateCharacter(createMessage->getGameFeatures(), Crc::calculate(templateName.c_str()))) + { + LOG("TraceCharacterCreation", ("%d sent a species template name their account was not authorized to use. Template was %s", createMessage->getStationId(), templateName.c_str())); + // Tell central we couldn't create the character + GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedNotAuthorizedForSpecies, FormattedString<2048>().sprintf("%lu sent a species template name their account was not authorized to use. Template was %s", createMessage->getStationId(), templateName.c_str())); + sendToCentralServer(characterCreateFailed); + delete createMessage; + return; + } + + StringId avatarReason = canCreateAvatar(templateName); + if (avatarReason != NameErrors::nameApproved) + { + LOG("TraceCharacterCreation", ("%d canCreateAvatar(%s) failed, sending GameCreateCharacterFailed(%d, %s, REASON) to central server", createMessage->getStationId(), createMessage->getTemplateName().c_str(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + DEBUG_REPORT_LOG(true, ("Can't create avatar\n")); + GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), avatarReason, FormattedString<2048>().sprintf("%lu canCreateAvatar(%s) failed, sending GameCreateCharacterFailed(%lu, %s, REASON) to central server", createMessage->getStationId(), createMessage->getTemplateName().c_str(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + sendToCentralServer(characterCreateFailed); + delete createMessage; + return; + } + + // verify the name against static tests - length, character set, etc. + StringId VerifyNameResponse = verifyCharacterName(templateName, createMessage->getCharacterName(), true); + if (VerifyNameResponse != NameErrors::nameApproved) + { + LOG("TraceCharacterCreation", ("%d VerifyNameResponse != NameErrors::nameApproved, sending GameCreateCharacterFailed(%d, %s, REASON) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), VerifyNameResponse, FormattedString<2048>().sprintf("%lu VerifyNameResponse != NameErrors::nameApproved, sending GameCreateCharacterFailed(%lu, %s, REASON) to central server", createMessage->getStationId(), createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + sendToCentralServer(characterCreateFailed); + delete createMessage; + return; + } + + // verify the name against known existing names + if (NameManager::getInstance().getPlayerId(NameManager::normalizeName(Unicode::wideToNarrow(createMessage->getCharacterName()))) != NetworkId::cms_invalid) + { + LOG("TraceCharacterCreation", ("%d character create name %s is in use, sending GameCreateCharacterFailed", createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + DEBUG_REPORT_LOG(true, ("Character create name %s is in use, declined for stationId %lu\n", Unicode::wideToNarrow(createMessage->getCharacterName()).c_str(), createMessage->getStationId())); + GameCreateCharacterFailed const characterCreateFailed(createMessage->getStationId(), createMessage->getCharacterName(), NameErrors::nameDeclinedInUse, FormattedString<2048>().sprintf("%lu character create name %s is in use, sending GameCreateCharacterFailed", createMessage->getStationId(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + sendToCentralServer(characterCreateFailed); + delete createMessage; + return; + } + + // Now verify against the database. + LOG("TraceCharacterCreation", ("%d sending VerifyNameRequest(%d, %s, %s) to the database for validation", createMessage->getStationId(), createMessage->getStationId(), createMessage->getTemplateName().c_str(), Unicode::wideToNarrow(createMessage->getCharacterName()).c_str())); + VerifyNameRequest const vrn(createMessage->getStationId(), NetworkId::cms_invalid, createMessage->getTemplateName(), createMessage->getCharacterName()); + sendToDatabaseServer(vrn); + (*m_charactersPendingCreation)[createMessage->getStationId()] = createMessage; +} + +//-------------------------------------------------------------------- + +void GameServer::handleNameFailure(const RandomNameRequest &request, const StringId &errorMessage) +{ + LOG("TraceCharacterCreation", ("%d sending RandomNameResponse(%d, %s, REASON) to central server", request.getStationId(), request.getCreatureTemplate().c_str())); + RandomNameResponse const rnr(request.getStationId(), request.getCreatureTemplate(), Unicode::String(), errorMessage); + sendToCentralServer(rnr); +} + +//-------------------------------------------------------------------- + +void GameServer::handleNameRequest(const RandomNameRequest &request) +{ + DEBUG_REPORT_LOG(true, ("Random name requested for stationId %lu\n", request.getStationId())); + + std::map::iterator findPendingCreation=m_charactersPendingCreation->find(request.getStationId()); + if (findPendingCreation != m_charactersPendingCreation->end()) + { + LOG("TraceCharacterCreation", ("%d received random name request after CharacterCreationRequest, ignoring request", request.getStationId())); + DEBUG_REPORT_LOG(true, ("Received random name request after CharacterCreation request")); + return; + } + + bool success = false; + + const ObjectTemplate * const objectTemplate = ObjectTemplateList::fetch(request.getCreatureTemplate()); + if (objectTemplate) + { + const ServerCreatureObjectTemplate * const creatureTemplate = dynamic_cast(objectTemplate); + if (creatureTemplate) + { + // generate a name + Unicode::String randomName = NameManager::getInstance().generateUniqueRandomName(ConfigServerGame::getCharacterNameGeneratorDirectory(),creatureTemplate->getNameGeneratorType()); + + LOG("TraceCharacterCreation", ("%d generated name %s", request.getStationId(), Unicode::wideToNarrow(randomName).c_str(), request.getStationId(), request.getCreatureTemplate().c_str(), Unicode::wideToNarrow(randomName).c_str())); + + DEBUG_REPORT_LOG(true, ("VerifyNameResponse: random name %s approved for stationId %lu\n", Unicode::wideToNarrow(randomName).c_str(), request.getStationId())); + RandomNameResponse const response(request.getStationId(), request.getCreatureTemplate(), randomName, NameErrors::nameApproved); + sendToCentralServer(response); + + success = true; + } + else + { + LOG("TraceCharacterCreation", ("%d failed to get a creature template to service random name request. The request failed", request.getStationId())); + } + objectTemplate->releaseReference(); + } + else + { + LOG("TraceCharacterCreation", ("%d could not get an ObjectTemplate for name request", request.getStationId())); + } + + if (!success) + { + WARNING(true, ("Could not generate a random name for template %s (template may not exist or may not be a CreatureTemplate).\n", request.getCreatureTemplate().c_str())); + handleNameFailure(request, NameErrors::nameDeclinedNoTemplate); + } +} + +//-------------------------------------------------------------------- + +const StringId GameServer::handleVerifyAndLockNameRequest(const VerifyAndLockNameRequest &request, bool sendFailedResponseToCentralServer, bool verifyAgainstDb) +{ + REPORT_LOG(true, ("Verify and lock name requested for stationId %lu\n", request.getStationId())); + + const std::string & templateName = request.getTemplateName(); + DEBUG_REPORT_LOG(true, ("Received verify and lock name request for account %li (name %s, template %s)\n", request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str(), templateName.c_str())); + if(templateName.empty ()) + { + // Tell central we couldn't create the character + if (sendFailedResponseToCentralServer) + { + LOG("TraceCharacterCreation", ("%lu sent an empty template name for name verification, sending VerifyAndLockNameResponse(%lu, %s, NameErrors::nameDeclinedNoTemplate) to central server", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + DEBUG_REPORT_PRINT(true, ("%lu sent an empty template name for name verification, sending VerifyAndLockNameResponse(%lu, %s, NameErrors::nameDeclinedNoTemplate) to central server\n", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + + VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), NameErrors::nameDeclinedNoTemplate); + sendToCentralServer(verifyAndLockNameResponse); + } + + return NameErrors::nameDeclinedNoTemplate; + } + + if (!SpeciesRestrictions::canCreateCharacter(request.getGameFeatures(), Crc::calculate(templateName.c_str()))) + { + // Tell central we couldn't create the character + if (sendFailedResponseToCentralServer) + { + LOG("TraceCharacterCreation", ("%lu sent a species template name their account was not authorized to use, sending VerifyAndLockNameResponse to CentralServer. Template was %s", request.getStationId(), templateName.c_str())); + DEBUG_REPORT_PRINT(true, ("%lu sent a species template name their account was not authorized to use, sending VerifyAndLockNameResponse to CentralServer. Template was %s\n", request.getStationId(), templateName.c_str())); + + VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), NameErrors::nameDeclinedNotAuthorizedForSpecies); + sendToCentralServer(verifyAndLockNameResponse); + } + + return NameErrors::nameDeclinedNotAuthorizedForSpecies; + } + + StringId avatarReason = canCreateAvatar(templateName); + if (avatarReason != NameErrors::nameApproved) + { + if (sendFailedResponseToCentralServer) + { + LOG("TraceCharacterCreation", ("%lu canCreateAvatar(%s) failed, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server", request.getStationId(), request.getTemplateName().c_str(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + DEBUG_REPORT_PRINT(true, ("%lu canCreateAvatar(%s) failed, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server\n", request.getStationId(), request.getTemplateName().c_str(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + + VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), avatarReason); + sendToCentralServer(verifyAndLockNameResponse); + } + + return avatarReason; + } + + // verify the name against static tests - length, character set, etc. + StringId VerifyNameResponse = verifyCharacterName(templateName, request.getCharacterName(), true); + if (VerifyNameResponse != NameErrors::nameApproved) + { + if (sendFailedResponseToCentralServer) + { + LOG("TraceCharacterCreation", ("%lu VerifyNameResponse != NameErrors::nameApproved, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + DEBUG_REPORT_PRINT(true, ("%lu VerifyNameResponse != NameErrors::nameApproved, sending VerifyAndLockNameResponse(%lu, %s, REASON) to central server\n", request.getStationId(), request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + + VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), VerifyNameResponse); + sendToCentralServer(verifyAndLockNameResponse); + } + + return VerifyNameResponse; + } + + // verify the name against known existing names + if (NameManager::getInstance().getPlayerId(NameManager::normalizeName(Unicode::wideToNarrow(request.getCharacterName()))) != NetworkId::cms_invalid) + { + if (sendFailedResponseToCentralServer) + { + LOG("TraceCharacterCreation", ("%lu character create name %s is in use, sending VerifyAndLockNameResponse", request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + DEBUG_REPORT_PRINT("TraceCharacterCreation", ("%lu character create name %s is in use, sending VerifyAndLockNameResponse\n", request.getStationId(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + + VerifyAndLockNameResponse const verifyAndLockNameResponse(request.getStationId(), request.getCharacterName(), NameErrors::nameDeclinedInUse); + sendToCentralServer(verifyAndLockNameResponse); + } + + return NameErrors::nameDeclinedInUse; + } + + // Now verify against the database. + if (verifyAgainstDb) + { + LOG("TraceCharacterCreation", ("%lu sending VerifyNameRequest(%lu, %s, %s) to the database for validation", request.getStationId(), request.getStationId(), request.getTemplateName().c_str(), Unicode::wideToNarrow(request.getCharacterName()).c_str())); + VerifyNameRequest const vrn(request.getStationId(), request.getCharacterId(), request.getTemplateName(), request.getCharacterName()); + sendToDatabaseServer(vrn); + } + + return NameErrors::nameApproved; +} + +//-------------------------------------------------------------------- + +void GameServer::handleCharacterCreateNameVerification(const VerifyNameResponse &vrn) +{ + std::map::iterator findPendingCreation=m_charactersPendingCreation->find(vrn.getStationId()); + const CentralCreateCharacter * createMessage = findPendingCreation->second; + + if (vrn.getErrorMessage() != NameErrors::nameApproved) + { + LOG("TraceCharacterCreation", ("%d VeryfyNameResponse character create name %s declined, sending GameCreateCharacterFailed(%d, %s, %s)", vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); + DEBUG_REPORT_LOG(true, ("VerifyNameResponse: character create name %s declined (%s) for stationId %lu\n", Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str(), vrn.getStationId())); + GameCreateCharacterFailed const characterCreateFailed(vrn.getStationId(), vrn.getName(), vrn.getErrorMessage(), FormattedString<2048>().sprintf("%lu VeryfyNameResponse character create name %s declined, sending GameCreateCharacterFailed(%lu, %s, %s)", vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); + sendToCentralServer(characterCreateFailed); + m_charactersPendingCreation->erase(vrn.getStationId()); + delete createMessage; + return; + } + std::string templateName(createMessage->getTemplateName()); + + DEBUG_REPORT_LOG(true, ("VerifyNameResponse: character create name %s approved for stationId %lu\n", Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getStationId())); + + TangibleObject *newCharacterObject = 0; + + if (createMessage->getUseNewbieTutorial()) + { + Transform tr; + tr.setPosition_p(NewbieTutorial::getTutorialLocation()); + newCharacterObject = safe_cast(ServerWorld::createNewObject(templateName, tr, 0, false)); + } + else + { + Transform tr; + tr.setPosition_p(createMessage->getCoordinates()); + newCharacterObject = safe_cast(ServerWorld::createNewObject(templateName, tr, 0, false)); + } + + if (!newCharacterObject) + { + LOG("TraceCharacterCreation", ("%d could not create a new character object on the game server, sending GameCreateCharacterFailed(%d, %s, %s) to central server", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); + DEBUG_REPORT_LOG(true, ("handleCharacterCreateNameVerification: failed to create character object (name %s, template %s, stationId %lu)\n", Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getCreatureTemplate().c_str(), vrn.getStationId())); + GameCreateCharacterFailed const characterCreateFailed(vrn.getStationId(), vrn.getName(), NameErrors::nameDeclinedInternalError, FormattedString<2048>().sprintf("%lu could not create a new character object on the game server, sending GameCreateCharacterFailed(%lu, %s, %s) to central server", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); + sendToCentralServer(characterCreateFailed); + m_charactersPendingCreation->erase(vrn.getStationId()); + delete createMessage; + return; + } + + newCharacterObject->setObjectName(createMessage->getCharacterName()); + newCharacterObject->setOwnerId(newCharacterObject->getNetworkId()); + newCharacterObject->setPlayerControlled(true); + if (createMessage->getUseNewbieTutorial()) + NewbieTutorial::setupCharacterForTutorial(newCharacterObject); + else + NewbieTutorial::setupCharacterToSkipTutorial(newCharacterObject); + + CollisionProperty * collision = newCharacterObject->getCollisionProperty(); + if(collision) + { + collision->setPlayerControlled(true); + } + + //@todo: scale factor should probably be in TangibleObject, not CreatureObject + CreatureObject * const creature = dynamic_cast(newCharacterObject); + if (creature) + { + float scaleFactor = createMessage->getScaleFactor (); + const SharedObjectTemplate * const tmpl = safe_cast(creature->getSharedTemplate ()); + + if (tmpl) + { + const float scaleMax = tmpl->getScaleMax (); + const float scaleMin = tmpl->getScaleMin (); + + scaleFactor = std::min (scaleFactor, scaleMax); + scaleFactor = std::max (scaleFactor, scaleMin); + } + + creature->setScaleFactor (scaleFactor); + creature->setScale (Vector::xyz111 * scaleFactor); + } + + TangibleObject * tangibleObject = dynamic_cast(newCharacterObject); + //@todo we might ought enforce this be a CreatureObject + if (tangibleObject) + tangibleObject->setAppearanceData(createMessage->getAppearanceData()); + + // hair equip hack + if(!createMessage->getHairTemplateName().empty ()) + { + ServerObject * const hair = ServerWorld::createNewObject(createMessage->getHairTemplateName(), *newCharacterObject, false); + if (!hair) + { + DEBUG_WARNING(true, ("Could not create hair %s\n", createMessage->getHairTemplateName().c_str())); + } + else + { + TangibleObject * const tangible_hair = dynamic_cast(hair); + + if (tangible_hair) + tangible_hair->setAppearanceData (createMessage->getHairAppearanceData ()); + else + WARNING (true, ("Hair is not tangible, wtf. Can't customize it. (among other things, probably)...")); + } + } + + if (!createMessage->getProfession ().empty ()) + { + CreatureObject * const creature = dynamic_cast(newCharacterObject); + if (creature) + PlayerCreationManagerServer::setupPlayer (*creature, createMessage->getProfession (), createMessage->getStationId(), createMessage->getJedi()); + } + + if (!createMessage->getBiography().empty()) + { + BiographyManager::setBiography(newCharacterObject->getNetworkId(),createMessage->getBiography()); + } + + // ---------------------------------------------------------------------- + // Set up the PlayerObject + + ServerObject *playerServerObject = ServerWorld::createNewObject(ConfigServerGame::getPlayerObjectTemplate(), *newCharacterObject, false); + PlayerObject *play = dynamic_cast(playerServerObject); + if (play) + { + play->setStationId(createMessage->getStationId()); + play->setBornDate(); + play->setSkillTemplate(createMessage->getSkillTemplate(), true); + play->setWorkingSkill(createMessage->getWorkingSkill(), true); + + // Setup initial A-Tab inventory. + SlottedContainer * const container = ContainerInterface::getSlottedContainer(*newCharacterObject); + if(container) + { + SlotId slot; + Container::ContainerErrorCode tmp; + slot = SlotIdManager::findSlotId(GameServerNamespace::SlotNames::appearance); + if(slot != SlotId::invalid) + { + Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); + Object* appearanceInventory = itemId.getObject(); + if(appearanceInventory == NULL) + { + WARNING(true, ("Player %s has lost their appearance inventory", newCharacterObject->getNetworkId().getValueString().c_str())); + appearanceInventory = ServerWorld::createNewObject(s_appearanceTemplate, *newCharacterObject, slot, false); + if(!appearanceInventory) + { + DEBUG_FATAL(true, ("Could not create an appearance inventory for the player who lost theirs")); + } + } + } + } + } + else + { + LOG("TraceCharacterCreation", ("%d unable to create player object for new character %s", vrn.getStationId(), newCharacterObject->getNetworkId().getValueString().c_str())); + WARNING_STRICT_FATAL(true,("Unable to create PlayerObject for new character %s.\n",newCharacterObject->getNetworkId().getValueString().c_str())); + } + + newCharacterObject->setSceneIdOnThisAndContents(createMessage->getPlanetName()); + + // ---------------------------------------------------------------------- + // Tell DB Process we're about to send it a character, then send it + AddCharacterMessage const acm(createMessage->getStationId(), newCharacterObject->getNetworkId(),getProcessId(),createMessage->getCharacterName(),createMessage->getJedi()); + sendToDatabaseServer(acm); + newCharacterObject->persist(); + + // ---------------------------------------------------------------------- + // Register player name with the global list + std::string const &firstName = Unicode::wideToNarrow(Unicode::toLower(newCharacterObject->getAssignedObjectFirstName())); + std::string const &fullName = Unicode::wideToNarrow(newCharacterObject->getAssignedObjectName()); + time_t const timeNow = Os::getRealSystemTime(); + NameManager::getInstance().addPlayer(newCharacterObject->getNetworkId(), createMessage->getStationId(), firstName, fullName, timeNow, timeNow, true); + + // ---------------------------------------------------------------------- + // Delete the new character -- will reload it from DB when player logs in + // (This is so that the player could log in to a different server, or not log in at all, and things would still work.) + ServerWorld::removeObjectFromGame(*newCharacterObject); + delete newCharacterObject; + + m_charactersPendingCreation->erase(vrn.getStationId()); + delete createMessage; + + // Destroy any existing chat avatar that may be using the new character's name + GenericValueTypeMessage const chatDestroyAvatar("ChatDestroyAvatar", firstName); + Chat::sendToChatServer(chatDestroyAvatar); +} + +//-------------------------------------------------------------------- + +void GameServer::handleVerifyAndLockNameVerification(const VerifyNameResponse &vrn) +{ + LOG("TraceCharacterCreation", ("%lu VerifyNameResponse from db for verify and lock name received, sending VerifyAndLockNameResponse(%lu, %s, %s)", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); + DEBUG_REPORT_PRINT(true, ("%lu VerifyNameResponse from db for verify and lock name received, sending VerifyAndLockResponse(%lu, %s, %s)\n", vrn.getStationId(), vrn.getStationId(), Unicode::wideToNarrow(vrn.getName()).c_str(), vrn.getErrorMessage().getText().c_str())); + + if (vrn.getCharacterId().isValid()) + { + if (vrn.getErrorMessage() != NameErrors::nameApproved) + { + std::string const errorText(std::string("@") + vrn.getErrorMessage().getCanonicalRepresentation()); + ScriptParams params; + params.addParam(errorText.c_str(), "reason"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(vrn.getCharacterId(), "renameCharacterNameValidationFail", dictionary->getSerializedData(), 0, false); + } + } + else + { + MessageToQueue::getInstance().sendMessageToJava(vrn.getCharacterId(), "renameCharacterNameValidationSuccess", std::vector(), 0, false); + } + } + else + { + VerifyAndLockNameResponse const verifyAndLockNameResponse(vrn.getStationId(), vrn.getName(), vrn.getErrorMessage()); + sendToCentralServer(verifyAndLockNameResponse); + } +} + +//-------------------------------------------------------------------- + +bool GameServer::isCreatePending(uint32 stationId) const +{ + std::map::const_iterator findPendingCreation=m_charactersPendingCreation->find(stationId); + // If there is not a creation request pending, just reply with the random name. + return findPendingCreation != m_charactersPendingCreation->end(); +} + +//-------------------------------------------------------------------- + +const StringId & GameServer::canCreateAvatar(const std::string &templateName) +{ + const ServerCreatureObjectTemplate * creatureTemplate = getServerCreatureObjectTemplate(templateName); + if (!creatureTemplate) + { + return NameErrors::nameDeclinedNotCreatureTemplate; + } + + if (!creatureTemplate->getCanCreateAvatar()) + { + creatureTemplate->releaseReference(); + return NameErrors::nameDeclinedCantCreateAvatar; + } + + creatureTemplate->releaseReference(); + return NameErrors::nameApproved; +} + +//-------------------------------------------------------------------- + +const ServerCreatureObjectTemplate * GameServer::getServerCreatureObjectTemplate(const std::string &templateName) const +{ + const ObjectTemplate * objectTemplate = ObjectTemplateList::fetch(templateName); + if (!objectTemplate) + return 0; + + const ServerCreatureObjectTemplate * creatureTemplate = dynamic_cast(objectTemplate); + + return creatureTemplate; +} +//----------------------------------------------------------------------- + +int GameServer::getNumClients() const +{ + if (m_clients) + return m_clients->size(); + return 0; +} + +//----------------------------------------------------------------------- + +void GameServer::handleTeleportMessage(TeleportMessage const &message) +{ + CreatureObject * const creature = dynamic_cast(NetworkIdManager::getObjectById(message.getActorId())); + if (creature) + { + char buf[256]; + IGNORE_RETURN(snprintf(buf, sizeof(buf)-1, "%s %g %g %g %s %g %g %g", + message.getSceneId().c_str(), + message.getPosition_w().x, + message.getPosition_w().y, + message.getPosition_w().z, + message.getContainerId().getValueString().c_str(), + message.getPosition_p().x, + message.getPosition_p().y, + message.getPosition_p().z)); + buf[sizeof(buf)-1] = '\0'; + + Command::ErrorCode status = Command::CEC_Success; + creature->forceExecuteCommand(CommandTable::getCommand(Crc::calculate("planetwarp")), NetworkId::cms_invalid, Unicode::narrowToWide(buf), status, false); + } +} + +//----------------------------------------------------------------------- + +void GameServer::handleRetrievedItemLoadMessage(RetrievedItemLoadMessage const &message) +{ + CachedNetworkId ownerId(message.getOwnerId()); + if (ownerId.getObject()) + { + CreatureObject *owner = dynamic_cast(ownerId.getObject()); + if (owner) + { + ServerObject *inventory = owner->getInventory(); + if (inventory) + { + NetworkId objectId = message.getItemId(); + if (objectId != NetworkId::cms_invalid) + { + inventory->loadContainedObjectFromDB(message.getItemId()); + } + } + } + UNREF(owner); + } +} + +//----------------------------------------------------------------------- + +void GameServer::handleReloadAdminTableMessage(ReloadAdminTableMessage const &message) +{ + AdminAccountManager::reload(); +} + +//----------------------------------------------------------------------- + +void GameServer::handleReloadCommandTableMessage(ReloadCommandTableMessage const &message) +{ + ServerCommandTable::load(); +} + +//----------------------------------------------------------------------- + +void GameServer::handleReloadDatatableMessage(ReloadDatatableMessage const &message) +{ + DataTableManager::reload(message.getTable()); +} + +//----------------------------------------------------------------------- + +void GameServer::handleReloadScriptMessage(ReloadScriptMessage const &message) +{ + GameScriptObject::reloadScript(message.getScript()); +} + +//----------------------------------------------------------------------- + +void GameServer::handleReloadTemplateMessage(ReloadTemplateMessage const &message) +{ + Iff templateFile; + if (templateFile.open(message.getTemplate().c_str(), true)) + { + ObjectTemplateList::reload(templateFile); + } +} + +//----------------------------------------------------------------------- + +void GameServer::handleEnableNewJediTrackingMessage(EnableNewJediTrackingMessage const &message) +{ + GameScriptObject::enableNewJediTracking(message.getEnableTracking()); +} + +//----------------------------------------------------------------------- + +void GameServer::checkIdleClients(float time) +{ + static float s_idleTimePassed; + + s_idleTimePassed += time; + + if (s_idleTimePassed > IDLE_CLIENTS_CHECK_TIME_SEC) + { + s_idleTimePassed = 0.0f; + + std::vector idleClients; + + for (ClientMap::iterator i = m_clients->begin(); i != m_clients->end(); ++i) + { + if ((*i).second->idledTooLong()) + { + PlayerObject const * playerObject = PlayerCreatureController::getPlayerObject(safe_cast((*i).second->getCharacterObject())); + if (!playerObject || (playerObject->getSessionLastActiveTime() == 0)) + { + idleClients.push_back((*i).second); + } + } + } + + for (std::vector::iterator j = idleClients.begin(); j != idleClients.end(); ++j) + (*j)->handleIdleDisconnect(); + } +} + +// ---------------------------------------------------------------------- + +void GameServer::getObjectsWithClients(std::vector &objects) const +{ + objects.clear(); + for (ClientMap::const_iterator i = m_clients->begin(); i != m_clients->end(); ++i) + if ((*i).second->getCharacterObject()) + objects.push_back((*i).second->getCharacterObject()); +} + +// ---------------------------------------------------------------------- + +void GameServer::setDone(char const *reasonfmt, ...) +{ + if (!m_done) + { + char reason[1024]; + va_list ap; + va_start(ap, reasonfmt); + _vsnprintf(reason, sizeof(reason), reasonfmt, ap); + reason[sizeof(reason)-1] = '\0'; + + LOG( + "ServerShutdown", + ( + "GameServer %d (pid %d) shutdown, reason: %s", + static_cast(getProcessId()), + static_cast(Os::getProcessId()), + reason)); + + REPORT_LOG( + true, + ( + "GameServer %d (pid %d) shutdown, reason: %s\n", + static_cast(getProcessId()), + static_cast(Os::getProcessId()), + reason)); + + va_end(ap); + m_done = true; + } +} + +// ---------------------------------------------------------------------- + +void GameServer::setDatabaseProcessConnection(DatabaseProcessConnection *newDatabaseProcessConnection) +{ + if (newDatabaseProcessConnection) + { + FATAL(newDatabaseProcessConnection != m_pendingDatabaseProcessConnection, ("Database process connection established but does not match pending?")); + m_databaseProcessConnection = newDatabaseProcessConnection; + m_pendingDatabaseProcessConnection = 0; + m_databaseProcessId = newDatabaseProcessConnection->getPid(); + + onDatabaseProcessConnectionEstablished(); + } + else + { + m_databaseProcessConnection = 0; + m_pendingDatabaseProcessConnection = 0; + } +} + +// ---------------------------------------------------------------------- + +uint32 GameServer::getDatabaseProcessId() const +{ + return m_databaseProcessId; +} + +// ---------------------------------------------------------------------- + +void GameServer::handleCSRequest( GameServerCSRequestMessage & message ) +{ + DEBUG_REPORT_LOG( true, ( "HandleCSRequest:GameServer\n" ) ); +} + +// ---------------------------------------------------------------------- + +bool GameServer::addPendingLoadRequest(NetworkId const & id) +{ + if (isAtPendingLoadRequestLimit()) + return false; + + if (s_pendingLoadRequests.find(id) != s_pendingLoadRequests.end()) + return false; + + s_pendingLoadRequests[id] = (unsigned int)::time(NULL); + + return true; +} + +// ---------------------------------------------------------------------- + +void GameServer::removePendingLoadRequest(NetworkId const & id) +{ + s_pendingLoadRequests.erase(id); +} + +// ---------------------------------------------------------------------- + +bool GameServer::isAtPendingLoadRequestLimit() +{ + return s_pendingLoadRequests.size() >= static_cast(getPendingLoadRequestLimit()); +} + +// ---------------------------------------------------------------------- + +int GameServer::getPendingLoadRequestLimit() +{ + static int pendingLoadRequestLimit = -1; + + if (pendingLoadRequestLimit == -1) + { + pendingLoadRequestLimit = ConfigServerGame::getPendingLoadRequestLimit(); + + // see if there's a pending load limit set for this particular game server + char key[128]; + snprintf(key, sizeof(key)-1, "pendingLoadRequestLimit_%s.%lu", ServerWorld::getSceneId().c_str(), GameServer::getInstance().getPreloadAreaId()); + key[sizeof(key)-1] = '\0'; + + if (GameServerNamespace::getConfigSetting("GameServer", key, pendingLoadRequestLimit)) + return pendingLoadRequestLimit; + + // see if there's a pending load limit set for this particular planet + snprintf(key, sizeof(key)-1, "pendingLoadRequestLimit_%s", ServerWorld::getSceneId().c_str()); + key[sizeof(key)-1] = '\0'; + + if (GameServerNamespace::getConfigSetting("GameServer", key, pendingLoadRequestLimit)) + return pendingLoadRequestLimit; + + // use default server pending load limit + pendingLoadRequestLimit = ConfigServerGame::getPendingLoadRequestLimit(); + } + + return pendingLoadRequestLimit; +} + +// ---------------------------------------------------------------------- + +int GameServer::getNumberOfPendingLoadRequests() +{ + return s_pendingLoadRequests.size(); +} + +// ---------------------------------------------------------------------- + +unsigned long GameServer::getOldestPendingLoadRequestTime(NetworkId & id) +{ + unsigned long oldestTime = std::numeric_limits::max(); + + std::map::const_iterator i = s_pendingLoadRequests.begin(); + for (; i != s_pendingLoadRequests.end(); ++i) + if (i->second < oldestTime) + { + id = i->first; + oldestTime = i->second; + } + + return oldestTime; +} + +// ---------------------------------------------------------------------- + +ShipObject *GameServerNamespace::getAttachedShip(CreatureObject *creature) +{ + // The "attached" ship is the ship which must move along with the creature. + // This means if the creature is piloting, the ship is is piloting, + // or the containing ship if the creature is the ship's owner. + ShipObject * const ship = ShipObject::getContainingShipObject(creature); + if ( ship + && ( ship->getOwnerId() == creature->getNetworkId() + || creature->getPilotedShip() == ship)) + return ship; + return 0; +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::loadRetroactiveCtsHistory() +{ + FATAL(GameServer::getInstance().getClusterName().empty(), ("cannot load retroactive CTS history until the cluster has received its cluster name")); + + static bool alreadyDone = false; + if (alreadyDone) + return; + + alreadyDone = true; + + // set up data to retroactive CTS history + std::string const retroactiveCtsHistoryFilename = ConfigServerGame::getRetroactiveCtsHistoryFilename(); + if (!retroactiveCtsHistoryFilename.empty()) + { + DataTable * table = DataTableManager::getTable(retroactiveCtsHistoryFilename, true); + if (table) + { + int const columnTransferTime = table->findColumnNumber("transfer time epoch"); + + int const columnSourceCluster = table->findColumnNumber("source cluster"); + int const columnSourceCharacterId = table->findColumnNumber("source character id"); + int const columnSourceCharacterName = table->findColumnNumber("source character name"); + int const columnSourceCharacterBornDate = table->findColumnNumber("source character born date"); + + int const columnTargetCluster = table->findColumnNumber("target cluster"); + int const columnTargetCharacterId = table->findColumnNumber("target character id"); + + FATAL((columnTransferTime < 0), ("column \"transfer time epoch\" not found in %s", retroactiveCtsHistoryFilename.c_str())); + + FATAL((columnSourceCluster < 0), ("column \"source cluster\" not found in %s", retroactiveCtsHistoryFilename.c_str())); + FATAL((columnSourceCharacterId < 0), ("column \"source character id\" not found in %s", retroactiveCtsHistoryFilename.c_str())); + FATAL((columnSourceCharacterName < 0), ("column \"source character name\" not found in %s", retroactiveCtsHistoryFilename.c_str())); + FATAL((columnSourceCharacterBornDate < 0), ("column \"source character born date\" not found in %s", retroactiveCtsHistoryFilename.c_str())); + + FATAL((columnTargetCluster < 0), ("column \"target cluster\" not found in %s", retroactiveCtsHistoryFilename.c_str())); + FATAL((columnTargetCharacterId < 0), ("column \"target character id\" not found in %s", retroactiveCtsHistoryFilename.c_str())); + + // read in retroactive objvars; these are stored in a variable number of + // colunms that are named in ascending order, so search for all such columns + std::vector columnsObjvarName; + std::vector columnsObjvarType; + std::vector columnsObjvarValue; + + char buffer[128]; + int columnNumber; + for (int i = 1; i <= 1000000000; ++i) + { + snprintf(buffer, sizeof(buffer)-1, "objvar name %d", i); + buffer[sizeof(buffer)-1] = '\0'; + + columnNumber = table->findColumnNumber(buffer); + if (columnNumber < 0) + break; + + columnsObjvarName.push_back(columnNumber); + + snprintf(buffer, sizeof(buffer)-1, "objvar type %d", i); + buffer[sizeof(buffer)-1] = '\0'; + + columnNumber = table->findColumnNumber(buffer); + FATAL((columnNumber < 0), ("column \"%s\" not found in %s", buffer, retroactiveCtsHistoryFilename.c_str())); + + columnsObjvarType.push_back(columnNumber); + + snprintf(buffer, sizeof(buffer)-1, "objvar value %d", i); + buffer[sizeof(buffer)-1] = '\0'; + + columnNumber = table->findColumnNumber(buffer); + FATAL((columnNumber < 0), ("column \"%s\" not found in %s", buffer, retroactiveCtsHistoryFilename.c_str())); + + columnsObjvarValue.push_back(columnNumber); + } + + // CTS data can also come from config file, so read that in, if any + std::list ctsDataFromConfig; + + { + int index = 0; + char const * pszCtsDataFromConfig = NULL; + do + { + pszCtsDataFromConfig = ConfigFile::getKeyString("GameServer", "retroactiveCtsHistory", index++, NULL); + if (pszCtsDataFromConfig != NULL) + { + ctsDataFromConfig.push_back(pszCtsDataFromConfig); + } + } + while (pszCtsDataFromConfig); + } + + CtsSourceCharacterInfo sourceCharacterInfo; + std::string retroactiveObjvarName; + int retroactiveObjvarType; + std::string retroactiveObjvarValue; + std::string targetCluster; + NetworkId targetCharacterId; + + // transfer time, source character info + // target cluster + // target character id + // \/ \/ \/ + std::map, CtsSourceCharacterInfo> allCtsHistoryList; + +#ifdef _DEBUG + std::set allCtsSourceCluster; +#endif + + int const currentBornDate = PlayerObject::getCurrentBornDate(); + + std::list::const_iterator iterCtsDataFromConfig = ctsDataFromConfig.begin(); + std::list::const_iterator const iterCtsDataFromConfigEnd = ctsDataFromConfig.end(); + Unicode::String const ctsDataFromConfigDelimiter(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector ctsDataFromConfigTokens; + std::string ctsDataFromConfigParsedData; + + int const numRows = table->getNumRows(); + int rowIndex = 0; + + while (true) + { + if (rowIndex < numRows) + { + sourceCharacterInfo.transferTime = static_cast(table->getIntValue(columnTransferTime, rowIndex)); + + sourceCharacterInfo.sourceCluster = table->getStringValue(columnSourceCluster, rowIndex); + sourceCharacterInfo.sourceCharacterId = NetworkId(table->getStringValue(columnSourceCharacterId, rowIndex)); + sourceCharacterInfo.sourceCharacterName = table->getStringValue(columnSourceCharacterName, rowIndex); + sourceCharacterInfo.sourceCharacterBornDate = table->getIntValue(columnSourceCharacterBornDate, rowIndex); + + targetCluster = table->getStringValue(columnTargetCluster, rowIndex); + targetCharacterId = NetworkId(table->getStringValue(columnTargetCharacterId, rowIndex)); + + // read retroactive objvars + { + sourceCharacterInfo.sourceCharacterRetroactiveObjvars.clear(); + + for (size_t i = 0, size = columnsObjvarName.size(); i < size; ++i) + { + retroactiveObjvarName = table->getStringValue(columnsObjvarName[i], rowIndex); + retroactiveObjvarType = table->getIntValue(columnsObjvarType[i], rowIndex); + retroactiveObjvarValue = table->getStringValue(columnsObjvarValue[i], rowIndex); + + if (!retroactiveObjvarName.empty() && !retroactiveObjvarValue.empty()) + { + // can only handle INT (type 0) and INT_ARRAY (type 1) objvar type at this time + FATAL(((retroactiveObjvarType != static_cast(DynamicVariable::INT)) && (retroactiveObjvarType != static_cast(DynamicVariable::INT_ARRAY))), ("invalid or unsupported objvar type %d in %s, row %d", retroactiveObjvarType, retroactiveCtsHistoryFilename.c_str(), (rowIndex+3))); + sourceCharacterInfo.sourceCharacterRetroactiveObjvars.push_back(std::make_pair(retroactiveObjvarName, DynamicVariable())); + sourceCharacterInfo.sourceCharacterRetroactiveObjvars[sourceCharacterInfo.sourceCharacterRetroactiveObjvars.size() - 1].second.load(-1, retroactiveObjvarType, Unicode::narrowToWide(retroactiveObjvarValue)); + } + } + } + + ++rowIndex; + } + else if (iterCtsDataFromConfig == iterCtsDataFromConfigEnd) + { + break; + } + else + { + ctsDataFromConfigTokens.clear(); + if ((Unicode::tokenize(Unicode::narrowToWide(*iterCtsDataFromConfig), ctsDataFromConfigTokens, &ctsDataFromConfigDelimiter, NULL)) && (ctsDataFromConfigTokens.size() == 7)) + { + // sanity check + ctsDataFromConfigParsedData = FormattedString<2048>().sprintf("%s|%s|%s|%s|%s|%s|%s", Unicode::wideToNarrow(ctsDataFromConfigTokens[0]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[1]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[2]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[3]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[4]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[5]).c_str(), Unicode::wideToNarrow(ctsDataFromConfigTokens[6]).c_str()); + FATAL((ctsDataFromConfigParsedData != *iterCtsDataFromConfig), ("parsed CTS data (%s) does not equal read CTS data (%s)", ctsDataFromConfigParsedData.c_str(), iterCtsDataFromConfig->c_str())); + + sourceCharacterInfo.transferTime = static_cast(::atol(Unicode::wideToNarrow(ctsDataFromConfigTokens[0]).c_str())); + + sourceCharacterInfo.sourceCluster = Unicode::wideToNarrow(ctsDataFromConfigTokens[1]); + sourceCharacterInfo.sourceCharacterId = NetworkId(Unicode::wideToNarrow(ctsDataFromConfigTokens[2])); + sourceCharacterInfo.sourceCharacterName = Unicode::wideToNarrow(ctsDataFromConfigTokens[3]); + sourceCharacterInfo.sourceCharacterBornDate = ::atoi(Unicode::wideToNarrow(ctsDataFromConfigTokens[4]).c_str()); + + targetCluster = Unicode::wideToNarrow(ctsDataFromConfigTokens[5]); + targetCharacterId = NetworkId(Unicode::wideToNarrow(ctsDataFromConfigTokens[6])); + + sourceCharacterInfo.sourceCharacterRetroactiveObjvars.clear(); + } + else + { + FATAL(true, ("cannot parse CTS data (%s) read from config file", iterCtsDataFromConfig->c_str())); + } + + ++iterCtsDataFromConfig; + } + + FATAL(((sourceCharacterInfo.sourceCharacterBornDate > 0) && (sourceCharacterInfo.sourceCharacterBornDate < 907)), ("source character (%s, %s) has born date (%d) < 907", sourceCharacterInfo.sourceCluster.c_str(), sourceCharacterInfo.sourceCharacterId.getValueString().c_str(), sourceCharacterInfo.sourceCharacterBornDate)); + FATAL((sourceCharacterInfo.sourceCharacterBornDate > currentBornDate), ("source character (%s, %s) has born date (%d) > current born date (%d)", sourceCharacterInfo.sourceCluster.c_str(), sourceCharacterInfo.sourceCharacterId.getValueString().c_str(), sourceCharacterInfo.sourceCharacterBornDate, currentBornDate)); + + std::map > * clusterCtsHistory = NULL; +#ifdef _DEBUG + IGNORE_RETURN(allCtsSourceCluster.insert(sourceCharacterInfo.sourceCluster)); + clusterCtsHistory = &(s_retroactiveCtsHistoryList[targetCluster]); +#else + // for release build, we only care about transfers into our cluster; + // for debug build, read them all so we can test out the logic to + // make sure it works for all clusters + if (targetCluster == GameServer::getInstance().getClusterName()) + clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; +#endif + if (clusterCtsHistory) + { + if (clusterCtsHistory->count(targetCharacterId) <= 0) + { + (*clusterCtsHistory)[targetCharacterId].push_back(sourceCharacterInfo); + } + } + + std::map, CtsSourceCharacterInfo>::const_iterator const iterFindCtsHistory = allCtsHistoryList.find(std::make_pair(targetCharacterId, targetCluster)); + if (iterFindCtsHistory == allCtsHistoryList.end()) + { + allCtsHistoryList[std::make_pair(targetCharacterId, targetCluster)] = sourceCharacterInfo; + } + else + { + FATAL(((iterFindCtsHistory->second.sourceCharacterId != sourceCharacterInfo.sourceCharacterId) || (iterFindCtsHistory->second.sourceCluster != sourceCharacterInfo.sourceCluster)), ("character (%s, %s) has 2 transfers from different source characters (%s, %s, %s, %ld, %s) and (%s, %s, %s, %ld, %s)", targetCluster.c_str(), targetCharacterId.getValueString().c_str(), iterFindCtsHistory->second.sourceCluster.c_str(), iterFindCtsHistory->second.sourceCharacterId.getValueString().c_str(), iterFindCtsHistory->second.sourceCharacterName.c_str(), iterFindCtsHistory->second.transferTime, CalendarTime::convertEpochToTimeStringLocal(iterFindCtsHistory->second.transferTime).c_str(), sourceCharacterInfo.sourceCluster.c_str(), sourceCharacterInfo.sourceCharacterId.getValueString().c_str(), sourceCharacterInfo.sourceCharacterName.c_str(), sourceCharacterInfo.transferTime, CalendarTime::convertEpochToTimeStringLocal(sourceCharacterInfo.transferTime).c_str())); + } + } + + DataTableManager::close(retroactiveCtsHistoryFilename); + +#ifdef _DEBUG + { + // make sure there are collection slots defined for CTS titles + for (std::set::const_iterator iter = allCtsSourceCluster.begin(); iter != allCtsSourceCluster.end(); ++iter) + { + std::string collectionSlotName = std::string("cts_from_") + Unicode::toLower(*iter); + + std::string::size_type pos = collectionSlotName.find('-'); + while (pos != std::string::npos) + { + collectionSlotName.replace(pos, 1, 1, '_'); + pos = collectionSlotName.find('-'); + } + + DEBUG_WARNING(!CollectionsDataTable::getSlotByName(collectionSlotName), ("no collection slot defined for CTS title (%s)", collectionSlotName.c_str())); + } + } +#endif + + // build CTS history for characters who have transferred multiple times + + // source cluster + // source character id + // \/ \/ + std::set > ctsHistorySourceCharacters; + +#ifdef _DEBUG + for (std::map > >::iterator iterCtsHistoryCluster = s_retroactiveCtsHistoryList.begin(); iterCtsHistoryCluster != s_retroactiveCtsHistoryList.end(); ++iterCtsHistoryCluster) + { + std::string const & ctsHistoryClusterName = iterCtsHistoryCluster->first; + std::map > & ctsHistoryCluster = iterCtsHistoryCluster->second; + +#else + { + std::string const & ctsHistoryClusterName = GameServer::getInstance().getClusterName(); + std::map > & ctsHistoryCluster = s_retroactiveCtsHistoryListThisCluster; +#endif + for (std::map >::iterator iterCtsHistoryCharacter = ctsHistoryCluster.begin(); iterCtsHistoryCharacter != ctsHistoryCluster.end(); ++iterCtsHistoryCharacter) + { + FATAL((iterCtsHistoryCharacter->second.size() != 1), ("character (%s, %s) should have exactly 1 CTS history at this point in the parsing", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str())); + CtsSourceCharacterInfo const & ctsHistoryLastSourceCharacter = iterCtsHistoryCharacter->second[0]; + + ctsHistorySourceCharacters.clear(); + IGNORE_RETURN(ctsHistorySourceCharacters.insert(std::make_pair(ctsHistoryLastSourceCharacter.sourceCharacterId, ctsHistoryLastSourceCharacter.sourceCluster))); + + std::map, CtsSourceCharacterInfo>::const_iterator iterFindCharacterCtsHistory = allCtsHistoryList.find(std::make_pair(ctsHistoryLastSourceCharacter.sourceCharacterId, ctsHistoryLastSourceCharacter.sourceCluster)); + while (iterFindCharacterCtsHistory != allCtsHistoryList.end()) + { + FATAL((ctsHistorySourceCharacters.count(std::make_pair(iterFindCharacterCtsHistory->second.sourceCharacterId, iterFindCharacterCtsHistory->second.sourceCluster)) > 0), ("character (%s, %s) has multiple CTS history for the same source character (%s, %s, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), iterFindCharacterCtsHistory->second.sourceCluster.c_str(), iterFindCharacterCtsHistory->second.sourceCharacterId.getValueString().c_str(), iterFindCharacterCtsHistory->second.sourceCharacterName.c_str())); + IGNORE_RETURN(ctsHistorySourceCharacters.insert(std::make_pair(iterFindCharacterCtsHistory->second.sourceCharacterId, iterFindCharacterCtsHistory->second.sourceCluster))); + + FATAL((iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].transferTime <= iterFindCharacterCtsHistory->second.transferTime), ("character (%s, %s) has out of order CTS history for source characters (%s, %s, %s, %ld, %s) and (%s, %s, %s, %ld, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].sourceCluster.c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].sourceCharacterId.getValueString().c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].sourceCharacterName.c_str(), iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].transferTime, CalendarTime::convertEpochToTimeStringLocal(iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1].transferTime).c_str(), iterFindCharacterCtsHistory->second.sourceCluster.c_str(), iterFindCharacterCtsHistory->second.sourceCharacterId.getValueString().c_str(), iterFindCharacterCtsHistory->second.sourceCharacterName.c_str(), iterFindCharacterCtsHistory->second.transferTime, CalendarTime::convertEpochToTimeStringLocal(iterFindCharacterCtsHistory->second.transferTime).c_str())); + iterCtsHistoryCharacter->second.push_back(iterFindCharacterCtsHistory->second); + + iterFindCharacterCtsHistory = allCtsHistoryList.find(std::make_pair(iterFindCharacterCtsHistory->second.sourceCharacterId, iterFindCharacterCtsHistory->second.sourceCluster)); + } + } + } + +#ifdef _DEBUG + { + // make sure that we have the born date of the "root" source character for each transfer + for (std::map > >::const_iterator iterCtsHistoryCluster = s_retroactiveCtsHistoryList.begin(); iterCtsHistoryCluster != s_retroactiveCtsHistoryList.end(); ++iterCtsHistoryCluster) + { + std::string const & ctsHistoryClusterName = iterCtsHistoryCluster->first; + std::map > const & ctsHistoryCluster = iterCtsHistoryCluster->second; + + for (std::map >::const_iterator iterCtsHistoryCharacter = ctsHistoryCluster.begin(); iterCtsHistoryCharacter != ctsHistoryCluster.end(); ++iterCtsHistoryCharacter) + { + FATAL(iterCtsHistoryCharacter->second.empty(), ("character (%s, %s) has empty CTS history list", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str())); + + // we only care about missing born date for transfers on or before + // Wed Nov 19 23:21:11 2008 Pacific Standard Time (epoch 1227165671) + // since transfers after that should correctly transfer the born date + FATAL((((iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).sourceCharacterBornDate <= 0) && ((iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).transferTime <= 1227165671)), ("character (%s, %s) has no born date for the \"root\" source character (%s, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), (iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).sourceCluster.c_str(), (iterCtsHistoryCharacter->second[iterCtsHistoryCharacter->second.size() - 1]).sourceCharacterId.getValueString().c_str())); + + // if the character has transferred multiple times, make sure that only the "root" source character has a born date + if (iterCtsHistoryCharacter->second.size() > 1) + { + for (size_t i = 0, sizeExcludingLastElement = (iterCtsHistoryCharacter->second.size() - 1); i < sizeExcludingLastElement; ++i) + { + FATAL(((iterCtsHistoryCharacter->second[i]).sourceCharacterBornDate > 0), ("character (%s, %s) has born date (%d) for a \"non root\" source character (%s, %s)", ctsHistoryClusterName.c_str(), iterCtsHistoryCharacter->first.getValueString().c_str(), (iterCtsHistoryCharacter->second[i]).sourceCharacterBornDate, (iterCtsHistoryCharacter->second[i]).sourceCluster.c_str(), (iterCtsHistoryCharacter->second[i]).sourceCharacterId.getValueString().c_str())); + } + } + } + } + } +#endif + } + } +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::loadRetroactivePlayerCityCreationTime() +{ + FATAL(GameServer::getInstance().getClusterName().empty(), ("cannot load retroactive player city creation time until the cluster has received its cluster name")); + + static bool alreadyDone = false; + if (alreadyDone) + return; + + alreadyDone = true; + + // set up data to player city creation time + std::string const retroactivePlayerCityCreationTimeFilename = ConfigServerGame::getRetroactivePlayerCityCreationTimeFilename(); + if (!retroactivePlayerCityCreationTimeFilename.empty()) + { + DataTable * table = DataTableManager::getTable(retroactivePlayerCityCreationTimeFilename, true); + if (table) + { + int const columnCreationTime = table->findColumnNumber("creation time epoch"); + int const columnCluster = table->findColumnNumber("cluster"); + int const columnCityId = table->findColumnNumber("city id"); + + FATAL((columnCreationTime < 0), ("column \"creation time epoch\" not found in %s", retroactivePlayerCityCreationTimeFilename.c_str())); + FATAL((columnCluster < 0), ("column \"cluster\" not found in %s", retroactivePlayerCityCreationTimeFilename.c_str())); + FATAL((columnCityId < 0), ("column \"city id\" not found in %s", retroactivePlayerCityCreationTimeFilename.c_str())); + + // player city creation time data can also come from config file, so read that in, if any + std::list playerCityCreationTimeDataFromConfig; + + { + int index = 0; + char const * pszPlayerCityCreationTimeDataFromConfig = NULL; + do + { + pszPlayerCityCreationTimeDataFromConfig = ConfigFile::getKeyString("GameServer", "retroactivePlayerCityCreationTime", index++, NULL); + if (pszPlayerCityCreationTimeDataFromConfig != NULL) + { + playerCityCreationTimeDataFromConfig.push_back(pszPlayerCityCreationTimeDataFromConfig); + } + } + while (pszPlayerCityCreationTimeDataFromConfig); + } + + std::list::const_iterator iterPlayerCityCreationTimeDataFromConfig = playerCityCreationTimeDataFromConfig.begin(); + std::list::const_iterator const iterPlayerCityCreationTimeDataFromConfigEnd = playerCityCreationTimeDataFromConfig.end(); + Unicode::String const playerCityCreationTimeDataFromConfigDelimiter(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector playerCityCreationTimeDataFromConfigTokens; + std::string playerCityCreationTimeDataFromConfigParsedData; + + time_t creationTime = 0; + std::string cluster; + int cityId = 0; + + int const numRows = table->getNumRows(); + int rowIndex = 0; + + while (true) + { + if (rowIndex < numRows) + { + creationTime = static_cast(table->getIntValue(columnCreationTime, rowIndex)); + cluster = table->getStringValue(columnCluster, rowIndex); + cityId = table->getIntValue(columnCityId, rowIndex); + + FATAL((cluster.empty()), ("cluster name is empty in %s, row %d", retroactivePlayerCityCreationTimeFilename.c_str(), (rowIndex+3))); + FATAL((cityId <= 0), ("city id for player city (%s, %d) is <= 0 in %s, row %d", cluster.c_str(), cityId, retroactivePlayerCityCreationTimeFilename.c_str(), (rowIndex+3))); + FATAL((creationTime <= 0), ("creation time (%d) for player city (%s, %d) is <= 0 in %s, row %d", creationTime, cluster.c_str(), cityId, retroactivePlayerCityCreationTimeFilename.c_str(), (rowIndex+3))); + + ++rowIndex; + } + else if (iterPlayerCityCreationTimeDataFromConfig == iterPlayerCityCreationTimeDataFromConfigEnd) + { + break; + } + else + { + playerCityCreationTimeDataFromConfigTokens.clear(); + if ((Unicode::tokenize(Unicode::narrowToWide(*iterPlayerCityCreationTimeDataFromConfig), playerCityCreationTimeDataFromConfigTokens, &playerCityCreationTimeDataFromConfigDelimiter, NULL)) && (playerCityCreationTimeDataFromConfigTokens.size() == 3)) + { + // sanity check + playerCityCreationTimeDataFromConfigParsedData = FormattedString<2048>().sprintf("%s|%s|%s", Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[0]).c_str(), Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[1]).c_str(), Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[2]).c_str()); + FATAL((playerCityCreationTimeDataFromConfigParsedData != *iterPlayerCityCreationTimeDataFromConfig), ("parsed player city creation time data (%s) does not equal read player city creation time data (%s)", playerCityCreationTimeDataFromConfigParsedData.c_str(), iterPlayerCityCreationTimeDataFromConfig->c_str())); + + creationTime = static_cast(::atol(Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[0]).c_str())); + cluster = Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[1]); + cityId = ::atoi(Unicode::wideToNarrow(playerCityCreationTimeDataFromConfigTokens[2]).c_str()); + + FATAL((cluster.empty()), ("cluster name is empty in config option (%s)", iterPlayerCityCreationTimeDataFromConfig->c_str())); + FATAL((cityId <= 0), ("city id for player city (%s, %d) is <= 0 in config option (%s)", cluster.c_str(), cityId, iterPlayerCityCreationTimeDataFromConfig->c_str())); + FATAL((creationTime <= 0), ("creation time (%d) for player city (%s, %d) is <= 0 in config option (%s)", creationTime, cluster.c_str(), cityId, iterPlayerCityCreationTimeDataFromConfig->c_str())); + } + else + { + FATAL(true, ("cannot parse player city creation time data (%s) read from config file", iterPlayerCityCreationTimeDataFromConfig->c_str())); + } + + ++iterPlayerCityCreationTimeDataFromConfig; + } + + std::map * clusterPlayerCityCreationTimeHistory = NULL; +#ifdef _DEBUG + clusterPlayerCityCreationTimeHistory = &(s_retroactivePlayerCityCreationTime[cluster]); +#else + // for release build, we only care about player cities created + // on our cluster cluster; for debug build, read them all so we + // can test out the logic to make sure it works for all clusters + if (cluster == GameServer::getInstance().getClusterName()) + clusterPlayerCityCreationTimeHistory = &s_retroactivePlayerCityCreationTimeThisCluster; +#endif + if (clusterPlayerCityCreationTimeHistory) + { + FATAL((clusterPlayerCityCreationTimeHistory->count(cityId) > 0), ("multiple entries found for player city (%s, %d)", cluster.c_str(), cityId)); + (*clusterPlayerCityCreationTimeHistory)[cityId] = creationTime; + } + } + + DataTableManager::close(retroactivePlayerCityCreationTimeFilename); + } + } +} + +// ---------------------------------------------------------------------- + +bool GameServerNamespace::checkAndSetOutstandingRequestSceneTransfer(ServerObject & object) +{ + int const timeNow = static_cast(::time(NULL)); + + // don't send multiple RequestSceneTransfer message + if (object.getObjVars().hasItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER) && (object.getObjVars().getType(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER) == DynamicVariable::INT)) + { + int requestTimeOut = 0; + if (object.getObjVars().getItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER, requestTimeOut)) + { + if (timeNow <= requestTimeOut) + { + LOG("RequestSceneWarp", ("%s already has an outstanding RequestSceneTransfer that will expire in %d seconds", PlayerObject::getAccountDescription(&object).c_str(), (requestTimeOut - timeNow))); + return true; + } + else + { + LOG("RequestSceneWarp", ("%s has an expired RequestSceneTransfer, so we are allowing a new RequestSceneTransfer", PlayerObject::getAccountDescription(&object).c_str())); + } + } + } + + IGNORE_RETURN(object.setObjVarItem(OBJVAR_HAS_OUTSTANDING_REQUEST_SCENE_TRANSFER, (timeNow + ConfigServerGame::getRequestSceneWarpTimeoutSeconds()))); + + return false; +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::handleFactionalSystemMessage(FactionalSystemMessage const & msg) +{ + // is it a ranged message? + if (msg.getRadius() >= 0.0f) + { + TangibleObject * to; + std::vector playersInRange; + ServerWorld::findPlayerCreaturesInRange(msg.getLocation(), msg.getRadius(), playersInRange); + for (std::vector::const_iterator i = playersInRange.begin(); i != playersInRange.end(); ++i) + { + if ((*i)->isAuthoritative() && (*i)->getClient()) + { + to = (*i)->asTangibleObject(); + if (to && + ((msg.getNotifyImperial() && PvpData::isImperialFactionId(to->getPvpFaction())) || + (msg.getNotifyRebel() && PvpData::isRebelFactionId(to->getPvpFaction())) + ) + ) + { + Chat::sendSystemMessage(**i, Unicode::String(), msg.getProsePackage()); + } + } + } + } + else + { + // not a ranged message, everyone gets it + std::set const &players = PlayerObject::getAllPlayerObjects(); + if (!players.empty()) + { + CreatureObject const * creatureObject; + for (std::set::const_iterator i = players.begin(); i != players.end(); ++i) + { + creatureObject = (*i)->getCreatureObject(); + if (creatureObject && creatureObject->isAuthoritative() && creatureObject->getClient()) + { + if ((msg.getNotifyImperial() && PvpData::isImperialFactionId(creatureObject->getPvpFaction())) || + (msg.getNotifyRebel() && PvpData::isRebelFactionId(creatureObject->getPvpFaction())) + ) + { + Chat::sendSystemMessage(*creatureObject, Unicode::String(), msg.getProsePackage()); + } + } + } + } + } +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::handleMessageToPlayersOnPlanet(std::string const & methodName, std::vector const & params, float const delay, Vector const & loc, float const radius, bool const includeDisconnectedPlayers) +{ + // we cannot use ServerWorld::findPlayerCreaturesInRange() because that only looks at creatures + // that are in the world, and disconnected players creatures are removed from the world + std::set const &players = PlayerObject::getAllPlayerObjects(); + if (!players.empty()) + { + float const radiusSquared = sqr(radius); + CreatureObject const * creatureObject; + for (std::set::const_iterator i = players.begin(); i != players.end(); ++i) + { + creatureObject = (*i)->getCreatureObject(); + if (creatureObject && creatureObject->isAuthoritative() && (includeDisconnectedPlayers || creatureObject->getClient())) + { + // check range, if necessary + if ((radius < 0.0f) || (loc.magnitudeBetweenSquared(creatureObject->getPosition_w()) < radiusSquared)) + { + MessageToQueue::getInstance().sendMessageToJava(creatureObject->getNetworkId(), methodName, params, static_cast(delay), false); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::handleMessageLocateStructureByOwnerIdReq(GameServer & gsInstance, uint32 responsePid, bool isGod, NetworkId const & ownerId, NetworkId const & ownerResidenceId, NetworkId const & responseId) +{ + static std::string const planetName(ServerWorld::getSceneId()); + static std::string const displayPlanetName(Unicode::wideToNarrow(StringId("planet_n", planetName).localize())); + std::vector response; + + // buildings + { + BuildingObject::AllBuildingsSet const & allBuildings = BuildingObject::getAllBuildings(); + for (BuildingObject::AllBuildingsSet::const_iterator iterBuilding = allBuildings.begin(); iterBuilding != allBuildings.end(); ++iterBuilding) + { + if ((*iterBuilding)->isAuthoritative() && ((*iterBuilding)->getOwnerId() == ownerId) && (*iterBuilding)->isInWorldCell()) + { + // player assigned name + std::string name = Unicode::wideToNarrow((*iterBuilding)->getAssignedObjectName()); + + // buildings have their name in the sign + if (name.empty() && (*iterBuilding)->getObjVars().hasItem("player_structure.sign.name") && ((*iterBuilding)->getObjVars().getType("player_structure.sign.name") == DynamicVariable::STRING)) + IGNORE_RETURN((*iterBuilding)->getObjVars().getItem("player_structure.sign.name", name)); + + // default/type name + Unicode::String nameTypeWide; + std::string nameTypeNarrow = "Building"; + if ((*iterBuilding)->getObjectNameStringId().localize(nameTypeWide)) + nameTypeNarrow = Unicode::wideToNarrow(nameTypeWide); + + if (!name.empty()) + { + if (name != nameTypeNarrow) + { + name += " ("; + name += nameTypeNarrow; + name += ")"; + } + } + else + { + name = nameTypeNarrow; + } + + // check for residence building + NetworkId residenceOf; + if ((*iterBuilding)->getObjVars().getItem("player_structure.residence.building", residenceOf) && (residenceOf == ownerId)) + { + if (ownerId == responseId) + { + if (ownerResidenceId == (*iterBuilding)->getNetworkId()) + { + name += " (residence)"; + } + else + { + // house thinks it's the residence of the owner, but owner doesn't think so, + // so fix up house so it no longer thinks it's the residence of the owner + (const_cast(*iterBuilding))->removeObjVarItem("player_structure.residence.building"); + } + } + else + { + name += " (residence)"; + } + } + + Vector const loc = (*iterBuilding)->findPosition_w(); + std::string cityAndPlanetName; + int const cityId = CityInterface::getCityAtLocation(planetName, static_cast(loc.x), static_cast(loc.z), 0); + if (cityId > 0) + cityAndPlanetName = CityInterface::getCityInfo(cityId).getCityName(); + + if (!cityAndPlanetName.empty()) + cityAndPlanetName += ", "; + + cityAndPlanetName += displayPlanetName; + + Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(planetName, loc.x, loc.z); + if (region) + { + cityAndPlanetName += ":"; + cityAndPlanetName += Unicode::wideToNarrow(StringId::decodeString(region->getName())); + } + + if (!isGod) + response.push_back(FormattedString<1024>().sprintf("%s at %s (%d, %d)", name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); + else + response.push_back(FormattedString<1024>().sprintf("%s, %s at %s (%d, %d)", (*iterBuilding)->getNetworkId().getValueString().c_str(), name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); + } + } + } + + // installations, including harvesters and factories + { + InstallationObject::AllInstallationsSet const & allInstallations = InstallationObject::getAllInstallations(); + for (ManufactureInstallationObject::AllInstallationsSet::const_iterator iterInstallation = allInstallations.begin(); iterInstallation != allInstallations.end(); ++iterInstallation) + { + if ((*iterInstallation)->isAuthoritative() && ((*iterInstallation)->getOwnerId() == ownerId) && (*iterInstallation)->isInWorldCell()) + { + // player assigned name + std::string name = Unicode::wideToNarrow((*iterInstallation)->getAssignedObjectName()); + + // default/type name + Unicode::String nameTypeWide; + std::string nameTypeNarrow; + if ((*iterInstallation)->getObjectNameStringId().localize(nameTypeWide)) + nameTypeNarrow = Unicode::wideToNarrow(nameTypeWide); + else if (dynamic_cast(*iterInstallation)) + nameTypeNarrow = "Harvester"; + else if (dynamic_cast(*iterInstallation)) + nameTypeNarrow = "Factory"; + else + nameTypeNarrow = "Installation"; + + if (!name.empty()) + { + if (name != nameTypeNarrow) + { + name += " ("; + name += nameTypeNarrow; + name += ")"; + } + } + else + { + name = nameTypeNarrow; + } + + Vector const loc = (*iterInstallation)->findPosition_w(); + std::string cityAndPlanetName; + int const cityId = CityInterface::getCityAtLocation(planetName, static_cast(loc.x), static_cast(loc.z), 0); + if (cityId > 0) + cityAndPlanetName = CityInterface::getCityInfo(cityId).getCityName(); + + if (!cityAndPlanetName.empty()) + cityAndPlanetName += ", "; + + cityAndPlanetName += displayPlanetName; + + Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(planetName, loc.x, loc.z); + if (region) + { + cityAndPlanetName += ":"; + cityAndPlanetName += Unicode::wideToNarrow(StringId::decodeString(region->getName())); + } + + if (!isGod) + response.push_back(FormattedString<1024>().sprintf("%s at %s (%d, %d)", name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); + else + response.push_back(FormattedString<1024>().sprintf("%s, %s at %s (%d, %d)", (*iterInstallation)->getNetworkId().getValueString().c_str(), name.c_str(), cityAndPlanetName.c_str(), static_cast(loc.x), static_cast(loc.z))); + } + } + } + + // if there are any matches, send reply + if (!response.empty()) + { + GenericValueTypeMessage, std::vector > > locateStructureByOwnerIdRsp("LSBOIRsp", std::make_pair(std::make_pair(responsePid, responseId), response)); + gsInstance.sendToCentralServer(locateStructureByOwnerIdRsp); + } +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::handleMessageLocateStructureByOwnerIdRsp(NetworkId const & responseId, std::vector const & response) +{ + if (response.empty()) + return; + + ServerObject const * const object = ServerWorld::findObjectByNetworkId(responseId); + if (!object) + return; + + Client * const clientObj = object->getClient(); + if (!clientObj) + return; + + for (std::vector::const_iterator iter = response.begin(); iter != response.end(); ++iter) + ConsoleMgr::broadcastString(*iter, clientObj); +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::handleAdjustAccountFeatureIdResponse(AdjustAccountFeatureIdResponse const & msg) +{ + Archive::ByteStream bs; + msg.pack(bs); + + if (msg.getRequestingPlayer().isValid()) + { + MessageToQueue::getInstance().sendMessageToC(msg.getRequestingPlayer(), + "C++AdjustAccountFeatureIdResponse", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } + + if (msg.getTargetPlayer().isValid() && (msg.getTargetPlayer() != msg.getRequestingPlayer())) + { + MessageToQueue::getInstance().sendMessageToC(msg.getTargetPlayer(), + "C++AdjustAccountFeatureIdResponse", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } + + if (msg.getTargetItem().isValid() && (msg.getTargetItem() != msg.getRequestingPlayer()) && (msg.getTargetItem() != msg.getTargetPlayer())) + { + MessageToQueue::getInstance().sendMessageToC(msg.getTargetItem(), + "C++AdjustAccountFeatureIdResponse", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } +} + +// ---------------------------------------------------------------------- + +void GameServerNamespace::handleAccountFeatureIdResponse(AccountFeatureIdResponse const & msg) +{ + // this message may arrive before the Client object has been attached + // to the character object, or even before we have loaded the character + // object into the game, so we'll just directly search for the Client + // object associated with the character object and update the information + bool needToNotifyRequester = (((msg.getRequestReason() == AccountFeatureIdRequest::RR_ConsoleCommandReloadRequest) || (msg.getRequestReason() == AccountFeatureIdRequest::RR_ReloadRewardCheck)) && msg.getRequester().isValid()); + + if (msg.getResultCode() == RESULT_SUCCESS) + { + Client * client = GameServer::getInstance().getClient(msg.getTarget()); + if (client) + { + if (msg.getGameCode() == PlatformGameCode::SWG) + client->setAccountFeatureIds(msg.getFeatureIds()); + } + else + { + // character object may have moved to a different game server, + // so forward the message to the character object for handling + Archive::ByteStream bs; + msg.pack(bs); + + MessageToQueue::getInstance().sendMessageToC(msg.getTarget(), + "C++AccountFeatureIdResponse", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + + // don't need to send another messageTo to the requester + if (needToNotifyRequester && (msg.getRequester() == msg.getTarget())) + needToNotifyRequester = false; + } + } + + if (needToNotifyRequester) + { + Archive::ByteStream bs; + msg.pack(bs); + + MessageToQueue::getInstance().sendMessageToC(msg.getRequester(), + "C++AccountFeatureIdResponse", + std::string(reinterpret_cast(bs.getBuffer()), static_cast(bs.getSize())), + 0, + false); + } +} + +// ---------------------------------------------------------------------- + +std::string GameServer::getRetroactiveCtsHistory(std::string const & clusterName, NetworkId const & characterId) +{ + std::string result; + std::map > const * clusterCtsHistory = NULL; + +#ifdef _DEBUG + std::map > >::const_iterator const iterFindCluster = s_retroactiveCtsHistoryList.find(clusterName); + if (iterFindCluster != s_retroactiveCtsHistoryList.end()) + clusterCtsHistory = &(iterFindCluster->second); +#else + if (clusterName == GameServer::getInstance().getClusterName()) + clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; +#endif + + if (!clusterCtsHistory) + return result; + + std::map >::const_iterator const iterFindCharacter = clusterCtsHistory->find(characterId); + if (iterFindCharacter == clusterCtsHistory->end()) + return result; + + int count = 0; + for (std::vector::const_reverse_iterator iterCtsHistory = iterFindCharacter->second.rbegin(); iterCtsHistory != iterFindCharacter->second.rend(); ++iterCtsHistory) + { + if (!result.empty()) + result += "\n"; + + ++count; + + if (iterCtsHistory->sourceCharacterBornDate <= 0) + result += FormattedString<1024>().sprintf("%2d) transferred from (%s, %s, %s) on (%ld, %s)", count, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterName.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->transferTime, CalendarTime::convertEpochToTimeStringLocal(iterCtsHistory->transferTime).c_str()); + else + result += FormattedString<1024>().sprintf("%2d) transferred from (%s, %s, %s, born date=%d, %s) on (%ld, %s)", count, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterName.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->sourceCharacterBornDate, CalendarTime::getCharacerBirthDateString(iterCtsHistory->sourceCharacterBornDate).c_str(), iterCtsHistory->transferTime, CalendarTime::convertEpochToTimeStringLocal(iterCtsHistory->transferTime).c_str()); + + for (std::vector >::const_iterator iterRetroactiveObjvar = iterCtsHistory->sourceCharacterRetroactiveObjvars.begin(); iterRetroactiveObjvar != iterCtsHistory->sourceCharacterRetroactiveObjvars.end(); ++iterRetroactiveObjvar) + result += FormattedString<1024>().sprintf("\n\t(%s, %s)", iterRetroactiveObjvar->first.c_str(), Unicode::wideToNarrow(iterRetroactiveObjvar->second.getPackedValueString()).c_str()); + } + + return result; +} + +// ---------------------------------------------------------------------- + +void GameServer::setRetroactiveCtsHistory(CreatureObject & player) +{ + if (!player.isAuthoritative()) + return; + + if (player.getObjVars().hasItem("ctsHistory")) + return; + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(&player); + if (!playerObject) + return; + + if (!playerObject->isAuthoritative()) + return; + + std::map > const * clusterCtsHistory = NULL; + +#ifdef _DEBUG + std::map > >::const_iterator const iterFindCluster = s_retroactiveCtsHistoryList.find(GameServer::getInstance().getClusterName()); + if (iterFindCluster != s_retroactiveCtsHistoryList.end()) + clusterCtsHistory = &(iterFindCluster->second); +#else + clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; +#endif + + if (!clusterCtsHistory) + return; + + std::map >::const_iterator const iterFindCharacter = clusterCtsHistory->find(player.getNetworkId()); + if (iterFindCharacter == clusterCtsHistory->end()) + return; + + int count = 0; + int rootSourceCharacterBornDate = 0; + std::vector ctsSourceGalaxies; + for (std::vector::const_reverse_iterator iterCtsHistory = iterFindCharacter->second.rbegin(); iterCtsHistory != iterFindCharacter->second.rend(); ++iterCtsHistory) + { + ++count; + LOG("CustomerService", ("CharacterTransferRetroactiveHistory: %s, setting objvar ctsHistory.%d = \"%ld %s %s %s\", transfer time (%s)", playerObject->getAccountDescription().c_str(), count, iterCtsHistory->transferTime, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->sourceCharacterName.c_str(), CalendarTime::convertEpochToTimeStringLocal(iterCtsHistory->transferTime).c_str())); + IGNORE_RETURN(player.setObjVarItem(FormattedString<1024>().sprintf("ctsHistory.%d", count), FormattedString<1024>().sprintf("%ld %s %s %s", iterCtsHistory->transferTime, iterCtsHistory->sourceCluster.c_str(), iterCtsHistory->sourceCharacterId.getValueString().c_str(), iterCtsHistory->sourceCharacterName.c_str()))); + + if (iterCtsHistory->sourceCharacterBornDate > 0) + { + if ((rootSourceCharacterBornDate == 0) || (iterCtsHistory->sourceCharacterBornDate < rootSourceCharacterBornDate)) + rootSourceCharacterBornDate = iterCtsHistory->sourceCharacterBornDate; + } + + ctsSourceGalaxies.push_back(iterCtsHistory->sourceCluster); + } + + if (rootSourceCharacterBornDate > 0) + { + // initialize the character's born date, if necessary + playerObject->setBornDate(); + + // fix up the character's born date, but only if the "fixup" date is earlier than the current date + int const characterBornDate = playerObject->getBornDate(); + if (rootSourceCharacterBornDate < characterBornDate) + { + playerObject->adjustBornDate(rootSourceCharacterBornDate - characterBornDate); + LOG("CustomerService", ("CharacterTransferRetroactiveHistory: %s, fixing born date from (%d, %s) to (%d, %s)", playerObject->getAccountDescription().c_str(), characterBornDate, CalendarTime::getCharacerBirthDateString(characterBornDate).c_str(), rootSourceCharacterBornDate, CalendarTime::getCharacerBirthDateString(rootSourceCharacterBornDate).c_str())); + + // send mail to player notifying of born date change + Chat::sendPersistentMessage("system", Unicode::wideToNarrow(Unicode::toLower(player.getAssignedObjectFirstName())), Unicode::narrowToWide("Birth Date Fixup"), Unicode::narrowToWide(FormattedString<1024>().sprintf("This character's birth date has been adjusted from %s to %s.", CalendarTime::getCharacerBirthDateString(characterBornDate).c_str(), CalendarTime::getCharacerBirthDateString(rootSourceCharacterBornDate).c_str())), Unicode::emptyString); + } + } + + // grant CTS titles for transfers that occurred between different galaxies + if (!ctsSourceGalaxies.empty()) + { + ctsSourceGalaxies.push_back(GameServer::getInstance().getClusterName()); + for (size_t i = 0, stopIndex = (ctsSourceGalaxies.size() - 2); i <= stopIndex; ++i) + { + if (ctsSourceGalaxies[i] != ctsSourceGalaxies[i+1]) + { + // lower case source cluster name and replace + // - with _ for use to grant CTS title + std::string collectionSlotName = std::string("cts_from_") + Unicode::toLower(ctsSourceGalaxies[i]); + + std::string::size_type pos = collectionSlotName.find('-'); + while (pos != std::string::npos) + { + collectionSlotName.replace(pos, 1, 1, '_'); + pos = collectionSlotName.find('-'); + } + + CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(collectionSlotName); + if (collectionSlot && !playerObject->hasCompletedCollectionSlot(*collectionSlot)) + { + LOG("CustomerService", ("CharacterTransferRetroactiveHistory: %s, granting CTS title %s", playerObject->getAccountDescription().c_str(), collectionSlotName.c_str())); + IGNORE_RETURN(playerObject->modifyCollectionSlotValue(collectionSlotName, 1ll)); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +std::vector > const *> const & GameServer::getRetroactiveCtsHistoryObjvars(NetworkId const & characterId) +{ + static std::vector > const *> returnValue; + returnValue.clear(); + + std::map > const * clusterCtsHistory = NULL; + +#ifdef _DEBUG + std::map > >::const_iterator const iterFindCluster = s_retroactiveCtsHistoryList.find(GameServer::getInstance().getClusterName()); + if (iterFindCluster != s_retroactiveCtsHistoryList.end()) + clusterCtsHistory = &(iterFindCluster->second); +#else + clusterCtsHistory = &s_retroactiveCtsHistoryListThisCluster; +#endif + + if (!clusterCtsHistory) + return returnValue; + + std::map >::const_iterator const iterFindCharacter = clusterCtsHistory->find(characterId); + if (iterFindCharacter == clusterCtsHistory->end()) + return returnValue; + + int numberOfNonEmptyVectorsReturned = 0; + for (std::vector::const_reverse_iterator iterCtsHistory = iterFindCharacter->second.rbegin(); iterCtsHistory != iterFindCharacter->second.rend(); ++iterCtsHistory) + { + returnValue.push_back(&(iterCtsHistory->sourceCharacterRetroactiveObjvars)); + + if (!iterCtsHistory->sourceCharacterRetroactiveObjvars.empty()) + { + ++numberOfNonEmptyVectorsReturned; + } + } + + if (numberOfNonEmptyVectorsReturned == 0) + returnValue.clear(); + + return returnValue; +} + +// ---------------------------------------------------------------------- + +time_t GameServer::getRetroactivePlayerCityCreationTime(std::string const & clusterName, int cityId) +{ + std::map const * clusterPlayerCityCreationTimeHistory = NULL; + +#ifdef _DEBUG + std::map >::const_iterator const iterFindCluster = s_retroactivePlayerCityCreationTime.find(clusterName); + if (iterFindCluster != s_retroactivePlayerCityCreationTime.end()) + clusterPlayerCityCreationTimeHistory = &(iterFindCluster->second); +#else + if (clusterName == GameServer::getInstance().getClusterName()) + clusterPlayerCityCreationTimeHistory = &s_retroactivePlayerCityCreationTimeThisCluster; +#endif + + if (!clusterPlayerCityCreationTimeHistory) + return -1; + + std::map::const_iterator const iterFindCity = clusterPlayerCityCreationTimeHistory->find(cityId); + if (iterFindCity != clusterPlayerCityCreationTimeHistory->end()) + return iterFindCity->second; + + return -1; +} + +// ---------------------------------------------------------------------- + +int GameServer::getServerSpawnLimit() +{ + static int serverSpawnLimit = -1; + + if (GameServer::getInstance().getPreloadAreaId() == 0) + { + return ConfigServerGame::getServerSpawnLimit(); + } + + if (serverSpawnLimit == -1) + { + serverSpawnLimit = ConfigServerGame::getServerSpawnLimit(); + + // see if there's a spawn limit set for this particular game server + char key[128]; + snprintf(key, sizeof(key)-1, "serverSpawnLimit_%s.%lu", ServerWorld::getSceneId().c_str(), GameServer::getInstance().getPreloadAreaId()); + key[sizeof(key)-1] = '\0'; + + if (getConfigSetting("GameServer", key, serverSpawnLimit)) + return serverSpawnLimit; + + // see if there's a spawn limit set for this particular planet + snprintf(key, sizeof(key)-1, "serverSpawnLimit_%s", ServerWorld::getSceneId().c_str()); + key[sizeof(key)-1] = '\0'; + + if (getConfigSetting("GameServer", key, serverSpawnLimit)) + return serverSpawnLimit; + + // use default server spawn limit + serverSpawnLimit = ConfigServerGame::getServerSpawnLimit(); + } + + return serverSpawnLimit; +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG +void GameServer::setExtraDelayPerFrameMs(int ms) // to emulate long loop time +{ + s_extraDelayPerFrameMs = ms; +} +#endif + +// ====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/core/NpcConversation.cpp b/src/engine/server/library/serverGame/src/shared/core/NpcConversation.cpp index 6ec9d47e4..bc457bbda 100644 --- a/src/engine/server/library/serverGame/src/shared/core/NpcConversation.cpp +++ b/src/engine/server/library/serverGame/src/shared/core/NpcConversation.cpp @@ -280,10 +280,8 @@ void NpcConversation::sendResponses() */ const NpcConversation::Response & NpcConversation::getResponse(int index) const { - const static Response dummy; - if (m_responses->empty()) - return dummy; + return m_responses->at(static_cast(0)); const int size = static_cast(m_responses->size()); if (index < 0) diff --git a/src/engine/server/library/serverGame/src/shared/core/PreloadManager.cpp b/src/engine/server/library/serverGame/src/shared/core/PreloadManager.cpp index 3a9ba6d13..799e45dfd 100644 --- a/src/engine/server/library/serverGame/src/shared/core/PreloadManager.cpp +++ b/src/engine/server/library/serverGame/src/shared/core/PreloadManager.cpp @@ -28,11 +28,11 @@ namespace PreloadManagerNameSpace void loadObjectTemplates() { FILE* fp = fopen("objectTemplates.plf","r"); - char buf [128]; + char buf [256]; if (fp) { DEBUG_REPORT_LOG(true, ("Scanning templates")); - char* line = fgets(buf, 128, fp); + char* line = fgets(buf, 256, fp); while (line) { //strip newline @@ -58,7 +58,7 @@ namespace PreloadManagerNameSpace objectTemplate->preloadAssets(); } DEBUG_REPORT_LOG(true, (".")); - line = fgets(buf, 128, fp); + line = fgets(buf, 256, fp); } fclose(fp); DEBUG_REPORT_LOG(true, ("\n")); @@ -68,11 +68,11 @@ namespace PreloadManagerNameSpace void loadDataTables() { FILE* fp = fopen("datatables.plf","r"); - char buf [128]; + char buf [256]; if (fp) { DEBUG_REPORT_LOG(true, ("Scanning tables")); - char* line = fgets(buf, 128, fp); + char* line = fgets(buf, 256, fp); while (line) { @@ -99,7 +99,7 @@ namespace PreloadManagerNameSpace UNREF(dt); #endif DEBUG_REPORT_LOG(true, (".")); - line = fgets(buf, 128, fp); + line = fgets(buf, 256, fp); } fclose(fp); DEBUG_REPORT_LOG(true, ("\n")); diff --git a/src/engine/server/library/serverGame/src/shared/core/ServerWorld.cpp b/src/engine/server/library/serverGame/src/shared/core/ServerWorld.cpp index a8d338020..9b94409a4 100644 --- a/src/engine/server/library/serverGame/src/shared/core/ServerWorld.cpp +++ b/src/engine/server/library/serverGame/src/shared/core/ServerWorld.cpp @@ -199,18 +199,11 @@ void compare_results_int( std::set &results, std::setgetOwner(); - if ( &volumeOwner == NULL ) - { - LOG("SphereGrid", ("Ack null owner!")); - } - else - { - const Object* pob = getContainingPobForObjectInWorld(volume->getOwner()); - Sphere const &localSphere = volumeOwner.getLocalSphere(); - Sphere world(volumeOwner.getTransform_o2w().rotateTranslate_l2p(localSphere.getCenter()), volume->getRadius()); - Vector c=world.getCenter(); - LOG("SphereGrid",(" (%f %f %f) %f POB = %p DIST=%f",c.x,c.y,c.z,world.getRadius(),pob, c.magnitudeBetween(v) )); - } + const Object* pob = getContainingPobForObjectInWorld(volume->getOwner()); + Sphere const &localSphere = volumeOwner.getLocalSphere(); + Sphere world(volumeOwner.getTransform_o2w().rotateTranslate_l2p(localSphere.getCenter()), volume->getRadius()); + Vector c=world.getCenter(); + LOG("SphereGrid",(" (%f %f %f) %f POB = %p DIST=%f",c.x,c.y,c.z,world.getRadius(),pob, c.magnitudeBetween(v) )); } LOG("SphereGrid", ("------------------ Grid Results %d ------------------",results2.size())); @@ -218,18 +211,11 @@ void compare_results_int( std::set &results, std::setgetOwner(); - if ( &volumeOwner == NULL ) - { - LOG("SphereGrid", ("shit null owner.")); - } - else - { - const Object* pob = getContainingPobForObjectInWorld(volume->getOwner()); - Sphere const &localSphere = volumeOwner.getLocalSphere(); - Sphere world(volumeOwner.getTransform_o2w().rotateTranslate_l2p(localSphere.getCenter()), volume->getRadius()); // o2p or o2w - Vector c=world.getCenter(); - LOG("SphereGrid",(" (%f %f %f) %f POB = %p DIST=%f",c.x,c.y,c.z,world.getRadius(),pob, c.magnitudeBetween(v) )); - } + const Object* pob = getContainingPobForObjectInWorld(volume->getOwner()); + Sphere const &localSphere = volumeOwner.getLocalSphere(); + Sphere world(volumeOwner.getTransform_o2w().rotateTranslate_l2p(localSphere.getCenter()), volume->getRadius()); // o2p or o2w + Vector c=world.getCenter(); + LOG("SphereGrid",(" (%f %f %f) %f POB = %p DIST=%f",c.x,c.y,c.z,world.getRadius(),pob, c.magnitudeBetween(v) )); } DEBUG_FATAL(true,("FATAL: SphereGrid failed to match SphereTree result set.")); diff --git a/src/engine/server/library/serverGame/src/shared/object/CellPermissions.h b/src/engine/server/library/serverGame/src/shared/object/CellPermissions.h index 8fcfccc38..d05703a70 100644 --- a/src/engine/server/library/serverGame/src/shared/object/CellPermissions.h +++ b/src/engine/server/library/serverGame/src/shared/object/CellPermissions.h @@ -48,8 +48,8 @@ namespace CellPermissions class PermissionObject { - friend void Archive::get( ReadIterator & source, CellPermissions::PermissionObject & target ); - friend void Archive::put( ByteStream & target, const CellPermissions::PermissionObject & source ); + friend void Archive::get( Archive::ReadIterator & source, CellPermissions::PermissionObject & target ); + friend void Archive::put( Archive::ByteStream & target, const CellPermissions::PermissionObject & source ); friend class ::BuildingObject; friend class ::CellObject; diff --git a/src/engine/server/library/serverGame/src/shared/object/CreatureObject.cpp b/src/engine/server/library/serverGame/src/shared/object/CreatureObject.cpp index 3fa656f5d..2800d79b6 100644 --- a/src/engine/server/library/serverGame/src/shared/object/CreatureObject.cpp +++ b/src/engine/server/library/serverGame/src/shared/object/CreatureObject.cpp @@ -1,15911 +1,15907 @@ -//======================================================================== -// -// CreatureObject.cpp -// Copyright 2001-2005, Sony Online Entertainment, Inc. -// All rights reserved. -// -//======================================================================== - -#include "serverGame/FirstServerGame.h" -#pragma warning(disable : 4100 4514) -#include "serverGame/CreatureObject.h" - -#include "SwgGameServer/CombatEngine.h" -#include "SwgGameServer/ConfigCombatEngine.h" -#include "UnicodeUtils.h" -#include "serverGame/AiCreatureController.h" -#include "serverGame/AttribModNameManager.h" -#include "serverGame/BiographyManager.h" -#include "serverGame/BuffManager.h" -#include "serverGame/BuildingObject.h" -#include "serverGame/CellObject.h" -#include "serverGame/Chat.h" -#include "serverGame/CitizenInfo.h" -#include "serverGame/CityInfo.h" -#include "serverGame/CityInterface.h" -#include "serverGame/Client.h" -#include "serverGame/CommandCppFuncs.h" -#include "serverGame/CommandQueue.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ConsoleManager.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/DraftSchematicObject.h" -#include "serverGame/GameServer.h" -#include "serverGame/GroupObject.h" -#include "serverGame/GroupMissionCriticalObjectsBuilder.h" -#include "serverGame/GroupStringId.h" -#include "serverGame/GuildInterface.h" -#include "serverGame/GuildMemberInfo.h" -#include "serverGame/GuildObject.h" -#include "serverGame/ServerImageDesignerManager.h" -#include "serverGame/ManufactureSchematicObject.h" -#include "serverGame/MessageToQueue.h" -#include "serverGame/MissionObject.h" -#include "serverGame/MoveSimManager.h" -#include "serverGame/NameManager.h" -#include "serverGame/NewbieTutorial.h" -#include "serverGame/NpcConversation.h" -#include "serverGame/ObjectTracker.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PlanetObject.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/PvpInternal.h" -#include "serverGame/Region.h" -#include "serverGame/RegionMaster.h" -#include "serverGame/ReportManager.h" -#include "serverGame/ServerCreatureObjectTemplate.h" -#include "serverGame/ServerMessageForwarding.h" -#include "serverGame/ServerMissionObjectTemplate.h" -#include "serverGame/ServerSecureTrade.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWeaponObjectTemplate.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/ShipObject.h" -#include "serverGame/SpaceVisibilityManager.h" -#include "serverGame/TriggerVolume.h" -#include "serverGame/VeteranRewardManager.h" -#include "serverGame/WeaponObject.h" -#include "serverNetworkMessages/AccountFeatureIdResponse.h" -#include "serverNetworkMessages/FeatureIdTransactionRequest.h" -#include "serverNetworkMessages/FeatureIdTransactionResponse.h" -#include "serverNetworkMessages/GroupMemberParam.h" -#include "serverNetworkMessages/LoginUpgradeAccountMessage.h" -#include "serverNetworkMessages/MessageQueueAlterAttribute.h" -#include "serverNetworkMessages/MessageQueueCommandQueueEnqueueFwd.h" -#include "serverNetworkMessages/MessageQueueSetState.h" -#include "serverNetworkMessages/MessageToPayload.h" -#include "serverNetworkMessages/TransferReplyMoveValidation.h" -#include "serverNetworkMessages/UnloadedPlayerMessage.h" -#include "serverNetworkMessages/UpdateObjectOnPlanetMessage.h" -#include "serverNetworkMessages/UploadCharacterMessage.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/JavaLibrary.h" -#include "serverScript/ScriptDictionary.h" -#include "serverScript/ScriptParameters.h" -#include "serverUtility/AdminAccountManager.h" -#include "serverUtility/ServerClock.h" -#include "Session/CommonAPI/CommonAPI.h" -#include "sharedCollision/BaseExtent.h" -#include "sharedCollision/CollisionProperty.h" -#include "sharedCollision/CollisionWorld.h" -#include "sharedCollision/Floor.h" -#include "sharedCollision/Footprint.h" -#include "sharedDebug/Profiler.h" -#include "sharedFile/TreeFile.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/Clock.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/Crc.h" -#include "sharedFoundation/DynamicVariableList.h" -#include "sharedFoundation/DynamicVariableListNestedList.h" -#include "sharedFoundation/DynamicVariableLocationData.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/GameControllerMessage.h" -#include "sharedFoundation/TemporaryCrcString.h" -#include "sharedGame/AppearanceManager.h" -#include "sharedGame/AttribModArchive.h" -#include "sharedGame/Buff.h" -#include "sharedGame/CityData.h" -#include "sharedGame/CommandTable.h" -#include "sharedGame/ConfigSharedGame.h" -#include "sharedGame/CraftingData.h" -#include "sharedGame/CustomizationManager.h" -#include "sharedGame/CustomizationManager_MorphParameter.h" -#include "sharedGame/GameObjectTypes.h" -#include "sharedGame/LfgDataTable.h" -#include "sharedGame/MatchMakingCharacterResult.h" -#include "sharedGame/OutOfBandPackager.h" -#include "sharedGame/PlatformFeatureBits.h" -#include "sharedGame/PlayerCreationManager.h" -#include "sharedGame/ProsePackage.h" -#include "sharedGame/PvpData.h" -#include "sharedGame/SharedCreatureObjectTemplate.h" -#include "sharedGame/SharedStringIds.h" -#include "sharedGame/ShipSlotIdManager.h" -#include "sharedGame/SlopeEffectProperty.h" -#include "sharedGame/SlowDownProperty.h" -#include "sharedGame/SpatialChatManager.h" -#include "sharedGame/VehicleHoverDynamics.h" -#include "sharedLog/Log.h" -#include "sharedMath/AxialBox.h" -#include "sharedMath/MxCifQuadTreeBounds.h" -#include "sharedMath/Ray3d.h" -#include "sharedNetworkMessages/ClientMfdStatusUpdateMessage.h" -#include "sharedNetworkMessages/ErrorMessage.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/GrantCommand.h" -#include "sharedNetworkMessages/MessageQueueCombatSpam.h" -#include "sharedNetworkMessages/MessageQueueCommandTimer.h" -#include "sharedNetworkMessages/MessageQueueDataTransformWithParent.h" -#include "sharedNetworkMessages/MessageQueueGenericValueType.h" -#include "sharedNetworkMessages/MessageQueueMissionListResponse.h" -#include "sharedNetworkMessages/MessageQueueOpponentInfo.h" -#include "sharedNetworkMessages/MessageQueuePosture.h" -#include "sharedNetworkMessages/MessageQueuePushCreature.h" -#include "sharedNetworkMessages/MessageQueueSitOnObject.h" -#include "sharedNetworkMessages/MessageQueueSlowDownEffect.h" -#include "sharedNetworkMessages/MessageQueueSpatialChat.h" -#include "sharedNetworkMessages/MessageQueueStringList.h" -#include "sharedNetworkMessages/RevokeCommand.h" -#include "sharedNetworkMessages/SceneChannelMessages.h" -#include "sharedNetworkMessages/SlowDownEffectMessage.h" -#include "serverNetworkMessages/TransferCharacterData.h" -#include "serverNetworkMessages/TransferCharacterDataArchive.h" -#include "sharedNetworkMessages/UpdatePostureMessage.h" -#include "sharedObject/AlterResult.h" -#include "sharedObject/CellProperty.h" -#include "sharedObject/ContainedByProperty.h" -#include "sharedObject/CustomizationData.h" -#include "sharedObject/MovementTable.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedObject/SlotId.h" -#include "sharedObject/SlotIdManager.h" -#include "sharedObject/SlottedContainer.h" -#include "sharedObject/SlottedContainmentProperty.h" -#include "sharedObject/VolumeContainer.h" -#include "sharedSkillSystem/ExpertiseManager.h" -#include "sharedSkillSystem/LevelManager.h" -#include "sharedSkillSystem/SkillManager.h" -#include "sharedSkillSystem/SkillObject.h" -#include "sharedTerrain/TerrainObject.h" -#include "sharedTerrain/WaterTypeManager.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" -#include "swgSharedNetworkMessages/MessageQueueCombatAction.h" -#include "swgSharedUtility/Attributes.h" -#include "swgSharedUtility/States.h" -#include "sharedUtility/ValueDictionary.h" -#include -#include -#include -#include -#include - -//---------------------------------------------------------------------- -// static CreatureObject vars - -const SharedObjectTemplate * CreatureObject::m_defaultSharedTemplate = NULL; - -//---------------------------------------------------------------------- - -// The max number of lots available to a player. This value is also defined in base_class.java -static const int HOUSING_MAX_LOTS = 10; - -// Slot names -static const ConstCharCrcLowerString DATAPAD_SLOT_NAME("datapad"); - -// Crafting objvar names -static const std::string OBJVAR_DISABLE_SCHEMATIC_FILTER("crafting.disableSchematicFiltering"); - -//objvar for banking -static const std::string OBJVAR_BANK_ID("banking_bankid"); -static const std::string OBJVAR_OPEN_BANK_TERMINAL_ID("open_bank_location"); - -//slot names -static const ConstCharCrcLowerString BANK_SLOT_NAME("bank"); -static const ConstCharCrcLowerString MISSION_BAG_SLOT_NAME("mission_bag"); - -// skill data granted independently from skills -static const std::string OBJVAR_NOT_SKILL_MODS("_notskill.mods"); -static const std::string OBJVAR_NOT_SKILL_COMMANDS("_notskill.commands"); -static const std::string OBJVAR_NOT_SKILL_SCHEMATICS("_notskill.schematics"); - -// special skill mods -static const std::string SLOPE_MOD("slope_move"); -static const std::string GROUP_SLOPE_MOD("group_slope_move"); - -// jedi/force power objvars -static const std::string OBJVAR_NEW_JEDI_FORCE("_start_force"); -static const std::string OBJVAR_JEDI("jedi"); -static const std::string OBJVAR_ADD_JEDI_ACK("jediAddedAcknowlege"); -//static const std::string OBJVAR_FORCE_REGEN_RATE("jedi.regenrate"); -//static const std::string OBJVAR_FORCE_REGEN_VALUE("jedi.regenvalue"); -static const std::string OBJVAR_JEDI_VISIBILITY("jedi.visibility"); - -// deprecated badge objvars (will be used to move old badges over to the collection system) -static const std::string OBJVAR_BADGES("badge.tracking"); -static const std::string OBJVAR_COUNT_BADGES("badge.count"); - -// residence house id objvar -const std::string OBJVAR_PLAYER_HOUSE_ID("residenceHouseId"); - -// If a pet accepts a group invitation but is deleted before -// being given the group information, we need to try to remove -// him from the group in the future -static const unsigned MAX_ATTEMPTS_TO_REMOVE_PET_FROM_GROUP = 30; -static const int TIME_BETWEEN_ATTEMPTS_TO_REMOVE_PET = 1; - -// creature regen constants -const static std::string CREATURES_TABLE("datatables/mob/creatures.iff"); - -//---------------------------------------------------------------------- - -namespace CreatureObjectNamespace -{ - const int POINTS_PER_TIER = 4; - // ---------------------------------------------------------------------- - - const char* s_inventoryTemplate = "object/tangible/inventory/character_inventory.iff"; - const char* s_datapadTemplate = "object/tangible/datapad/character_datapad.iff"; - const char* s_missionBagTemplate = "object/tangible/mission_bag/mission_bag.iff"; - const char* s_bankTemplate = "object/tangible/bank/character_bank.iff"; - const char* s_appearanceTemplate = "object/tangible/inventory/appearance_inventory.iff"; - - SlotId s_defaultWeaponSlotId = SlotId::invalid; - SlotId s_inventorySlotId = SlotId::invalid; - SlotId s_appearanceSlotId = SlotId::invalid; - bool s_allowNullDefaultWeapon = false; - - // ---------------------------------------------------------------------- - - std::map > s_instrumentTypeMap; - - // ---------------------------------------------------------------------- - - void loadInstrumentTable() - { - char const *fileName = ConfigServerGame::getInstrumentDataTableFilename(); - DataTable *t = DataTableManager::getTable(fileName, true); - if (!t) - { - FATAL(true, ("Could not find instrument datatable %s.", fileName)); - } - for (int row = 0; row < t->getNumRows(); ++row) - { - std::string name = t->getStringValue("serverTemplateName", row); - int visualId = t->getIntValue("instrumentVisualId", row); - int audioId = t->getIntValue("instrumentAudioId", row); - IGNORE_RETURN(s_instrumentTypeMap.insert(std::make_pair(name, std::make_pair(visualId, audioId)))); - } - DataTableManager::close(fileName); - } - - // ---------------------------------------------------------------------- - - int lookupInstrumentVisualId(char const * serverTemplateName) - { - std::map >::const_iterator i = s_instrumentTypeMap.find(std::string(serverTemplateName)); - if (i != s_instrumentTypeMap.end()) - return (*i).second.first; - return 0; - } - - // ---------------------------------------------------------------------- - - int lookupInstrumentAudioId(char const * serverTemplateName) - { - std::map >::const_iterator i = s_instrumentTypeMap.find(std::string(serverTemplateName)); - if (i != s_instrumentTypeMap.end()) - return (*i).second.second; - return 0; - } - - // ---------------------------------------------------------------------- - - std::map s_danceVisualMap; - - // ---------------------------------------------------------------------- - - void loadDanceVisualTable() - { - char const *fileName = ConfigServerGame::getPerformanceDataTableFilename(); - DataTable *t = DataTableManager::getTable(fileName, true); - for (int row = 0; row < t->getNumRows(); ++row) - { - int visualId = t->getIntValue("danceVisualId", row); - if (visualId) - { - IGNORE_RETURN(s_danceVisualMap.insert(std::make_pair(row+1, visualId))); - } - } - DataTableManager::close(fileName); - } - - struct CommandSeriesRecord - { - std::string commandName; - std::string baseCommandName; - int level; - }; - std::vector s_commandSeriesRecords; - - void loadCommandSeriesTable() - { - DataTable *t = DataTableManager::getTable("datatables/command/command_series.iff", true); - for (int row = 0; row < t->getNumRows(); ++row) - { - CommandSeriesRecord csr; - csr.commandName = t->getStringValue("commandName", row); - csr.baseCommandName = t->getStringValue("baseCommandName", row); - csr.level = t->getIntValue("level", row); - IGNORE_RETURN(s_commandSeriesRecords.push_back(csr)); - } - DataTableManager::close("datatables/command/command_series.iff"); - } - - // ---------------------------------------------------------------------- - - int lookupDanceVisual(int performanceType) - { - std::map::const_iterator i = s_danceVisualMap.find(performanceType); - if (i != s_danceVisualMap.end()) - return (*i).second; - return 0; - } - - // ---------------------------------------------------------------------- - - bool instrumentTooFar(Vector const &playerPos_w, Vector const &instrumentPos_w) - { - static float maxDistSquared = sqr(ConfigServerGame::getMaxInstrumentPlayDistance()); - if (playerPos_w.magnitudeBetweenSquared(instrumentPos_w) < maxDistSquared) - return false; - return true; - } - - // ---------------------------------------------------------------------- - - CreatureObject::AllCreaturesSet g_creatureList; - - std::vector > gs_missionRequestQueue; - std::vector > gs_missionRequestQueueDeferredRemoves; - - void removeCreatureFromMissionRequestQueue(const CreatureObject * creature) - { - std::vector >::iterator qiter; - for(qiter = gs_missionRequestQueue.begin(); qiter != gs_missionRequestQueue.end(); ++qiter) - { - if((*qiter).first == creature) - { - gs_missionRequestQueueDeferredRemoves.push_back((*qiter)); - } - } - } - - std::deque s_spawnQueue; - std::deque s_missionQueue; - - //---------------------------------------------------------------------- - //- @odo: these lists really need to be moved into C++ - - bool isBuildingAdminForTarget (const ServerObject & object, const ServerObject & target) - { - - const TangibleObject* hopperObject = target.asTangibleObject(); - const CreatureObject* player = object.asCreatureObject(); - if (!player || !hopperObject) - return false; - return hopperObject->isOnAdminList(*player); - } - - //---------------------------------------------------------------------- - - bool canHopperForTarget (const ServerObject & object, const ServerObject & target) - { - const TangibleObject* hopperObject = target.asTangibleObject(); - const CreatureObject* player = object.asCreatureObject(); - if (!player || !hopperObject) - return false; - return hopperObject->isOnHopperList(*player); - } - - //---------------------------------------------------------------------- - - bool isTargetBuildingBaseObject (const ServerObject & buildingObject, const ServerObject & target) - { - static const std::string objvarname_baseObjects = "player_structure.base_objects"; - - const NetworkId & targetId = target.getNetworkId (); - - typedef stdvector::fwd NetworkIdVector; - static NetworkIdVector ids; - ids.clear (); - - if (buildingObject.getObjVars ().getItem (objvarname_baseObjects, ids)) - { - for (NetworkIdVector::const_iterator it = ids.begin (); it != ids.end (); ++it) - { - const NetworkId & id = *it; - if (id == targetId) - return true; - } - } - - return false; - } - - bool isOnVendorList(const CreatureObject& object, const ServerObject& target) - { - static const std::string objvarname_vendorList = "player_structure.vendor.vendorList"; - - const Unicode::String & requestorFirstName = object.getAssignedObjectFirstName (); - typedef stdvector::fwd StringVector; - static StringVector sv; - sv.clear (); - - if (target.getObjVars ().getItem (objvarname_vendorList, sv)) - { - for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) - { - const Unicode::String & vendorFirstName = *it; - if (Unicode::caseInsensitiveCompare (vendorFirstName, requestorFirstName)) - { - return true; - } - } - } - return false; - } - - //---------------------------------------------------------------------- - - namespace SlotNames - { - static const ConstCharCrcLowerString datapad ("datapad"); - static const ConstCharCrcLowerString inventory ("inventory"); - static const ConstCharCrcLowerString bank ("bank"); - static const ConstCharCrcLowerString hair ("hair"); - static const ConstCharCrcLowerString ghost ("ghost"); - static const ConstCharCrcLowerString appearance ("appearance_inventory"); - static const ConstCharCrcLowerString hangar ("hangar"); - } - - uint64 s_containmentStatesMask = 0; - std::map s_containerSlotStates; - - namespace GroupHelpers - { - bool creatureIsContainedInPOBShip(CreatureObject const * creatureObject); - void findAllTargetsForGroup(CreatureObject * const targetObj, std::vector & targets); - bool roomInGroup(GroupObject const * groupObj, int additionalMembers); - GroupMemberParam const buildGroupMemberParam(CreatureObject const * creatureObject); - void buildGroupMemberParamsFromCreatures(std::vector const & targets, GroupObject::GroupMemberParamVector & targetMemberParams); - } - - // ---------------------------------------------------------------------- - - void skipField(std::string const &source, unsigned int &pos) - { - while (source[pos] && source[pos] != '~') - ++pos; - if (source[pos] == '~') - ++pos; - } - - // ---------------------------------------------------------------------- - - void nextString(std::string const &source, unsigned int &pos, std::string &ret) - { - unsigned int oldPos = pos; - while (source[pos] && source[pos] != '~') - ++pos; - ret = source.substr(oldPos, pos-oldPos); - if (source[pos] == '~') - ++pos; - } - - // ---------------------------------------------------------------------- - - void nextOid(std::string const &source, unsigned int &pos, NetworkId &ret) - { - unsigned int oldPos = pos; - skipField(source, pos); - ret = NetworkId(source.substr(oldPos, pos-oldPos)); - } - - // ---------------------------------------------------------------------- - - void nextFloat(std::string const &source, unsigned int &pos, float &ret) - { - ret = static_cast(atof(source.c_str()+pos)); - skipField(source, pos); - } - - // for enforcing height restriction when restoring decoration layout - std::map, std::pair > s_mapCellHeightRestriction; - - void restoreItemDecorationLayout(CreatureObject & decorator, PlayerObject & decoratorPlayerObject, CachedNetworkId const & item, TangibleObject const & pob, CachedNetworkId const & cell, Vector const & position, Quaternion const & orientation); -} - -//======================================================================= - -using namespace CreatureObjectNamespace; - -//======================================================================= - -void CreatureObject::PostureChangeCallback::modified(CreatureObject &target, Postures::Enumerator oldValue, Postures::Enumerator value, bool) const -{ - UNREF(oldValue); - // Make creatures not collidable when they're in dead or incapacitated posture - CollisionProperty * collision = target.getCollisionProperty(); - if (collision) - { - bool collidable = (value != Postures::Dead && value != Postures::Incapacitated); - collision->setCollidable(collidable); - } - - //-- Retrieve the collection of avialable locomotions for fast/slow/stationary movement speeds. - // This info is used on authoritative and proxy objects to make calcLocomotions(), called every alter, - // considerably more efficient. - target.getAvailableLocomotions(); - if (value == Postures::Dead) - Pvp::handleCreatureDied(target); -} - -//======================================================================= - -void CreatureObject::LocomotionChangeCallback::modified(CreatureObject &target, Locomotions::Enumerator oldValue, Locomotions::Enumerator value, bool) const -{ - ScriptParams params; - params.addParam(value); - params.addParam(oldValue); - - if (target.isAuthoritative()) - { - GameScriptObject * const script = target.getScriptObject(); - - if (script != 0) - { - script->trigAllScripts(Scripting::TRIG_LOCOMOTION_CHANGED, params); - } - } -} - -// ====================================================================== - -void CreatureObject::StateChangeCallback::modified(CreatureObject &target, uint64 oldValue, uint64 newValue, bool isLocal) const -{ - UNREF(newValue); - UNREF(isLocal); - UNREF(oldValue); - //-- Retrieve the collection of avialable locomotions for fast/slow/stationary movement speeds. - // This info is used on authoritative and proxy objects to make calcLocomotions(), called every alter, - // considerably more efficient. - target.getAvailableLocomotions(); -} - -// ====================================================================== - -CreatureAttitude::CreatureAttitude() : - m_behavior(Behaviors::Invalid), - m_angerState(kAngerCalm), - m_fearState(kFearCalm) -{ - for (int i = 0; i (getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_walk)), - m_baseRunSpeed (-1.0f), - m_runSpeed (safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_run)), - m_accelScale (1.0f), - m_accelPercent (1.0f), - m_turnScale (1.0f), - m_slopeModAngle (safe_cast(getSharedTemplate())->getSlopeModAngle() * PI / 180), - m_baseSlopeModPercent (safe_cast(getSharedTemplate())->getSlopeModPercent()), - m_slopeModPercent (1.0f), - m_waterModPercent (safe_cast(getSharedTemplate())->getWaterModPercent()), - m_lookAtTarget (), - m_intendedTarget (), - m_cover (0), - m_coverVisibility (true), - m_currentWeapon (), - m_modMap (), - m_skills (), - m_deferComputeTotalAttributes (0), - m_group (), - m_groupInviter (), - m_inviterForPendingGroup (), - m_performanceType (), - m_performanceStartTime (), - m_animatingSkillData (), - m_level (-1), - m_previousLevel (-1), - m_totalLevelXp (0), - m_levelHealthGranted (0), - m_invulnerabilityTimer (), - m_alternateAppearanceSharedObjectTemplateName (), - m_clientMfdStatusUpdateMessage(0), - m_timedMod (), - m_timedModDuration (), - m_timedModUpdateTime (), - m_addedToSpawnQueue (false), - m_numberOfMissionsWantedInMissionBag(0), - m_fastLocomotion (Locomotions::Invalid), - m_slowLocomotion (Locomotions::Invalid), - m_stationaryLocomotion (Locomotions::Invalid), - m_vehiclePhysicsData (0), - m_missionCriticalObjectSet(), - m_groupMissionCriticalObjectSet(), - m_triggerVolumeEntered(), - m_pseudoPlayedTime(0.0f), - m_buffs(), - m_persistedBuffs(), - m_clientUsesAnimationLocomotion(false), - m_difficulty(static_cast(D_normal)), - m_hologramType(-1), - m_visibleOnMapAndRadar(true), - m_lookAtYaw(0.0f), - m_useLookAtYaw(false), - m_fixedupPersistentBuffsAfterLoading(false), - m_fixedupLevelXpAfterLoading(false), - m_lavaResistance(0.0f), - m_lastWaterDamageTime(0), - m_isBeast(false), - m_forceShowHam(false), - m_regionFlagTimer(ConfigServerGame::getRegionFlagUpdateTimeSecs()), - m_wearableAppearanceData(), - m_decoyOrigin(NetworkId::cms_invalid) -{ - addProperty(*(new CommandQueue(*this))); - - // get the shared object template - const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); - NOT_NULL(sharedTemplate); - - // Handle scale. - // setScaleFactor(safe_cast(getSharedTemplate())->getScale()); - // Cannot set scale with setScaleFactor() since this object isn't authoratative yet. Expect many - // bugs from the lack of authority setting within a constructor. - const float scale = std::max (0.0f, sharedTemplate->getScale()); - m_scaleFactor = scale; - setScale (Vector::xyz111 * scale); - - // get the attribute values - { - for (int i = 0; i < Attributes::NumberOfAttributes; ++i) - { - m_attributes.set(i, static_cast( - newTemplate->getAttributes(static_cast< - ServerCreatureObjectTemplate::Attributes>(i)))); - m_maxAttributes.set(i, m_attributes.get(i)); - m_cachedCurrentAttributeModValues.set(i, 0); - m_cachedMaxAttributeModValues.set(i, 0); - m_regeneration[i] = 0; - } - // store the default regen values in the former faucet attrib slots - m_attributes.set(Attributes::Constitution, static_cast(ConfigServerGame::getDefaultHealthRegen())); - m_attributes.set(Attributes::Stamina, static_cast(ConfigServerGame::getDefaultActionRegen())); - m_attributes.set(Attributes::Willpower, static_cast(ConfigServerGame::getDefaultMindRegen())); - } - - // fix the size of the mental state vectors - m_maxMentalStates.resize(MentalStates::NumberOfMentalStates, 0); - m_mentalStateDecays.resize(MentalStates::NumberOfMentalStates, 0); - - CreatureAttitude initialState; - - // get the mental state values - { - for (int i = 0; i < MentalStates::NumberOfMentalStates; ++i) - { - const ServerCreatureObjectTemplate::MentalStates state = static_cast(i); - - m_maxMentalStates.set(i, static_cast(newTemplate->getMaxMentalStates(state))); - initialState.m_currentValues[i] = 0; - m_mentalStateDecays.set(i, float(newTemplate->getMentalStatesDecay(state))); - } - } - - m_currentAttitude.set(initialState); - m_lastBehavior.set(-1); - - m_fearCutoffs[CreatureAttitude::kFearCalm] = 0; - m_fearCutoffs[CreatureAttitude::kFearAlert] = 25; - m_fearCutoffs[CreatureAttitude::kFearThreaten] = 50; - m_fearCutoffs[CreatureAttitude::kFearFlee] = 75; - m_fearCutoffs[CreatureAttitude::kFearPanic] = 100; - - m_angerCutoffs[CreatureAttitude::kAngerCalm] = 0; - m_angerCutoffs[CreatureAttitude::kAngerAttack] = 60; - m_angerCutoffs[CreatureAttitude::kAngerFrenzy] = 100; - - CollisionProperty * pCollision = getCollisionProperty(); - - if(pCollision) - { - pCollision->setServerSide(true); - } - - addMembersToPackages(); - - m_guildId.setSourceObject(this); - m_guildWarEnabled.setSourceObject(this); - m_militiaOfCityId.setSourceObject(this); - m_locatedInCityId.setSourceObject(this); - m_group.setSourceObject(this); - m_posture.setSourceObject(this); - m_locomotion.setSourceObject(this); - m_invulnerabilityTimer.setSourceObject(this); - - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - CustomizationData *const cd = fetchCustomizationData(); - if (cd) - { - VehicleHoverDynamics::setInitialParams (*cd, - safe_cast (getSharedTemplate ())->getSpeedMin (SharedCreatureObjectTemplate::MT_walk), - safe_cast (getSharedTemplate ())->getSpeed (SharedCreatureObjectTemplate::MT_run), - safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_walk), - safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_run), - safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_walk), - safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_run)); - - cd->release (); - } - } - - m_lavaResistance = WaterTypeManager::getLavaResistance(getObjectTemplateName()); - - IGNORE_RETURN(g_creatureList.insert(this)); - - ObjectTracker::addCreature(); -} - -//----------------------------------------------------------------------- - -CreatureObject::~CreatureObject() -{ - //-- This must be the first line in the destructor to invalidate any watchers watching this object - nullWatchers(); - - if (m_vehiclePhysicsData) - { - delete m_vehiclePhysicsData; - m_vehiclePhysicsData = 0; - } - - if (isAuthoritative()) - { - GroupObject *group = getGroup(); - if (group) - { - group->removeGroupMember(getNetworkId()); - } - else - { - // If we are a pet... - if ( getMasterId() != NetworkId::cms_invalid ) - { - // We need to clean up outstanding group invitations since - // there are race conditions with ServerUniverse group - // objects and us getting added to them - - // Check for an outstanding group formation - const NetworkId groupInviterNetworkId = getInviterForPendingGroup(); - if ( groupInviterNetworkId != NetworkId::cms_invalid ) - { - // Send a message to the group inviter to tell them to remove - // us from the group... - - // We need to tell the network ID of the pet and we need to keep - // of how many times this message has been sent to the inviter - char msgBuffer[100]; - sprintf( msgBuffer, "%s 1", getNetworkId().getValueString().c_str() ); - - // Send the message with a delay - if ( MessageToQueue::isInstalled() ) - { - MessageToQueue::getInstance().sendMessageToC( groupInviterNetworkId, - "C++RemovePetFromGroup", - msgBuffer, - TIME_BETWEEN_ATTEMPTS_TO_REMOVE_PET, - false ); // reliable - } - } - } - } - - if (getGuildId()) - GuildInterface::onAboutToClearGuildId(*this); - } - - if (isPlayerControlled()) - removeFromSpawnQueue(); - - removeCreatureFromMissionRequestQueue(this); - if (isInWorld()) - removeFromWorld(); - - Controller *controller = getController(); - if (controller) - { - CreatureController *creatureController = safe_cast(controller); - ServerSecureTrade *trade = creatureController->getSecureTrade(); - if (trade) - trade->cancelTrade(*this); - } -// AICreatureController * aiController = AICreatureController::asAiCreatureController(controller); -// if (aiController != NULL) -// { -// aiController->stop(); -// } - - IGNORE_RETURN(g_creatureList.erase(this)); - - delete m_clientMfdStatusUpdateMessage; - - // We should have have been removed from all TriggerVolumes by - // now, but if we haven't, we need to tell any TriggerVolumes - // that we haven't been removed from to remove us from their - // contents list, or else those TriggerVolumes will have a - // pointer to a non-existent object - for (std::set::const_iterator i = m_triggerVolumeEntered.begin(); i != m_triggerVolumeEntered.end(); ++i) - { - WARNING(true, ("CreatureObject (%s) being destroyed but hasn't been removed from TriggerVolume (%s) owned by (%s)", - getDebugInformation().c_str(), - (*i)->getName().c_str(), - (*i)->getOwner().getDebugInformation().c_str())); - - (*i)->objectDestroyed(*this); - } - - ObjectTracker::removeCreature(); -} - - -//----------------------------------------------------------------------- - -CreatureObject * CreatureObject::asCreatureObject() -{ - return this; -} - -//----------------------------------------------------------------------- - -CreatureObject const * CreatureObject::asCreatureObject() const -{ - return this; -} - -//----------------------------------------------------------------------- - -void CreatureObject::install() -{ - loadDanceVisualTable(); - loadInstrumentTable(); - loadCommandSeriesTable(); - - installForMounts(); - - s_defaultWeaponSlotId = SlotIdManager::findSlotId(ConstCharCrcLowerString("default_weapon")); - FATAL(s_defaultWeaponSlotId == SlotId::invalid, ("failed to find SlotId for default_weapon: the slot definition file was improperly loaded or modified.")); - - s_inventorySlotId = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); - FATAL(s_inventorySlotId == SlotId::invalid, ("failed to find SlotId for inventory: the slot definition file was improperly loaded or modified.")); - - s_appearanceSlotId = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); - FATAL(s_appearanceSlotId == SlotId::invalid, ("Failed to find SlotId for appearance: the slot definition file was improperly loaded or modified.")); - - s_containerSlotStates[ShipSlotIdManager::getShipPilotSlotId()] = States::getStateMask(States::PilotingShip); - s_containerSlotStates[ShipSlotIdManager::getPobShipPilotSlotId()] = States::getStateMask(States::PilotingPobShip); - s_containerSlotStates[ShipSlotIdManager::getShipOperationsSlotId()] = States::getStateMask(States::ShipOperations); - s_containerSlotStates[ShipSlotIdManager::getPobShipOperationsSlotId()] = States::getStateMask(States::ShipOperations); - - { - // corresponds to slots in CreatureObject_Mounts.cpp - char slotName[256]; - s_containerSlotStates[SlotIdManager::findSlotId(ConstCharCrcLowerString("rider"))] = States::getStateMask(States::RidingMount); - for (int i = 1; i < 8; ++i) - { - snprintf(slotName, 255, "rider%d", i); - SlotId const slot = SlotIdManager::findSlotId(ConstCharCrcLowerString(slotName)); - s_containerSlotStates[slot] = States::getStateMask(States::RidingMount); - } - } - - for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex) - { - s_containerSlotStates[ShipSlotIdManager::getShipGunnerSlotId(weaponIndex)] = States::getStateMask(States::ShipGunner); - s_containerSlotStates[ShipSlotIdManager::getPobShipGunnerSlotId(weaponIndex)] = States::getStateMask(States::ShipGunner); - } - - s_containmentStatesMask = States::getStateMask(States::ShipInterior); - for (std::map::const_iterator i = s_containerSlotStates.begin(); i != s_containerSlotStates.end(); ++i) - s_containmentStatesMask |= (*i).second; - - // for enforcing height restriction when restoring decoration layout - { - char const * const cellHeightDataTableName = "datatables/structure/cell_height.iff"; - DataTable * table = DataTableManager::getTable(cellHeightDataTableName, true); - if (table) - { - int const columnStructure = table->findColumnNumber("template"); - int const columnCell = table->findColumnNumber("cell"); - int const columnMinHeight = table->findColumnNumber("min_height"); - int const columnMaxHeight = table->findColumnNumber("max_height"); - if ((columnStructure >= 0) && (columnCell >= 0) && (columnMinHeight >= 0) && (columnMaxHeight >= 0)) - { - std::string structure; - std::string cell; - - for (int i = 0, numRows = table->getNumRows(); i < numRows; ++i) - { - structure = table->getStringValue(columnStructure, i); - if (structure.empty()) - continue; - - cell = table->getStringValue(columnCell, i); - if (cell.empty()) - continue; - - s_mapCellHeightRestriction[std::make_pair(CrcLowerString::calculateCrc(structure.c_str()), CrcLowerString::calculateCrc(cell.c_str()))] = std::make_pair(table->getFloatValue(columnMinHeight, i), table->getFloatValue(columnMaxHeight, i)); - } - } - - DataTableManager::close(cellHeightDataTableName); - } - } - - ExitChain::add(CreatureObject::remove, "CreatureObject::remove"); -} - -//----------------------------------------------------------------------- - -void CreatureObject::remove() -{ -} - -//----------------------------------------------------------------------- - -/** - * Returns a shared template if none was given for this object. - * - * @return the shared template - */ -const SharedObjectTemplate * CreatureObject::getDefaultSharedTemplate() const -{ -static const ConstCharCrcLowerString templateName("object/creature/base/shared_creature_default.iff"); - - if (m_defaultSharedTemplate == NULL) - { - m_defaultSharedTemplate = safe_cast( - ObjectTemplateList::fetch(templateName)); -#ifdef DEBUG - WARNING(m_defaultSharedTemplate == NULL, ("Cannot create " - "default shared object template %s", templateName.getString())); -#endif - if (m_defaultSharedTemplate != NULL) - ExitChain::add (removeDefaultTemplate, "CreatureObject::removeDefaultTemplate"); - } - return m_defaultSharedTemplate; -} // CreatureObject::getDefaultSharedTemplate - -//----------------------------------------------------------------------- - -/** - * Cleans up the default shared template. - */ -void CreatureObject::removeDefaultTemplate() -{ - if (m_defaultSharedTemplate != NULL) - { - m_defaultSharedTemplate->releaseReference(); - m_defaultSharedTemplate = NULL; - } -} // CreatureObject::removeDefaultTemplate - -//----------------------------------------------------------------------- - -bool CreatureObject::isSpawningAllowed() const -{ - ServerObject const * container = safe_cast(ContainerInterface::getContainedByObject(*this)); - - return isAuthoritative() - && getScriptObject()->isScriptListInitialized() - && - ( - !container || container->asCreatureObject() - ) - && ( ConfigServerGame::getBoundarySpawningAllowed() - || getExposedProxyList().empty()) - && ( ConfigServerGame::getEnableSpawningNearLoadBeacons() - || !ServerWorld::isInLoadBeaconRange(getPosition_w())); -} - -//----------------------------------------------------------------------- - -void CreatureObject::addToSpawnQueue() -{ - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::addToSpawnQueue"); - - if (m_addedToSpawnQueue || !isSpawningAllowed()) - return; - - DEBUG_FATAL(std::find(s_spawnQueue.begin(), s_spawnQueue.end(), getNetworkId()) != s_spawnQueue.end(), ("spawn queue is inconsistant with m_addedToSpawnQueue flag")); - - s_spawnQueue.push_back(getNetworkId()); - - m_addedToSpawnQueue = true; -} - -//----------------------------------------------------------------------- - -void CreatureObject::removeFromSpawnQueue() -{ - if (m_addedToSpawnQueue) - { - std::deque::iterator f = std::find(s_spawnQueue.begin(), s_spawnQueue.end(), getNetworkId()); - if (f != s_spawnQueue.end()) - s_spawnQueue.erase(f); - m_addedToSpawnQueue = false; - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::runSpawnQueue() -{ - static int framesPerSpawn = ConfigServerGame::getFramesPerSpawn(); - static int64 lastSpawnFrame = 0; - static int64 currentSpawnFrame = 0; - - ++currentSpawnFrame; - - if (currentSpawnFrame - lastSpawnFrame >= framesPerSpawn) - { - int i = 1; - if (framesPerSpawn == 0) - i = ConfigServerGame::getSpawnQueueSize(); - - while (i > 0 && !s_spawnQueue.empty()) - { - NetworkId const id = s_spawnQueue.front(); - s_spawnQueue.pop_front(); - - // Only spawn if we can resolve the object, and it believes spawning - // should be allowed. If we can resolve the object but spawning is not - // allowed, do not re-add it to the queue and mark it as such. - - CreatureObject * const spawner = safe_cast(NetworkIdManager::getObjectById(id)); - - if (spawner) - { - if (spawner->isSpawningAllowed()) - { - ScriptParams params; - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(id, "spawn_Trigger", dictionary->getSerializedData(), 0, false); - } - s_spawnQueue.push_back(id); - } - else - spawner->m_addedToSpawnQueue = false; - } - --i; - } - lastSpawnFrame = currentSpawnFrame; - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::showSpawnQueue(Unicode::String & result) -{ - for (std::deque::iterator i = s_spawnQueue.begin(); i != s_spawnQueue.end(); ++i) - { - ServerObject const * const obj = safe_cast(NetworkIdManager::getObjectById((*i))); - if (obj) - { - result += Unicode::narrowToWide((*i).getValueString()); - result += Unicode::narrowToWide(" - "); - result += obj->getObjectName(); - result += Unicode::narrowToWide("\n"); - } - } -} - -//----------------------------------------------------------------------- -/** -*/ -bool CreatureObject::assignMission(MissionObject * missionObject) -{ - bool result = false; - if(missionObject) - { - ServerObject * datapad = getDatapad(); - if(datapad) - { - // if this mission is coming from our own mission bag, increment missions wanted - ServerObject * missionBag = getMissionBag(); - if(missionBag) - { - Container * container = ContainerInterface::getContainer(*missionBag); - ContainerIterator iter; - bool found = false; - int i = 0; - for(iter = container->begin(); iter != container->end(); ++iter) - { - MissionObject * mo = safe_cast((*iter).getObject()); - if(mo) - { - i++; - if(mo == missionObject) - { - found = true; - } - } - } - if(found) - { - setNumberOfMissionsWantedInMissionBag(i + 1); - } - } - - Container::ContainerErrorCode tmp = Container::CEC_Success; - result = ContainerInterface::transferItemToGeneralContainer(*datapad, *missionObject, NULL, tmp); - if(result) - { - missionObject->setMissionHolderId(getNetworkId()); - - } - } - } - return result; -} - -//----------------------------------------------------------------------- - -void CreatureObject::setMissionBoardUISequenceId(const uint8 sequenceId) -{ - m_missionListRequestSequenceId = sequenceId; -} - -//----------------------------------------------------------------------- - -std::vector CreatureObject::getMissions() -{ - std::vector result; - ServerObject * const datapad = getDatapad(); - if (datapad) - { - Container * const container = ContainerInterface::getContainer(*datapad); - if (container) - { - for (ContainerIterator iter = container->begin(); iter != container->end(); ++iter) - { - ServerObject * const serverMissionObject = safe_cast((*iter).getObject()); - if (serverMissionObject) - { - MissionObject * const missionObject = serverMissionObject->asMissionObject(); - if (missionObject) - result.push_back(*iter); - } - } - } - } - return result; -} - -//----------------------------------------------------------------------- - -bool CreatureObject::canManipulateObject(ServerObject const &target, bool movingObject, bool doPermissionCheckOnItem, bool doPermissionCheckOnParents, float maxRange, Container::ContainerErrorCode& code, bool skipNoTradeCheck, bool * allowedByGodMode) const -{ - if (allowedByGodMode) - *allowedByGodMode = false; - - if (getClient() && !ObserveTracker::isObserving(*getClient(), target) && (target.getCacheVersion() == 0)) - { - code = Container::CEC_Unknown; - return false; - } - - code = Container::CEC_Success; - ServerObjectTemplate const * const targetTemplate = safe_cast(target.getObjectTemplate()); - NOT_NULL(targetTemplate); - - bool canMoveInWorld = false; - bool godCanMove = false; - - ServerObject const * const serverTarget = safe_cast(&target); - if (!serverTarget || (movingObject && serverTarget->getCacheVersion() > 0)) - { - code = Container::CEC_Unmovable; - return false; - } - - if (serverTarget->isInBazaarOrVendor() && !(serverTarget->isVendor() || serverTarget->isBazaarTerminal())) - { - code = Container::CEC_Unknown; - return false; - } - - ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*serverTarget)); - - //-- don't transfer from/to factory crates - if (containedBy && containedBy->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) - { - code = Container::CEC_Unknown; - return false; - } - - { - for (size_t i = 0; i < targetTemplate->getMoveFlagsCount(); ++i) - { - if (targetTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_player) - { - canMoveInWorld = true; - godCanMove = true; - } - else if (targetTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_gm) - godCanMove = true; - } - } - - //Gods don't have distance checks or anything, so we can exit early if they are a god at this point. - if ((canMoveInWorld || godCanMove) && getClient() && getClient()->isGod()) - { - if (allowedByGodMode) - *allowedByGodMode = true; - - return true; - } - - //---------------------------------------------------------------------- - - // see if the object is flagged as being owner-only manipulatable - if (!skipNoTradeCheck) - { - if (target.markedNoTrade()) - { - // the item must be owned by this creature - - NetworkId ownerId; - if (target.asIntangibleObject()) - ownerId = containedBy ? containedBy->getOwnerId() : NetworkId::cms_invalid; - else - ownerId = target.getOwnerId(); - - if (ownerId != getNetworkId()) - { - code = Container::CEC_NoPermission; - return false; - } - } - } - - //---------------------------------------------------------------------- - - // exclude these object types from being moved by players - const int got = serverTarget->getGameObjectType (); - - CreatureObject const * const creatureTarget = serverTarget->asCreatureObject(); - if (movingObject) - { - // If the object isn't contained they may be trying to move the object - // check the flags on the template to see if it can be picked up. - if (!canMoveInWorld && target.isInWorld ()) - { -// DEBUG_REPORT_LOG(true, ("canManipulate failed - This object is in the world and is flagged as immobile\n")); - code = Container::CEC_NoPermission; - return false; - } - - // can't move creatures we don't own - if (creatureTarget && creatureTarget->getOwnerId() != getNetworkId()) - { - code = Container::CEC_NoPermission; - return false; - } - - if (GameObjectTypes::isTypeOf (got, SharedObjectTemplate::GOT_building) || - GameObjectTypes::isTypeOf (got, SharedObjectTemplate::GOT_installation) || - got == SharedObjectTemplate::GOT_lair || - got == SharedObjectTemplate::GOT_camp || - got == SharedObjectTemplate::GOT_vehicle || - got == SharedObjectTemplate::GOT_corpse || - serverTarget->asCellObject() || - got == SharedObjectTemplate::GOT_data_mission_object) - { - code = Container::CEC_UnmovableType; - return false; - } - - //-- can't move items in the world cell unless we are explicitly owning them - if (serverTarget->isInWorldCell () && serverTarget->getOwnerId () != getNetworkId ()) - { - code = Container::CEC_NoPermission; - return false; - } - } - - //---------------------------------------------------------------------- - - ServerObject const * const firstParentInWorld = safe_cast(ContainerInterface::getFirstParentInWorld(target)); - if (firstParentInWorld && firstParentInWorld != ContainerInterface::getFirstParentInWorld(*this) && firstParentInWorld->asTangibleObject()) - { - - if (maxRange > 0.0f) - { - float distance = findPosition_w().magnitudeBetween(firstParentInWorld->findPosition_w()); - distance -= getRadius(); - distance -= firstParentInWorld->getRadius(); - // Check range on the server with a 1m fudge factor in it. - if (distance > maxRange + 1.0f) - { - code = Container::CEC_OutOfRange; - return false; - } - } - - // skip LOS check if the item is being restored as part of decoration layout restore - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (!playerObject || (playerObject->getRestoreDecorationObjectBeingRestored() != target.getNetworkId())) - { - if (!checkLOSTo(*firstParentInWorld)) - { - code = Container::CEC_CantSee; -// DEBUG_REPORT_LOG(true, ("LOS check failed in can manipulate\n")); - return false; - } - } - } - - //---------------------------------------------------------------------- - - bool manipulateOk = true; - - if (target.asTangibleObject() && target.asTangibleObject()->isLocked()) - { - TangibleObject const * tangibleTarget = target.asTangibleObject(); - - bool allow = false; - - if(tangibleTarget->isUserOnAccessList(getNetworkId()) || tangibleTarget->isGuildOnAccessList(getGuildId())) - { - // Still have to obey house rules. - ServerObject const * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*serverTarget)); - if (movingObject && topmost) - { - //Handle the case where we are in a designer placed building and a designer placed container (loot chest) - if ( topmost->getOwnerId() == NetworkId::cms_invalid - && ( firstParentInWorld->getOwnerId() == NetworkId::cms_invalid - || firstParentInWorld->getOwnerId() == getNetworkId()) - && serverTarget != firstParentInWorld) - { - allow = true; - } - //Handle the case where we are in a player building or pob ship - else if (topmost->getOwnerId() == getNetworkId() || isBuildingAdminForTarget (*this, *topmost)) - { - const bool isContainerPortallized = topmost->getPortalProperty() != 0; - - allow = (!isContainerPortallized || !movingObject || !isTargetBuildingBaseObject (*topmost, *serverTarget)); - } - else - allow = false; - } - else - allow = true; - } - else - { - // Our target is locked, but allow admins on a building to be able to manipulate the object. - - - ServerObject const * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*serverTarget)); - if (topmost) - { - //Handle the case where we are in a designer placed building and a designer placed container (loot chest) - if ( topmost->getOwnerId() == NetworkId::cms_invalid - && ( firstParentInWorld->getOwnerId() == NetworkId::cms_invalid - || firstParentInWorld->getOwnerId() == getNetworkId()) - && serverTarget != firstParentInWorld) - { - allow = true; - } - //Handle the case where we are in a player building or pob ship - else if (topmost->getOwnerId() == getNetworkId()) - { - const bool isContainerPortallized = topmost->getPortalProperty() != 0; - - allow = (!isContainerPortallized || !movingObject || !isTargetBuildingBaseObject (*topmost, *serverTarget)); - } - else - allow = false; - } - - } - - if(!allow) - code = Container::CEC_NoPermission; - - return allow; - } - - //---------------------------------------------------------------------- - //-- see if we need to check permissions of the object itself - - if (doPermissionCheckOnItem) - { - //Do not allow players to manipulate other players or things contained by other players - if (serverTarget->isPlayerControlled() && serverTarget != this) - { - code = Container::CEC_NoPermission; - return false; - } - - if (serverTarget->getOwnerId () == getNetworkId()) - { - manipulateOk = true; - } - - //-- an invalid owner means we can manipulate the item in general, - //-- e.g. opening a container, but not move it - else if (movingObject || serverTarget->getOwnerId ().isValid ()) - { - manipulateOk = false; - } - } - - //---------------------------------------------------------------------- - //-- see if the permission check on parents needs to be carried out. - -//ParentCheck on item -//if item is a vendor, get topmost and check vendor list -//else -// get first parent in world -// if is an installation check hopper list -// else if it is a creature, check the immediate parent for ownership only (covers corpses, inventory, etc) -// else check ownership of topmost, with 0 being allowed. -// if topmost happens to be a player building, check its admin list and make sure the object being moved isn't part of the house -// else if topmost happens to be an unowned building, then any sub containers can be looted - - if (doPermissionCheckOnParents) - { - - // Check our access list. - if(containedBy && containedBy->asTangibleObject() && containedBy->asTangibleObject()->isLocked()) - { - TangibleObject const * tangibleParent = containedBy->asTangibleObject(); - - if(tangibleParent->isUserOnAccessList(getNetworkId()) || tangibleParent->isGuildOnAccessList(getGuildId())) - { - manipulateOk = true; - } - else - { - manipulateOk = false; - code = Container::CEC_NoPermission; - } - - } - else if (!manipulateOk || movingObject) - { - //-- can't move items contained by a manufacturing schematic - { - if (containedBy && containedBy->getGameObjectType () == SharedObjectTemplate::GOT_data_manufacturing_schematic) - { - code = Container::CEC_NoPermission; - return false; - } - } - - if (firstParentInWorld) - { - const int containerGot = firstParentInWorld->getGameObjectType (); - if (GameObjectTypes::isTypeOf (containerGot, SharedObjectTemplate::GOT_installation)) - { - //-- test admin status on installation - manipulateOk = canHopperForTarget (*this, *firstParentInWorld); - } - else if (firstParentInWorld->asCreatureObject()) - { - // check for ownership - manipulateOk = (containedBy && (containedBy->getOwnerId() == getNetworkId() || containedBy->getOwnerId() == NetworkId::cms_invalid)); - } - else - { - ServerObject const * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*serverTarget)); - if (topmost) - { - //Handle the case where we are in a designer placed building and a designer placed container (loot chest) - if ( topmost->getOwnerId() == NetworkId::cms_invalid - && ( firstParentInWorld->getOwnerId() == NetworkId::cms_invalid - || firstParentInWorld->getOwnerId() == getNetworkId()) - && serverTarget != firstParentInWorld) - { - manipulateOk = true; - } - //Handle the case where we are in a player building or pob ship - else if (topmost->getOwnerId() == getNetworkId() || isBuildingAdminForTarget (*this, *topmost)) - { - const bool isContainerPortallized = topmost->getPortalProperty() != 0; - - manipulateOk = (!isContainerPortallized || !movingObject || !isTargetBuildingBaseObject (*topmost, *serverTarget)); - } - else - manipulateOk = false; - } - else - manipulateOk = false; - } - } - else - manipulateOk = false; - } - } - - - //---------------------------------------------------------------------- - - if (!manipulateOk && code == Container::CEC_Success) - code = Container::CEC_NoPermission; - - return manipulateOk; -} - -//----------------------------------------------------------------------- -/** - * Do any processing needed during endBaselines() to handle this object if - * it is contained by another object. - * - * @return true if object should have addToWorld() called on it; false otherwise. - */ - -bool CreatureObject::handleContentsSetup() -{ - bool ret = TangibleObject::handleContentsSetup(); - setStatesDueToContainment(); - return ret; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setStatesDueToContainment() -{ - uint64 oldStates = m_states.get(); - uint64 states = oldStates&(~s_containmentStatesMask); - - ServerObject const *containingObject = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (containingObject) - { - SlottedContainer const *slottedContainer = containingObject->getSlottedContainerProperty(); - if (slottedContainer) - { - SlottedContainmentProperty const *slottedContainmentProperty = ContainerInterface::getSlottedContainmentProperty(*this); - if (slottedContainmentProperty) - { - int currentArrangement = slottedContainmentProperty->getCurrentArrangement(); - if (currentArrangement != -1) - { - SlottedContainmentProperty::SlotArrangement const &slotArrangement = slottedContainmentProperty->getSlotArrangement(currentArrangement); - for (SlottedContainmentProperty::SlotArrangement::const_iterator i = slotArrangement.begin(); i != slotArrangement.end(); ++i) - states |= s_containerSlotStates[*i]; - } - } - } - else if (containingObject->asCellObject()) - { - // special case - state set when in the interior of a pob ship - ServerObject const * const portallizedObject = safe_cast(ContainerInterface::getContainedByObject(*containingObject)); - if (portallizedObject && portallizedObject->asShipObject()) - states |= States::getStateMask(States::ShipInterior); - } - } - - if (states != oldStates) - m_states = states; -} - -//----------------------------------------------------------------------- - -void CreatureObject::forwardServerObjectSpecificBaselines() const -{ - TangibleObject::forwardServerObjectSpecificBaselines(); - - Property const * const property = getProperty(SlowDownProperty::getClassPropertyId()); - if (property != NULL) - { - SlowDownProperty const * const slowdownProperty = safe_cast(property); - - SlowDownEffectMessage const message(getNetworkId(), slowdownProperty->getTarget(), slowdownProperty->getConeLength(), slowdownProperty->getConeAngle(), slowdownProperty->getSlopeAngle(), slowdownProperty->getExpireTime()); - ServerMessageForwarding::send(message); - } - - // if we are an ai creature, have our controller send our current ai state - AICreatureController const * const aiCreatureController = AICreatureController::asAiCreatureController(getController()); - - if (aiCreatureController != NULL) - { - aiCreatureController->forwardServerObjectSpecificBaselines(); -} -} - -//----------------------------------------------------------------------- - -void CreatureObject::sendObjectSpecificBaselinesToClient(Client const &client) const -{ - TangibleObject::sendObjectSpecificBaselinesToClient(client); - - Property const * const property = getProperty(SlowDownProperty::getClassPropertyId()); - if (property != NULL) - { - SlowDownProperty const * const slowdownProperty = safe_cast(property); - - SlowDownEffectMessage const message(getNetworkId(), slowdownProperty->getTarget(), slowdownProperty->getConeLength(), slowdownProperty->getConeAngle(), slowdownProperty->getSlopeAngle(), slowdownProperty->getExpireTime()); - client.send(message, true); - } - - UpdatePostureMessage const updatePostureMessage(getNetworkId(), getPosture()); - client.send(updatePostureMessage, true); -} - -//----------------------------------------------------------------------- - -/** - * Initializes a newly created object. - */ -void CreatureObject::initializeFirstTimeObject() -{ - TangibleObject::initializeFirstTimeObject(); - - //-- Get ourselves into a reasonable locomotion state. - updateMovementInfo(); - - // create the default weapon - initializeDefaultWeapon(); - - // set the current weapon - WeaponObject * weapon = getReadiedWeapon(); - if (weapon != NULL) - setCurrentWeapon(*weapon); - - //Quick error check since all creatures should have a default weapon - WARNING_STRICT_FATAL(!getDefaultWeapon(), ("Creature %s (%s) has no default " - "weapon", getNetworkId().getValueString().c_str(), getTemplateName())); - - const ServerCreatureObjectTemplate * myTemplate = safe_cast(getObjectTemplate()); - Unicode::String newName = NameManager::getInstance().generateRandomName(ConfigServerGame::getCharacterNameGeneratorDirectory(), myTemplate->getNameGeneratorType()); - if (!newName.empty()) - { - setObjectName(newName); - } - - setOwnerId(getNetworkId()); - recomputeSlopeModPercent(); - - setupSkillData(); - packWearables(); - - ServerObject *bankContainer = getBankContainer(); - if (bankContainer) - bankContainer->setLoadContents(false); - - // note: this MUST come after TangibleObject::initializeFirstTimeObject() is called - float defaultAlterTime = 0; - if (!isPlayerControlled()) - defaultAlterTime = AlterResult::cms_alterQuickly; -// DEBUG_REPORT_LOG(true, ("[aitest] setting creature %s default alter time to %f\n", getNetworkId().getValueString().c_str(), defaultAlterTime)); - setDefaultAlterTime(defaultAlterTime); -} // CreatureObject::initializeFirstTimeObject - -//----------------------------------------------------------------------- - -void CreatureObject::onLoadedFromDatabase() -{ - typedef const std::string * strptr; - - if (isAuthoritative()) - { - if (isPlayerControlled()) - { - onClientAboutToLoad(); - - // Initialize A-Tab info if we need to. - SlottedContainer * const container = ContainerInterface::getSlottedContainer(*this); - if(container) - { - SlotId slot; - Container::ContainerErrorCode tmp; - slot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); - if(slot != SlotId::invalid) - { - Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); - Object* appearanceInventory = itemId.getObject(); - if(appearanceInventory == NULL) - { - WARNING(true, ("Player %s has lost their appearance inventory", getNetworkId().getValueString().c_str())); - appearanceInventory = ServerWorld::createNewObject(s_appearanceTemplate, *this, slot, false); - if(!appearanceInventory) - { - DEBUG_FATAL(true, ("Could not create an appearance inventory for the player who lost theirs")); - } - } - } - } - - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - // move old badges over to the collection system - if (getObjVars().hasItem(OBJVAR_BADGES) && (getObjVars().getType(OBJVAR_BADGES) == DynamicVariable::INT_ARRAY)) - { - std::vector badges; - getObjVars().getItem(OBJVAR_BADGES, badges); - - if (!badges.empty()) - playerObject->migrateLegacyBadgesToCollection(badges); - - removeObjVarItem(OBJVAR_BADGES); - removeObjVarItem(OBJVAR_COUNT_BADGES); - } - - // check for Jedi initialization - if (getObjVars().hasItem(OBJVAR_NEW_JEDI_FORCE)) - { - int start_force; - getObjVars().getItem(OBJVAR_NEW_JEDI_FORCE, start_force); - removeObjVarItem(OBJVAR_NEW_JEDI_FORCE); - if (start_force > 0) - { - playerObject->setMaxForcePower(start_force); - playerObject->setForcePowerRegenRate(ConfigServerGame::getMinForcePowerRegenRate()); - } - else - { - WARNING(true, ("Player %s had the %s objvar, but it had a " - "value of %d", getNetworkId().getValueString().c_str(), - OBJVAR_NEW_JEDI_FORCE.c_str(), start_force)); - } - } - - // check the non-pool attributes: their value should be the - // same as their max value, since we don't regenerate/heal them - for (int i = 0; i < Attributes::NumberOfAttributes; ++i) - { - if (Attributes::isAttribPool(i)) - continue; - - Attributes::Value attrib = getUnmodifiedAttribute(i); - Attributes::Value max = getUnmodifiedMaxAttribute(i); - if (attrib != max) - setAttribute(i, max); - } - - // initialize the character born date, if necessary - playerObject->setBornDate(); - - // retroactively set CTS history and CTS title(s), if necessary, - // and fix up the character's born date, if necessary, if it was - // incorrectly changed from a prior CTS where the character's born - // date was not transferred; - // - // should be done *AFTER* the above statement to initialize the - // character born date, if necessary - GameServer::setRetroactiveCtsHistory(*this); - - // set the "born on " title if this galaxy supports - // it and it hasn't already been set on this character - if (!getObjVars().hasItem("bornOnGalaxyTitleSet")) - { - // lower case cluster name and replace - with _ for use with the collection slot name - std::string collectionSlotName = std::string("born_on_") + Unicode::toLower(GameServer::getInstance().getClusterName()); - - std::string::size_type pos = collectionSlotName.find('-'); - while (pos != std::string::npos) - { - collectionSlotName.replace(pos, 1, 1, '_'); - pos = collectionSlotName.find('-'); - } - - CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(collectionSlotName); - if (collectionSlot) - { - FATAL((collectionSlot->collection.name != std::string("born_on_collection")), ("collection slot %s must be in collection born_on_collection", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.name != std::string("born_on_page")), ("collection slot %s must be in collection page born_on_page", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.book.name != std::string("born_on_book")), ("collection slot %s must be in collection book born_on_book", collectionSlot->name.c_str())); - - // see if character transferred from another galaxy, and - // if yes, then the original galaxy is the home galaxy - std::string originalSourceGalaxy; - int earliestTransferTime = -1; - - DynamicVariableList::NestedList const ctsTransactions(getObjVars(), "ctsHistory"); - for (DynamicVariableList::NestedList::const_iterator i = ctsTransactions.begin(); i != ctsTransactions.end(); ++i) - { - Unicode::String ctsTransactionDetail; - if (i.getValue(ctsTransactionDetail)) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(ctsTransactionDetail, tokens, NULL, NULL) && (tokens.size() >= 4)) - { - int const transferTime = atoi(Unicode::wideToNarrow(tokens[0]).c_str()); - if ((earliestTransferTime == -1) || (transferTime < earliestTransferTime)) - { - earliestTransferTime = transferTime; - originalSourceGalaxy = Unicode::wideToNarrow(tokens[1]); - } - } - } - } - - // character transferred from another galaxy, so - // use the original galaxy as the home galaxy - if (!originalSourceGalaxy.empty()) - { - // lower case cluster name and replace - with _ for use with the collection slot name - collectionSlotName = std::string("born_on_") + Unicode::toLower(originalSourceGalaxy); - - std::string::size_type pos = collectionSlotName.find('-'); - while (pos != std::string::npos) - { - collectionSlotName.replace(pos, 1, 1, '_'); - pos = collectionSlotName.find('-'); - } - - collectionSlot = CollectionsDataTable::getSlotByName(collectionSlotName); - if (collectionSlot) - { - FATAL((collectionSlot->collection.name != std::string("born_on_collection")), ("collection slot %s must be in collection born_on_collection", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.name != std::string("born_on_page")), ("collection slot %s must be in collection page born_on_page", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.book.name != std::string("born_on_book")), ("collection slot %s must be in collection book born_on_book", collectionSlot->name.c_str())); - } - } - } - - // set "born on " collection slot and clear all the other "born on " collection slots; - // this still needs to be run even if collectionSlot is NULL in order to forcefully clear all of the - // other "born on " collection slots, since we are reusing deleted/no longer used collection - // slot bits, and those bits may be left in a set state at the time they were deleted/no longer used - std::vector const & slots = CollectionsDataTable::getSlotsInCollection("born_on_collection"); - - for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) - { - playerObject->modifyCollectionSlotValue((*iter)->name, ((*iter == collectionSlot) ? 1ll : -1ll)); - } - - IGNORE_RETURN(setObjVarItem("bornOnGalaxyTitleSet", 1)); - } - } - - // wait for all loading/initialization to complete, and then double - // check the character's title to make sure it is a valid title - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++CheckCharacterTitle", "", 30, false); - } - - // store the default regen values in the former faucet attrib slots - m_attributes.set(Attributes::Constitution, static_cast(ConfigServerGame::getDefaultHealthRegen())); - m_attributes.set(Attributes::Stamina, static_cast(ConfigServerGame::getDefaultActionRegen())); - m_attributes.set(Attributes::Willpower, static_cast(ConfigServerGame::getDefaultMindRegen())); - - if(!isPlayerControlled()) - fixupPersistentBuffsAfterLoading(); - else - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject && playerObject->isInitialized()) - { - fixupPersistentBuffsAfterLoading(); - fixupLevelXpAfterLoading(); - } - } - - // there are cetain states we don't want to be in on start-up - setState(States::Cover, false); - setState(States::Combat, false); - setState(States::Peace, false); - setState(States::Aiming, false); - setState(States::Meditate, false); - setState(States::Berserk, false); - setState(States::FeignDeath, false); - setState(States::Tumbling, false); - setState(States::Rallied, false); - setState(States::Stunned, false); - setState(States::Blinded, false); - setState(States::Dizzy, false); - setState(States::Intimidated, false); - setState(States::Immobilized, false); - setState(States::Crafting, false); - setState(States::MountedCreature, false); - setState(States::Disguised, false); - setStatesDueToContainment(); - - // override the speeds stored in the database - // @todo: make the speeds non-persisted - setBaseWalkSpeed((safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_walk))); - setBaseRunSpeed((safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_run))); - } - - // setupSkillData MUST be called before we add the bonuses for equipment! - setupSkillData(); - packWearables(); - - if (isAuthoritative() && isPlayerControlled()) - { - // make sure the player has no more expertise skills than they should have for their level - // if they do, log them as a suspected cheater - int const remainingExpertisePoints = getRemainingExpertisePoints(); - - if (remainingExpertisePoints < 0) - { - LOG("CustomerService", - ("SuspectedCheaterChannel: %s has more expertises than level %d allows. Amount over limit is %d.", - PlayerObject::getAccountDescription(this).c_str(), getLevel(), -remainingExpertisePoints) - ); - } - - // if we are a player, go through all the creature's equipment and update for - // bonus skill mods - std::vector > skillModBonuses; - std::vector > attribBonuses; - Container const * const equipment = ContainerInterface::getContainer(*this); - if (equipment != NULL) - { - for (ContainerConstIterator i(equipment->begin()); i != equipment->end(); ++i) - { - ServerObject const * const so = safe_cast((*i).getObject()); - if (so) - { - TangibleObject const * const equippedItem = so->asTangibleObject(); - if (equippedItem != NULL) - { - equippedItem->getSkillModBonuses(skillModBonuses); - int bonusCount = skillModBonuses.size(); - { - for (int j = 0; j < bonusCount; ++j) - { - std::pair const &bonus = skillModBonuses[j]; - addModBonus(bonus.first, bonus.second); - } - } - equippedItem->getAttribBonuses(attribBonuses); - bonusCount = attribBonuses.size(); - { - for (int j = 0; j < bonusCount; ++j) - { - std::pair const &bonus = attribBonuses[j]; - addAttribBonus(bonus.first, bonus.second); - } - } - } - } - } - } - } - - TangibleObject::onLoadedFromDatabase(); - - if (isAuthoritative()) - { - // note: this MUST come after TangibleObject::onLoadedFromDatabase() is called - float defaultAlterTime = 0; - if (!isPlayerControlled()) - defaultAlterTime = AlterResult::cms_alterQuickly; -// DEBUG_REPORT_LOG(true, ("[aitest] setting creature %s default alter time to %f\n", getNetworkId().getValueString().c_str(), defaultAlterTime)); - setDefaultAlterTime(defaultAlterTime); - - CreatureController * controller = getCreatureController(); - if (controller != NULL) - controller->updateHibernate(); - } -} - -//----------------------------------------------------------------------- - -/** - * Initializes a proxy object. - */ -void CreatureObject::endBaselines() -{ - // catch people in potentially deleted newbie halls - if (NewbieTutorial::getSceneId() == ServerWorld::getSceneId()) - getContainedByProperty()->setContainedBy(NetworkId::cms_invalid); - - TangibleObject::endBaselines(); - - if (isAuthoritative()) - { - // set our initial posture depending if we are incapacitated/dead or not - Postures::Enumerator posture = getPosture(); - if (isDead()) - posture = Postures::Dead; - if (getAttribute(Attributes::Health) <= 0) - { - // make sure we are incapacitated, unless we are dead - if (posture != Postures::Dead) - posture = Postures::Incapacitated; - } - - if (posture != getPosture()) - setPosture(posture); - - updateMovementInfo(); - - // Fix up guildId - set regardless of whether it is already correct, as this - // triggers entry into the guild chat room. - int guildId = GuildInterface::getGuildId(getNetworkId()); - - // fix up issue there a guild leader gets mistakenly removed - // from the guild (i.e. the guild leader's permission is reset - // to 0, meaning he is only a sponsored member, and the guild - // id won't be returned in GuildInterface::getGuildId()), causing - // the guild to be leaderless; we only need to get the guild id - // for the guild that this character is the leader of; setGuildId() - // will do the rest of the work - if (guildId == 0) - guildId = GuildInterface::getGuildIdForGuildLeader(getNetworkId()); - - setGuildId(guildId); - - // Fix up guildWarEnabled - setGuildWarEnabled(GuildInterface::getGuildMemberGuildWarEnabled(getGuildId(), getNetworkId())); - - // Fix up militiaOfCityId - setMilitiaOfCityId(CityInterface::getMilitiaOfCityId(getNetworkId())); - - // Mount: needs to grab its position from the rider since the rider dictates - // mount position. - if (getState(States::MountedCreature)) - { - CreatureObject const *const rider = getPrimaryMountingRider(); - if (rider) - { - // Use parent space since both the rider and mount should be - // attached to the same thing. Initially this is limited to - // the world. - setPosition_p(rider->getPosition_p()); - } - } - - // depersist persisted command cooldowns - CommandQueue * commandQueue = getCommandQueue(); - if (commandQueue) - { - commandQueue->depersistCooldown(); - } - - // make sure that factional player characters are at least rank 1 (rating 0) - // and non-factional player characters have no current GCW points or rating - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - if (player) - { - static int const min = std::numeric_limits::min(); - if (PvpData::isImperialFactionId(getPvpFaction()) || PvpData::isRebelFactionId(getPvpFaction())) - { - // decrementing the value by a really large - // number will cause it to reset to 0 - if (player->getCurrentGcwRating() < Pvp::getMinRatingForRank()) - player->modifyCurrentGcwRating(min, true); - } - else - { - // decrementing the value by a really large - // number will cause it to reset to 0 - if (player->getCurrentGcwPoints() > 0) - player->modifyCurrentGcwPoints(min, false); - - if (player->getCurrentGcwRating() != -1) - player->modifyCurrentGcwRating(min, false); - - if (player->getCurrentPvpKills() > 0) - player->modifyCurrentPvpKills(min, false); - } - - // make sure that m_nextGcwRatingCalcTime is set so that the - // rating will be recalculated at the next recalculation interval - player->setNextGcwRatingCalcTime(true); - - // migrate veteran rewards claim tracking information to new system - VeteranRewardManager::migrateVeteranRewardsClaimInformation(*this); - - // request the list of account feature transactions for the character - // from the LoginServer DB which will be compared to the list of account - // feature transactions stored on the character, and if there is any - // discrepancy, then it probably means there was a rollback, so we would - // need to grant the character any missing item(s) - FeatureIdTransactionRequest const fitr(GameServer::getInstance().getProcessId(), player->getStationId(), getNetworkId()); - GameServer::getInstance().sendToCentralServer(fitr); - - // set the guild rank - GuildMemberInfo const * const guildMemberInfo = GuildInterface::getGuildMemberInfo(getGuildId(), getNetworkId()); - if (guildMemberInfo) - player->setGuildRank(guildMemberInfo->m_rank); - - // set the citizen rank - // join the city chat room - std::vector const & cityIds = CityInterface::getCitizenOfCityId(getNetworkId()); - if (!cityIds.empty()) - { - int const cityId = cityIds.front(); - CitizenInfo const * const citizenInfo = CityInterface::getCitizenInfo(cityId, getNetworkId()); - if (citizenInfo) - player->setCitizenRank(citizenInfo->m_citizenRank); - - // join the city chat room - CityInterface::enterCityChatRoom(cityId, *this); - } - - // set the player's citizenship information - player->updateCitizenshipInfo(); - - // set the player's GCW Region info - player->updateGcwRegionInfo(); - - // set the player's GCW Region Defender info - player->updateGcwDefenderRegionInfo(); - - // fix the citizen name in the citizen roster, if necessary - CityInterface::verifyCitizenName(getNetworkId(), Unicode::wideToNarrow(getAssignedObjectName())); - - // check for over lot limit condition - player->setAccountNumLotsOverLimitSpam(); - - // fix the pgc chronicler's name in the pgc rating data, if necessary - CityInterface::verifyPgcChroniclerName(getNetworkId(), Unicode::wideToNarrow(getAssignedObjectName())); - - // depersist galactic reserve - { - // migrate any galactic reserve information that's stored in the PlayerObject into the CreatureObject - int temp; - if (player->getObjVars().getItem("galactic_reserve", temp)) - { - player->removeObjVarItem("galactic_reserve"); - setObjVarItem("galactic_reserve", temp); - } - - if (player->getObjVars().getItem("galactic_reserve_cooldown", temp)) - { - player->removeObjVarItem("galactic_reserve_cooldown"); - setObjVarItem("galactic_reserve_cooldown", temp); - } - - player->depersistGalacticReserveDeposit(); - } - - // depersist mercenary status - if (!ConfigServerGame::getEnableCovertImperialMercenary()) - { - player->modifyCollectionSlotValue("covert_imperial_mercenary", -1); - } - - if (!ConfigServerGame::getEnableOvertImperialMercenary()) - { - player->modifyCollectionSlotValue("overt_imperial_mercenary", -1); - } - - if (!ConfigServerGame::getEnableCovertRebelMercenary()) - { - player->modifyCollectionSlotValue("covert_rebel_mercenary", -1); - } - - if (!ConfigServerGame::getEnableOvertRebelMercenary()) - { - player->modifyCollectionSlotValue("overt_rebel_mercenary", -1); - } - - if (!PvpData::isNeutralFactionId(getPvpFaction())) - { - player->modifyCollectionSlotValue("covert_imperial_mercenary", -1); - player->modifyCollectionSlotValue("overt_imperial_mercenary", -1); - player->modifyCollectionSlotValue("covert_rebel_mercenary", -1); - player->modifyCollectionSlotValue("overt_rebel_mercenary", -1); - } - else - { - if (player->hasCompletedCollectionSlot("covert_imperial_mercenary")) - { - Pvp::setNeutralMercenaryFaction(*this, PvpData::getImperialFactionId(), PvpType_Covert); - } - else if (player->hasCompletedCollectionSlot("overt_imperial_mercenary")) - { - Pvp::setNeutralMercenaryFaction(*this, PvpData::getImperialFactionId(), PvpType_Declared); - } - else if (player->hasCompletedCollectionSlot("covert_rebel_mercenary")) - { - Pvp::setNeutralMercenaryFaction(*this, PvpData::getRebelFactionId(), PvpType_Covert); - } - else if (player->hasCompletedCollectionSlot("overt_rebel_mercenary")) - { - Pvp::setNeutralMercenaryFaction(*this, PvpData::getRebelFactionId(), PvpType_Declared); - } - } - } - } - else - { - getAvailableLocomotions(); - } - - checkAndRestoreRequiredSlots(); - - // get the current weapon, which will set it to our held or default weapon - IGNORE_RETURN(getCurrentWeapon()); - - // Rider: needs to not participate in CollisionWorld. - if (getState(States::RidingMount)) - { - CollisionProperty *const collisionProperty = getCollisionProperty(); - if (collisionProperty) - { - if (isInWorld()) - CollisionWorld::removeObject(this); - - collisionProperty->setDisableCollisionWorldAddRemove(true); - } - } - - // Fix up the footprint's swim height to take into consideration any scaling on this creature. - Footprint *const footprint = getFootprint(); - if (footprint) - footprint->setSwimHeight(getSwimHeight()); - - if (isAuthoritative()) - recomputeSlopeModPercent(); - - if (ConfigServerGame::getMoveSimEnabled ()) - MoveSimManager::checkApplySimulation (*this); - - if (isAuthoritative()) - GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); -} // CreatureObject::endBaselines - -//----------------------------------------------------------------------- - -void CreatureObject::checkAndRestoreRequiredSlots() -{ - SlottedContainer * const container = ContainerInterface::getSlottedContainer(*this); - if (container == NULL) - { - WARNING_STRICT_FATAL(true, ("This creature is not slotted!")); - return; - } - - // get the default weapon from it's slot and set the class variable - - bool foundDefaultWeapon = false; - Container::ContainerErrorCode tmp = Container::CEC_Success; - Container::ContainedItem const itemId = container->getObjectInSlot(s_defaultWeaponSlotId, tmp); - Object * const o = itemId.getObject(); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so && so->asWeaponObject()) - foundDefaultWeapon = true; - } - - if (!foundDefaultWeapon) - { - if (isAuthoritative()) - { - // try to make the default weapon from the template instead - initializeDefaultWeapon(); - } - else - { - WARNING_STRICT_FATAL(true, ("Unable to find default weapon slot id for %s(%s)", - getNetworkId().getValueString().c_str(), - getObjectTemplateName())); - } - } - - if (isPlayerControlled() && isAuthoritative()) - { - //restore inventory, mission bag, and datapad for players - - SlotId slot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); - if (slot != SlotId::invalid) - { - Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); - Object* inventory = itemId.getObject(); - if (inventory == NULL) - { - WARNING(true, ("Player %s has lost their inventory", getNetworkId().getValueString().c_str())); - inventory = ServerWorld::createNewObject(s_inventoryTemplate, *this, slot, false); - if (!inventory) - { - DEBUG_FATAL(true, ("Could not create an inventory for the player who lost theirs")); - } - } - } - - slot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::datapad); - if (slot != SlotId::invalid) - { - Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); - Object* datapad = itemId.getObject(); - if (datapad == NULL) - { - WARNING(true, ("Player %s has lost their datapad", getNetworkId().getValueString().c_str())); - datapad = ServerWorld::createNewObject(s_datapadTemplate, *this, slot, false); - if (!datapad) - { - DEBUG_FATAL(true, ("Could not create an datapad for the player who lost theirs")); - } - } - } - - slot = SlotIdManager::findSlotId(ConstCharCrcLowerString("mission_bag")); - if (slot != SlotId::invalid) - { - Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); - ServerObject* missionBag = safe_cast(itemId.getObject()); - if (missionBag == NULL) - { - WARNING(true, ("Player %s has lost their mission bag", getNetworkId().getValueString().c_str())); - missionBag = ServerWorld::createNewObject(s_missionBagTemplate, *this, slot, false); - if (!missionBag) - { - DEBUG_FATAL(true, ("Could not create a mission bag for the player who lost theirs")); - } - else - missionBag->persist(); - } - } - - slot = SlotIdManager::findSlotId(ConstCharCrcLowerString("bank")); - if (slot != SlotId::invalid) - { - Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); - ServerObject* bank = safe_cast(itemId.getObject()); - if (bank == NULL) - { - WARNING(true, ("Player %s has lost their bank", getNetworkId().getValueString().c_str())); - bank = ServerWorld::createNewObject(s_bankTemplate, *this, slot, false); - if (!bank) - { - DEBUG_FATAL(true, ("Could not create a bank for the player who lost theirs")); - } - else - { - bank->persist(); - bank->setLoadContents(false); - } - } - } - } -} - -//----------------------------------------------------------------------- - -/** - * Allows an object to do pre-deletion cleanup. - */ -void CreatureObject::onRemovingFromWorld() -{ - TangibleObject::onRemovingFromWorld(); - if (isAuthoritative()) - { - // if we are crafting, end the crafting session - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - if (player != NULL && player->isCrafting()) - player->stopCrafting(false); - - // exit all notify regions - Archive::AutoDeltaSet >::const_iterator i; - for(i = m_notifyRegions.begin(); i != m_notifyRegions.end(); ++i) - { - ScriptParams params; - params.addParam(i->first.c_str()); - params.addParam(i->second.c_str()); - if(getScriptObject()) - { - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_EXIT_REGION, params)); - } - } - m_notifyRegions.clear(); - } - - if (isMountable()) - IGNORE_RETURN(detachAllRiders()); - { - } -} - -void CreatureObject::addToWorld() -{ - if (getKill()) - return; - - if (isInWorld()) - { - DEBUG_WARNING(true, ("Calling add to world on object already in it %s", getNetworkId().getValueString().c_str())); - return; - } - updateWorldSphere(); - - Object::addToWorld(); - updateTriggerVolumes(); - - if (getScriptObject() != NULL) - getScriptObject()->setOwnerIsLoaded(); - - ContainedByProperty * const containedByProperty = getContainedByProperty(); - if (containedByProperty && containedByProperty->getContainedByNetworkId().isValid()) - { - Object const * const containedByObject = containedByProperty->getContainedBy(); - if (containedByObject && !containedByObject->isInWorld()) - { - if (!ServerWorld::isSpaceScene()) - { - // attempt to put the character at the ejection point of the building - DynamicVariableLocationData ejectionPoint; - if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) - { - DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building does not exist anymore or is not loaded in the world\n",getNetworkId().getValueString().c_str(), containedByProperty->getContainedByNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building does not exist anymore or is not loaded in the world",getNetworkId().getValueString().c_str(), containedByProperty->getContainedByNetworkId().getValueString().c_str())); - removeObjVarItem("building_ejection_point"); - teleportObject(ejectionPoint.pos, ejectionPoint.cell, "", ejectionPoint.pos,""); - - } - else - // warp the player to the Mos Eisley Starport - { - DEBUG_REPORT_LOG(true, ("Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); - GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this),"tatooine",Vector(3528,5,-4804),NetworkId::cms_invalid,Vector(3528,5,-4804)); - } - } - } - } - - onAddedToWorld(); -} - -//----------------------------------------------------------------------- - -void CreatureObject::initializeNewPlayer() -{ -} - -//----------------------------------------------------------------------- - -/** Set up the inventory object for the creature and initialize with contents from template. - */ -void CreatureObject::setupInventory() -{ - -} - -//----------------------------------------------------------------------- - -/** - * Sets up the creature's skills and related data. - */ -void CreatureObject::setupSkillData() -{ - if (isAuthoritative()) - { - // clear out our current skill related data - m_modMap.clear(); - if (isPlayerControlled()) - { - clearCommands(); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - { - playerObject->clearSchematics(); - } - } - - m_skills.erase(0); - - // set the skill related data from the skills - for (SkillList::const_iterator skillIter = m_skills.begin(); skillIter != m_skills.end(); ++skillIter) - { - SkillObject const * skill = *skillIter; - if (skill) - { - // init skillmods - std::vector > const &statMods = skill->getStatisticModifiers(); - std::vector >::const_iterator modIter; - for (modIter = statMods.begin(); modIter != statMods.end(); ++modIter) - { - addModValue((*modIter).first, (*modIter).second, true); - } - // init skill commands - { - const SkillObject::StringVector & sv = skill->getCommandsProvided (); - for (SkillObject::StringVector::const_iterator i = sv.begin(); - i != sv.end(); ++i) - { - grantCommand(*i, true); - } - } - // init schematics - { - const SkillObject::StringVector & sv = skill->getSchematicsGranted (); - for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) - grantSchematicGroup("+" + *i, true); - } - } - } - - // read the non-skill data from the objvars and add those to the creature - // note that we add them as "from skill" so that they don't get added to the - // objvar list again - { - DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_NOT_SKILL_MODS); - DynamicVariableList::NestedList::const_iterator i(mods.begin()); - int value; - for (; i != mods.end(); ++i) - { - i.getValue(value); - addModValue(i.getName(), value, true); - } - } - { - DynamicVariableList::NestedList commands(getObjVars(), OBJVAR_NOT_SKILL_COMMANDS); - DynamicVariableList::NestedList::const_iterator i(commands.begin()); - for (; i != commands.end(); ++i) - { - grantCommand(i.getName(), true); - } - if(getClient()) - { - revokeCommand(AdminAccountManager::getAdminCommandName(), false); - - if (getClient()->isGod()) - grantCommand(AdminAccountManager::getAdminCommandName(), false); - } - } - { - DynamicVariableList::NestedList schematics(getObjVars(), OBJVAR_NOT_SKILL_SCHEMATICS); - DynamicVariableList::NestedList::const_iterator i(schematics.begin()); - for (; i != schematics.end(); ++i) - { - grantSchematic(strtoul(i.getName().c_str(), NULL, 10), true); - } - } - - // calculate the level based on the skill list - recalculateLevel(); - } -} // CreatureObject::setupSkillData - -//----------------------------------------------------------------------- - -/** - * Creates a default controller for this object. - * - * @return the object's controller - */ -Controller* CreatureObject::createDefaultController () -{ - const ServerCreatureObjectTemplate * myTemplate = safe_cast< - const ServerCreatureObjectTemplate *>(getObjectTemplate()); - - Controller * controller = 0; - if (myTemplate->getCanCreateAvatar()) - { - controller = new PlayerCreatureController(this); - } - else - { - controller = new AICreatureController(this); - - AICreatureController * const aiCreatureController = AICreatureController::asAiCreatureController(controller); - - if (aiCreatureController != NULL) - { - aiCreatureController->addServerNpAutoDeltaVariables(m_serverPackage_np); - } - } - - setController(controller); - return controller; -} // CreatureObject::createDefaultController - -//----------------------------------------------------------------------- - -CreatureController* CreatureObject::getCreatureController() -{ - return safe_cast(getController()); -} - -//---------------------------------------------------------------------- - -const CreatureController* CreatureObject::getCreatureController() const -{ - return safe_cast(getController()); -} - -//---------------------------------------------------------------------- - -void CreatureObject::setAuthority() -{ - // don't recalculate our attribs until all our equipment has been made - // authoritative - ++m_deferComputeTotalAttributes; - TangibleObject::setAuthority(); - --m_deferComputeTotalAttributes; - computeTotalAttributes(); -} - -//---------------------------------------------------------------------- - - -void CreatureObject::setAuthServerProcessId(uint32 processId) -{ - uint32 const oldProcess = getAuthServerProcessId(); - TangibleObject::setAuthServerProcessId(processId); - - if (oldProcess != getAuthServerProcessId()) - { - // we can't trade if we are on different servers, so cancel it - if (getCreatureController()->getSecureTrade() != NULL) - { - getCreatureController()->getSecureTrade()->cancelTrade(*this); - } - } -} - -//---------------------------------------------------------------------- - -/** - * Updates the creature. Removes it from combat if it is incapacitated. - * - * @param time current game time - * - * @return base class result - */ -float CreatureObject::alter(float time) -{ - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter"); - float const result = TangibleObject::alter(time); - - m_regionFlagTimer.updateNoReset(time); // Update our notify timer. - - if (isPlayerControlled() && (isIncapacitated() || isDead())) - { - // If the player is trading, cancel the trade. - // We need to force the issue to catch edge cases. - ServerSecureTrade * const secureTradeObject = getCreatureController()->getSecureTrade(); - if (secureTradeObject != NULL) - { - secureTradeObject->cancelTrade(*this); - } - } - - if (!isAuthoritative()) - { - // Non-authoritative activity. - removeFromSpawnQueue(); - } - else - { - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter auth stuff"); - //-- Mounts/vehicles: driver moves the server's mount/vehicle position to that of the driver. - transferRiderPositionToMount(); - - updateVehiclePhysicsData (); - - // Authoritative activity. - - // update the invulnerability timer - if (m_invulnerabilityTimer.get() != 0.0f) - { - float const timeLeft = std::max(0.f, m_invulnerabilityTimer.get()-time); - m_invulnerabilityTimer.set(timeLeft); - } - else - { - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter commandqueue"); - // update the command queue - getCommandQueue()->update(time); - } - - //check timer and migrate stats if necessary - -//disable self stat migration -#if 0 - migrateStats(time); -#endif - - if (isPlayerControlled()) - { - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter auth player stuff"); - // keep the spawn queue pumping. - // todo: if the spawn queue is starving out players because - // there are too may other players on the queue, make some - // preliminary checks (e.g. in a city, too many creatures nearby) - // and reduce the spawn queue size - addToSpawnQueue(); - - { - PROFILER_AUTO_BLOCK_DEFINE("gradual customizations"); - ServerImageDesignerManager::updateGradualCustomizations(this); - } - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - PROFILER_AUTO_BLOCK_DEFINE("playerobject stuff"); - playerObject->alterPlayedTime(time); - playerObject->updateKillMeter(time); - playerObject->checkStomach(); - playerObject->checkTheater(getPosition_w(), getSceneId(), getRunSpeed(), 128.0f); - updateGroup(); - - if (playerObject->getIsUnsticking() && getPositionChanged()) - { - Chat::sendSystemMessageSimple(*this, SharedStringIds::unstick_request_cancelled, NULL); - playerObject->setIsUnsticking(false); - } - } - - if (!ServerWorld::isSpaceScene()) - { - // if we're in a conversation, end it if we move too far from the npc - if (m_npcConversation != NULL) - { - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter::npcConvCheck"); - bool endConversation = false; - // check the distance to the npc - ServerObject const * const npc = safe_cast(m_npcConversation->getNPC().getObject()); - if (npc != NULL) - { - float distance = findPosition_w().magnitudeBetween(npc->findPosition_w()); - distance -= getRadius(); - distance -= npc->getRadius(); - if (distance > ConfigServerGame::getNpcConversationDistance()) - endConversation = true; - } - else - { - endConversation = true; - } - if (endConversation) - endNpcConversation(); - } - } - } - alterPseudoPlayedTime(time); - updateBuffs(); - - //-- Handle mounts-specific functionality for an authoritative rider or mount. - alterAuthoritativeForMounts(); - } - - // see if we are performing a slow down effect - Property * property = getProperty(SlowDownProperty::getClassPropertyId()); - if (property != NULL) - { - // has it expired? - SlowDownProperty * slowdown = safe_cast(property); - if (slowdown->getExpireTime() <= ServerClock::getInstance().getGameTimeSeconds()) - { - // yes, remove the effect - removeProperty(SlowDownProperty::getClassPropertyId()); - } - else - { - // we need to find every authoritative non-player creature in the effect's - // area, and and tell them they are moving on our effect "hill" during their next alter - // (player creatures are handled on the player's client) - Object * target = slowdown->getTarget().getObject(); - if (target != NULL) - { - std::vector found; - ServerWorld::findAuthoritativeNonPlayerCreaturesInCone(*this, *target, slowdown->getConeLength(), slowdown->getConeAngle(), found); - if (!found.empty()) - { - // compute the effective normal vector of our "hill" - Vector normal(getPosition_w() - target->getPosition_w()); - normal.y = 0; - normal.normalize(); - normal *= cos(slowdown->getSlopeAngle() + PI_OVER_2); - normal.y = sin(slowdown->getSlopeAngle() + PI_OVER_2); - for (std::vector::iterator i = found.begin(); i != found.end(); ++i) - { - if ((*i)->getNetworkId() != getNetworkId()) - safe_cast(*i)->addTerrainSlopeEffect(normal); - } - } - } - } - } - - //-- Handle mounts-specific functionality for all mounts. We'll do sanity checking in here. - alterAnyForMounts(); - - //-- Handle updateMovementInfo. - if (getLocalFlag(LocalObjectFlags::CreatureObject_RequiresMovementInfoUpdate)) - { - updateMovementInfo(); - setLocalFlag(LocalObjectFlags::CreatureObject_RequiresMovementInfoUpdate, false); - } - - m_locomotion = calcLocomotion(); - - if (PlayerCreatureController::getPlayerObject(this) != 0) - { - if (m_level.get() != m_previousLevel) - { - if (isAuthoritative()) - { - GameScriptObject * const script = getScriptObject(); - - if (script != 0) - { - ScriptParams params; - params.addParam(m_previousLevel); - params.addParam(m_level.get()); - script->trigAllScripts(Scripting::TRIG_COMBAT_LEVEL_CHANGED, params); - } - } - m_previousLevel = m_level.get(); - levelChanged(); - } - } - - return result; -} - -//----------------------------------------------------------------------- - -bool CreatureObject::canDestroy() const -{ - // turn off our default weapon so it won't prevent us from getting - // destroyed - WeaponObject * defaultWeapon = getDefaultWeapon(); - if (defaultWeapon != NULL) - defaultWeapon->setAsDefaultWeapon(false); - - bool result = TangibleObject::canDestroy(); - if (!result) - { - // we're not being destroyed, turn our default weapon back on - if (defaultWeapon != NULL) - defaultWeapon->setAsDefaultWeapon(true); - } - - return result; -} - -//----------------------------------------------------------------------- - -float CreatureObject::getPvpRegionCheckTime() -{ - return ConfigServerGame::getCreaturePvpRegionCheckTime(); -} - -//----------------------------------------------------------------------- - -/** - * Sets the default weapon for a creature. This function bootstraps the default weapon. - * After this function is called, there should always be a weapon in the default - * weapon slot. - */ -void CreatureObject::initializeDefaultWeapon() -{ - FATAL(!isAuthoritative(), ("CreatureObject::initializeDefaultWeapon: obj %s, while nonauth", getDebugInformation().c_str())); - - ServerCreatureObjectTemplate const * const myTemplate = safe_cast(getObjectTemplate()); - if (myTemplate != NULL) - { - ServerWeaponObjectTemplate const *weaponTemplate = myTemplate->getDefaultWeapon(); - if (weaponTemplate == NULL) - { - WARNING(true, ("Creature template %s has no valid default weapon!", getTemplateName())); - - // try to use the fallback weapon - weaponTemplate = dynamic_cast(ObjectTemplateList::fetch(ConfigServerGame::getFallbackDefaultWeapon())); - - FATAL(weaponTemplate == NULL, ("CreatureObject::initializeFirstTimeObject fallback weapon template %s is bad!", ConfigServerGame::getFallbackDefaultWeapon())); - } - - WeaponObject * const weapon = safe_cast(ServerWorld::createNewObject(*weaponTemplate, *this, s_defaultWeaponSlotId, false)); - - if (weapon != NULL) - weapon->setAsDefaultWeapon(true); - else - { - WARNING_STRICT_FATAL(true, ("CreatureObject::initializeDefaultWeapon unable to create default weapon %s for creature %s", weaponTemplate->getName(), getNetworkId().getValueString().c_str())); - } - - weaponTemplate->releaseReference(); - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::swapDefaultWeapons(WeaponObject &newDefaultWeapon, ServerObject &weaponContainer) -{ - FATAL(!isAuthoritative(), ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, while obj nonauth", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); - FATAL(!newDefaultWeapon.isAuthoritative(), ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, while newDefaultWeapon nonauth", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); - FATAL(!weaponContainer.isAuthoritative(), ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, while weaponContainer nonauth", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); - - // There is a window here where the default weapon can be null, so we - // set a flag that it's ok until we've finished the transfer. - FATAL(s_allowNullDefaultWeapon, ("CreatureObject::swapDefaultWeapons has been recursively called!")); - - WeaponObject * const oldDefaultWeapon = getDefaultWeapon(); - FATAL(!oldDefaultWeapon, ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, with no current default weapon", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); - - s_allowNullDefaultWeapon = true; - - // Move the current default weapon into the weapon container - oldDefaultWeapon->setAsDefaultWeapon(false); - Container::ContainerErrorCode err = Container::CEC_Success; - bool const success1 = ContainerInterface::transferItemToVolumeContainer(weaponContainer, *oldDefaultWeapon, 0, err, true); - FATAL(!success1, ("CreatureObject::swapDefaultWeapons: obj %s, old default weapon %s, new default weapon %s, weaponContainer %s, old default weapon transfer to weaponContainer failed with error %d", getDebugInformation().c_str(), oldDefaultWeapon->getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str(), static_cast(err))); - - // Try to move the new default weapon into the default weapon slot - bool const success2 = ContainerInterface::transferItemToSlottedContainer(*this, newDefaultWeapon, s_defaultWeaponSlotId, 0, err); - if (success2) - newDefaultWeapon.setAsDefaultWeapon(true); - else - { - // We failed to swap in the new default weapon, so we need to move the old one back in. - bool const success3 = ContainerInterface::transferItemToSlottedContainer(*this, *oldDefaultWeapon, s_defaultWeaponSlotId, 0, err); - FATAL(!success3, ("CreatureObject::swapDefaultWeapons: obj %s, old default weapon %s, new default weapon %s, weaponContainer %s, old default weapon transfer back to default weapon slot after failure to switch to new default weapon failed with error %d", getDebugInformation().c_str(), oldDefaultWeapon->getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str(), static_cast(err))); - oldDefaultWeapon->setAsDefaultWeapon(true); - } - - s_allowNullDefaultWeapon = false; - return success2; -} - -// ---------------------------------------------------------------------- - -WeaponObject *CreatureObject::getDefaultWeapon() const -{ - SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); - if (container == NULL) - { - return NULL; - } - - WeaponObject * defaultWeapon = NULL; - Container::ContainerErrorCode error; - Container::ContainedItem itemId = container->getObjectInSlot(s_defaultWeaponSlotId, error); - if (error == Container::CEC_Success) - { - Object * const o = itemId.getObject(); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so) - defaultWeapon = so->asWeaponObject(); - } - FATAL(!s_allowNullDefaultWeapon && defaultWeapon == NULL, ("CreatureObject::getDefaultWeapon, weapon is NULL! Object in default slot is %s", itemId.getValueString().c_str())); - } - return defaultWeapon; -} - -// ---------------------------------------------------------------------- - -/** - * Returns an attribute value, modified by attribute mods. - * - * @param attribute the attribute to get - */ -Attributes::Value CreatureObject::getAttribute(Attributes::Enumerator attribute) const -{ - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - { - DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); - return 0; - } - - return getAdjustedAttribute(attribute, m_attributes[attribute]); -} - -//----------------------------------------------------------------------- - -/** - * Returns an attribute value, adjusted by wounds, etc. - * - * @param attribute the attribute type - * @param value the value to adjust - * - * @returns value adjusted by various params - */ -Attributes::Value CreatureObject::getAdjustedAttribute(Attributes::Enumerator attribute, - Attributes::Value value) const -{ - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - { - DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); - return value; - } - - // modify the attribute for attrib mods - value = static_cast( - value + m_cachedCurrentAttributeModValues[attribute]); - - // modify for partial regeneration - value = static_cast(value + static_cast(floor(m_regeneration[attribute]))); - - //cap maximum value - Attributes::Value max = getMaxAttribute(attribute); - if (value > max) - value = max; - - return value; -} // CreatureObject::getAdjustedAttribute - -//----------------------------------------------------------------------- - -/** - * Returns a max attribute value, modified by attribute mods. - * - * @param attribute the attribute to get - */ -Attributes::Value CreatureObject::getMaxAttribute(Attributes::Enumerator attribute, bool capStat) const -{ - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - { - DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); - return 0; - } - - Attributes::Value value = getUnmodifiedMaxAttribute(attribute); - value = static_cast( - value + m_cachedMaxAttributeModValues[attribute] + m_attribBonus[attribute]); - - if (capStat) - { - // make sure the value doesn't go below the defined minimum value - if (Attributes::isAttribPool(attribute) && value < ConfigServerGame::getMinPoolValue()) - value = static_cast(ConfigServerGame::getMinPoolValue()); - - // double-check that the max isn't <= 0 - if (value < 1) - value = 1; - } - return value; -} - -//----------------------------------------------------------------------- - -const std::map > & CreatureObject::getModMap() const -{ - return m_modMap.getMap(); -} - -//----------------------------------------------------------------------- - -const int CreatureObject::getModValue(const std::string & modName) const -{ - int result = 0; - std::map >::const_iterator f = m_modMap.find(modName); - if(f != m_modMap.end()) - { - result = (*f).second.first; - } - return result; -} - -//----------------------------------------------------------------------- - -/** - * Returns the value for a skill mod, modified by any special equipment the - * creature may be wearing. - * - * @param statMod the name of the skill mod - * - * @return the mod value - */ -const int CreatureObject::getEnhancedModValue(const std::string & modName) const -{ - int base = 0; - int bonus = 0; - - std::map >::const_iterator f = m_modMap.find(modName); - if (f != m_modMap.end()) - { - base = (*f).second.first; - bonus = (*f).second.second; - } - if (bonus > ConfigSharedGame::getMaxCreatureSkillModBonus()) - bonus = ConfigSharedGame::getMaxCreatureSkillModBonus(); - return base + bonus; -} // CreatureObject::getEnhancedSkillStatMod - -//----------------------------------------------------------------------- - -/** - * Returns the value for a skill mod, modified by any special equipment the - * creature may be wearing. This version does not respect getMaxCreatureSkillModBonus - * - * @param statMod the name of the skill mod - * - * @return the mod value - */ -const int CreatureObject::getEnhancedModValueUncapped(const std::string & modName) const -{ - int base = 0; - int bonus = 0; - - std::map >::const_iterator f = m_modMap.find(modName); - if (f != m_modMap.end()) - { - base = (*f).second.first; - bonus = (*f).second.second; - } - return base + bonus; -} // CreatureObject::getEnhancedSkillStatMod - -//----------------------------------------------------------------------- - -void CreatureObject::setModValue(const std::string & modName, const int value) -{ - if(isAuthoritative()) - { - int oldBonus = 0; - Archive::AutoDeltaMap >::const_iterator found = - m_modMap.find(modName); - if (found != m_modMap.end()) - oldBonus = (*found).second.second; - if (value != 0 || oldBonus != 0) - { - m_modMap.set(modName, std::make_pair(value, oldBonus)); - } - else - { - m_modMap.erase(modName); - } - - updateSlopeMovement(modName); - } - else - { - sendControllerMessageToAuthServer(CM_setModValue, new MessageQueueGenericValueType >(std::make_pair(modName, value))); - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::addModValue(const std::string & modName, const int value, bool fromSkill) -{ - int currentVal = getModValue(modName); - setModValue(modName, currentVal + value); - if (!fromSkill) - { - // update the objvars for the value - std::string objvarName(OBJVAR_NOT_SKILL_MODS + "." + modName); - int currentValue = 0; - getObjVars().getItem(objvarName, currentValue); - currentValue += value; - if (currentValue != 0) - setObjVarItem(objvarName, currentValue); - else - removeObjVarItem(objvarName); - } -} - -// ---------------------------------------------------------------------- - -/** - * Adds a skill mod bonus to the creature. - * - * @param statMod the skill mod name - * @param bonus the bonus value - */ -void CreatureObject::addModBonus(const std::string & modName, int bonus) -{ - if(isAuthoritative()) - { - int oldBase = 0; - int oldBonus = 0; - Archive::AutoDeltaMap >::const_iterator found = - m_modMap.find(modName); - if (found != m_modMap.end()) - { - oldBase = (*found).second.first; - oldBonus = (*found).second.second; - } - bonus += oldBonus; - if (bonus != 0 || oldBase != 0) - { - m_modMap.set(modName, std::make_pair(oldBase, bonus)); - } - else - { - m_modMap.erase(modName); - } - - updateSlopeMovement(modName); - } - else - { -// sendControllerMessageToAuthServer(CM_setModValue, new MessageQueueGenericValueType >(std::make_pair(modName, value))); - } -} // CreatureObject::addModBonus - -// ---------------------------------------------------------------------- - -/** - * Adds an attrib bonus to the creature. - * - * @param attrib the attribute - * @param bonus the bonus value - */ -void CreatureObject::addAttribBonus(int attrib, int bonus) -{ - if (isAuthoritative()) - { - if (attrib < 0 || attrib >= Attributes::NumberOfAttributes) - return; - - int newBonus = m_attribBonus[attrib] + bonus; - if (newBonus > ConfigServerGame::getMaxTotalAttribBonus()) - newBonus = ConfigServerGame::getMaxTotalAttribBonus(); - else if (newBonus < -ConfigServerGame::getMaxTotalAttribBonus()) - newBonus = -ConfigServerGame::getMaxTotalAttribBonus(); - m_attribBonus.set(attrib, newBonus); - } -} // CreatureObject::addAttribBonus - -// ---------------------------------------------------------------------- - -void CreatureObject::updateSlopeMovement(const std::string & modName) -{ - // if I'm modifiying the slope mod, update my speed - if (modName == SLOPE_MOD) - recomputeSlopeModPercent(); - // if I'm modifiying the group slope mod and I'm a group leader, - // update my group's speed - else if (modName == GROUP_SLOPE_MOD && getGroup() != NULL && - getGroup()->getGroupLeaderId() == getNetworkId()) - { - const GroupObject::GroupMemberVector & members = getGroup()->getGroupMembers(); - GroupObject::GroupMemberVector::const_iterator iter; - for (iter = members.begin(); iter != members.end(); ++iter) - { - CreatureObject * member = safe_cast( - NetworkIdManager::getObjectById((*iter).first)); - if (member != NULL) - member->recomputeSlopeModPercent(); - } - } -} - -// ---------------------------------------------------------------------- - -/** - * Cause the client to dance using the specified dance style. - * - * This function will change the server and clients to the SkillAnimating - * posture. - * - * @param enabled if true, start doing the skill. If false, stop doing the skill. - * @param danceStyle the number of the dance style. - * - * @return true if this function succeeded, false if it failed for any reason. - */ - -bool CreatureObject::showDanceVisuals(bool enabled) -{ - //-- Ensure we are authoratative. This function should only be called - // indirectly via the command table, which guarantees it is called on the - // authoratative object. - if (!isAuthoritative()) - { - DEBUG_WARNING(true, ("showDanceVisuals() should be called only on the authoratative object.")); - return false; - } - - if (!enabled) - { - //-- Set the server object to the upright posture. - setPosture(Postures::Upright); - - //-- Tell all clients to switch to the specified posture. - Controller *const controller = getController(); - if (controller) - controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::Upright, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); - else - DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); - } - else - { - int visualId = lookupDanceVisual(getPerformanceType()); - if (visualId == 0) - return false; - - //-- Set the server object to animating skill posture. - setPosture(Postures::SkillAnimating); - - //-- Tell all clients to switch to the specified posture. - Controller *const controller = getController(); - if (controller) - controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::SkillAnimating, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); - else - DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); - - //-- Modify the animating skill data string. - char buffer[64]; - - sprintf(buffer, "dance_%d", visualId); - m_animatingSkillData = buffer; - } - - //-- Success. - return true; -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::showMusicianVisuals(bool enabled) -{ - //-- Ensure we are authoratative. This function should only be called - // indirectly via the command table, which guarantees it is called on the - // authoratative object. - if (!isAuthoritative()) - { - DEBUG_WARNING(true, ("showMusicianVisuals() should be called only on the authoratative object.")); - return false; - } - - if (!enabled) - { - //-- Set the server object to the upright posture. - setPosture(Postures::Upright); - - //-- Tell all clients to switch to the specified posture. - Controller *const controller = getController(); - if (controller) - controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::Upright, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); - else - DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); - } - else - { - //-- Determine the type of instrument used by this creature. - // @todo - const int instrumentId = getInstrumentVisualId(); - if (instrumentId == 0) - { - WARNING(true, ("tried to call showMusicianVisuals without a valid instrument")); - return false; - } - - //-- Set the server object to animating skill posture. - setPosture(Postures::SkillAnimating); - - //-- Tell all clients to switch to the specified posture. - Controller *const controller = getController(); - if (controller) - controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::SkillAnimating, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); - else - DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); - - //-- Modify the animating skill data string. - char buffer[64]; - - sprintf(buffer, "music_%d", instrumentId); - m_animatingSkillData = buffer; - } - - //-- Success. - return true; -} - -//----------------------------------------------------------------------- - -void CreatureObject::sendMusicFlourish(int flourishIndex) -{ - Controller *controller = getController(); - if (controller) - { - MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(flourishIndex); - controller->appendMessage( - CM_musicFlourish, - 0.0f, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_ALL_CLIENT); - } -} - -//----------------------------------------------------------------------- - -/** - * Returns a mental state value, modified by mental state mods. - * - * @param attribute the attribute to get - */ -MentalStates::Value CreatureObject::getMentalState(MentalStates::Enumerator attribute) const -{ - if (attribute < 0 || attribute >= MentalStates::NumberOfMentalStates) - { - DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", attribute)); - return 0.0f; - } - - MentalStates::Value value = static_cast(m_currentAttitude.get().m_currentValues[attribute]); - return value; -} - -//----------------------------------------------------------------------- - -/** - * Returns a mental state value, modified by mental state mods. - * - * @param attribute the attribute to get - */ -MentalStates::Value CreatureObject::getMentalStateToward(const NetworkId &target, MentalStates::Enumerator attribute) const -{ - if (attribute < 0 || attribute >= MentalStates::NumberOfMentalStates) - { - DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", attribute)); - return 0.0f; - } - - MentalStates::Value value = static_cast(m_currentAttitude.get().m_currentValues[attribute]); - - CreatureAttitude const * const cs = getAttitudeToward(target); - if (cs) - { - value = static_cast(value + cs->m_currentValues[attribute]); - } - return value; -} - -//----------------------------------------------------------------------- - -int CreatureObject::getExperiencePoints(const std::string & experienceType) const -{ - if (isPlayerControlled()) - { - const PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - return playerObject->getExperiencePoints(experienceType); - } - return 0; -} - -//----------------------------------------------------------------------- - -const std::map & CreatureObject::getExperiencePoints() const -{ - static const std::map emptyResult; - if(isPlayerControlled()) - { - const PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if(playerObject != NULL) - { - return playerObject->getExperiencePoints(); - } - } - return emptyResult; -} - -//----------------------------------------------------------------------- - -const CreatureObject::SkillList & CreatureObject::getSkillList() const -{ - return m_skills.get(); -} - -//----------------------------------------------------------------------- - -const int CreatureObject::grantExperiencePoints(const std::string & experienceType, int amount) -{ - if (isPlayerControlled()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - { - int const amountGranted = playerObject->grantExperiencePoints(experienceType, amount); - - LevelManager::LevelData levelData(m_level.get(), m_totalLevelXp.get()); - LevelManager::addXpToLevelData(levelData, experienceType, amountGranted); - - setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); - - return amountGranted; - } - } - return INT_MIN; -} - -// ---------------------------------------------------------------------- - -const bool CreatureObject::grantSkill(const SkillObject & newSkill) -{ - if(isAuthoritative()) - { - //-- jww: simply return true if the skill is already in the vector - //-- this was the previous behavior, dunno if it should return false - if (hasSkill (newSkill)) - return true; - - // signal scripts that skill is about to be granted. If the script returns override, cancel skill grant. - { - ScriptParams params; - params.addParam(newSkill.getSkillName().c_str()); - if (getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_ABOUT_TO_BE_GRANTED, params) == SCRIPT_OVERRIDE) - { - return false; - } - } - - m_skills.insert(&newSkill); - if(getClient()) - { - LOG("CustomerService", ("Skill: Account %s CharacterId %s has acquired skill %s", getClient()->getAccountName().c_str(), getNetworkId().getValueString().c_str(), newSkill.getSkillName().c_str())); - } - - { - const SkillObject::StringVector & sv = newSkill.getCommandsProvided (); - for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) - grantCommand(*i, true); - } - - const std::vector > & statMods = newSkill.getStatisticModifiers(); - std::vector >::const_iterator modIter; - for(modIter = statMods.begin(); modIter != statMods.end(); ++ modIter) - { - addModValue((*modIter).first, (*modIter).second, true); - } - - { - const SkillObject::StringVector & sv = newSkill.getSchematicsGranted (); - for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) - grantSchematicGroup("+" + *i, true); - } - - // signal scripts that skill has been granted - ScriptParams params; - params.addParam(newSkill.getSkillName().c_str()); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_GRANTED, - params)); - - LevelManager::LevelData levelData(m_level.get(), m_totalLevelXp.get()); - LevelManager::addSkillToLevelData(levelData, newSkill.getSkillName()); - - setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); - } - else - { - sendControllerMessageToAuthServer(CM_grantSkill, new MessageQueueGenericValueType(newSkill.getSkillName())); - } - - return true; -} - -//----------------------------------------------------------------------- - -void CreatureObject::revokeSkill(const SkillObject & oldSkill, bool silent) -{ - if(isAuthoritative()) - { - // signal scripts that skill has been revoked - ScriptParams params; - params.addParam(oldSkill.getSkillName().c_str()); - if(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_ABOUT_TO_BE_REVOKED, params) == SCRIPT_CONTINUE) - { - - for (SkillList::const_iterator it = m_skills.begin(); it != m_skills.end(); ++it) - { - const SkillObject * const skill = *it; - - if (skill) - { - const SkillObject::SkillVector &prerequisiteSkills = skill->getPrerequisiteSkills(); - - for (SkillObject::SkillVector::const_iterator pit = prerequisiteSkills.begin(); pit != prerequisiteSkills.end(); ++pit) - { - const SkillObject * const prereq = *pit; - NOT_NULL (prereq); - - if (oldSkill.getSkillName() == prereq->getSkillName()) - { - if (!silent) - Chat::sendSystemMessage(*this, SharedStringIds::revoke_dependant_skill, Unicode::emptyString); - return; - } - } - } - } - - if (m_skills.contains(&oldSkill)) - { - // remove granted commands - { - const SkillObject::StringVector & sv = oldSkill.getCommandsProvided (); - for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) - revokeCommand(*i, true); - } - - // remove granted skill mods - const std::vector > & statMods = oldSkill.getStatisticModifiers(); - std::vector >::const_iterator modIter; - for(modIter = statMods.begin(); modIter != statMods.end(); ++ modIter) - { - addModValue((*modIter).first, -(*modIter).second, true); - } - - // remove schematics that were granted by any schematic groups - { - const SkillObject::StringVector & sv = oldSkill.getSchematicsGranted (); - for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) - { - const std::string & grantedGroup = *i; - grantSchematicGroup("-" + grantedGroup, true); - } - } - - m_skills.erase(&oldSkill); - if(getClient()) - { - LOG("CustomerService", ("Skill: Account %s CharacterId %s has lost skill %s", getClient()->getAccountName().c_str(), getNetworkId().getValueString().c_str(), oldSkill.getSkillName().c_str())); - } - - // Remove the current skill title if this is a player and their current title - // is this skill - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - - if ((playerObject != NULL) && - (oldSkill.getSkillName() == playerObject->getTitle())) - { - StringId message("shared", "skill_title_removed"); - Unicode::String outOfBand; - if (!silent) - Chat::sendSystemMessage(*this, message, outOfBand); - - playerObject->setTitle(""); - } - - // signal scripts that skill has been revoked - ScriptParams params; - params.addParam(oldSkill.getSkillName().c_str()); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_REVOKED,params)); - - // update the level data - LevelManager::LevelData levelData(m_level.get(), m_totalLevelXp.get()); - LevelManager::removeSkillFromLevelData(levelData, oldSkill.getSkillName()); - - setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); - } - } - } - else - { - LOG("CustomerService", ("Skill: Could not revoke skill %s from character %s because it is a proxy so we're forwarding this to the auth server.", - oldSkill.getSkillName().c_str(), getNetworkId().getValueString().c_str())); - sendControllerMessageToAuthServer(CM_revokeSkill, new MessageQueueGenericValueType(oldSkill.getSkillName())); - } -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::grantSchematicGroup(const std::string & groupNameWithModifier, bool fromSkill) -{ - if (isPlayerControlled()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - return playerObject->grantSchematicGroup(groupNameWithModifier, fromSkill); - } - return false; -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::grantSchematic(const std::string & schematicName, bool fromSkill) -{ - return grantSchematic(Crc::calculate(schematicName.c_str()), fromSkill); -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::grantSchematic(uint32 schematicCrc, bool fromSkill) -{ - if (isPlayerControlled()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - return playerObject->grantSchematic(schematicCrc, fromSkill); - } - return false; -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::revokeSchematic(const std::string & schematicName, bool fromSkill) -{ - return revokeSchematic(Crc::calculate(schematicName.c_str()), fromSkill); -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::revokeSchematic(uint32 schematicCrc, bool fromSkill) -{ - if (isPlayerControlled()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - return playerObject->revokeSchematic(schematicCrc, fromSkill); - } - return false; -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::hasSchematic(const std::string & schematicName) -{ - return hasSchematic(Crc::calculate(schematicName.c_str())); -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::hasSchematic(uint32 schematicCrc) -{ - if (isPlayerControlled()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - return playerObject->hasSchematic(schematicCrc); - } - return false; -} - -//----------------------------------------------------------------------- - -const bool CreatureObject::hasSkill(const SkillObject & skill) const -{ - return std::find (m_skills.begin(), m_skills.end (), &skill) != m_skills.end(); -} - -//----------------------------------------------------------------------- - -/** - * Sets up the object for being in or out of combat. - * @todo: this should really be in tangible only, we need to have a command queue - * for tangibles - * - * @param inCombat flag to put the object in combat-ready state or not - * - * @return true if state was set, false if something went wrong - */ -void CreatureObject::setInCombat(bool inCombat) -{ - TangibleObject::setInCombat(inCombat); - - if (isAuthoritative()) - { - if (!inCombat) - { - setState(States::Aiming, false); - } - else - { - // if we are crafting, end the crafting session - - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - - if (player != NULL && player->isCrafting()) - { - player->stopCrafting(false); - } - } - } -} - -//----------------------------------------------------------------------- - -/** - * If this object is in combat, adds an aim to it. - */ -void CreatureObject::addAim () -{ - TangibleObject::addAim(); - if (isInCombat()) - { - setState(States::Aiming, true); - } -} // CreatureObject::addAim - -//----------------------------------------------------------------------- - -/** - * If this object is in combat, clear's it's aims. - */ -void CreatureObject::clearAims () -{ - TangibleObject::clearAims(); - if (isInCombat()) - { - setState(States::Aiming, false); - } -} // CreatureObject::clearAims - -//----------------------------------------------------------------------- - -/** - * Modifies a creature's attribute. No other function should modify the pool indexes - * of m_attributes. Will incapacitate the creature if an attribute drops to 0. - * - * @param attrib the attribute to modify - * @param delta amount to modify the attribute by - * @param checkIncapacitation flag to check for incap/recap - * @param source who is doing the damage (NetworkId::cms_invalid - * for no one) - * @param force force the change, even if we would normally not - * make it - * - * @return the amount of damage actually applied - */ -int CreatureObject::alterAttribute(Attributes::Enumerator attrib, int delta, - bool checkIncapacitation, const NetworkId & source, bool force) -{ - if (isAuthoritative()) - { - if (attrib < 0 || attrib >= Attributes::NumberOfAttributes) - { - DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attrib)); - return 0; - } - - if (!Attributes::isAttribPool(attrib)) - { - // we only alter pool values now, regeneration is set directly - DEBUG_REPORT_LOG(true, ("CreatureObject::alterAttribute called on %s for non-pool attrib (%d)\n", - getNetworkId().getValueString().c_str(), attrib)); - return 0; - } - - if (delta == 0) - return 0; - - // Use TangibleObject::isInvulnerable so we don't consider invulnerability timers - if ((isDead() || TangibleObject::isInvulnerable()) && !force) - return 0; - - if (getMaxAttribute(attrib) <= 0 && !force) - return 0; - - // if we are taking damage, try and damage any attrib mods instead - int attribModChange = 0; - int regenChange = 0; - if (delta < 0) - { - attribModChange = changeAttribModCurrentValue(attrib, delta, false); - if (attribModChange == delta) - { - computeTotalAttributes(); - if (checkIncapacitation) - testIncapacitation(source); - return attribModChange; - } - else - { - delta -= attribModChange; - } - - // if we are still taking damage, try and reduce any accumulated - // regeneration points - if (delta < 0 && m_regeneration[attrib] > 0) - { - if (m_regeneration[attrib] >= -delta) - { - // regen can absorb it all - m_regeneration[attrib] += delta; - computeTotalAttributes(); - if (checkIncapacitation) - testIncapacitation(source); - return attribModChange + delta; - } - else - { - regenChange = -static_cast(floor(m_regeneration[attrib])); - m_regeneration[attrib] += regenChange; - delta -= regenChange; - } - } - } - - // Don't set the actual attribute until the end of this function, - // to avoid changing it multiple times and generating network spam - int newValue = m_attributes[attrib] + delta; - - // if the attribute is more than the max attribute, reduce it - int maxAttribLimit = getUnmodifiedMaxAttribute(attrib) + getAttributeBonus(attrib); - if (newValue > maxAttribLimit) - { - int overflow = newValue - maxAttribLimit; - delta -= overflow; - newValue = maxAttribLimit; - - // try and heal any attrib mods - attribModChange = changeAttribModCurrentValue(attrib, overflow, false); - } - - // cap for min attrib value, depending on attrib type - int minValue = 0; - if (isPlayerControlled()) - { - if (Attributes::isAttribPool(attrib)) - minValue = ConfigServerGame::getMinPoolValue(); - } - int adjustedNewValue = getAdjustedAttribute(attrib, static_cast< - Attributes::Value>(newValue)); - if (adjustedNewValue < minValue) - { - newValue = minValue - (adjustedNewValue - newValue); - adjustedNewValue = minValue; -#ifdef _DEBUG - adjustedNewValue = getAdjustedAttribute(attrib, static_cast< - Attributes::Value>(newValue)); - if (adjustedNewValue != minValue) - { - DEBUG_WARNING(true, ("CreatureObject::alterAttribute, " - "adjustedNewValue != minValue")); - } -#endif - } - - if (newValue != m_attributes[attrib]) - { - // clip delta so whoever did the damage won't get overkill xp - if (adjustedNewValue < 0) - adjustedNewValue = 0; - delta = adjustedNewValue - getAttribute(attrib); - - // change the attribute - m_attributes.set(attrib, static_cast(newValue)); - - // update the client and check for incapacitation - computeTotalAttributes(); - if (checkIncapacitation) - testIncapacitation(source); - } - else - delta = 0; - - return delta + attribModChange + regenChange; - } - else - { - sendControllerMessageToAuthServer(CM_alterAttribute, - new MessageQueueAlterAttribute(attrib, delta, checkIncapacitation, - source)); - return 0; - } -} // CreatureObject::alterAttribute - -//----------------------------------------------------------------------- - -/** - * Tests to see if we need to be incapacitated/recapacitated. - * - * @param attackerId the object that may have caused our incapacitation. - */ -void CreatureObject::testIncapacitation(const NetworkId & attackerId) -{ - WARNING_STRICT_FATAL(!isAuthoritative(), ("CreatureObject::testIncapacitation invoked on non-authoritative object %s:%s", getObjectTemplateName(), getNetworkId().getValueString().c_str())); - - if (m_deferComputeTotalAttributes <= 0) - { - int const health = getAttribute(Attributes::Health); - - if (!isIncapacitated()) - { - // see if we are incapacitated - - if (health <= 0) - { - setIncapacitated(true, attackerId); - } - } - else - { - // recapacitate if any attribute is above 0 - - if (health > 0) - { - setIncapacitated(false, attackerId); - } - } - } -} - -//----------------------------------------------------------------------- - -/** - * Applies an attribute modifier to this creature. - * - * @param name the attrib mod name - * @param attrib the attribute to modify - * @param value the value to apply - * @param duration how long the modifier lasts - * @param attackRate time to get to the peak modifier value - * @param decayRate time for the modifier to be reduced to 0 - * @param flags flags that define how the mod works - */ -void CreatureObject::addAttributeModifier(const std::string & name, - Attributes::Enumerator attrib, int value, float duration, float attackRate, - float decayRate, int flags) -{ - AttribMod::AttribMod mod; - - if (!name.empty()) - { - AttribModNameManager::getInstance().addAttribModName(name.c_str()); - mod.tag = Crc::calculate(name.c_str()); - } - else - mod.tag = 0; - mod.attrib = attrib; - mod.value = value; - mod.attack = attackRate; - mod.sustain = duration; - mod.decay = decayRate; - mod.flags = flags; - if (!Attributes::isAttribPool(mod.attrib)) - { - // non-pool mods must change both max and current - mod.flags |= - AttribMod::AMF_changeMax | - AttribMod::AMF_attackCurrent | - AttribMod::AMF_decayCurrent; - } - LOG("CustomerService", ("Attribs: Added attrib mod to %s. Mod data: " - "%s(%u) %d %d %.2f %.2f %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - name.c_str(), mod.tag, mod.attrib, mod.value, mod.attack, mod.sustain, - mod.decay, mod.flags)); - addAttributeModifier(mod); -} // CreatureObject::addAttributeModifier - -//----------------------------------------------------------------------- - -/** - * Applies a skillmod modifier to this creature. - * - * @param name the attrib mod name - * @param skill the skillmod to modify - * @param value the value to apply - * @param duration how long the modifier lasts (-1 = infinite, or until the player logs off) - * @param flags flags that define how the mod works - */ -void CreatureObject::addSkillmodModifier(const std::string & name, - const std::string & skill, int value, float duration, int flags) -{ - AttribMod::AttribMod mod; - - if (skill.empty()) - { - WARNING_STRICT_FATAL(true, ("CreatureObject::addSkillmodModifier called " - "with empty string for skill")); - return; - } - - if (!name.empty()) - { - AttribModNameManager::getInstance().addAttribModName(name.c_str()); - mod.tag = Crc::calculate(name.c_str()); - } - else - mod.tag = 0; - - AttribModNameManager::getInstance().addAttribModName(skill.c_str()); - mod.skill = Crc::calculate(skill.c_str()); - mod.value = value; - mod.attack = 0; - mod.sustain = duration; - mod.decay = 0; - mod.flags = flags | AttribMod::AMF_skillMod; - - LOG("CustomerService", ("Attribs: Added skill mod to %s. Mod data: " - "%s(%u) %s(%u) %d %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - name.c_str(), mod.tag, skill.c_str(), mod.skill, - mod.value, mod.sustain, mod.flags)); - addAttributeModifier(mod); -} // CreatureObject::addSkillmodModifier - -//----------------------------------------------------------------------- - -/** - * Applies an attribute modifier to this creature. - * - * @param mod the mod to add - * @param attacker who is causing the mod to be applied - * - * @return the amount the attrib was modified by, if the mod did direct damage - */ -int CreatureObject::addAttributeModifier(const AttribMod::AttribMod & mod, - ServerObject * attacker) -{ -static char internalTagBuf[] = {'_','_','i','n','t','e','r','n','a','l','T','a','g','N','a','m','e','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','\0'}; -static const int internalTagBufLen = strlen(internalTagBuf); - - int damage = 0; - - if (isAuthoritative()) - { - ++m_deferComputeTotalAttributes; - - if (AttribMod::isDirectDamage(mod)) - { - // check if we're making a potentially dangerous mod - if (!Attributes::isAttribPool(mod.attrib)) - { - WARNING(true, ("Creature %s is having non-pool attribute %d instantly " - "modified! This change will be permanent!", - getNetworkId().getValueString().c_str(), mod.attrib)); - } - - // apply instantanious damage directly -#ifdef _DEBUG - if (ConfigCombatEngine::getDebugDamage()) - { - char debugBuffer[1024]; - snprintf(debugBuffer, 1024, "creature %s attribute %d(%d) modified by %d to %d\n", - getNetworkId().getValueString().c_str(), - mod.attrib, - m_attributes[mod.attrib], - mod.value, - m_attributes[mod.attrib] + mod.value); - DEBUG_REPORT_LOG (true, ("%s", debugBuffer)); - if (attacker != NULL) - { - Client *client = attacker->getClient(); - if (client != NULL) - ConsoleMgr::broadcastString(debugBuffer, client); - } - } -#endif - - damage = alterAttribute(mod.attrib, mod.value, false, - attacker ? attacker->getNetworkId() : NetworkId::cms_invalid); - } - else if (AttribMod::isAttribMod(mod) && mod.decay == AttribMod::AMDS_antidote) - { - removeAttributeModifiers(mod.attrib); - } - else - { - if (mod.attack >= 0 && (mod.sustain >= 0 || mod.sustain == -1.0f)) - { - // apply other damage to the attribMod list - CreatureMod newMod; - newMod.startTime = ServerClock::getInstance().getGameTimeSeconds(); - newMod.maxVal = 0; - newMod.currentVal = 0; - newMod.mod = mod; - if (newMod.mod.tag == 0) - { - // we need to have some sort of tag, so we use an internal - // name hash - std::pair::const_iterator, bool> insertResult; - do - { - newMod.mod.tag = Crc::calculate(&internalTagBuf[0]); - char * c = &internalTagBuf[internalTagBufLen-1]; - while (++(*c) == '9' + 1) - { - *c-- = '0'; - } - insertResult = m_attributeModList.insert(newMod.mod.tag, newMod); - } while (!insertResult.second); - - // clear any flags that assume we have a valid tag. - if (newMod.mod.flags & AttribMod::AMF_triggerOnDone) - { - newMod.mod.flags &= ~AttribMod::AMF_triggerOnDone; - - DEBUG_WARNING(true, ("Creature %s has a mod flagged as " - "trigger when done, but has no mod name.", - getNetworkId().getValueString().c_str())); - } - if (newMod.mod.flags & AttribMod::AMF_visible) - { - newMod.mod.flags &= ~AttribMod::AMF_visible; - - DEBUG_WARNING(true, ("Creature %s received a mod flagged as " - "visible, but has no mod name.", - getNetworkId().getValueString().c_str())); - } - } - else - { - m_attributeModList.insert(mod.tag, newMod); - } - - if ((mod.flags & AttribMod::AMF_visible) && isPlayerControlled()) - { - // send the mod name and the mod time length to the player - // NOTE: we just send the tag value to the client, we expect - // the client to get the mod name from a datatable - float time = mod.attack; - if (mod.decay > 0) - time += mod.decay; - if (mod.sustain > 0) - time += mod.sustain; - else if (mod.sustain == -1.0f) - time = -1.0f; - sendTimedModData(mod.tag, time); - } - } - else - { - const char * modName = AttribModNameManager::getInstance().getAttribModName(mod.tag); - if (modName == NULL) - modName = ""; - WARNING(true, ("Creature %s received a mod %s with invalid " - "attack(%.2f) or duration(%.2f)", - getNetworkId().getValueString().c_str(), modName, mod.attack, - mod.sustain)); - } - } - - --m_deferComputeTotalAttributes; - } - else - { - sendControllerMessageToAuthServer(CM_addAttributeModifier, - new MessageQueueGenericValueType(mod)); - } - return damage; -} // CreatureObject::addAttributeModifier - -//----------------------------------------------------------------------- - -/** - * Checks if the creature has a given attrib/skill mod on them. - * - * @param modName the name of the mod to look for - * - * @return tue if the creature has the mod, false if not - */ -bool CreatureObject::hasAttribModifier(const std::string & modName) const -{ - // since the mod name may be a group name, we need to get any names - // that may be derived from the modName - std::vector nameCrcs; - AttribModNameManager::getInstance().getAttribModCrcsFromBase(modName, nameCrcs); - - // if we have any name that matches a value in nameCrcs, we can return true - for (std::vector::const_iterator i = nameCrcs.begin(); - i != nameCrcs.end(); ++i) - { - if (m_attributeModList.find(*i) != m_attributeModList.end()) - return true; - } - return false; -} // CreatureObject::hasAttribModifier - -//----------------------------------------------------------------------- - -/** - * Removes an attribute/skill modifier from this creature. - * - * @param modName the name of the mod to look for - */ -void CreatureObject::removeAttributeModifier (const std::string & modName) -{ - // since the mod name may be a group name, we need to get any names - // that may be derived from the modName - std::vector nameCrcs; - AttribModNameManager::getInstance().getAttribModCrcsFromBase(modName, nameCrcs); - - // if we have any name that matches a value in nameCrcs, we can return true - std::map::const_iterator f; - for (std::vector::const_iterator i = nameCrcs.begin(); - i != nameCrcs.end(); ++i) - { - f = m_attributeModList.find(*i); - if (f != m_attributeModList.end()) - { - const CreatureMod & m = (*f).second; - - // if the mod is visible, we need to tell the player it's being - // removed - if (m.mod.flags & AttribMod::AMF_visible) - { - sendCancelTimedMod(m.mod.tag); - } - const char * type = "attrib"; - if (AttribMod::isSkillMod(m.mod)) - { - const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); - if (skillModName != NULL) - addModValue(skillModName, -m.maxVal, true); - else - { - WARNING(true, ("Unable to remove skillmod mod on player %s due to " - "unknown skill mod crc. Mod data: %u %u %d %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); - } - type = "skill"; - } - m_attributeModList.erase(f); -// LOG("CustomerService", ("Attribs: Removed named %s mod %s from %s", -// type, modName.c_str(), PlayerObject::getAccountDescription(this).c_str())); - } - } -} // CreatureObject::removeAttributeModifier - -//----------------------------------------------------------------------- - -/** - * Removes all attribute modifiers for a given attribute from this creature. - * - * @param attribute the attribute to clear - */ -void CreatureObject::removeAttributeModifiers(Attributes::Enumerator attribute) -{ - if(isAuthoritative()) - { - DEBUG_FATAL(attribute < 0 || attribute >= Attributes::NumberOfAttributes, - ("attribute out of range\n")); - - LOG("CustomerService", ("Attribs: Removed all attrib mods affecting " - "attrib %d from %s", attribute, - PlayerObject::getAccountDescription(this).c_str())); - - m_cachedCurrentAttributeModValues.set(attribute, 0); - m_cachedMaxAttributeModValues.set(attribute, 0); - - typedef Archive::AutoDeltaMap::const_iterator ModIter; - for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) - { - if (!AttribMod::isSkillMod((*i).second.mod) && - (*i).second.mod.attrib == attribute) - { - // if the mod is visible, we need to tell the player it's being - // removed - if ((*i).second.mod.flags & AttribMod::AMF_visible) - { - sendCancelTimedMod((*i).second.mod.tag); - } - - i = m_attributeModList.erase(i); - } - else - ++i; - } - - computeTotalAttributes(); - } - else - { - sendControllerMessageToAuthServer(CM_removeAttributeModifiers, new MessageQueueGenericValueType(attribute)); - } -} // CreatureObject::removeAttributeModifiers - -//----------------------------------------------------------------------- - -/** - * Removes all the attribute modifiers from this creature. - */ -void CreatureObject::removeAllAttributeModifiers () -{ -int i; - - if (isAuthoritative()) - { - for (i = 0; i < Attributes::NumberOfAttributes; ++i) - { - m_cachedCurrentAttributeModValues.set(i, 0); - m_cachedMaxAttributeModValues.set(i, 0); - } - - typedef Archive::AutoDeltaMap::const_iterator ModIter; - for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) - { - if (!AttribMod::isSkillMod((*i).second.mod)) - { - // if the mod is visible, we need to tell the player it's being - // removed - if ((*i).second.mod.flags & AttribMod::AMF_visible) - { - sendCancelTimedMod((*i).second.mod.tag); - } - - i = m_attributeModList.erase(i); - } - else - ++i; - } - - computeTotalAttributes(); - - LOG("CustomerService", ("Attribs: removed all attrib mods from %s.", - PlayerObject::getAccountDescription(this).c_str())); - } - else - { - sendControllerMessageToAuthServer(CM_removeAllAttributeModifiers, 0); - } -} // CreatureObject::removeAllAttributeModifiers - -//----------------------------------------------------------------------- - -/** -* Removes all the attribute and skill mod modifiers from this creature. -* Does NOT remove buffs, only the effects so be sure to manually remove -* any buffs for which you need the icons to go away. -*/ -void CreatureObject::removeAllAttributeAndSkillmodMods () -{ - if (isAuthoritative()) - { - // remove all attrib and skill mod mods - typedef Archive::AutoDeltaMap::const_iterator ModIter; - for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) - { - const CreatureMod & m = (*i).second; - if (AttribMod::isSkillMod(m.mod)) - { - const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); - if (skillModName != NULL) - addModValue(skillModName, -m.maxVal, true); - } - // if the mod is visible, we need to tell the player it's being - // removed - if (m.mod.flags & AttribMod::AMF_visible) - { - sendCancelTimedMod(m.mod.tag); - } - // if the mod is flagged as having a callback, call the script - if (m.mod.flags & AttribMod::AMF_triggerOnDone) - { - const char * modName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); - if (modName != NULL) - { - ScriptParams params; - params.addParam(modName); - params.addParam(true); - if (AttribMod::isAttribMod(m.mod)) - { - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_ATTRIB_MOD_DONE, params)); - } - else if (AttribMod::isSkillMod(m.mod)) - { - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_SKILL_MOD_DONE, params)); - } - - } - } - - i = m_attributeModList.erase(i); - } - for (int j = 0; j < Attributes::NumberOfAttributes; ++j) - { - m_cachedCurrentAttributeModValues.set(j, 0); - m_cachedMaxAttributeModValues.set(j, 0); - } - computeTotalAttributes(); - } - else - { - sendControllerMessageToAuthServer(CM_removeAllAttributeAndSkillmodModifiers, 0); - } - -} - -//----------------------------------------------------------------------- - -/** - * Returns a attrib/skillmod mod with a given name attached to the creature. - * - * @param modName the mod to look for - * - * @return the mod, or NULL if there is no mod with that name attached to us - */ -const AttribMod::AttribMod * CreatureObject::getAttributeModifier( - const std::string & modName) const -{ - // since the mod name may be a group name, we need to get any names - // that may be derived from the modName - std::vector nameCrcs; - AttribModNameManager::getInstance().getAttribModCrcsFromBase(modName, nameCrcs); - - // if we have any name that matches a value in nameCrcs, we can return it - for (std::vector::const_iterator i = nameCrcs.begin(); - i != nameCrcs.end(); ++i) - { - std::map::const_iterator found = m_attributeModList.find(*i); - if (found != m_attributeModList.end()) - return &((*found).second.mod); - } - return NULL; -} // CreatureObject::getAttributeModifier - -//----------------------------------------------------------------------- - -/** - * Returns the attribute modifiers on this creature. - */ -const std::map & CreatureObject::getAttributeModifiers() const -{ - return m_attributeModList.getMap(); -} // CreatureObject::getAttributeModifiers - -//----------------------------------------------------------------------- - -/** - * Sends info about a mod that's affecting a player to the client. - * - * @param id the mod id - * @param time how long the mod lasts (in sec) - * @param updateCache whether or not to update the cached list of timed mods that have been sent to the client - */ -void CreatureObject::sendTimedModData(uint32 id, float time, bool updateCache/* = true*/) -{ - if (isPlayerControlled() && getController() != NULL && id != 0) - { - MessageQueueGenericValueType > * const msg = - new MessageQueueGenericValueType >( - std::make_pair(id, time)); - getController()->appendMessage( - static_cast(CM_modData), - 0, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - - if (isPlayerControlled() && isAuthoritative() && updateCache && id != 0) - { - const int index = m_timedMod.find(id); - - if (index >= 0) - { - m_timedModDuration.set(index, time); - m_timedModUpdateTime.set(index, ServerClock::getInstance().getGameTimeSeconds()); - } - else - { - m_timedMod.push_back(id); - m_timedModDuration.push_back(time); - m_timedModUpdateTime.push_back(ServerClock::getInstance().getGameTimeSeconds()); - } - } -} // CreatureObject::sendTimedModData - -//----------------------------------------------------------------------- - -/** - * Tells a client to cancel a timed mod. - * - * @param id the mod id - */ -void CreatureObject::sendCancelTimedMod(uint32 id) -{ - if (isPlayerControlled() && getController() != NULL && id != 0) - { - MessageQueueGenericValueType * const msg = - new MessageQueueGenericValueType(id); - getController()->appendMessage( - static_cast(CM_cancelMod), - 0, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - - if (isPlayerControlled() && isAuthoritative() && id != 0) - { - const int index = m_timedMod.find(id); - - if (index >= 0) - { - m_timedMod.erase(index); - m_timedModDuration.erase(index); - m_timedModUpdateTime.erase(index); - } - } -} // CreatureObject::sendCancelTimedMod - -//----------------------------------------------------------------------- - -/** - * Applies damage done during combat to the creature. - * - * @param damageData the damage - */ -void CreatureObject::applyDamage(const CombatEngineData::DamageData &damageData) -{ - WARNING_STRICT_FATAL(!isAuthoritative(), ("CreatureObject::applyDamageTo " - "invoked on non-authoritative object %s:%s", getObjectTemplateName(), - getNetworkId().getValueString().c_str())); - - if (!isAuthoritative()) - return; - - //-- vehicles get damaged like tangibles - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - TangibleObject::applyDamage (damageData); - return; - } - - int healthDamage = 0; // damage info we will send to the client - int actionDamage = 0; // damage info we will send to the client - int mindDamage = 0; // damage info we will send to the client - - ServerObject *attacker = safe_cast(damageData.attackerId.getObject()); - - // if the attacker is a player and we are not, and we are incapped/dead, - // don't allow additional damage - if (attacker != NULL && attacker->isPlayerControlled() && !isPlayerControlled() && - (isIncapacitated() || isDead())) - { - return; - } - - ++m_deferComputeTotalAttributes; - - std::vector::const_iterator iter; - for (iter = damageData.damage.begin(); iter != damageData.damage.end(); ++iter) - { - const AttribMod::AttribMod &mod = *iter; - if (mod.value == 0) - continue; - - int damage = -addAttributeModifier(mod, attacker); - if (damage != 0) - { - if (mod.attrib == Attributes::Health) - healthDamage += damage; - else if (mod.attrib == Attributes::Action) - actionDamage += damage; - else if (mod.attrib == Attributes::Mind) - mindDamage += damage; - } - } - - --m_deferComputeTotalAttributes; - - computeTotalAttributes(); - - // tell scripts we have taken combat damage - if (damageData.attackerId != NetworkId::cms_invalid && - (healthDamage > 0 || actionDamage > 0 || mindDamage > 0)) - { - NOT_NULL(getScriptObject()); - int damageArray[] = {healthDamage, 0, actionDamage, 0, mindDamage, 0}; - std::vector damageParam(&damageArray[0], &damageArray[Attributes::NumberOfAttributes]); - - ScriptParams params; - params.addParam(damageData.attackerId); - params.addParam(damageData.weaponId); - params.addParam(damageParam); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_CREATURE_DAMAGED, - params)); - } - testIncapacitation(damageData.attackerId); -} // CreatureObject::applyDamage - -//----------------------------------------------------------------------- - -/** - * Changes attrib mod(s) on the creature due to combat damage or healing. Note - * that only positive attrib mods can be changed - * - * @param attrib the index of the attribute getting damaged - * @param delta the amount to change the mod by - * @param checkPoolOverflow flag to check if a pool value is over its max value - * - * @return the amount the attrib mod(s) changed - */ -int CreatureObject::changeAttribModCurrentValue(Attributes::Enumerator attrib, int delta, bool checkPoolOverflow) -{ - if (!isAuthoritative()) - { - DEBUG_WARNING(true, ("CreatureObject::damageAttribMods called for " - "non-authoritative creature %s, attrib %d", - getNetworkId().getValueString().c_str(), attrib)); - return 0; - } - - if (attrib < 0 || attrib >= Attributes::NumberOfAttributes) - { - DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attrib)); - return 0; - } - - int startDelta = delta; - typedef Archive::AutoDeltaMap::const_iterator ModIter; - for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end() && - delta != 0; ++i) - { - CreatureMod m = (*i).second; - if (AttribMod::isAttribMod(m.mod) && m.mod.attrib == attrib && m.mod.value > 0) - { - if (delta > 0) - { - // healing mods - if (m.maxVal > m.currentVal) - { - if (m.maxVal - m.currentVal >= delta) - { - // this mod can take the entire change - m.currentVal += delta; - delta = 0; - } - else - { - // this mod can only take part of the change - delta -= (m.maxVal - m.currentVal); - m.currentVal = m.maxVal; - } - m_attributeModList.set((*i).first, m); - } - } - else - { - // damaging mods - if (m.currentVal > 0) - { - if (m.currentVal + delta > 0) - { - // this mod can take the entire change - m.currentVal += delta; - delta = 0; - } - else - { - // this mod can only take part of the change - delta += m.currentVal; - m.currentVal = 0; - } - m_attributeModList.set((*i).first, m); - } - } - } - } - - if (startDelta != delta) - recomputeAttribModTotals(checkPoolOverflow); - - return startDelta - delta; -} // CreatureObject::changeAttribModCurrentValue - -//----------------------------------------------------------------------- - -/** - * Recomputes the values due to attrib mods to be added to the creature's current - * and max attribs. - * - * @param checkPoolOverflow flag to check if a pool value is over its max value - */ -void CreatureObject::recomputeAttribModTotals(bool checkPoolOverflow) -{ -int i; - - if (!isAuthoritative()) - return; - - int newCachedMaxAttributeModValues[Attributes::NumberOfAttributes]; - int newCachedCurrentAttributeModValues[Attributes::NumberOfAttributes]; - for (i = 0; i < Attributes::NumberOfAttributes; ++i) - { - newCachedMaxAttributeModValues[i] = 0; - newCachedCurrentAttributeModValues[i] = 0; - } - - typedef Archive::AutoDeltaMap::const_iterator ModIter; - for (ModIter j = m_attributeModList.begin(); j != m_attributeModList.end(); ++j) - { - const CreatureMod & m = (*j).second; - if (AttribMod::isAttribMod(m.mod)) - { - if ((m.mod.flags & AttribMod::AMF_changeMax)) - newCachedMaxAttributeModValues[m.mod.attrib] += m.maxVal; - newCachedCurrentAttributeModValues[m.mod.attrib] += m.currentVal; - } - } - - for (i = 0; i < Attributes::NumberOfAttributes; ++i) - { - m_cachedMaxAttributeModValues.set(i, static_cast(newCachedMaxAttributeModValues[i])); - m_cachedCurrentAttributeModValues.set(i, static_cast(newCachedCurrentAttributeModValues[i])); - - if (newCachedCurrentAttributeModValues[i] < 0) - { - // don't let the mod prevent us from healing out of incapacitation - int healedAttrib = getAdjustedAttribute(i, getUnmodifiedMaxAttribute(i)); - if (healedAttrib < 0) - { - m_cachedMaxAttributeModValues.set(i, static_cast( - m_cachedMaxAttributeModValues[i] - healedAttrib + 1)); - m_cachedCurrentAttributeModValues.set(i, static_cast( - m_cachedCurrentAttributeModValues[i] - healedAttrib + 1)); - } - } - - if (Attributes::isAttribPool(i) && checkPoolOverflow) - { - // since we can modify the max value and not the current value, damage - // the attribute if it is over the max - int max = getMaxAttribute(i); - int current = getUnmodifiedAttribute(i) + m_cachedCurrentAttributeModValues[i]; - if (current > max) - { - IGNORE_RETURN(alterAttribute(i, max - current, true)); - } - } - } -} // CreatureObject::recomputeAttribModTotals - -//----------------------------------------------------------------------- - -/** - * Advances the timing of attribute buffs and debuffs. Should be called by the controller from the - * authoritative object. - * - * @param time The amount of time to advance the buff. - */ -void CreatureObject::decayAttributes(float time) -{ - if (!isAuthoritative()) - return; - - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::decayAttributes"); - - // prevent client-seen attributes from being updated until all the attributes - // have been modified - ++m_deferComputeTotalAttributes; - - const uint32 currentTime = ServerClock::getInstance().getGameTimeSeconds(); - typedef Archive::AutoDeltaMap::const_iterator ModIter; - { // contain i because VC isn't compilant - for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) - { - CreatureMod m = (*i).second; - if (AttribMod::isDirectDamage(m.mod)) - { - DEBUG_WARNING(true, ("CreatureObject::decayAttributes has direct " - "damage mod in its list")); - continue; - } - - const float deltaTime = static_cast(currentTime - m.startTime); - float decayBegin = m.mod.attack; - if (m.mod.sustain > 0) - decayBegin += m.mod.sustain; - float totalTime = decayBegin; - if (m.mod.decay > 0) - totalTime += m.mod.decay; - if (m.mod.sustain == -1.0f) - { - // mod never expires - decayBegin = -1.0f; - totalTime = -1.0f; - } - int modValue = 0; - - if (deltaTime >= totalTime && totalTime != -1.0f) - { - // end of the mod time, erase the mod - if (AttribMod::isSkillMod(m.mod)) - { - const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); - if (skillModName != NULL) - { - addModValue(skillModName, -m.maxVal, true); - - LOG("CustomerService", ("Attribs: Expired skill mod on %s. Mod data: " - "%u %u %d %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); - } - else - { - WARNING(true, ("Unable to expire skillmod mod on player %s due to " - "unknown skill mod crc. Mod data: %u %u %d %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); - } - } - else - { - LOG("CustomerService", ("Attribs: Expired attrib mod on %s. Mod data: " - "%u %d %d %.2f %.2f %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - m.mod.tag, m.mod.attrib, m.mod.value, m.mod.attack, m.mod.sustain, - m.mod.decay, m.mod.flags)); - } - - // remove the mod from ourself - i = m_attributeModList.erase(i); - - if (m.mod.flags & AttribMod::AMF_triggerOnDone) - { - // tell scripts the mod has ended - const char * modName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); - if (modName != NULL) - { - ScriptParams params; - params.addParam(modName); - params.addParam(false); - if (AttribMod::isAttribMod(m.mod)) - { - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_ATTRIB_MOD_DONE, params)); - } - else if (AttribMod::isSkillMod(m.mod)) - { - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_SKILL_MOD_DONE, params)); - } - } - else - { - WARNING(true, ("Unable to trigger mod done on player %s due to " - "unknown mod name crc. Mod data: %u %u %d %.2f %.2f %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - m.mod.tag, m.mod.attrib, m.mod.value, m.mod.attack, - m.mod.sustain, m.mod.decay, m.mod.flags)); - } - } - if (m.mod.flags & AttribMod::AMF_visible) - { - // tell the client to erase the mod icon - sendCancelTimedMod(m.mod.tag); - } - } - else - { - if (deltaTime < m.mod.attack) // in attack phase - { - float t = deltaTime / m.mod.attack; - modValue = static_cast(m.mod.value * t + 0.5f); - } - else if (deltaTime < decayBegin || decayBegin == -1.0f) // in sustain phase - { - modValue = m.mod.value; - } - else if (deltaTime < totalTime) // in decay phase - { - float t = (deltaTime - decayBegin) / m.mod.decay; - modValue = static_cast(m.mod.value * (1.0f-t) + 0.5f); - } - - if (m.maxVal != modValue) - { - int delta = modValue - m.maxVal; - // Even if the mod is flagged as not updating max, we still need - // to change it here so we can calculate the next frame's delta. - // We'll check for updating max in recomputeAttribModTotals instead. - m.maxVal = modValue; - - if (AttribMod::isSkillMod(m.mod)) - { - // add the skillmod mod as if it were from a skill, - // which makes it temporary - const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); - if (skillModName != NULL) - addModValue(skillModName, delta, true); - else - { - WARNING(true, ("Unable to add skillmod mod on player %s due to " - "unknown skill mod crc. Mod data: %u %u %d %.2f %d", - PlayerObject::getAccountDescription(this).c_str(), - m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); - } - } - else - { - // see if we need to update the mod current value in addition - // to the max value - // non-pool attribs must update the current value - bool updateCurrent = !Attributes::isAttribPool(m.mod.attrib); - if (!updateCurrent) - { - // check the mod flags - if (deltaTime < decayBegin) - { - if ((m.mod.flags & AttribMod::AMF_attackCurrent)) - updateCurrent = true; - } - else - { - if ((m.mod.flags & AttribMod::AMF_decayCurrent)) - updateCurrent = true; - } - } - if (updateCurrent) - { - if ((m.mod.flags & AttribMod::AMF_changeMax) || - !Attributes::isAttribPool(m.mod.attrib)) - { - m.currentVal += delta; - } - else - { - // we are doing damage/healing over time, modify the - // attribute directly - IGNORE_RETURN(alterAttribute(m.mod.attrib, delta, true, - NetworkId::cms_invalid, false)); - } - } - } - - // make sure the mod's current val doesn't get out of range - if (m.mod.value >= 0) - { - if (m.currentVal > m.maxVal) - m.currentVal = m.maxVal; - else if (m.currentVal < 0) - m.currentVal = 0; - } - else - { - if (m.currentVal < m.maxVal) - m.currentVal = m.maxVal; - else if (m.currentVal > 0) - m.currentVal = 0; - } - m_attributeModList.set((*i).first, m); - } - ++i; - } - } - } - - recomputeAttribModTotals(true); - - // regenerate attributes - int i; - bool attribRegen = false; - float regenerationRate[3] = {0,0,0}; - m_regenerationTime += time; - for (i = 0; i < 3; ++i) - { - int poolAttrib = Attributes::POOLS[i]; - int maxAttrib = getMaxAttribute(poolAttrib); - int currentAttrib = getAttribute(poolAttrib); - if (currentAttrib < maxAttrib) - { - attribRegen = true; - regenerationRate[i] = getRegenRate(poolAttrib); - m_regeneration[poolAttrib] += regenerationRate[i] * time; - } - } - - //-- - //-- update player incapacitation timer - //-- - - if (isPlayerControlled()) - { - // regenerate force powers - if (!isIncapacitated()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - playerObject->regenerateForcePower(time); - } - } - } - - // update the client - --m_deferComputeTotalAttributes; - computeTotalAttributes(); - if (isAuthoritative()) - testIncapacitation(NetworkId::cms_invalid); -} - -//----------------------------------------------------------------------- - -/** - * Advances the timing of mental state buffs and debuffs and decays mental states toward - * their default values. Should be called by the controller from the - * authoritative object. - * - * @param time The amount of time to advance the buff. - */ - -void CreatureObject::decayMentalStates(float time) -{ - if (isDead()) - return; - - // @todo AJS - make this take into account time since objects were unloaded when they are reloaded - int oldBehavior = m_currentAttitude.get().m_behavior; - CreatureAttitude newState = m_currentAttitude.get(); - updateBehavior(0, newState); - - CreatureAttitude newTargetState; - - int i; - // Initialize the decay values for each mental state - float decays[MentalStates::NumberOfMentalStates]; - for (i=0; i::const_iterator targetIterator, targetEnd = m_mentalStatesToward.end(); - for (targetIterator=m_mentalStatesToward.begin(); targetIterator != targetEnd; ++targetIterator) - { - newTargetState = targetIterator->second; - for (i=0; isecond.m_currentValues[i]; - if (newValue > 0) - { - newValue = std::max(newValue - decays[i], 0.0f); - } - else - { - newValue = std::min(newValue + decays[i], 0.0f); - } - newTargetState.m_currentValues[i] = newValue; - } - m_mentalStatesToward.set(targetIterator->first, newTargetState); - } - - // Now change the behaviors for all of the targetted objects - bool behaviorChanged[Behaviors::NumberOfBehaviors]; - - int behavior; - - // Clear the accumulated values for each behavior - for (behavior = 0; behavior < Behaviors::NumberOfBehaviors; ++behavior) - { - behaviorChanged[behavior] = false; - } - - clipMentalStatesToward(); - deleteUnusedMentalStatesToward(behaviorChanged); - - int newBehavior = newState.m_behavior; - if (!m_mentalStatesToward.empty()) - { - // Update the behavior toward each target, and also update the accumulated state values for each behavior - Archive::AutoDeltaMap::const_iterator i = m_mentalStatesToward.begin(), e=m_mentalStatesToward.end(); - for (; i != e; ++i) - { - oldBehavior = i->second.m_behavior; - newTargetState = i->second; - updateBehavior(&i->first, newTargetState); - if (newTargetState.m_behavior != oldBehavior) - { - if (oldBehavior >= 0) - { - m_targetsByBehavior[oldBehavior].erase(i->first); - behaviorChanged[oldBehavior] = true; - } - m_targetsByBehavior[newTargetState.m_behavior].insert(i->first); - behaviorChanged[newTargetState.m_behavior] = true; - } - m_mentalStatesToward.set(i->first, newTargetState); - if (newTargetState.m_behavior > newBehavior) - newBehavior = newTargetState.m_behavior; - } - } - - m_currentAttitude.set(newState); - - if (m_lastBehavior.get() != newBehavior) - { - const int lastBehavior = m_lastBehavior.get(); - m_lastBehavior = newBehavior; - behaviorChanged[newBehavior] = false; - - notifyTargetChange(lastBehavior, newBehavior, behaviorChanged); - } - else - { - notifyTargetChange(m_lastBehavior.get(), m_lastBehavior.get(), behaviorChanged); - } -} - -// -------------------------------------------------------------------------- - -/** - * Returns the weapon currently being carried by the creature, which may or may - * not be the weapon it is using. If the creature is not carrying a weapon, - * returns the default weapon. - * - * @return the weapon - */ -WeaponObject *CreatureObject::getReadiedWeapon() const -{ - static SlotId const rightHandSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("hold_r")); - - // first check the right hand. - SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*this); - if (slottedContainer) - { - if (slottedContainer->hasSlot(rightHandSlot)) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - Object * const o = slottedContainer->getObjectInSlot(rightHandSlot, tmp).getObject(); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so) - { - WeaponObject * const wo = so->asWeaponObject(); - if (wo) - return wo; - } - } - } - } - // nothing in the hand, return the default weapon - return getDefaultWeapon(); -} - -//---------------------------------------------------------------------- - -/** - * Returned the weapon the creature will use for combat. - * - * @return the weapon - */ -WeaponObject *CreatureObject::getCurrentWeapon() -{ - Object * const o = m_currentWeapon.get().getObject(); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so) - { - WeaponObject * const currentWeapon = so->asWeaponObject(); - if (currentWeapon) - return currentWeapon; - } - } - - WeaponObject * const readiedWeapon = getReadiedWeapon(); - if (readiedWeapon) - setCurrentWeapon(*readiedWeapon); - return readiedWeapon; -} - -//---------------------------------------------------------------------- - -/** - * Sets the weapon the creature will use for combat. - * - * @param weapon the weapon - */ -void CreatureObject::setCurrentWeapon(WeaponObject & weapon) -{ - if(isAuthoritative()) - { - m_currentWeapon = CachedNetworkId(weapon); - } - else - { - sendControllerMessageToAuthServer(CM_setCurrentWeapon, new MessageQueueGenericValueType(weapon.getNetworkId())); - }; -} - -// -------------------------------------------------------------------------- - -int CreatureObject::getInstrumentVisualId() const -{ - static SlotId rightHandSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("hold_r")); - bool hasWeapon = false; - - // first check the right hand. - SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*this); - if (slottedContainer) - { - if (slottedContainer->hasSlot(rightHandSlot)) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - Object const * const object = slottedContainer->getObjectInSlot(rightHandSlot, tmp).getObject(); - if (object) - { - int type = lookupInstrumentVisualId(object->getObjectTemplateName()); - if (type) - return type; - ServerObject const * const so = object->asServerObject(); - if (so && so->asWeaponObject()) - hasWeapon = true; - } - } - } - - // then check the intended target if no weapon is equipped - if(!hasWeapon) - { - int visualId = internalGetInstrumentVisualId(getIntendedTarget()); - if(visualId) - return visualId; - } - - // last, check the look at target if no weapon is equipped - if (!hasWeapon) - { - int visualId = internalGetInstrumentVisualId(getLookAtTarget()); - if(visualId) - return visualId; - } - - return 0; -} - -// -------------------------------------------------------------------------- - -int CreatureObject::getInstrumentAudioId() const -{ - static SlotId rightHandSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("hold_r")); - bool hasWeapon = false; - - // first check the right hand. - SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*this); - if (slottedContainer) - { - if (slottedContainer->hasSlot(rightHandSlot)) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - Object const * const object = slottedContainer->getObjectInSlot(rightHandSlot, tmp).getObject(); - if (object) - { - int type = lookupInstrumentAudioId(object->getObjectTemplateName()); - if (type) - return type; - ServerObject const * const so = object->asServerObject(); - if (so && so->asWeaponObject()) - hasWeapon = true; - } - } - } - - // then check the intended target if no weapon is equipped - if (!hasWeapon) - { - int audioId = internalGetInstrumentAudioId(getIntendedTarget()); - if(audioId) - return audioId; - } - - // last, check the look at target if no weapon is equipped - if (!hasWeapon) - { - int audioId = internalGetInstrumentAudioId(getLookAtTarget()); - if(audioId) - return audioId; - } - return 0; -} - -// -------------------------------------------------------------------------- - -int CreatureObject::internalGetInstrumentAudioId(NetworkId const &id) const -{ - if (id != NetworkId::cms_invalid) - { - Object const * const object = NetworkIdManager::getObjectById(id); - if ( object - && !instrumentTooFar(getPosition_w(), object->getPosition_w()) - && ContainerInterface::getContainedByObject(*this) == ContainerInterface::getContainedByObject(*object)) - { - ServerObject const * const serverObj = object->asServerObject(); - if (!serverObj->getSharedTemplate()->getArrangementDescriptor()) - { - int type = lookupInstrumentAudioId(object->getObjectTemplateName()); - if (type) - return type; - } - } - } - return 0; -} - -// -------------------------------------------------------------------------- - -int CreatureObject::internalGetInstrumentVisualId(NetworkId const &id) const -{ - if (id != NetworkId::cms_invalid) - { - Object const * const object = NetworkIdManager::getObjectById(id); - if ( object - && !instrumentTooFar(getPosition_w(), object->getPosition_w()) - && ContainerInterface::getContainedByObject(*this) == ContainerInterface::getContainedByObject(*object)) - { - ServerObject const * const serverObj = object->asServerObject(); - if (!serverObj->getSharedTemplate()->getArrangementDescriptor()) - { - int type = lookupInstrumentVisualId(object->getObjectTemplateName()); - if (type) - return type; - } - } - } - return 0; -} - -// -------------------------------------------------------------------------- - -GroupObject *CreatureObject::getGroup() const -{ - if (m_group.get() != NetworkId::cms_invalid) - { - Object *obj = m_group.get().getObject(); - if (obj) - { - ServerObject *serverObj = obj->asServerObject(); - return serverObj->asGroupObject(); - } - } - return 0; -} - -// -------------------------------------------------------------------------- - -void CreatureObject::setGroup(GroupObject *group, bool disbandingCurrentGroup) -{ - if (isAuthoritative()) - { - NetworkId const oldGroupId = m_group.get(); - - m_group = group ? CachedNetworkId(*group) : CachedNetworkId::cms_cachedInvalid; - recomputeSlopeModPercent(); - - // Our group has finally been established, so don't worry about - // keeping track of who invited us to the group - setInviterForPendingGroup( NetworkId::cms_invalid ); - setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject && (playerObject->getSessionStartPlayTime() != 0)) - { - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); - if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.groupId != m_group.get())) - ServerUniverse::setConnectedCharacterGroupData(getNetworkId(), m_group.get()); - } - - // if joining a group, and the group currently - // has an active group pickup point, handle it - if (group && (oldGroupId != group->getNetworkId())) - { - unsigned int const secondsLeftOnGroupPickup = group->getSecondsLeftOnGroupPickup(); - if (secondsLeftOnGroupPickup) - { - std::pair const & groupPickupLocation = group->getGroupPickupLocation(); - if (!groupPickupLocation.first.empty()) - { - // tell group member that there's an active group pickup point - if (getClient()) - { - StringId::LocUnicodeString response; - if (StringId("group", "create_group_pickup_success_new_group_member").localize(response)) - { - ConsoleMgr::broadcastString(FormattedString<2048>().sprintf(Unicode::wideToNarrow(response).c_str(), CalendarTime::convertSecondsToMS(secondsLeftOnGroupPickup).c_str()), - getClient()); - } - } - - // create/update the group member's group pickup point waypoint - if (playerObject) - { - Location const location(groupPickupLocation.second, NetworkId::cms_invalid, Location::getCrcBySceneName(groupPickupLocation.first)); - playerObject->createOrUpdateReusableWaypoint(location, "groupPickupWp", Unicode::narrowToWide("Group Pickup Point"), Waypoint::White); - } - } - } - } - } - else - { - NetworkId groupId; - if(group) - groupId = group->getNetworkId(); - - sendControllerMessageToAuthServer(CM_setGroup, new MessageQueueGenericValueType >(std::make_pair(disbandingCurrentGroup, groupId))); - } -} - -// -------------------------------------------------------------------------- - -NetworkId const & CreatureObject::getGroupInviterId() const -{ - return m_groupInviter.get().first.first; -} - -// -------------------------------------------------------------------------- - -std::string const & CreatureObject::getGroupInviterName() const -{ - return m_groupInviter.get().first.second; -} - -// -------------------------------------------------------------------------- - -CreatureObject *CreatureObject::getGroupInviter() const -{ - NetworkId const & inviterId = m_groupInviter.get().first.first; - if (inviterId != NetworkId::cms_invalid) - { - Object * const o = NetworkIdManager::getObjectById(inviterId); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so) - return so->asCreatureObject(); - } - } - return 0; -} - -// -------------------------------------------------------------------------- - -void CreatureObject::setGroupInviter(NetworkId const &inviterId, std::string const& inviterName, NetworkId const &inviterShipId) -{ - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - MessageQueueGenericValueType > > *msg = new MessageQueueGenericValueType > >(std::make_pair(inviterName, std::make_pair(inviterId, inviterShipId))); - controller->appendMessage( - CM_setGroupInviter, - 0.0f, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - } - else - { - m_groupInviter = PlayerAndShipPair(std::make_pair(inviterId, inviterName), inviterShipId); - } -} - -// -------------------------------------------------------------------------- - -NetworkId const &CreatureObject::getInviterForPendingGroup() const -{ - // We agreed to join a group and this is the guy that invited us - return m_inviterForPendingGroup.get(); -} - -// -------------------------------------------------------------------------- - -void CreatureObject::setInviterForPendingGroup(NetworkId const &inviterId) -{ - // Once we agree to join a group, we keep track of who extended - // the invitation until we get an actual group object - m_inviterForPendingGroup = inviterId; -} - -// -------------------------------------------------------------------------- - -void CreatureObject::notifyTargetChange(int lastBehavior, int newBehavior, bool * i_targetsChanged) -{ - bool sendMessage = false; - Scripting::TrigId notification = Scripting::TRIG_TARGET_CHANGE; - ScriptParams params; - params.addParam(newBehavior); - if (lastBehavior != newBehavior) - { - notification = Scripting::TRIG_BEHAVIOR_CHANGE; - params.addParam(lastBehavior); - sendMessage = true; - } - std::vector targetListChanged; - targetListChanged.reserve(Behaviors::NumberOfBehaviors); - targetListChanged.resize(Behaviors::NumberOfBehaviors); - int i; - for (i=0; itrigAllScripts(notification, params)); - } -} - -// ---------------------------------------------------------------------- - -CreatureAttitude const *CreatureObject::getAttitudeToward(NetworkId const &target) const -{ - Archive::AutoDeltaMap::const_iterator i = m_mentalStatesToward.find(target); - if (i == m_mentalStatesToward.end()) - return 0; - return &i->second; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::clipMentalStatesToward() -{ - float maxDeltas[MentalStates::NumberOfMentalStates]; - float minValues[MentalStates::NumberOfMentalStates]; - MentalStates::Enumerator state; - for (state=0; state::const_iterator i = m_mentalStatesToward.begin(); - Archive::AutoDeltaMap::const_iterator e = m_mentalStatesToward.end(); - for (; i != e; ++i) - { - CreatureAttitude newState = i->second; - for (state=0; statesecond.m_currentValues[state]; - if (delta > maxDeltas[state]) - { - newState.m_currentValues[state] = maxDeltas[state]; - } - else if (delta < minValues[state]) - { - newState.m_currentValues[state] = 0; - } - } - m_mentalStatesToward.set(i->first, newState); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::deleteUnusedMentalStatesToward(bool * i_behaviorChanged) -{ - Archive::AutoDeltaMap::const_iterator i = m_mentalStatesToward.begin(); - Archive::AutoDeltaMap::const_iterator e = m_mentalStatesToward.end(); - std::vector to_erase; - for (; i != e; ++i) - { - ServerObject * object = ServerWorld::findObjectByNetworkId(i->first); - bool erase = true; - int state; - if (object) - { - for (state=0; statesecond.m_currentValues[state] > 0) - erase = false; - } - } - if (erase) - { - int currentObjectBehavior = i->second.m_behavior; - if (currentObjectBehavior != -1) // if -1, we are deleting an object that was added and removed in the same alter - { - if (currentObjectBehavior < Behaviors::Calm || currentObjectBehavior >= Behaviors::NumberOfBehaviors) - { - DEBUG_REPORT_LOG(true, ("deleteUnusedMentalStatesToward: currentBehavior %d is invalid", currentObjectBehavior)); - } - else - { - std::set::iterator currentTargetByBehaviorIter = m_targetsByBehavior[currentObjectBehavior].find(i->first); - if (currentTargetByBehaviorIter != m_targetsByBehavior[currentObjectBehavior].end()) - { - i_behaviorChanged[currentObjectBehavior] = true; - m_targetsByBehavior[currentObjectBehavior].erase(currentTargetByBehaviorIter); - } - } - } - to_erase.push_back(i->first); - } - } - std::vector::iterator tei; - for (tei = to_erase.begin(); tei!=to_erase.end(); ++tei) - { - m_mentalStatesToward.erase(*tei); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setMentalStateToward(const NetworkId &target, MentalStates::Enumerator state, MentalStates::Value value) -{ - if(! isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setMentalStateToward, new MessageQueueGenericValueType > >(std::make_pair(target, std::make_pair(state, value)))); - } - else - { - if (state < 0 || state >= MentalStates::NumberOfMentalStates) - { - DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); - return; - } - - ServerObject * object = ServerWorld::findObjectByNetworkId(target); - if (!object) - return; - - CreatureAttitude const * const cs = getAttitudeToward(target); - CreatureAttitude newState; - - if (!cs && value <= 0) - return; - - if (cs) - { - newState = *cs; - } - newState.m_currentValues[state] = value; - m_mentalStatesToward.set(target, newState); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setMentalStateTowardClampBehavior(const NetworkId &target, MentalStates::Enumerator state, MentalStates::Value value, Behaviors::Enumerator behavior) -{ - if(! isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setMentalStateTowardClampBehavior, new MessageQueueGenericValueType > > >(std::make_pair(target, std::make_pair(state, std::make_pair(value, behavior))))); - } - else - { - if (state < 0 || state >= MentalStates::NumberOfMentalStates) - { - DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); - return; - } - - if (behavior < Behaviors::Calm || behavior >= Behaviors::NumberOfBehaviors) - { - DEBUG_REPORT_LOG(true, ("setMentalStateTowardClampBehavior: behavior %d is invalid", behavior)); - return; - } - - ServerObject * object = ServerWorld::findObjectByNetworkId(target); - if (!object) - return; - - CreatureAttitude const * const cs = getAttitudeToward(target); - if (!cs && value <= 0) - return; - - CreatureAttitude newState; - if (cs) - { - newState = *cs; - } - float oldValue = newState.m_currentValues[state]; - - float maxValue = 0; - if (behavior >= Behaviors::Alert && behavior <= Behaviors::Retreat) // [1..3] 4 = flee - { - if (state != MentalStates::Fear) - { - DEBUG_REPORT_LOG(true, ("Bad mental state %d for behavior %d in setMentalStateTowardClampBehavior", state, behavior)); - return; - } - maxValue = m_fearCutoffs[behavior - Behaviors::Alert + 2]; // [2..4] out of [0..4] - } - else if (behavior == Behaviors::Attack) // [5] 6 = frenzy - { - if (state != MentalStates::Anger) - { - DEBUG_REPORT_LOG(true, ("Bad mental state %d for behavior %d in setMentalStateTowardClampBehavior", state, behavior)); - return; - } - maxValue = m_angerCutoffs[behavior - Behaviors::Attack + 2]; // [2..2] out of [0..2] - } - else if (behavior == Behaviors::Calm) - { - if (state == MentalStates::Fear) - { - maxValue = m_fearCutoffs[behavior+1]; - } - else - { - maxValue = 0.0f; - } - } - else - { - maxValue = 1e30f; // allow any value - } - maxValue = std::max(0.0f, maxValue - 1.0f); - if (oldValue < maxValue) - { - if (value > maxValue) - value = maxValue; - - newState.m_currentValues[state] = value; - m_mentalStatesToward.set(target, newState); - } - } -} - -//----------------------------------------------------------------------- - -/** -* Gets the creatures current state. 0 = calm, 1-4 = afraid, 5-7 = angry. -*/ - -bool CreatureObject::updateBehavior(const NetworkId * id, CreatureAttitude &state) const -{ - int attitude = state.m_behavior; - float anger = id ? getMentalStateToward(*id, MentalStates::Anger) : getMentalState(MentalStates::Anger); - float fear = id ? getMentalStateToward(*id, MentalStates::Fear) : getMentalState(MentalStates::Fear); - - while ((state.m_fearState > 0) && fear <= m_fearCutoffs[state.m_fearState-1]) // much less fearful than current state - { - state.m_fearState = static_cast(state.m_fearState - 1); - } - while ((state.m_fearState < CreatureAttitude::kFearStateCount-1) && fear >= m_fearCutoffs[state.m_fearState+1]) - { - state.m_fearState = static_cast(state.m_fearState + 1); - } - if (anger == 0) - state.m_angerState = CreatureAttitude::kAngerCalm; - else - { - while ((state.m_angerState > CreatureAttitude::kAngerAttack) && anger <= m_angerCutoffs[state.m_angerState-1]) // much less angry than current state - { - state.m_angerState = static_cast(state.m_angerState - 1); - } - while ((state.m_angerState < CreatureAttitude::kAngerStateCount-1) && anger >= m_angerCutoffs[state.m_angerState+1]) - { - state.m_angerState = static_cast(state.m_angerState + 1); - } - } - - if (anger > 0) - { - if (state.m_angerState == CreatureAttitude::kAngerCalm) // got here somehow, I don't know - state.m_behavior = CreatureAttitude::kAngerAttack + CreatureAttitude::kFearStateCount-1; - else - state.m_behavior = state.m_angerState + CreatureAttitude::kFearStateCount-1; - } - else - { - if (state.m_fearState == CreatureAttitude::kFearCalm) - state.m_behavior = 0; - else - state.m_behavior = state.m_fearState; - } - - return state.m_behavior != attitude; -} - -//----------------------------------------------------------------------- - -/** - * Returns the list of draft schematics this creature can use. - * - * @return the schematic list - */ -const std::map,int> & CreatureObject::getDraftSchematics() const -{ -static const std::map,int> npcSchematics; - - if (isPlayerControlled()) - { - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - return playerObject->getDraftSchematics(); - } - return npcSchematics; -} // CreatureObject::getDraftSchematics - -//----------------------------------------------------------------------- - -/** - * Tests if a given ingredient for use in crafting is in this creature's inventory. - * - * @param ingredient the ingredient to test - * - * @return true if the ingredient in in our inventory, false if not - */ -bool CreatureObject::isIngredientInInventory(const Object & ingredient) const -{ - const ServerObject * inventory = getInventory(); - if (inventory == NULL) - return false; - - const Object * container = ContainerInterface::getContainedByObject(ingredient); - while (container != NULL) - { - if (inventory->getNetworkId() == container->getNetworkId() || - getNetworkId() == container->getNetworkId()) - { - return true; - } - // go up a container level - container = ContainerInterface::getContainedByObject(*container); - } - return false; -} // CreatureObject::isIngredientInInventory - -//----------------------------------------------------------------------- - -/** - * Disables schematic filtering when this creature crafts. Note this only works - * if the creature is controlled by a god-mode player. - */ -void CreatureObject::disableSchematicFiltering() -{ - if (getClient() == NULL || !getClient()->isGod()) - return; - - setObjVarItem(OBJVAR_DISABLE_SCHEMATIC_FILTER, 1); -} // CreatureObject::disableSchematicFiltering - -//----------------------------------------------------------------------- - -/** - * Enables schematic filtering when this creature crafts. Note this only works - * if the creature is controlled by a god-mode player. - */ -void CreatureObject::enableSchematicFiltering() -{ - if (getClient() == NULL || !getClient()->isGod()) - return; - - removeObjVarItem(OBJVAR_DISABLE_SCHEMATIC_FILTER); -} // CreatureObject::enableSchematicFiltering - -//----------------------------------------------------------------------- - -/** - * Returns if schematic filtering is enabled or not. Note this only works - * if the creature is controlled by a god-mode player. - * - * @return true if filtering is on, false if it is off - */ -bool CreatureObject::isSchematicFilteringEnabled() -{ - if (getClient() == NULL || !getClient()->isGod()) - return true; - - return (!getObjVars().hasItem(OBJVAR_DISABLE_SCHEMATIC_FILTER)); -} // CreatureObject::isSchematicFilteringEnabled - -//----------------------------------------------------------------------- - -/** - * Returns a list of manufacture schematics in this creature's datapad. - * - * @param schematics list to be filled with the schematics - */ -void CreatureObject::getManufactureSchematics(std::vector & schematics) -{ - const ServerObject * datapad = getDatapad(); - if (datapad == NULL) - return; - const VolumeContainer * container = ContainerInterface::getVolumeContainer(*datapad); - if (container == NULL) - return; - - for (ContainerConstIterator iter = container->begin(); iter != container->end(); ++iter) - { - const ManufactureSchematicObject * schematic = dynamic_cast((*iter).getObject()); - if (schematic != NULL) - schematics.push_back(schematic); - } -} // CreatureObject::getManufactureSchematics(unfiltered) - -//----------------------------------------------------------------------- - -/** - * Returns a list of manufacture schematics in this creature's datapad, filtered - * by a bitmask of crafting types. - * - * @param schematics list to be filled with the schematics - * @param craftingTypes bitmask of valid crafting types - */ -void CreatureObject::getManufactureSchematics(std::vector & schematics, uint32 craftingTypes) -{ - const ServerObject * datapad = getDatapad(); - if (datapad == NULL) - return; - const VolumeContainer * container = ContainerInterface::getVolumeContainer(*datapad); - if (container == NULL) - return; - - for (ContainerConstIterator iter = container->begin(); iter != container->end(); ++iter) - { - const ManufactureSchematicObject * schematic = dynamic_cast((*iter).getObject()); - if (schematic != NULL && ((schematic->getCategory() & craftingTypes) != 0)) - schematics.push_back(schematic); - } -} // CreatureObject::getManufactureSchematics(filtered) - -//----------------------------------------------------------------------- - - -bool CreatureObject::isItemEquipped(const Object & item) const -{ - Object const * const itemContainedBy = ContainerInterface::getContainedByObject (item); - - if (itemContainedBy) - { - return (getNetworkId () == itemContainedBy->getNetworkId ()); - } - - return false; -} - -//----------------------------------------------------------------------- - -void CreatureObject::getBehaviorTargets(int behavior, std::vector &targets) -{ - if (behavior < 0 || behavior >= Behaviors::NumberOfBehaviors) - { - return; - } - - targets.clear(); - targets.reserve(m_targetsByBehavior[behavior].size()); - targets.resize(m_targetsByBehavior[behavior].size()); - std::set::const_iterator i; - std::vector::iterator src = targets.begin(); - for (i=m_targetsByBehavior[behavior].begin(); i!= m_targetsByBehavior[behavior].end(); ++i) - { - *src++=*i; - } -} - -//----------------------------------------------------------------------- - -int CreatureObject::getBehavior() const -{ - return m_lastBehavior.get(); -} - - -//----------------------------------------------------------------------- - -int CreatureObject::getBehaviorToward(const NetworkId &target) const -{ - CreatureAttitude const * const cs = getAttitudeToward(target); - if (!cs) - return 0; - return cs->m_behavior; -} - -//---------------------------------------------------------------------- - -int CreatureObject::getNiche() const -{ - const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); - return static_cast(sharedTemplate->getNiche()); -} - -//---------------------------------------------------------------------- - -SharedCreatureObjectTemplate::Species CreatureObject::getSpecies() const -{ - const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); - return static_cast(sharedTemplate->getSpecies()); -} - -//---------------------------------------------------------------------- - -SharedCreatureObjectTemplate::Race CreatureObject::getRace() const -{ - const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); - return static_cast(sharedTemplate->getRace()); -} - -//---------------------------------------------------------------------- -/* -void CreatureObject::setAnimationState(CreatureObject::AnimationState state) -{ - m_animState = static_cast(state); -} -*/ -//---------------------------------------------------------------------- - -void CreatureObject::setMood(uint32 mood) -{ - if(isAuthoritative()) - { - DEBUG_WARNING (mood > 255, ("Mood %d out of range", mood)); - m_mood = static_cast(mood); - } - else - { - sendControllerMessageToAuthServer(CM_setMood, new MessageQueueGenericValueType(mood)); - } -} - -//---------------------------------------------------------------------- - -/** - * Sets the incapacitated state on the creature. - * - * @param flag true to incapacitate, false to recapacitate - * @param attacker who incapacitated us - */ -void CreatureObject::setIncapacitated(bool flag, const NetworkId & attackerId) -{ - if (isAuthoritative()) - { - if (flag) - { - clearHateList(); - } - - int oldPosture = getPosture(); - if (flag && oldPosture != Postures::Incapacitated) - { - ScriptParams params; - params.addParam(attackerId); - if (getScriptObject()->trigAllScripts( - Scripting::TRIG_ABOUT_TO_BE_INCAPACITATED, params) == SCRIPT_OVERRIDE) - { - LOG("CustomerService", ("Combat: %s not incapacitated due to script", - PlayerObject::getAccountDescription(this).c_str())); - return; - } - LOG("CustomerService", ("Combat: %s incapacitated", - PlayerObject::getAccountDescription(this).c_str())); - - // if we are crafting, end the crafting session - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - if (player != NULL && player->isCrafting()) - player->stopCrafting(false); - - if (isInNpcConversation()) - endNpcConversation(); - - setPosture(Postures::Incapacitated); - setState(States::FeignDeath, false); - - // invoke incapacitation script on us - if (oldPosture != Postures::Dead) - { - params.clear(); - params.addParam(attackerId); - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_INCAPACITATED, params)); - if (attackerId != NetworkId::cms_invalid) - { - // invoke incapacitation script on who incapacitated us - ServerObject * attacker = safe_cast( - NetworkIdManager::getObjectById(attackerId)); - if (attacker != NULL) - { - params.clear(); - params.addParam(getNetworkId()); - IGNORE_RETURN(attacker->getScriptObject()->trigAllScripts( - Scripting::TRIG_INCAPACITATE_TARGET, params)); - - TangibleObject * const tangibleAttacker = attacker->asTangibleObject(); - - if (tangibleAttacker != NULL) - { - tangibleAttacker->verifyHateList(); - } - } - } - } - } - else if (!flag && oldPosture == Postures::Incapacitated) - { - // allow scripts to prevent recapacitation - ScriptParams params; - if (getScriptObject()->trigAllScripts(Scripting::TRIG_RECAPACITATED, - params) == SCRIPT_OVERRIDE) - { - LOG("CustomerService", ("Combat: %s not recapacitated due to script", - PlayerObject::getAccountDescription(this).c_str())); - return; - } - - LOG("CustomerService", ("Combat: %s recapacitated", - PlayerObject::getAccountDescription(this).c_str())); - // recapacitate us - // Force the stand command to execute - setPosture(Postures::Upright); - } - // if we are a player, send us our new posture - if ((getController() != NULL) && !isInCombat()) - { - getController()->appendMessage( - CM_setPosture, - 0.0f, - new MessageQueuePosture(getPosture(), true), - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_ALL_CLIENT - ); - } - } - else - { - sendControllerMessageToAuthServer(CM_setIncapacitated, new MessageQueueGenericValueType >(std::make_pair(flag, attackerId))); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::updateMovementInfo() -{ - // TODO RAD - figure out a real fix for this - if (!canMove() && !isPlayerControlled()) - m_stopWalkRun = 0; - - //-- Retrieve walk and run multipliers from movement table. These are based on the creature's posture and states. - float walkSpeedModifier = 0.0f; - float runSpeedModifier = 0.0f; - - float accelScale = 0.0f; - float turnScale = 0.0f; - - getMovementTable()->getAllMovementRateScales(m_posture.get(), m_states.get(), walkSpeedModifier, runSpeedModifier, accelScale, turnScale); - m_accelScale = accelScale; - m_turnScale = turnScale; - - DEBUG_WARNING((walkSpeedModifier > 0.0f) && (runSpeedModifier > 0.0f) && (walkSpeedModifier != runSpeedModifier), ("updateMovementInfo(): both walk and run speed are nonzero but not equal,walk=[%g],run=[%g].", walkSpeedModifier, runSpeedModifier)); - m_movementScale = std::max(walkSpeedModifier, runSpeedModifier); - - //-- Calculate walk and run speed. - m_walkSpeed = (walkSpeedModifier > 0.0f) ? getBaseWalkSpeed() : 0.0f; - m_runSpeed = (runSpeedModifier > 0.0f) ? getBaseRunSpeed() : 0.0f; - - // If this creature is mounted, we want this creature's walkSpeed, runSpeed, movementScale and movementPercent set to the mount's - if (getState(States::RidingMount)) - { - CreatureObject *const mountedCreature = getMountedCreature(); - if (mountedCreature) - { - if (GameObjectTypes::isTypeOf (mountedCreature->getGameObjectType (), SharedObjectTemplate::GOT_vehicle) && - mountedCreature->m_vehiclePhysicsData) - { - m_runSpeed = mountedCreature->m_vehiclePhysicsData->m_runSpeed; - m_walkSpeed = mountedCreature->m_vehiclePhysicsData->m_walkSpeed; - } - else - { - m_walkSpeed = mountedCreature->getBaseWalkSpeed(); - m_runSpeed = mountedCreature->getBaseRunSpeed(); - } - } - } - - //-- Update fast/slow/stationary locomotion mappings. - getAvailableLocomotions(); - - //-- Choose locomotion. - m_locomotion = calcLocomotion(); - - // if the posture isn't sneak, make sure we don't have cover - if (getPosture() != Postures::Sneaking && getCover() != 0) - setCover(0); - - // if we are prone and have a movement mod > 50, increase our movement rate - if (getPosture() == Postures::Prone) - { - int movementMod = getEnhancedModValue(SLOPE_MOD); - GroupObject const *group = getGroup(); - if (group) - { - // get my group leader skill mod - NetworkId const &leaderId = group->getGroupLeaderId(); - if (leaderId != NetworkId::cms_invalid) - { - Object const *o = NetworkIdManager::getObjectById(leaderId); - if (o) - { - ServerObject const *so = o->asServerObject(); - if (so) - { - CreatureObject const *co = so->asCreatureObject(); - if (co) - movementMod += co->getEnhancedModValue(GROUP_SLOPE_MOD); - } - } - } - } - if (movementMod > 50) - { - float moveScale, accelScale, turnScale; - getMovementTable()->getRates(Postures::Upright, moveScale, accelScale, turnScale); - - movementMod -= 50; - if (movementMod > 50) - movementMod = 50; - float modScale = (movementMod / 50.0f) * ((moveScale / m_movementScale.get()) - 1.0f) + 1.0f; - m_movementScale = m_movementScale.get() * modScale; - } - } - - //-- Mounts: update to a mount's movement info needs to propagate to - // its rider. - if (getState(States::MountedCreature)) - { - typedef std::vector Riders; - Riders riders; - - getMountingRiders(riders); - - Riders::const_iterator ii = riders.begin(); - Riders::const_iterator iiEnd = riders.end(); - - for (; ii != iiEnd; ++ii) - { - CreatureObject *const rider = * ii; - - if (rider) - rider->requestMovementInfoUpdate(); - else - { - LOG("mounts-bug", ("CreatureObject::updateMovementInfo(): server id=[%d],mount id=[%s],has MountedCreature state but getMountingRider() returns null.", static_cast(GameServer::getInstance().getProcessId()), getNetworkId().getValueString().c_str())); - detachAllRiders(); - } - } - } - - //-- Prevent player from moving while stunned - if (getState(States::Stunned)) - { - m_turnScale = 0.0f; - m_movementScale = 0.0f; - } -} - -//---------------------------------------------------------------------- - -/** - * Sets a creature's posture, if it's allowed for its current state. This function - * should be called directly if source is CS_player, otherwise it should be called - * from setCombatState(). - * - * Note: callers should set isClientImmediate to false (the default) if changing - * posture during combat. Combat generally controls when the client visuals for - * posture will actually change. Setting isClientImmediate to true causes the client - * to drop any combat actions currently playing involving this creature and will - * make the client's visual posture change immediately. - * - * @param posture the new posture. - * @param isClientImmediate if set, the client changes visual posture immediately; - * otherwise, combat is assumed to migrate to this posture - * at the appropriate time (as instructed by the combat action - * message) or the client will revert to this new server posture - * in 5 seconds (as of this writing). - */ -void CreatureObject::setPosture(Postures::Enumerator newPosture, bool isClientImmediate) -{ - //-- vehicles can't be anything but upright - if (newPosture != Postures::Upright && GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - WARNING (true, ("CreatureObject attempt to set a vehicle to posture [%d].", newPosture)); - return; - } - - //-- Only do server message processing if the posture changed, but always send the - // posture to the clients if isClientImmediate is true --- the client visual posture - // is unknown on the server and may be different than the server posture. - Postures::Enumerator oldPosture = m_posture.get(); - bool const doServerProcessing = (oldPosture != newPosture); - - if (doServerProcessing) - { - //-- Process the posture change on the server only if the posture changed. - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setPosture, new MessageQueuePosture(newPosture, isClientImmediate)); - return; - } - - if (getMovementTable()->getLocomotion(newPosture, m_states.get(), MovementTable::kStationary) != Locomotions::Invalid) - { - Postures::Enumerator oldPosture = m_posture.get(); - - m_posture = newPosture; - - // If we were previously sitting on a chair, clear the flag. - if(oldPosture == Postures::Sitting) - setState(States::SittingOnChair, false); - - // @todo revisit this. updateMoevementInfo() indirectly changes auto delta variables. Since this isn't - // guaranteed to be the authoritative object, this is an invalid thing to do. - requestMovementInfoUpdate(); - - if (getScriptObject() != NULL) - { - ScriptParams params; - params.addParam(oldPosture); - params.addParam(newPosture); - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_CHANGED_POSTURE, params)); - } - - recomputeSlopeModPercent(); - } - } - - //-- Handle posture changes that should take effect immediately on the client. - if (isClientImmediate) - { - //-- Send if we're the authoritative server OR if we're not passing the message on to the authoritative server. - // This guarantees that we only send this message to the clients once. - bool const sendToClient = isAuthoritative() || !doServerProcessing; - if (sendToClient) - { - Controller *const controller = getController(); - if (controller) - controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(newPosture, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); - else - DEBUG_WARNING(true, ("setPosture(): called with isClientImmediate but object id=[%s],template=[%s] has no controller.", getNetworkId().getValueString().c_str(), getObjectTemplateName())); - } - } -} - -// ---------------------------------------------------------------------- -/** - * Call this function to request that movement info be updated at the - * end of the next frame's alter. - * - * This function was needed to delay the updateMovementInfo() until - * after all transitive mount-related state was complete. It has the - * side effect of preventing the call from being made multiple times - * in the same frame. - */ - -void CreatureObject::requestMovementInfoUpdate() -{ - setLocalFlag(LocalObjectFlags::CreatureObject_RequiresMovementInfoUpdate, true); -} - -//----------------------------------------------------------------------- - -void CreatureObject::setCover(int cover) -{ - if(!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setCover, new MessageQueueGenericValueType(cover)); - } - else - { - m_cover = cover; - } -} - -// ---------------------------------------------------------------------- - -/** - * Sets the value of a state on a creature, if it's allowed for its current - * state. - * - * @param whichState which state to change - * @param value new value of the state - */ -void CreatureObject::setState(States::Enumerator whichState, bool value) -{ - if (isAuthoritative()) - { - if(whichState == States::Combat) - { - setInCombat(value); - return; - } - - //-- vehicles can't have most states - if (value && GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - switch (whichState) - { - case States::MountedCreature: - case States::Swimming: - case States::Combat: - // these states are okay for a vehicle to have, continue on with state change processing. - break; - - default: - // all other states are not okay for a vehicle to have, warn about them. - WARNING (true, ("CreatureObject id=[%s] attempt to set state id=[%d], name=[%s] on a vehicle, unsupported.", getNetworkId().getValueString().c_str(), whichState, States::getStateName(whichState))); - return; - } - } - - uint64 stateFlags = m_states.get(); - - // enforce a no state change if the creature is a glowing Jedi - if (value) - stateFlags |= States::getStateMask(whichState); - else - stateFlags &= ~States::getStateMask(whichState); - if (m_states.get() != stateFlags) - { - m_states = stateFlags; - requestMovementInfoUpdate(); - } - } - else - { - sendControllerMessageToAuthServer(CM_setState, new MessageQueueSetState(static_cast(whichState), value)); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setSayMode(uint32 sayMode) -{ - if(isAuthoritative()) - { - DEBUG_WARNING (sayMode > 255, ("Saymode %d out of range", sayMode)); - m_sayMode = static_cast(sayMode); - } - else - { - sendControllerMessageToAuthServer(CM_setSayMode, new MessageQueueGenericValueType(sayMode)); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setAnimationMood(const std::string & mood) -{ - if(isAuthoritative()) - { - m_animationMood = mood; - } - else - { - sendControllerMessageToAuthServer(CM_setAnimationMood, new MessageQueueGenericValueType(mood)); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setAttribute(Attributes::Enumerator attribute, Attributes::Value value) -{ - if(!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setAttribute, new MessageQueueGenericValueType >(std::make_pair(attribute, value))); - } - else - { - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - { - DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); - return; - } - if (!Attributes::isAttribPool(attribute)) - { - WARNING(true, ("CreatureObject::setAttribute called with non-pool attribute %d on creature %s. If this is a regeneration value, call setRegenRate() instead.", - attribute, getNetworkId().getValueString().c_str())); - return; - } - const Attributes::Value currentValue = m_attributes[attribute]; - IGNORE_RETURN(alterAttribute(attribute, value - currentValue, true)); - } -} - -//---------------------------------------------------------------------- - -/** Set the maximum value for an attribute. Optionally revalidate the stats for players. - */ -void CreatureObject::setMaxAttribute(Attributes::Enumerator attribute, Attributes::Value value, bool verifyPlayerMaxStats) -{ - if(! isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setMaxAttribute, new MessageQueueGenericValueType >(std::make_pair(attribute, value))); - } - else - { - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - { - DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); - return; - } - if (!Attributes::isAttribPool(attribute)) - { - WARNING(true, ("CreatureObject::setMaxAttribute called with non-pool attribute %d on creature %s. If this is a regeneration value, call setRegenRate() instead.", - attribute, getNetworkId().getValueString().c_str())); - return; - } - m_maxAttributes.set(attribute, value); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setMentalState(MentalStates::Enumerator state, MentalStates::Value value) -{ - if(! isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setMentalState, new MessageQueueGenericValueType >(std::make_pair(state, value))); - } - else - { - if (state < 0 || state >= MentalStates::NumberOfMentalStates) - { - DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); - return; - } - - if (value > m_maxMentalStates[state]) - value = m_maxMentalStates[state]; - else if (value < 0) - value = 0; - CreatureAttitude newState = m_currentAttitude.get(); - newState.m_currentValues[state] = value; - m_currentAttitude.set(newState); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setMaxMentalState(MentalStates::Enumerator state, MentalStates::Value value) -{ - if(isAuthoritative()) - { - if (state < 0 || state >= MentalStates::NumberOfMentalStates) - { - DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); - return; - } - - m_maxMentalStates.set(state, value); - } - else - { - sendControllerMessageToAuthServer(CM_setMaxMentalState, new MessageQueueGenericValueType >(std::make_pair(state, value))); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setMentalStateDecay(MentalStates::Enumerator state, float value) -{ - if(! isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setMentalStateDecay, new MessageQueueGenericValueType >(std::make_pair(state, value))); - } - else - { - if (state < 0 || state >= MentalStates::NumberOfMentalStates) - { - DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); - return; - } - - m_mentalStateDecays.set(state, value); - } -} - -//---------------------------------------------------------------------- - -ServerObject *CreatureObject::getObjectInSlot(ConstCharCrcLowerString const &slotName) -{ - SlottedContainer * const s = ContainerInterface::getSlottedContainer(*this); - if (s) - { - SlotId const dp = SlotIdManager::findSlotId(slotName); - Container::ContainerErrorCode tmp = Container::CEC_Success; - return safe_cast(s->getObjectInSlot(dp, tmp).getObject()); - } - - return 0; -} - -//---------------------------------------------------------------------- - -const ServerObject * CreatureObject::getObjectInSlot (const ConstCharCrcLowerString & slotName) const -{ - return const_cast(this)->getObjectInSlot (slotName); -} - -//----------------------------------------------------------------------- - -ServerObject * CreatureObject::getDatapad() -{ - return getObjectInSlot (SlotNames::datapad); -} - -//---------------------------------------------------------------------- - -const ServerObject * CreatureObject::getDatapad() const -{ - return const_cast(this)->getDatapad (); -} - -//---------------------------------------------------------------------- - -ServerObject * CreatureObject::getBank () -{ - return getObjectInSlot (SlotNames::bank); -} - -//---------------------------------------------------------------------- - -const ServerObject * CreatureObject::getBank () const -{ - return const_cast(this)->getBank (); -} - -//----------------------------------------------------------------------- - -ServerObject * CreatureObject::getInventory() -{ - return getObjectInSlot (SlotNames::inventory); -} - -//---------------------------------------------------------------------- - -const ServerObject * CreatureObject::getInventory() const -{ - return const_cast(this)->getInventory (); -} - -//---------------------------------------------------------------------- - -ServerObject * CreatureObject::getHair() -{ - return getObjectInSlot (SlotNames::hair); -} - -//------------------------------------------------------------------------ - -const ServerObject * CreatureObject::getHair() const -{ - return const_cast(this)->getHair (); -} - -//---------------------------------------------------------------------- - - -ServerObject * CreatureObject::getAppearanceInventory() -{ - return getObjectInSlot (SlotNames::appearance); -} - -//---------------------------------------------------------------------- - -const ServerObject * CreatureObject::getAppearanceInventory() const -{ - return const_cast(this)->getAppearanceInventory (); -} - -//---------------------------------------------------------------------- - - -ServerObject * CreatureObject::getHangar() -{ - return getObjectInSlot (SlotNames::hangar); -} - -//---------------------------------------------------------------------- - -const ServerObject * CreatureObject::getHangar() const -{ - return const_cast(this)->getHangar(); -} - - -//----------------------------------------------------------------------- - -bool CreatureObject::onContainerAboutToTransfer(ServerObject * destination, ServerObject* transferer) -{ - bool const baseResult = TangibleObject::onContainerAboutToTransfer(destination, transferer); - if (!baseResult) - return false; - - const PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - // let's prevent CS from putting any more players in their inventories - if(player && destination) - { - const CreatureObject * creatureDestination = destination->asCreatureObject(); - if(creatureDestination) - { - const PlayerObject * const playerDestination = PlayerCreatureController::getPlayerObject(creatureDestination); - if(playerDestination) - { - return false; - } - } - } - return onContainerAboutToTransferForMounts(destination, transferer); -} - - -/** - * Callback for when the creature is about to equip an item. Checks to make sure - * we don't equip two shields, and prevents equiping armor that would incapacitate - * us. - * - * @param item the item being equipped - * @param transferer who is causing the item to be equipped - * - * @return true to allow the transfer, false to prevent it - */ -int CreatureObject::onContainerAboutToGainItem(ServerObject& item, ServerObject* transferer) -{ - TangibleObject const * const object = item.asTangibleObject(); - if (object != NULL) - { - // See if this item is equippable - const char *sharedTemplateName = item.getSharedTemplateName(); - if (!isAppearanceEquippable(sharedTemplateName)) - { - if (getClient() != NULL) - { - StringId message("shared", "item_not_equippable"); - Unicode::String outOfBand; - Chat::sendSystemMessage(*this, message, outOfBand); - return Container::CEC_SilentError; - } - else - return Container::CEC_BlockedByDestinationContainer; - } - } - - - return TangibleObject::onContainerAboutToGainItem(item, transferer); -} // CreatureObject::onContainerAboutToGainItem - -//---------------------------------------------------------------------- - -/** - * Callback for when the creature unequips an item. - * - * @param destination where the item was transferred to - * @param item the item that was unequipped - * @param transferer who caused the transfer - */ -void CreatureObject::onContainerLostItem(ServerObject *destination, ServerObject &item, ServerObject *transferer) -{ - TangibleObject const * const tangibleObject = item.asTangibleObject(); - if (tangibleObject == NULL) - return; - - // check if the object applies skill mod bonuses when equipped - { - std::vector > skillModBonuses; - tangibleObject->getSkillModBonuses(skillModBonuses); - int const bonusCount = skillModBonuses.size(); - if (bonusCount > 0) - { - std::vector modNames(bonusCount); - std::vector modValues(bonusCount); - for (int i = 0; i < bonusCount; ++i) - { - std::pair const &bonus = skillModBonuses[i]; - addModBonus(bonus.first, -bonus.second); - modNames[i] = bonus.first.c_str(); - modValues[i] = -bonus.second; - } - ScriptParams params; - params.addParam(modNames); - params.addParam(modValues); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILLMODS_CHANGED, params)); - } - } - - // check if the object applies attribute bonuses when equipped - { - std::vector > attribBonuses; - tangibleObject->getAttribBonuses(attribBonuses); - int const bonusCount = attribBonuses.size(); - for (int i = 0; i < bonusCount; ++i) - { - std::pair const &bonus = attribBonuses[i]; - addAttribBonus(bonus.first, -bonus.second); - } - } - - - - // if the item is a weapon, make our current weapon our default weapon - WeaponObject const * const weaponObject = tangibleObject->asWeaponObject(); - if (weaponObject != NULL && getDefaultWeapon() != NULL) - setCurrentWeapon(*getDefaultWeapon()); - - // check if the object is our shield - if (tangibleObject == m_shield) - m_shield = NULL; - - //Update wearbles data - SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); - if (scp) - { - WearableEntry e("", scp->getCurrentArrangement(), item.getNetworkId(), 0); - int index = m_wearableData.find(e); - if (index >= 0) - { - m_wearableData.erase(index); - } - } - - TangibleObject::onContainerLostItem(destination, item, transferer); -} // CreatureObject::onContainerLostItem - -//---------------------------------------------------------------------- - -/** - * Callback for when the creature equips an item. - * shields, and weapons. - * - * @param item the item that was equipped - * @param transferer who caused the transfer - */ -void CreatureObject::onContainerGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) -{ - TangibleObject * const tangibleObject = item.asTangibleObject(); - if (tangibleObject == NULL) - return; - - // check if the object applies skill mod bonuses when equipped - { - std::vector > skillModBonuses; - tangibleObject->getSkillModBonuses(skillModBonuses); - int const bonusCount = skillModBonuses.size(); - if (bonusCount > 0) - { - std::vector modNames(bonusCount); - std::vector modValues(bonusCount); - for (int i = 0; i < bonusCount; ++i) - { - std::pair const &bonus = skillModBonuses[i]; - addModBonus(bonus.first, bonus.second); - modNames[i] = bonus.first.c_str(); - modValues[i] = bonus.second; - } - ScriptParams params; - params.addParam(modNames); - params.addParam(modValues); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILLMODS_CHANGED, params)); - } - } - - // check if the object applies attribute bonuses when equipped - { - std::vector > attribBonuses; - tangibleObject->getAttribBonuses(attribBonuses); - int const bonusCount = attribBonuses.size(); - for (int i = 0; i < bonusCount; ++i) - { - std::pair const &bonus = attribBonuses[i]; - addAttribBonus(bonus.first, bonus.second); - } - } - - // if the item is a weapon, make it our current weapon - WeaponObject * const weaponObject = tangibleObject->asWeaponObject(); - if (weaponObject != NULL) - setCurrentWeapon(*weaponObject); - - //Update wearables data - SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); - if (scp) - { - Object const * inventory = 0; - Object const * datapad = 0; - Object const * appearance = 0; - - SlottedContainer const * const myContainer = ContainerInterface::getSlottedContainer(*this); - - if (myContainer) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - static SlotId const inventorySlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); - if (inventorySlot != SlotId::invalid) - { - Container::ContainedItem itemId = myContainer->getObjectInSlot(inventorySlot, tmp); - inventory = itemId.getObject(); - } - SlotId datapadSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::datapad); - if (datapadSlot != SlotId::invalid) - { - Container::ContainedItem itemId = myContainer->getObjectInSlot(datapadSlot, tmp); - datapad = itemId.getObject(); - } - SlotId appearanceInvSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); - if (appearanceInvSlot != SlotId::invalid) - { - Container::ContainedItem itemId = myContainer->getObjectInSlot(appearanceInvSlot, tmp); - appearance = itemId.getObject(); - } - } - - if ( scp->isInAppearanceSlot() || tangibleObject == inventory || tangibleObject == datapad) - { - ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tangibleObject->getClientSharedTemplateName()); - if (clientSharedTemplateNameCrcString.isEmpty()) - WARNING(true, ("Could not find crc for %s. Wearable will not be streamed to client", tangibleObject->getClientSharedTemplateName())); - else if (tangibleObject->asWeaponObject() != NULL) - { - addPackedWearable(tangibleObject->getAppearanceData(), scp->getCurrentArrangement(), tangibleObject->getNetworkId(), clientSharedTemplateNameCrcString.getCrc(), - tangibleObject->createSharedBaselinesMessage(), tangibleObject->createSharedNpBaselinesMessage()); - } - else - addPackedWearable(tangibleObject->getAppearanceData(), scp->getCurrentArrangement(), tangibleObject->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); - } - } - - TangibleObject::onContainerGainItem(item, source, transferer); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::onContainerTransferComplete(ServerObject *oldContainer, ServerObject *newContainer) -{ - TangibleObject::onContainerTransferComplete(oldContainer, newContainer); - - setStatesDueToContainment(); - - if (!isInWorld()) - setMovementStationary(); - - ShipObject const * const oldContainingShipObject = ShipObject::getContainingShipObject(oldContainer); - ShipObject const * const newContainingShipObject = ShipObject::getContainingShipObject(newContainer); - - if (oldContainingShipObject != newContainingShipObject) - { - GroupObject * const groupObject = getGroup(); - - if (groupObject != 0) - { - if (oldContainingShipObject != 0) - { - if (oldContainingShipObject->getPortalProperty() != 0) - { - if (getNetworkId() == oldContainingShipObject->getOwnerId()) - { - NetworkId const & shipId = oldContainingShipObject->getNetworkId(); - groupObject->removePOBShip(shipId); - } - } - } - - if (newContainingShipObject != 0) - { - if (newContainingShipObject->getPortalProperty() != 0) - { - groupObject->addPOBShipAndOwner(newContainingShipObject->getNetworkId(), newContainingShipObject->getOwnerId()); - } - } - - NetworkId const & shipId = (newContainingShipObject != 0) ? newContainingShipObject->getNetworkId() : NetworkId::cms_invalid; - groupObject->setShipForMember(getNetworkId(), shipId); - } - } - - Client * const client = getClient(); - if (client && ServerWorld::isSpaceScene()) - { - ServerObject const * const oldTopmost = oldContainer ? safe_cast(ContainerInterface::getTopmostContainer(*oldContainer)) : this; - ServerObject * const newTopmost = newContainer ? safe_cast(ContainerInterface::getTopmostContainer(*newContainer)) : this; - if (oldTopmost != newTopmost) - { - SpaceVisibilityManager::removeClient(*client); - SpaceVisibilityManager::addClient(*client, *newTopmost); - } - } -} - -// ---------------------------------------------------------------------- -// this object got added to a trigger volume -void CreatureObject::onAddedToTriggerVolume(TriggerVolume & triggerVolume) -{ - WARNING(!isInWorld(), ("CreatureObject (%s) not in world but being added to TriggerVolume (%s) owned by (%s)", - getDebugInformation().c_str(), - triggerVolume.getName().c_str(), - triggerVolume.getOwner().getDebugInformation().c_str())); - - IGNORE_RETURN(m_triggerVolumeEntered.insert(&triggerVolume)); -} - -// ---------------------------------------------------------------------- -// this object got removed from a trigger volume -void CreatureObject::onRemovedFromTriggerVolume(TriggerVolume & triggerVolume) -{ - // NOTE: be careful about referencing the TriggerVolume because this - // function can be called from the TriggerVolume's dtor - IGNORE_RETURN(m_triggerVolumeEntered.erase(&triggerVolume)); -} - -// ---------------------------------------------------------------------- - -// ---------------------------------------------------------------------- - -/** - * Computes the total attributes and max attributes for sending to clients, - */ -void CreatureObject::computeTotalAttributes () -{ -int i; - - WARNING_STRICT_FATAL(!isAuthoritative(), ("computeTotalAttributes called on nonauthoritative object %s:%s", getObjectTemplateName(), getNetworkId().getValueString().c_str())); - - if (!isAuthoritative()) - return; - - if (m_deferComputeTotalAttributes <= 0) - { - if (m_regenerationTime >= ConfigServerGame::getRegenThreshold()) - { - // send updates to the client - m_regenerationTime -= ConfigServerGame::getRegenThreshold(); - for (i = 0; i < 3; ++i) - { - int poolAttrib = Attributes::POOLS[i]; - const float delta = static_cast(floor(m_regeneration[ - poolAttrib])); - if (delta >= 1.0f) - { - m_regeneration[poolAttrib] -= delta; - IGNORE_RETURN(alterAttribute(poolAttrib, static_cast( - delta), true)); - } - } - } - - if (ConfigServerGame::getCheckAttribLimits()) - { - // check and make sure our current attribs are <= our max attribs, - // for both unmodified and modified versions - for (i = 0; i < Attributes::NumberOfAttributes; ++i) - { - if (Attributes::isAttribPool(i)) - { - if (getUnmodifiedAttribute(i) > getUnmodifiedMaxAttribute(i)) - { - WARNING_STRICT_FATAL(true, ("Creature %s has attribute %d with " - "an unmodified current value > its max value! We will change " - "the current value! Current = %d, max = %d, " - "cur mods = %d, max mods = %d", - getNetworkId().getValueString().c_str(), - i, - static_cast(getUnmodifiedAttribute(i)), - static_cast(getUnmodifiedMaxAttribute(i)), - static_cast(m_cachedCurrentAttributeModValues[i]), - static_cast(m_cachedMaxAttributeModValues[i]))); - m_attributes.set(i, getUnmodifiedMaxAttribute(i)); - } - if (getAttribute(i) > getMaxAttribute(i)) - { - WARNING_STRICT_FATAL(true, ("Creature %s has attribute %d with " - "a current value > its max value! Current = %d(%d), max = " - "%d(%d), cur mods = %d, max mods = %d", - getNetworkId().getValueString().c_str(), - i, - static_cast(getAttribute(i)), - static_cast(getUnmodifiedAttribute(i)), - static_cast(getMaxAttribute(i)), - static_cast(getUnmodifiedMaxAttribute(i)), - static_cast(m_cachedCurrentAttributeModValues[i]), - static_cast(m_cachedMaxAttributeModValues[i]))); - } - } - } - } - - for (i = 0; i < Attributes::NumberOfAttributes; ++i) - { - if (Attributes::isAttribPool(i)) - { - m_totalAttributes.set(i, getAttribute(i) - static_cast(floor(m_regeneration[i]))); - m_totalMaxAttributes.set(i, getMaxAttribute(i)); - } - } - } -} // CreatureObject::computeTotalAttributes - -//---------------------------------------------------------------------- - -void CreatureObject::resetAttribute (Attributes::Enumerator attrib, Attributes::Value value) -{ - setMaxAttribute (attrib, value); - setAttribute (attrib, value); - m_shockWounds = 0; -} - -//---------------------------------------------------------------------- - -void CreatureObject::initializeAttribute(Attributes::Enumerator attrib, Attributes::Value value) -{ - m_maxAttributes.set(attrib, value); - m_attributes.set (attrib, value); -} - -//---------------------------------------------------------------------- - -/** - * Drains a creature's special abilities, based on it's drain attributes. - * - * @param action amount to drain the creature's action SA - * @param mind amount to drain the creature's mind SA - * - * @return true if the SA were drained, false if draining them would cause one - * to be < 0 - */ -bool CreatureObject::drainAttributes(Attributes::Value action, Attributes::Value mind) -{ - int i; - int mods[3] = {0, action, mind}; - int deltas[3]; - - // determine the amount to drain and make sure it won't incapaciate the creature - for (i = 0; i < 3; ++i) - { - if (mods[i] > 0) - { - deltas[i] = getAttribute(Attributes::POOLS[i]) - mods[i]; - if (deltas[i] < 0) - return false; - } - else - deltas[i] = -1; - } - - // drain the attributes - for (i = 0; i < 3; ++i) - { - if (deltas[i] >= 0) - alterAttribute(Attributes::POOLS[i], -mods[i], false); - } - return true; -} // CreatureObject::drainAttributes - -//---------------------------------------------------------------------- - -/** - * Tests draining an attribute, but does not actually modify the attrib. - * - * @param attribute the attribute to test - * @param value the amount to drain the attribute by - * - * @return the amount the attribute would be drained by, or -1 on error - */ -int CreatureObject::testDrainAttribute(Attributes::Enumerator attribute, - Attributes::Value value) const -{ - // we can only drain action and mind - if (attribute != Attributes::Action && attribute != Attributes::Mind) - return -1; - - if (getAttribute(attribute) - value <= 0) - return -1; - - return static_cast(value); -} // CreatureObject::testDrainAttribute - -//---------------------------------------------------------------------- - -void CreatureObject::onClientReady(Client *c) -{ - TangibleObject::onClientReady(c); - - // check cell permissions - Object * const attachedTo = getAttachedTo(); - if (attachedTo) - { - ServerObject * const serverAttachedTo = attachedTo->asServerObject(); - if (serverAttachedTo) - { - CellObject * const cellObject = serverAttachedTo->asCellObject(); - if (cellObject && !cellObject->isAllowed(*this)) - { - BuildingObject * const ownerBuilding = cellObject->getOwnerBuilding(); - if (ownerBuilding) - ownerBuilding->expelObject(*this); - } - } - } - - GroupObject *group = getGroup(); - if (group) - group->onGroupMemberConnect(getNetworkId()); - - // update the client with the list of mods currently on the character - - // but first, remove any mods from the list that has expired - uint32 const gameTimeSeconds = ServerClock::getInstance().getGameTimeSeconds(); - std::vector expiredMods; - std::vector::const_iterator iterTimedMod = m_timedMod.begin(); - std::vector::const_iterator iterTimedModDuration = m_timedModDuration.begin(); - std::vector::const_iterator iterTimedModUpdateTime = m_timedModUpdateTime.begin(); - - for (; iterTimedMod != m_timedMod.end(); ++iterTimedMod, ++iterTimedModDuration, ++iterTimedModUpdateTime) - { - if (*iterTimedModDuration >= 0) - { - if ((*iterTimedModUpdateTime + static_cast(*iterTimedModDuration)) < gameTimeSeconds) - expiredMods.push_back(*iterTimedMod); - } - } - - int index; - for (iterTimedMod = expiredMods.begin(); iterTimedMod != expiredMods.end(); ++iterTimedMod) - { - index = m_timedMod.find(*iterTimedMod); - - if (index >= 0) - { - m_timedMod.erase(index); - m_timedModDuration.erase(index); - m_timedModUpdateTime.erase(index); - } - } - - // send the mods to the client - iterTimedMod = m_timedMod.begin(); - iterTimedModDuration = m_timedModDuration.begin(); - iterTimedModUpdateTime = m_timedModUpdateTime.begin(); - - for (; iterTimedMod != m_timedMod.end(); ++iterTimedMod, ++iterTimedModDuration, ++iterTimedModUpdateTime) - { - if (*iterTimedModDuration >= 0) - sendTimedModData(*iterTimedMod, *iterTimedModDuration - static_cast(gameTimeSeconds - *iterTimedModUpdateTime), false); - else - sendTimedModData(*iterTimedMod, -1.0f, false); - } - - // update the client with the list of cooldowns currently on the character - - // visual only cooldown timers are stored in objvars - DynamicVariableList const & objvars = getObjVars(); - std::map > visualCooldownTimers; - for (DynamicVariableList::MapType::const_iterator iterObjVar = objvars.begin(); iterObjVar != objvars.end(); ++iterObjVar) - { - if (iterObjVar->first.find("visualCooldown.beginTime.") == 0) - { - int cooldownGroupCrc = 0; - if (1 == sscanf(iterObjVar->first.c_str(), "visualCooldown.beginTime.%d", &cooldownGroupCrc)) - { - int beginTime = 0; - if (iterObjVar->second.get(beginTime)) - { - std::map >::iterator iterFind = visualCooldownTimers.find(cooldownGroupCrc); - if (iterFind == visualCooldownTimers.end()) - { - visualCooldownTimers[cooldownGroupCrc] = std::make_pair(beginTime, 0); - } - else - { - iterFind->second.first = beginTime; - } - } - } - } - else if (iterObjVar->first.find("visualCooldown.endTime.") == 0) - { - int cooldownGroupCrc = 0; - if (1 == sscanf(iterObjVar->first.c_str(), "visualCooldown.endTime.%d", &cooldownGroupCrc)) - { - int endTime = 0; - if (iterObjVar->second.get(endTime)) - { - std::map >::iterator iterFind = visualCooldownTimers.find(cooldownGroupCrc); - if (iterFind == visualCooldownTimers.end()) - { - visualCooldownTimers[cooldownGroupCrc] = std::make_pair(0, endTime); - } - else - { - iterFind->second.second = endTime; - } - } - } - } - } - - char buffer[256]; - int const currentGameTime = static_cast(ServerClock::getInstance().getGameTimeSeconds()); - for (std::map >::const_iterator iterCooldown = visualCooldownTimers.begin(); iterCooldown != visualCooldownTimers.end(); ++iterCooldown) - { - // send any unexpired cooldowns to the client - if ((iterCooldown->second.first > 0) && (iterCooldown->second.second > 0) && (iterCooldown->second.first <= currentGameTime) && (currentGameTime < iterCooldown->second.second)) - { - CreatureController *controller = getCreatureController(); - if (controller) - { - MessageQueueCommandTimer *msg = new MessageQueueCommandTimer( - 0, - iterCooldown->first, - -1, - 0); - msg->setCurrentTime(MessageQueueCommandTimer::F_cooldown, static_cast(currentGameTime - iterCooldown->second.first)); - msg->setMaxTime (MessageQueueCommandTimer::F_cooldown, static_cast(iterCooldown->second.second - iterCooldown->second.first)); - - controller->appendMessage( - static_cast< int >( CM_commandTimer ), - 0.0f, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } - else - { - // cleanup the objvars for any expired/invalid cooldowns - snprintf(buffer, sizeof(buffer)-1, "visualCooldown.beginTime.%d", iterCooldown->first); - buffer[sizeof(buffer)-1] = '\0'; - removeObjVarItem(buffer); - - snprintf(buffer, sizeof(buffer)-1, "visualCooldown.endTime.%d", iterCooldown->first); - buffer[sizeof(buffer)-1] = '\0'; - removeObjVarItem(buffer); - } - } - - // command cooldown timers are stored in the command queue - CommandQueue const * commandQueue = getCommandQueue(); - if (commandQueue && getClient()) - { - double const currentTime = Clock::getCurrentTime(); - uint32 currentCooldownTimeSecond = 0; - uint32 maxCooldownTimeSecond = 0; - std::map > const & cooldowns = commandQueue->getCooldowns().getMap(); - for (std::map >::const_iterator cooldownsIter = cooldowns.begin(); cooldownsIter != cooldowns.end(); ++cooldownsIter) - { - if ((cooldownsIter->second.first <= currentTime) && (currentTime < cooldownsIter->second.second)) - { - // don't bother sending cooldown with less than 1 second left because - // by the time it gets to the client, it will probably have already expired - currentCooldownTimeSecond = static_cast(currentTime - cooldownsIter->second.first); - maxCooldownTimeSecond = static_cast(cooldownsIter->second.second - cooldownsIter->second.first); - - if (currentCooldownTimeSecond < maxCooldownTimeSecond) - { - GenericValueTypeMessage > > commandCooldown("SetCommandCooldown", std::make_pair(cooldownsIter->first, std::make_pair(currentCooldownTimeSecond, maxCooldownTimeSecond))); - getClient()->send(commandCooldown, true); - } - } - } - } - - // sync chat character count with chat server - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - if (player && (player->getChatSpamTimeEndInterval() > 0)) - { - time_t timeUnsquelch = static_cast(player->getSecondsUntilUnsquelched()); - if (timeUnsquelch > 0) - timeUnsquelch += ::time(NULL); - - GenericValueTypeMessage, int>, std::pair > > chatStatistics("ChatStatisticsGS", std::make_pair(std::make_pair(std::make_pair(getNetworkId(), static_cast(timeUnsquelch)), player->getChatSpamTimeEndInterval()), std::make_pair(player->getChatSpamSpatialNumCharacters(), player->getChatSpamNonSpatialNumCharacters()))); - Chat::sendToChatServer(chatStatistics); - } - - // if necessary, announce TCG monthly bonus booster pack and Swg Tcg Beta - if (getClient() && !getClient()->isUsingAdminLogin()) - { - VeteranRewardManager::announceMonthlyBonusBoosterPack(*this); - - if (ConfigServerGame::getAccountFeatureIdForTcgBetaAnnouncement() > 0) - VeteranRewardManager::announceSwgTcgBeta(*this); - } - // Make sure our player has the server's speed maximum - PlayerCreatureController const * playerController = safe_cast(getCreatureController()); - if(playerController) - { - GenericValueTypeMessage const msg("fca11a62d23041008a4f0df36aa7dca6", playerController->getServerSpeedForPlayer()); - Client const * const client = getClient(); - if (client) - return client->send(msg, true); - } - -} - -// ---------------------------------------------------------------------- - -void CreatureObject::onClientAboutToLoad() -{ - if (isAuthoritative()) - setInvulnerabilityTimer(ConfigServerGame::getCreatureLoadInvulnerableTimeWithoutClient()); - - TangibleObject::onClientAboutToLoad(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::onLoadingScreenComplete() -{ - TangibleObject::onLoadingScreenComplete(); - - if (isAuthoritative() && isInvulnerable()) - setInvulnerabilityTimer(ConfigServerGame::getCreatureLoadInvulnerableTimeWithClient()); -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::monitorCreatureMovement(const CachedNetworkId &ofTarget, float i_skittishness, float i_curve) -{ - Object * object = ofTarget.getObject(); - if (!object || object == this) - return false; - - Archive::AutoDeltaMap::const_iterator i = m_monitoredCreatureMovements.find(ofTarget); - MonitoredCreatureMovement newMovement; - if (i == m_monitoredCreatureMovements.end()) - { - newMovement.m_lastDistance = object->getPosition_w().magnitudeBetween(getPosition_w()); - newMovement.m_skittishness = i_skittishness; - newMovement.m_curve = i_curve; - } - else - { - newMovement = i->second; - newMovement.m_skittishness = i_skittishness; - newMovement.m_curve = i_curve; - - } - if (newMovement != i->second) - { - m_monitoredCreatureMovements.set(ofTarget, newMovement); - } - return true; -} - -//---------------------------------------------------------------------- - -bool CreatureObject::ignoreCreatureMovement(const CachedNetworkId &ofTarget) -{ - Archive::AutoDeltaMap::const_iterator i = m_monitoredCreatureMovements.find(ofTarget); - if (i == m_monitoredCreatureMovements.end()) - return false; - m_monitoredCreatureMovements.erase(ofTarget); - return true; -} - -//---------------------------------------------------------------------- - -void CreatureObject::reportMonitoredCreatures(float time) -{ - Vector ownerPosition = getPosition_w(); - std::vector toRemove; - Archive::AutoDeltaMap::const_iterator i; - for (i=m_monitoredCreatureMovements.begin(); i!=m_monitoredCreatureMovements.end(); ++i) - { - CachedNetworkId cnid(i->first); - Object * o = cnid.getObject(); - if (o) - { - MonitoredCreatureMovement newMovement = i->second; - - float lastDistance = newMovement.m_lastDistance; - float currentDistance = o->getPosition_w().magnitudeBetween(ownerPosition); - float approach = lastDistance - currentDistance; - //float tangentVelocity = sqrt(((mobDelta - targetDelta)/i_time).magnitudeSquared() - approachVelocity * approachVelocity); - - // calculate the fear delta - if (approach > 0) - { - float approachVelocity = approach / time; - float totalDistance = getApproachTriggerRange(); - float percent = 1 - ((lastDistance + currentDistance) * 0.5f) / totalDistance; - if (percent > 1) - percent = 1; - else if (percent < 0) - percent = 0; - if (i->second.m_curve < 0) - { - percent = -percent; - } - float absCurve = std::abs(i->second.m_curve); - float scale = pow(percent, absCurve) * (1+absCurve); - float speedScale = float(sqrt(approachVelocity / getRunSpeed())); - float fearDelta = approach * i->second.m_skittishness * speedScale * scale; - setMentalStateToward(i->first, MentalStates::Fear, getMentalStateToward(i->first, MentalStates::Fear)+fearDelta); - } - newMovement.m_lastDistance = currentDistance; - m_monitoredCreatureMovements.set(i->first, newMovement); - } - else - { - toRemove.push_back(i->first); - } - } - std::vector::iterator removeIt; - for (removeIt = toRemove.begin(); removeIt != toRemove.end(); ++removeIt) - { - m_monitoredCreatureMovements.erase(*removeIt); - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::doWarmupChecks(Command const &command, NetworkId const &targetId, Unicode::String const ¶ms, Command::ErrorCode &status, int &statusDetail) -{ - if (doesLocomotionInvalidateCommand(command)) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to locomotion %d", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str(), - getLocomotion())); - } - status = Command::CEC_Locomotion; - statusDetail = static_cast(getLocomotion()); - } - else if (isPlayerControlled() && command.m_characterAbility.size() && !hasCommand(command.m_characterAbility)) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to ability %s", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str(), - command.m_characterAbility.c_str())); - } - status = Command::CEC_Ability; - } - // target verification - don't execute the command if a target is - // required and none is present, or if there is never a target and - // one is specified - else if ( (command.m_targetType == Command::CTT_None && targetId != NetworkId::cms_invalid) - || (command.m_targetType == Command::CTT_Required && targetId == NetworkId::cms_invalid)) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to target type", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str())); - } - status = Command::CEC_TargetType; - } - else - { - // target range checking - if (command.m_targetType != Command::CTT_None && targetId != NetworkId::cms_invalid && command.m_maxRangeToTargetSquared != 0.0f) - { - Object *targetObj = NetworkIdManager::getObjectById(targetId); - if (!targetObj) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to range to target", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str())); - } - status = Command::CEC_TargetRange; - } - else - { - TangibleObject const * const tangible = dynamic_cast(targetObj); - if(tangible) - { - float distance = this->getDistanceBetweenCollisionSpheres_w(*tangible); - distance = sqr(distance); - - if(distance > command.m_maxRangeToTargetSquared) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to range to target", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str())); - } - status = Command::CEC_TargetRange; - } - } - else - { - if(findPosition_w().magnitudeBetweenSquared(targetObj->findPosition_w()) > command.m_maxRangeToTargetSquared) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to range to target", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str())); - } - - status = Command::CEC_TargetRange; - } - - } - - } - - } - if (status == Command::CEC_Success) - { - // make sure that the command is allowed in all states set on the creature currently - for (States::Enumerator i = 0; i < States::NumberOfStates; ++i) - { - // @todo: don't gate npc command usage on swimming - if (!isPlayerControlled() && i == States::Swimming) - continue; - - if (getState(i) && !command.m_statePermissions[i]) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to state %d", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str(), - i)); - } - status = Command::CEC_StateMustNotHave; - statusDetail = i; - break; - } - - if (!getState(i) && command.m_stateRequired[i]) - { - if (ConfigServerGame::getLogAllCommands()) - { - LOG( - "Command", - ("%s>%s %s ignored due to missing required state %d", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str(), - i)); - } - status = Command::CEC_StateMustHave; - statusDetail = i; - break; - } - } - } - } - -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::isDisabled() const -{ - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - return TangibleObject::isDisabled (); - - return (isIncapacitated() || isDead()); -} - -// ------------------------------------------------------------------- - -bool CreatureObject::makeDead(const NetworkId & killer, const NetworkId & corpse) -{ - if (isAuthoritative()) - { - if (isDead()) - { - clearHateList(); - return true; - } - - ScriptParams params; - params.addParam(killer); - params.addParam(corpse); - if (getScriptObject()->trigAllScripts(Scripting::TRIG_DEATH, params) != SCRIPT_CONTINUE) - return false; - - clearHateList(); - - // if we are crafting, end the crafting session - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - if (player != NULL && player->isCrafting()) - player->stopCrafting(false); - - // if we are in a conversation, end it - if (isInNpcConversation()) - endNpcConversation(); - - // remove all attrib and skill mod mods - typedef Archive::AutoDeltaMap::const_iterator ModIter; - for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) - { - const CreatureMod & m = (*i).second; - - bool remove = true; - //check to see if this attribute mod comes from a buff that should not be removed on death - const char * rawModName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); - if(rawModName) - { - std::string tmpModName(rawModName); - - //strip the attribute number from the mod name to get the raw buff name - //this is a little fragile because we are looking up the name of the - //buff, trusting that the mod name will be based on it - //in BuffManager.cpp, attributes that are assigned by a buff have the - //mod name as ("%s_%d", buffname, effectNum) so we will check to see if - //the name matches that format and if the resulting buff name is flagged - //to not be removed on death. - int namelength = tmpModName.size(); - if(namelength > 2 && tmpModName[namelength-2] == '_' && tmpModName[namelength-1] >= '0' && tmpModName[namelength-1] <= '9') - { - std::string buffname = tmpModName.substr(0,namelength-2); - uint32 buffNameCrc = Crc::normalizeAndCalculate(buffname.c_str()); - remove = BuffManager::getIsBuffRemovedOnDeath(buffNameCrc); - - // Check to see if this is a Pvp related death and we should ignore the removal. - if(remove && BuffManager::getDoesBuffDecayOnPvPDeath(buffNameCrc)) // We only care about buffs that would normally be removed on death and have the decay flag. - { - Object * killerObj = NetworkIdManager::getObjectById(killer); - if(killerObj && killerObj->asServerObject() && killerObj->asServerObject()->asCreatureObject()) - { - CreatureObject * killerCreature = killerObj->asServerObject()->asCreatureObject(); - PlayerObject * const playerKiller = PlayerCreatureController::getPlayerObject(killerCreature); - if(playerKiller) - remove = false; // Buffs that decay on PvP death don't get removed on PvP death. - else if(killerCreature->getMasterId() != NetworkId::cms_invalid) // Check to see if this is some type of pet. - { - Object * masterObj = NetworkIdManager::getObjectById(killerCreature->getMasterId()); - if(masterObj && masterObj->asServerObject() && masterObj->asServerObject()->asCreatureObject()) - { - CreatureObject * masterCreature = masterObj->asServerObject()->asCreatureObject(); - PlayerObject * const masterPlayer = PlayerCreatureController::getPlayerObject(masterCreature); // Pet has a valid player as a master. Pvp related. - if(masterPlayer) - remove = false; - } - } - } - }// End PvP check - } - } - - if(remove) - { - if (AttribMod::isSkillMod(m.mod)) - { - const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); - if (skillModName != NULL) - addModValue(skillModName, -m.maxVal, true); - } - // if the mod is visible, we need to tell the player it's being - // removed - if (m.mod.flags & AttribMod::AMF_visible) - { - sendCancelTimedMod(m.mod.tag); - } - // if the mod is flagged as having a callback, call the script - if (m.mod.flags & AttribMod::AMF_triggerOnDone) - { - const char * modName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); - if (modName != NULL) - { - ScriptParams params; - params.addParam(modName); - params.addParam(true); - if (AttribMod::isAttribMod(m.mod)) - { - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_ATTRIB_MOD_DONE, params)); - } - else if (AttribMod::isSkillMod(m.mod)) - { - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_SKILL_MOD_DONE, params)); - } - - } - } - - i = m_attributeModList.erase(i); - } - else - { - ++i; - } - } - for (int j = 0; j < Attributes::NumberOfAttributes; ++j) - { - m_cachedCurrentAttributeModValues.set(j, 0); - m_cachedMaxAttributeModValues.set(j, 0); - } - computeTotalAttributes(); - - LOG("CustomerService", ("Attribs: removed all attrib and skillmod mods " - "from %s due to death.", - PlayerObject::getAccountDescription(this).c_str())); - - if (!isPlayerControlled()) - setDefaultAlterTime(AlterResult::cms_keepNoAlter); - - //-- If we're in combat, the client will take care of arranging for - // a suitable transition to the dead posture; otherwise, make it - // happen immediately. - setPosture(Postures::Dead, !isInCombat()); - } - else - { - sendControllerMessageToAuthServer(CM_makeDead, new MessageQueueGenericValueType< - std::pair >(std::make_pair(killer, corpse))); - } - return true; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::makeNotDead() -{ - if (!isDead()) - return true; - - if (!isPlayerControlled()) - setDefaultAlterTime(AlterResult::cms_alterQuickly); - - setPosture(Postures::Prone, true); - testIncapacitation(NetworkId::cms_invalid); - return true; -} - -//-------------------------------------------------------------------- - -Locomotions::Enumerator CreatureObject::calcLocomotion() const -{ - Locomotions::Enumerator ret = Locomotions::Invalid; - if (m_stopWalkRun.get() > 1) - ret = m_fastLocomotion; - if (ret == Locomotions::Invalid && m_stopWalkRun.get() > 0) - ret = m_slowLocomotion; - if (ret == Locomotions::Invalid) - ret = m_stationaryLocomotion; - return ret; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::canMove() const -{ - return getMovementTable()->hasMovingLocomotion(m_posture.get(), m_states.get()) && !getObjVars().hasItem("forceNoMovement"); -} - -//---------------------------------------------------------------------- - -void CreatureObject::setScaleFactor(float scale) -{ - if(isAuthoritative()) - { - scale = std::max (0.0f, scale); - m_scaleFactor = scale; - setScale (Vector::xyz111 * scale); - } - else - { - sendControllerMessageToAuthServer(CM_setScaleFactor, new MessageQueueGenericValueType(scale)); - } -} - -//---------------------------------------------------------------------- - -/** - * Gets the approximate height of the creature, modified by it's posture. - * - * @return the creature's height - */ -float CreatureObject::getHeight() const -{ - float height = TangibleObject::getHeight(); - height *= getMovementTable()->getCanSeeHeightMod(m_posture.get(), m_states.get()); - - return height; -} // CreatureObject::getHeight - -//---------------------------------------------------------------------- - -/** - * Gets the approximate radius of the object. - * - * @return the object's radius - */ -float CreatureObject::getRadius() const -{ - const SharedCreatureObjectTemplate * myTemplate = safe_cast(getSharedTemplate()); - return myTemplate->getCollisionRadius() * std::max(getScale().x, getScale().z); -} // CreatureObject::getHeight - -//---------------------------------------------------------------------- - -Object const * CreatureObject::getStandingOn() const -{ - CollisionProperty const * collision = getCollisionProperty(); - - if(collision) - { - return collision->getStandingOn(); - } - else - { - return NULL; - } -} - -//---------------------------------------------------------------------- - -float CreatureObject::getFarNetworkUpdateRadius() const -{ - if (ServerWorld::getSceneId() == NewbieTutorial::getSceneId()) - return 0.f; - - float height = TangibleObject::getHeight(); - float radius; - - if (height < ConfigServerGame::getMaxSmallCreatureHeight()) - radius = ConfigServerGame::getSmallCreatureUpdateRadius(); - else if (height < ConfigServerGame::getMaxMediumCreatureHeight()) - radius = ConfigServerGame::getMediumCreatureUpdateRadius(); - else - radius = ConfigServerGame::getLargeCreatureUpdateRadius(); - - return radius; -} - -//---------------------------------------------------------------------- - -void CreatureObject::setShockWounds(int wound) -{ -static const StringId SHOCK_WOUND_ID("cbt_spam", "shock_wound"); - - if(isAuthoritative()) - { - // Use TangibleObject::isInvulnerable so we don't account for the invulnerability timer - if (TangibleObject::isInvulnerable()) - return; - - if (wound < 0) - wound = 0; - else if (wound > 1000) - wound = 1000; - if (wound != m_shockWounds.get()) - { - if (isInCombat()) - { - ProsePackage pp; - pp.stringId = SHOCK_WOUND_ID; - pp.digitInteger = wound - m_shockWounds.get(); - Unicode::String oob; - OutOfBandPackager::pack(pp, 0, oob); - MessageQueueCombatSpam spam(oob, false, false, false, 1); - performCombatSpam (spam, true, false, false); - } - m_shockWounds = wound; - } - } - else - { - sendControllerMessageToAuthServer(CM_setShockWounds, new MessageQueueGenericValueType(wound)); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setLookAtTarget(const NetworkId& id) -{ - if(isAuthoritative()) - { - m_lookAtTarget.set(id); - } - else - { - sendControllerMessageToAuthServer(CM_setLookAtTarget, new MessageQueueGenericValueType(id)); - } - - ShipObject * const ship = getPilotedShip(); - if(ship) - { - ship->setLookAtTargetFromPilot(id); - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::setIntendedTarget(const NetworkId& id) -{ - if(isAuthoritative()) - { - DEBUG_WARNING(true, ("CreatureObject::setIntendedTarget: '%s'", id.getValueString().c_str())); - m_intendedTarget.set(id); - } - else - { - sendControllerMessageToAuthServer(CM_setIntendedTarget, new MessageQueueGenericValueType(id)); - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::setMovementStationary() -{ - if (isAuthoritative()) - m_stopWalkRun = 0; -} - -//----------------------------------------------------------------------- - -void CreatureObject::setMovementWalk() -{ - if (isAuthoritative()) - m_stopWalkRun = 1; -} - -//----------------------------------------------------------------------- - -void CreatureObject::setMovementRun() -{ - if (isAuthoritative()) - m_stopWalkRun = 2; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::setSlopeModAngle(float angle) -{ - if(isAuthoritative()) - { - m_slopeModAngle = angle; - } - else - { - sendControllerMessageToAuthServer(CM_setSlopeModAngle, new MessageQueueGenericValueType(angle)); - } - return true; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::setSlopeModPercent(float percent) -{ - if(isAuthoritative()) - { - if (percent < 0.0f) - percent = 0.0f; - else if (percent > 1.0f) - percent = 1.0f; - m_baseSlopeModPercent = percent; - - // - // modify the percent reduced due to skill mods - // - - // get my skill mod - int movementMod = getEnhancedModValue(SLOPE_MOD); - if (getGroup() != NULL) - { - // get my group leader skill mod - const NetworkId & leaderId = getGroup()->getGroupLeaderId(); - if (leaderId != NetworkId::cms_invalid) - { - const CreatureObject * leader = safe_cast( - NetworkIdManager::getObjectById(leaderId)); - if (leader != NULL) - { - movementMod += leader->getEnhancedModValue(GROUP_SLOPE_MOD); - } - } - } - if (movementMod > 100) - movementMod = 100; - - switch (getPosture()) - { - case Postures::Upright: - if (movementMod > 50) - movementMod = 50; - if (movementMod > 0 && percent < 1.0f) - { - percent += (1.0f - percent) * ((float)movementMod / 50.0f); - } - break; - case Postures::Prone: - case Postures::Sneaking: -// movementMod -= 50; -// if (movementMod > 0 && percent < 1.0f) -// { -// percent += (1.0f - percent) * ((float)movementMod / 50.0f); -// } -// break; - case Postures::Crouched: - case Postures::Blocking: - case Postures::Climbing: - case Postures::Flying: - case Postures::LyingDown: - case Postures::Sitting: - case Postures::SkillAnimating: - case Postures::DrivingVehicle: - case Postures::RidingCreature: - case Postures::KnockedDown: - case Postures::Incapacitated: - case Postures::Dead: - default: - break; - } - - m_slopeModPercent = percent; - } - else - { - sendControllerMessageToAuthServer(CM_setSlopeModPercent, new MessageQueueGenericValueType(percent)); - } - return true; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::setWaterModPercent(float percent) -{ - if(isAuthoritative()) - { - m_waterModPercent = percent; - } - else - { - sendControllerMessageToAuthServer(CM_setWaterModPercent, new MessageQueueGenericValueType(percent)); - } - return true; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::setMovementScale(float scale) -{ - if(isAuthoritative()) - { - m_movementScale = scale; - } - else - { - sendControllerMessageToAuthServer(CM_setMovementScale, new MessageQueueGenericValueType(scale)); - } - return true; -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::setMovementPercent(float percent) -{ - if(isAuthoritative()) - { - m_movementPercent = percent; - } - else - { - sendControllerMessageToAuthServer(CM_setMovementPercent, new MessageQueueGenericValueType(percent)); - } - return true; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::setTurnPercent(float percent) -{ - if(isAuthoritative()) - { - m_turnScale = percent; - } - else - { - sendControllerMessageToAuthServer(CM_setTurnPercent, new MessageQueueGenericValueType(percent)); - } - return true; -} - -//-------------------------------------------------------------------- - -bool CreatureObject::setAccelScale(float scale) -{ - if(isAuthoritative()) - { - m_accelScale = scale; - } - else - { - sendControllerMessageToAuthServer(CM_setAccelScale, new MessageQueueGenericValueType(scale)); - } - return true; -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::setAccelPercent(float percent) -{ - if(isAuthoritative()) - { - m_accelPercent = percent; - } - else - { - sendControllerMessageToAuthServer(CM_setAccelPercent, new MessageQueueGenericValueType(percent)); - } - return true; -} - -//-------------------------------------------------------------------- -/** - * Instruct the clients to display the visuals for having this creature - * sit on the specified chair-like target object in the specified position. - * - * For chairs, where there is only a single spot to sit in, the positionIndex - * should be zero. For couches where, theoretically, we could have multiple - * creatures sit, the value should represent the space in which the player - * is sitting. - * - * @param targetObjectId the network id for the object on which the creature - * will sit. - * @param positionIndex the 0-based index of the position of the chair-like object - * in which the creature will sit. Typically this will be zero. - */ -void CreatureObject::sitOnObject(NetworkId const &chairCellId, Vector const &chairPosition_p) -{ - if (isAuthoritative()) - { - // you can't sit on something in a different cell than you - if (ContainerInterface::getContainedByProperty(*this)->getContainedByNetworkId() != chairCellId) - return; - - //-- If the chair is more than the allowed distance away from the authoritative position for the creature, log the attempt and ignore. - Vector const creaturePosition_p = getPosition_p(); - float const separationSquared = creaturePosition_p.magnitudeBetweenSquared(chairPosition_p); - - if (separationSquared > MessageQueueSitOnObject::cs_maximumChairRangeSquared) - { - LOG("move_validation", ("CreatureObject::sitOnObject: object id=[%s] out of range for specified chair position, separation=[%.2f] meters.", getNetworkId().getValueString().c_str(), separationSquared)); - return; - } - - //-- Get the controller. - Controller * const controller = getController(); - NetworkController * const networkController = safe_cast(controller); - ServerController * const serverController = safe_cast(networkController); - NOT_NULL(serverController); - - // teleport the player to the chairs location - // orientation doesn't matter in this case - Transform transform; - transform.setPosition_p(chairPosition_p); - serverController->teleport(transform, ContainerInterface::getContainingCellObject(*this)); - - //-- Send the SitOnObject controller message to all clients. - serverController->appendMessage(CM_sitOnObject, 0.0f, new MessageQueueSitOnObject(chairCellId, chairPosition_p), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); - - //-- Set the server posture to sitting & set SittingInChair state. - setPosture(Postures::Sitting); - setState(States::SittingOnChair, true); - } - else - { - sendControllerMessageToAuthServer(CM_sitOnObject, new MessageQueueSitOnObject(chairCellId, chairPosition_p)); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::onBiographyRetrieved(const NetworkId &owner, const Unicode::String &bio) -{ - //TODO: Biography handling code - //DEBUG_REPORT_LOG(true,("Biography for object %s received: %s\n",owner.getValueString().c_str(), Unicode::wideToNarrow(bio).c_str())); - - CreatureController *creatureController = getCreatureController(); - - if (creatureController != NULL) - { - typedef std::pair Payload; - - MessageQueueGenericValueType * const msg = new MessageQueueGenericValueType(Payload(owner, bio)); - - creatureController->appendMessage(static_cast(CM_biographyRetrieved), 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::onCharacterMatchRetrieved(MatchMakingCharacterResult const &results) -{ - CreatureController *creatureController = getCreatureController(); - - if (creatureController != NULL) - { - typedef std::pair Payload; - - MessageQueueGenericValueType * const msg = new MessageQueueGenericValueType(results); - - creatureController->appendMessage(static_cast(CM_characterMatchRetrieved), 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::setLocomotion(Locomotions::Enumerator posture) -{ - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_setLocomotion, new MessageQueueGenericValueType(posture)); - } - else - { - Postures::Enumerator newPosture; - MovementTable::eLocomotionSpeed speed = getMovementTable()->getLocomotionData(posture, newPosture); - if (speed != MovementTable::kInvalid) - { - setPosture(newPosture); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::speakText(MessageQueueSpatialChat const &spatialChat) -{ - // a speech type may only be used if it either has no skills listed as providing it, or the creature has - // at least one of the skills listed. - - std::vector const &skillsProviding = SpatialChatManager::getSkillsProviding(spatialChat.getChatType()); - if (!skillsProviding.empty()) - { - bool found = false; - for (std::vector::const_iterator i = skillsProviding.begin(); i != skillsProviding.end(); ++i) - { - if (hasCommand(*i)) - { - found = true; - break; - } - } - if (!found) - return; - } - - TangibleObject::speakText(spatialChat); -} - -// ---------------------------------------------------------------------- - -int CreatureObject::getPerformanceType() const -{ - return m_performanceType.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setPerformanceType(int performanceType) -{ - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(performanceType); - controller->appendMessage( - CM_setPerformanceType, - 0.0f, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - } - else - { - m_performanceType = performanceType; - } -} - -// ---------------------------------------------------------------------- - -int CreatureObject::getPerformanceStartTime() const -{ - return m_performanceStartTime.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setPerformanceStartTime(int performanceStartTime) -{ - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(performanceStartTime); - controller->appendMessage( - CM_setPerformanceStartTime, - 0.0f, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - } - else - { - m_performanceStartTime = performanceStartTime; - } -} - -// ---------------------------------------------------------------------- - -NetworkId const &CreatureObject::getPerformanceListenTarget() const -{ - return m_performanceListenTarget.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setPerformanceListenTarget(NetworkId const &who) -{ - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(who); - controller->appendMessage( - CM_setPerformanceListenTarget, - 0.0f, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - } - else - { - m_performanceListenTarget = who; - } -} - -// ---------------------------------------------------------------------- - -NetworkId const &CreatureObject::getPerformanceWatchTarget() const -{ - return m_performanceWatchTarget.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setPerformanceWatchTarget(NetworkId const &who) -{ - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(who); - controller->appendMessage( - CM_setPerformanceWatchTarget, - 0.0f, - msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - } - else - { - m_performanceWatchTarget = who; - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::setGuildId(int guildId) -{ - FATAL(!isAuthoritative(), ("setGuildId called on nonauthoritative object")); - int oldGuildId = getGuildId(); - if (oldGuildId != guildId) - { - if (oldGuildId) - GuildInterface::onAboutToClearGuildId(*this); - m_guildId = guildId; - } - if (guildId) - GuildInterface::onGuildIdSet(*this); -} - -//----------------------------------------------------------------------- - -void CreatureObject::setTimeToUpdateGuildWarPvpStatus(unsigned long timeToUpdateGuildWarPvpStatus) -{ - FATAL(!isAuthoritative(), ("setTimeToUpdateGuildWarPvpStatus called on nonauthoritative object")); - m_timeToUpdateGuildWarPvpStatus = timeToUpdateGuildWarPvpStatus; -} - -//----------------------------------------------------------------------- - -void CreatureObject::setGuildWarEnabled(bool guildWarEnabled) -{ - FATAL(!isAuthoritative(), ("setGuildWarEnabled called on nonauthoritative object")); - m_guildWarEnabled = guildWarEnabled; - m_timeToUpdateGuildWarPvpStatus = 0; -} - -// ---------------------------------------------------------------------- - -int CreatureObject::getMilitiaOfCityId() const -{ - return m_militiaOfCityId.get(); -} - -//----------------------------------------------------------------------- - -void CreatureObject::setMilitiaOfCityId(int cityId) -{ - FATAL(!isAuthoritative(), ("setMilitiaOfCityId called on nonauthoritative object")); - m_militiaOfCityId = cityId; -} - -// ---------------------------------------------------------------------- - -int CreatureObject::getLocatedInCityId() const -{ - return m_locatedInCityId.get(); -} - -//----------------------------------------------------------------------- - -void CreatureObject::setLocatedInCityId(int newCityId) -{ - FATAL(!isAuthoritative(), ("setLocatedInCityId called on nonauthoritative object")); - int oldCityId = m_locatedInCityId.get(); - if (oldCityId != newCityId) - { - m_locatedInCityId.set(newCityId); - if (getScriptObject()) - { - ScriptParams params; - params.addParam(oldCityId); - params.addParam(newCityId); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_CITY_CHANGED, params)); - } - } -} - -// ---------------------------------------------------------------------- - -NetworkId const &CreatureObject::getMasterId() const -{ - return m_masterId.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setMasterId(NetworkId const &masterId) -{ - if (isAuthoritative()) - m_masterId = masterId; - else - sendControllerMessageToAuthServer(CM_setMasterId, new MessageQueueGenericValueType(masterId)); -} - -// ---------------------------------------------------------------------- - -float CreatureObject::getSwimHeight() const -{ - return safe_cast(getSharedTemplate())->getSwimHeight() * getScaleFactor(); -} - -//----------------------------------------------------------------------- - -const CreatureObject::AllCreaturesSet & CreatureObject::getAllCreatures() -{ - return g_creatureList; -} - -//----------------------------------------------------------------------- - -void CreatureObject::addToMissionRequestQueue(const NetworkId & terminalId) -{ - if (!ConfigServerGame::getDisableMissions()) - { - std::vector >::const_iterator f = std::find(gs_missionRequestQueue.begin(), gs_missionRequestQueue.end(), std::make_pair(this, terminalId)); - if(f == gs_missionRequestQueue.end()) - { - gs_missionRequestQueue.push_back(std::make_pair(this, terminalId)); - } - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::removeFromMissionRequestQueue(const NetworkId & creatureId) -{ - CreatureObject * creature = safe_cast(NetworkIdManager::getObjectById(creatureId)); - if (creature) - { - removeCreatureFromMissionRequestQueue(creature); - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::updateMissionRequestQueue() -{ - if(! gs_missionRequestQueue.empty()) - { - // remove pending creatures from previous run - std::vector >::const_iterator remIter; - std::vector >::iterator i; - for(remIter = gs_missionRequestQueueDeferredRemoves.begin(); remIter != gs_missionRequestQueueDeferredRemoves.end(); ++remIter) - { - for(i = gs_missionRequestQueue.begin(); i != gs_missionRequestQueue.end(); ++i) - { - if((*i).first == (*remIter).first) - { - gs_missionRequestQueue.erase(i); - break; - } - } - } - - gs_missionRequestQueueDeferredRemoves.clear(); - int count = 0; - - for(i = gs_missionRequestQueue.begin(); i != gs_missionRequestQueue.end(); ++i) - { - CreatureObject * creature = (*i).first; - - // if a delete happened while processing the queue, find the - // creature in the defferred deleted queue. If it's there, skip this - // creature and move on to the next - if(! gs_missionRequestQueueDeferredRemoves.empty()) - { - // is this creature in the queue? - remIter = std::find(gs_missionRequestQueueDeferredRemoves.begin(), gs_missionRequestQueueDeferredRemoves.end(), std::make_pair(creature, (*i).second)); - if(remIter != gs_missionRequestQueueDeferredRemoves.end()) - continue; - } - - // build vector of network ids for all mission objects in the mission bag - ServerObject * missionBag = creature->getMissionBag(); - if(missionBag) - { - static std::vector missionObjects; - - Container * container = ContainerInterface::getContainer(*missionBag); - ContainerIterator iter; - for(iter = container->begin(); iter != container->end(); ++iter) - { - MissionObject * missionObject = safe_cast((*iter).getObject()); - if(missionObject) - { - missionObjects.push_back(missionObject->getNetworkId()); - } - } - - ScriptParams p; - p.addParam(creature->getNetworkId()); - p.addParam((*i).second); - p.addParam(missionObjects); - GameScriptObject * script = creature->getScriptObject(); - if(script) - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_PLAYER_REQUEST_MISSION_BOARD, p)); - removeCreatureFromMissionRequestQueue(creature); - missionObjects.clear(); - } - ++count; - if (count >= ConfigServerGame::getMissionRequestsPerFrame()) - { - break; - } - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::getAttributes(stdvector >::fwd &data) const -{ - TangibleObject::getAttributes(data); -} - -//----------------------------------------------------------------------- - -bool CreatureObject::isAppearanceEquippable(const char *appearanceTemplateName) -{ - // Returns whether an object template is wearable based on the data in the - // appearance_table.tab - - bool result = true; - - // Make sure this object has a valid appearance - - if (appearanceTemplateName == NULL) - { - result = false; - } - else - { - // Check to see if we even care about the creature object depending - // on its gender/species combination - - SharedCreatureObjectTemplate::Species species = getSpecies(); - SharedCreatureObjectTemplate::Gender gender = getGender(); - - int column = -1; - - // Get the species index - - switch (species) - { - case SharedCreatureObjectTemplate::SP_human: { column = 1; } break; - case SharedCreatureObjectTemplate::SP_rodian: { column = 3; } break; - case SharedCreatureObjectTemplate::SP_monCalamari: { column = 5; } break; - case SharedCreatureObjectTemplate::SP_wookiee: { column = 7; } break; - case SharedCreatureObjectTemplate::SP_twilek: { column = 9; } break; - case SharedCreatureObjectTemplate::SP_trandoshan: { column = 11; } break; - case SharedCreatureObjectTemplate::SP_zabrak: { column = 13; } break; - case SharedCreatureObjectTemplate::SP_bothan: { column = 15; } break; - case SharedCreatureObjectTemplate::SP_ithorian: { column = 17; } break; - case SharedCreatureObjectTemplate::SP_sullustan: { column = 19; } break; - default: { } break; - } - - // Add in the gender index - - switch (gender) - { - case SharedCreatureObjectTemplate::GE_male: { } break; - case SharedCreatureObjectTemplate::GE_female: { column += 1; } break; - default: { } break; - } - - if (column > 0) - { - // If the object template is in the list, then check if it is equippable, otherwise - // there is no restriction so the item must be equippable - - std::string objectTemplateName(appearanceTemplateName); - - if (!objectTemplateName.empty()) - { - // Strip out just the object template name - - size_t const slashIndex = objectTemplateName.rfind('/'); - size_t const dotIndex = objectTemplateName.rfind('.'); - - std::string fileName; - - if (slashIndex == std::string::npos) - { - fileName = objectTemplateName.substr(0, dotIndex); - } - else if (dotIndex == std::string::npos) - { - fileName = objectTemplateName.substr(slashIndex + 1); - } - else - { - fileName = objectTemplateName.substr(slashIndex + 1, dotIndex - slashIndex - 1); - } - - if (AppearanceManager::isAppearanceManaged(fileName)) - { - // A ':block' token in the data table denotes the item is not equippable - - std::string destAppearancePath; - - AppearanceManager::getAppearanceName(destAppearancePath, fileName, column); - - static const std::string tagBlock = ":block"; - - if (destAppearancePath == tagBlock) - { - result = false; - } - } - } - } - } - - return result; -} - -// ---------------------------------------------------------------------- - -/** - * Sends a message to the Planet Server to update the position of the object. - */ -void CreatureObject::updatePlanetServerInternal(const bool forceUpdate) const -{ - if (forceUpdate || getPositionChanged()) - { - // If this is a mount with a rider on it, use the larger of the rider and mount's - // interest radius for the mount. This allows the planet server to update nodes - // marked for proxy subscription properly. Otherwise we'll get a destroy proxy - // for the mount the first time it moves into a node that hasn't yet been subscribed, - // immediately followed by a create proxy message for the mount when the rider's - // position gets updated. - - int effectiveInterestRadius = getInterestRadius(); - if (getState(States::MountedCreature)) - { - CreatureObject const *const rider = getPrimaryMountingRider(); - if (rider) - effectiveInterestRadius = std::max(rider->getInterestRadius(), getInterestRadius()); - } - - if (!ContainerInterface::getContainedByObject(*this) || (effectiveInterestRadius > 0)) - { - bool hibernating = false; - if(getCreatureController()) - hibernating = getCreatureController()->getHibernate(); - - AICreatureController const * const aiCreatureController = dynamic_cast(getCreatureController()); - - Object const * const topmostContainer = ContainerInterface::getTopmostContainer(*this); - FATAL(!topmostContainer, ("Object %s was contained by something, but getTopmostContainer() returned NULL", getNetworkId().getValueString().c_str())); - Vector const &position = topmostContainer->getPosition_p(); - UpdateObjectOnPlanetMessage const msg( - getNetworkId(), - topmostContainer == this ? NetworkId::cms_invalid : topmostContainer->getNetworkId(), - static_cast(position.x), - static_cast(position.y), - static_cast(position.z), - effectiveInterestRadius, - static_cast(getLocationReservationRadius()), - false, - true, - static_cast(getObjectType()), - static_cast(getLevel()), - hibernating, - getTemplateCrc(), - aiCreatureController ? aiCreatureController->getMovementType() : -1, - getIsStatic() == true ? 1 : 0); - GameServer::getInstance().sendToPlanetServer(msg); - } - } -} - -// ---------------------------------------------------------------------- - -int CreatureObject::getCurrentTargetsTotal(const std::map & targets) -{ - int sum = 0; - for(std::map::const_iterator i = targets.begin(); i != targets.end(); ++i) - { - sum += i->second; - } - return sum; -} - -// ====================================================================== - -ServerObject *CreatureObject::getMissionBag() const -{ - SlottedContainer const * const s = ContainerInterface::getSlottedContainer(*this); - if (s) - { - static SlotId const bankId = SlotIdManager::findSlotId(MISSION_BAG_SLOT_NAME); - Container::ContainerErrorCode tmp = Container::CEC_Success; - Object * const o = s->getObjectInSlot(bankId, tmp).getObject(); - if (o) - return o->asServerObject(); - } - return 0; -} - -// ====================================================================== - -ServerObject *CreatureObject::getBankContainer() const -{ - return const_cast(this)->getBank (); -} - -// ====================================================================== - -namespace PlayerBanks -{ - const static Unicode::String invalidBankName = - Unicode::narrowToWide("INVALID_BANK_NAME"); -} - -//---------------------------------------------------------------------- - -Unicode::String CreatureObject::getBankName() const -{ - Unicode::String bankName = PlayerBanks::invalidBankName; - getObjVars().getItem(OBJVAR_BANK_ID,bankName); - return bankName; -} - -// ====================================================================== - -bool CreatureObject::isBankMember(Unicode::String bankName) const -{ - return (bankName.compare(getBankName()) == 0); -} - -// ====================================================================== - -bool CreatureObject::joinBank(Unicode::String bankName) -{ - if (getBankName() == bankName) - { - StringId message("system_msg", "already_member_of_bank"); - Unicode::String outOfBand; - Chat::sendSystemMessage(*this, message, outOfBand); - return false; - } - if (getBankName() != PlayerBanks::invalidBankName) - { - StringId message("system_msg", "member_of_different_bank"); - Unicode::String outOfBand; - Chat::sendSystemMessage(*this, message, outOfBand); - return false; - } - StringId message("system_msg", "succesfully_joined_bank"); - Unicode::String outOfBand; - Chat::sendSystemMessage(*this, message, outOfBand); -// printf("Setting item (%s) on objvars (%x)\n", OBJVAR_BANK_ID.c_str(), (int)objVars); - setObjVarItem(OBJVAR_BANK_ID, bankName); - /*DynamicVariable *objvar = objVars->getItemByName(OBJVAR_BANK_ID); - if (objvar) - { - DynamicVariableString *stringVar = dynamic_cast(objvar); - stringVar->setValue(bankName); - }*/ - return true; -} - -// ====================================================================== - -void CreatureObject::quitBank() -{ - ServerObject *bankContainer = getBankContainer(); - if (bankContainer) - { - Container *container = ContainerInterface::getContainer(*bankContainer); - if (container->getNumberOfItems() != 0) - { - //Can't quit bank, you still have items in it - StringId message("system_msg", "bank_not_empty"); - Unicode::String outOfBand; - Chat::sendSystemMessage(*this, message, outOfBand); - return; - } - } - StringId message("system_msg", "succesfully_quit_bank"); - Unicode::String outOfBand; - Chat::sendSystemMessage(*this, message, outOfBand); - setObjVarItem(OBJVAR_BANK_ID, PlayerBanks::invalidBankName); - /*DynamicVariable *objvar = objVars->getItemByName(OBJVAR_BANK_ID); - if (objvar) - { - DynamicVariableString *stringVar = dynamic_cast(objvar); - stringVar->setValue(PlayerBanks::invalidBankName); - }*/ - setObjVarItem(OBJVAR_OPEN_BANK_TERMINAL_ID, NetworkId::cms_invalid); - if (bankContainer) - { - ScriptParams params; - params.addParam(getNetworkId()); - IGNORE_RETURN (bankContainer->getScriptObject()->trigAllScripts(Scripting::TRIG_CLOSED_CONTAINER, params)) - ; - Client *client = getClient(); - if (client) - { - GenericValueTypeMessage m("ClosedContainerMessage", bankContainer->getNetworkId()); - client->send(m, true); - ObserveTracker::onClientClosedContainer(*client, *bankContainer); - } - } -} - -// ---------------------------------------------------------------------- - -float CreatureObject::getInvulnerabilityTimer() const -{ - return m_invulnerabilityTimer.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setInvulnerabilityTimer(float duration) -{ - if (isAuthoritative()) - { - DEBUG_REPORT_LOG(true, ("Setting creature invulnerability timer for %s to %g\n", getDebugInformation().c_str(), duration)); - m_invulnerabilityTimer = duration; - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::isInvulnerable() const -{ - if (m_invulnerabilityTimer.get() > 0.f) - return true; - return TangibleObject::isInvulnerable(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::handleCMessageTo(MessageToPayload const &message) -{ - if (message.getMethod() == "C++RenameFailed") - { - std::string reason(message.getDataAsString()); - if (reason.empty()) - reason = "Rename request failed."; - - Chat::sendSystemMessage(*this,Unicode::narrowToWide(reason),Unicode::String()); - } - else if ((message.getMethod() == "C++PlayerRenameRequestSubmitted") || (message.getMethod() == "C++PlayerLastNameRenameRequestSubmitted")) - { - // set objvar to indicate there's a pending rename request for this character, - // and the time of the rename request, to enforce the 90 days wait between rename - if (!getClient() || !getClient()->isGod()) - setObjVarItem("renameCharacterRequest.requestTime", static_cast(::time(NULL))); - - std::string const newName(message.getDataAsString()); - if (getObjVars().hasItem("renameCharacterRequest.requestTime") && !newName.empty()) - { - setObjVarItem("renameCharacterRequest.requestNewName", newName); - } - - // for player requested rename, send message to CentralServer to drop the character, - // and prevent the character from further login until the rename request has been completed - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - GenericValueTypeMessage > > > const msg("PlayerRenameRequestSubmitted", std::make_pair(static_cast(playerObject->getStationId()), std::make_pair(getNetworkId(), std::make_pair(newName, (message.getMethod() == "C++PlayerLastNameRenameRequestSubmitted"))))); - GameServer::getInstance().sendToCentralServer(msg); - } - } - else if (message.getMethod() == "C++GmRenameRequestSubmitted") - { - std::string reason(message.getDataAsString()); - if (reason.empty()) - reason = "Rename request submitted."; - - Chat::sendSystemMessage(*this,Unicode::narrowToWide(reason),Unicode::String()); - } - else if (message.getMethod() == "C++experience") - { - std::vector const & packedData = message.getPackedDataVector(); - std::vector::const_iterator spacePos = std::find(packedData.begin(), packedData.end(), ' '); - if (spacePos != packedData.end()) - { - int amount = atoi(std::string(spacePos + 1, packedData.end()).c_str()); - grantExperiencePoints(std::string(packedData.begin(), spacePos), amount); - } - } - else if (message.getMethod() == "C++AddJediSlot") - { - // if we haven't received an addJediToAccountAck(), resend the Jedi request - if (!getObjVars().hasItem(OBJVAR_ADD_JEDI_ACK)) - { - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - if (player != NULL) - { - player->addJediToAccount(); - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++AddJediSlot", "", 5 * 60, true); - } - } - else - { - removeObjVarItem(OBJVAR_ADD_JEDI_ACK); - } - } - else if (message.getMethod() == "ClientMfdStatusUpdateMessage") - { - if (getClient() && isAuthoritative()) - { - if (!message.getPackedDataVector().empty()) - { - static Archive::ByteStream bs; - bs.clear(); - bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); - Archive::put(bs, message.getPackedDataVector()); - Archive::ReadIterator ri = bs.begin(); - ClientMfdStatusUpdateMessage mfdUpdate(ri); - getClient()->send(mfdUpdate, false); - } - } - } - else if (message.getMethod() == "FindFriend") - { - if (getClient() && isAuthoritative()) - { - if (!message.getPackedDataVector().empty()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - static Archive::ByteStream bs; - bs.clear(); - bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); - Archive::put(bs, message.getPackedDataVector()); - Archive::ReadIterator ri = bs.begin(); - NetworkId source; - std::string sourceName; - Archive::get(ri, source); - Archive::get(ri, sourceName); - playerObject->replyLocationToFriend(sourceName, source); - } - } - } - } - else if (message.getMethod() == "LocationToFriend") - { - if (getClient() && isAuthoritative()) - { - if (!message.getPackedDataVector().empty()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - static Archive::ByteStream bs; - bs.clear(); - bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); - Archive::put(bs, message.getPackedDataVector()); - Archive::ReadIterator ri = bs.begin(); - Location friendLocation; - NetworkId friendId; - Archive::get(ri, friendLocation); - Archive::get(ri, friendId); - playerObject->receiveLocationToFriend(friendId, friendLocation); - } - } - } - } - else if (message.getMethod() == "FailLocationToFriend") - { - if (getClient() && isAuthoritative()) - { - if (!message.getPackedDataVector().empty()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - static Archive::ByteStream bs; - bs.clear(); - bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); - Archive::put(bs, message.getPackedDataVector()); - Archive::ReadIterator ri = bs.begin(); - NetworkId friendId; - Archive::get(ri, friendId); - playerObject->receiveFailLocationToFriend(friendId); - } - } - } - } - else if (message.getMethod() == "C++TheaterDestroyed") - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - playerObject->handleCMessageTo(message); - } - } - else if (message.getMethod() == "C++RemovePetFromGroup") - { - if (!message.getPackedDataVector().empty()) - { - std::string packedData(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - - // Parse the info from the message - char petNetworkIdBuffer[100]; - unsigned msgSendCount; - sscanf(packedData.c_str(), "%s %u", petNetworkIdBuffer, &msgSendCount); - - // Turn the string into a network Id - NetworkId petNetworkId( petNetworkIdBuffer ); - - // Try to remove the pet from the group - GroupObject *group = getGroup(); - if (group && group->isGroupMember(petNetworkId)) - { - group->removeGroupMember(petNetworkId); - } - else - { - // We will only try to remove the pet so many times... - if (msgSendCount < MAX_ATTEMPTS_TO_REMOVE_PET_FROM_GROUP) - { - // We will try again in the future... - ++msgSendCount; - - // We need to tell the network ID of the pet and we need to keep - // of how many times this message has been sent to the inviter - char msgBuffer[100]; - sprintf( msgBuffer, "%s %u", petNetworkId.getValueString().c_str(), msgSendCount ); - - // Send the message with a delay - MessageToQueue::getInstance().sendMessageToC( getNetworkId(), - "C++RemovePetFromGroup", - msgBuffer, - TIME_BETWEEN_ATTEMPTS_TO_REMOVE_PET, - false ); // reliable - } - } - } - } - else if (message.getMethod() == "C++WaitForPatrolPreload") - { - if (ServerWorld::isPreloadComplete()) - { - DEBUG_REPORT_LOG(ConfigServerGame::isAiLoggingEnabled(),("C++WaitForPatrolPreload being handled for %s\n", getNetworkId().getValueString().c_str())); - - MessageToQueue::cancelRecurringMessageTo(getNetworkId(), "C++WaitForPatrolPreload"); - - AICreatureController * const aiCreatureController = safe_cast(getController()); - if (aiCreatureController != NULL) - { - const std::string data = message.getDataAsString(); - std::string::size_type locationStart = 0; - std::string::size_type locationEnd = data.find('|', locationStart); - std::vector locations; - while (locationEnd != std::string::npos) - { - locations.push_back(Unicode::narrowToWide(data.substr(locationStart, locationEnd - locationStart))); - locationStart = locationEnd + 1; - locationEnd = data.find('|', locationStart); - } - - bool random = false; - bool flip = false; - bool repeat = false; - - if (data.size() > (locationStart+2)) - { - random = data.at(locationStart++) != '0'; - flip = data.at(locationStart++) != '0'; - repeat = data.at(locationStart++) != '0'; - } - int startPoint = 0; - if (data.size() > locationStart && data.at(locationStart) == '*') - { - ++locationStart; - startPoint = atoi(data.substr(locationStart).c_str()); - } - - aiCreatureController->patrol(locations, random, flip, repeat, startPoint); - } - } - } - else if (message.getMethod() == "C++WarnAboutVendorPurge") - { - LOG("CustomerService",("Purge: Sending warning emails to the owner (%s) of vendor (%s) effected by a purge",getNetworkId().getValueString().c_str(),message.getDataAsString().c_str())); - - const StringId subject("player_structure", "vendor_purge_warning_subject"); - const StringId body("player_structure", "vendor_purge_warning_body"); - const Unicode::String mail_subject = Unicode::narrowToWide("@" + subject.getCanonicalRepresentation()); - const Unicode::String mail_body = Unicode::narrowToWide("@" + body.getCanonicalRepresentation()); - - ProsePackage pp; - pp.stringId = body; - pp.other.str = Unicode::narrowToWide(message.getDataAsString()); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("Galactic Housing Authority", Unicode::wideToNarrow(getObjectName()), - mail_subject, Unicode::emptyString, oob); - } - else if (message.getMethod() == "C++CheckCharacterTitle") - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject && !playerObject->getTitle().empty()) - { - static uint32 const commandHash = Crc::normalizeAndCalculate("setCurrentSkillTitle"); - const Command &command = CommandTable::getCommand(static_cast(commandHash)); - if (!command.isNull()) - { - commandQueueEnqueue(command, NetworkId::cms_invalid, Unicode::narrowToWide(playerObject->getTitle()), 0, false); - } - } - } - else if (message.getMethod() == "C++CharacterSheetInfoResidenceLocationRsp") - { - if (!message.getPackedDataVector().empty()) - { - // location of residence - std::string const residenceLoc(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - - // get the city(ies) this character is a citizen of - std::string citizensOf; - std::vector const & cityId = CityInterface::getCitizenOfCityId(getNetworkId()); - if (!cityId.empty()) - { - std::string cityName; - for (std::vector::const_iterator iterCity = cityId.begin(); iterCity != cityId.end(); ++iterCity) - { - CityInfo const & cityInfo = CityInterface::getCityInfo(*iterCity); - cityName = cityInfo.getCityName(); - if (cityName.empty()) - continue; - - if (!citizensOf.empty()) - citizensOf += ","; - - if (getNetworkId() == cityInfo.getLeaderId()) - citizensOf += "*"; - - citizensOf += cityName; - } - } - - // send to client - GenericValueTypeMessage > message("CharacterSheetResponseResLoc", std::make_pair(residenceLoc, citizensOf)); - Client * const client = getClient(); - if (client) - client->send(message, true); - } - } - else if (message.getMethod() == "C++SpammerReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - std::string::size_type const pos = params.find(' '); - if ((pos != std::string::npos) && (params.size() > (pos + 1))) - { - NetworkId const actor(params.substr(0, pos)); - std::string const actorName(params.substr(pos + 1)); - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - bool canSpammer = true; - - // on a session-authenticated cluster, cannot /spammer a secured login character - if (getClient() && getClient()->isGodValidated()) - { - if (!ConfigServerGame::getAdminGodToAll() && !ConfigServerGame::getEnableWardenCanSquelchSecuredLogin()) - { - canSpammer = false; - } - } - - // cannot /spammer self - if (canSpammer && (actor == getNetworkId())) - { - canSpammer = false; - } - - // cannot /spammer a target that is already squelched - if (canSpammer && (playerObject->getSecondsUntilUnsquelched() != 0)) - { - canSpammer = false; - } - - if (!canSpammer) - { - MessageToQueue::getInstance().sendMessageToC(actor, - "C++SpammerRspCannotSpammerTarget", - Unicode::wideToNarrow(getAssignedObjectName()), - 0, - false); - } - else - { - // do it - playerObject->squelch(actor, actorName, ConfigServerGame::getWardenSquelchDurationSeconds()); - - std::string result = getNetworkId().getValueString(); - result += "|"; - result += Unicode::wideToNarrow(getAssignedObjectName()); - result += "|"; - result += playerObject->getAccountDescription(); - - MessageToQueue::getInstance().sendMessageToC(actor, - "C++SpammerRspSuccess", - result, - 0, - false); - } - } - else - { - MessageToQueue::getInstance().sendMessageToC(actor, - "C++SpammerRspInvalidTarget", - std::string(), - 0, - false); - } - } - } - } - else if (message.getMethod() == "C++SpammerRspTargetNotFound") - { - Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); - } - else if (message.getMethod() == "C++SpammerRspInvalidTarget") - { - Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); - } - else if (message.getMethod() == "C++SpammerRspCannotSpammerTarget") - { - if (!message.getPackedDataVector().empty()) - { - std::string const targetName(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "cannot_spammer_target"); - prosePackage.target.str = Unicode::narrowToWide(targetName); - Chat::sendSystemMessage(*this, prosePackage); - } - } - else if (message.getMethod() == "C++SpammerRspSuccess") - { - if (!message.getPackedDataVector().empty()) - { - std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - std::string::size_type const pos1 = result.find('|'); - if ((pos1 != std::string::npos) && (result.size() > (pos1 + 1))) - { - std::string::size_type const pos2 = result.find('|', (pos1 + 1)); - if ((pos2 != std::string::npos) && (result.size() > (pos2 + 1))) - { - NetworkId const target(result.substr(0, pos1)); - std::string const targetName(result.substr(pos1 + 1, pos2 - pos1 - 1)); - std::string const targetAccountDescription(result.substr(pos2 + 1)); - - // request /report - ReportManager::addReport(getAssignedObjectFirstName(), getNetworkId(), Unicode::narrowToWide(NameManager::normalizeName(targetName)), target, std::string("Warden")); - - // log it - LOG("CustomerService", ("Warden:%s has spammer %s", PlayerObject::getAccountDescription(this).c_str(), targetAccountDescription.c_str())); - - // display confirmation message - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "confirm_spammer"); - prosePackage.target.str = Unicode::narrowToWide(targetName); - Chat::sendSystemMessage(*this, prosePackage); - } - } - } - } - else if (message.getMethod() == "C++UnspammerReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - NetworkId const actor(params); - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - bool canUnspammer = true; - - // cannot /unspammer a target that is not currently /spammer(ed) - if (playerObject->getSecondsUntilUnsquelched() <= 0) - { - canUnspammer = false; - } - - // can only /unspammer target that was /spammer(ed) by the actor - if (canUnspammer && (playerObject->getSquelchedById() != actor)) - { - canUnspammer = false; - } - - if (!canUnspammer) - { - MessageToQueue::getInstance().sendMessageToC(actor, - "C++UnspammerRspCannotUnspammerTarget", - Unicode::wideToNarrow(getAssignedObjectName()), - 0, - false); - } - else - { - // do it - playerObject->unsquelch(); - - std::string result = Unicode::wideToNarrow(getAssignedObjectName()); - result += "|"; - result += playerObject->getAccountDescription(); - - MessageToQueue::getInstance().sendMessageToC(actor, - "C++UnspammerRspSuccess", - result, - 0, - false); - } - } - else - { - MessageToQueue::getInstance().sendMessageToC(actor, - "C++UnspammerRspInvalidTarget", - std::string(), - 0, - false); - } - } - } - else if (message.getMethod() == "C++UnspammerRspTargetNotFound") - { - Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); - } - else if (message.getMethod() == "C++UnspammerRspInvalidTarget") - { - Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); - } - else if (message.getMethod() == "C++UnspammerRspCannotUnspammerTarget") - { - if (!message.getPackedDataVector().empty()) - { - std::string const targetName(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "cannot_unspammer_target"); - prosePackage.target.str = Unicode::narrowToWide(targetName); - Chat::sendSystemMessage(*this, prosePackage); - } - } - else if (message.getMethod() == "C++UnspammerRspSuccess") - { - if (!message.getPackedDataVector().empty()) - { - std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - std::string::size_type const pos = result.find('|'); - if ((pos != std::string::npos) && (result.size() > (pos + 1))) - { - std::string const targetName(result.substr(0, pos)); - std::string const targetAccountDescription(result.substr(pos + 1)); - - // log it - LOG("CustomerService", ("Warden:%s has unspammer %s", PlayerObject::getAccountDescription(this).c_str(), targetAccountDescription.c_str())); - - // display confirmation message - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "confirm_unspammer"); - prosePackage.target.str = Unicode::narrowToWide(targetName); - Chat::sendSystemMessage(*this, prosePackage); - } - } - } - else if (message.getMethod() == "C++DeputizeWardenReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - NetworkId existingWarden; - StationId existingWardenStationId; - bool success = false; - - Unicode::String const delimiters(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector tokens; - if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 2)) - { - existingWarden = NetworkId(Unicode::wideToNarrow(tokens[0])); - - // quick way to convert a string to a uint32 - existingWardenStationId = static_cast(NetworkId(Unicode::wideToNarrow(tokens[1])).getValue()); - - if (existingWarden != getNetworkId()) - { - PlayerObject * po = PlayerCreatureController::getPlayerObject(this); - if (po && !po->isWarden() && (po->getStationId() == existingWardenStationId)) - { - // make warden - success = true; - po->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::Warden)); - - // send success message back to existing warden who deputized this warden - std::string result = Unicode::wideToNarrow(getAssignedObjectName()); - result += "|"; - result += po->getAccountDescription(); - - MessageToQueue::getInstance().sendMessageToC(existingWarden, - "C++DeputizeWardenRspSuccess", - result, - 0, - false); - } - } - } - - if (!success) - { - MessageToQueue::getInstance().sendMessageToC(existingWarden, - "C++DeputizeWardenRspCannotDeputize", - std::string(), - 0, - false); - } - } - } - else if (message.getMethod() == "C++DeputizeWardenRspSuccess") - { - if (!message.getPackedDataVector().empty()) - { - std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - std::string::size_type const pos = result.find('|'); - if ((pos != std::string::npos) && (result.size() > (pos + 1))) - { - std::string const newWardenName(result.substr(0, pos)); - std::string const newWardenAccountInfo(result.substr(pos + 1)); - - // log it - LOG("CustomerService", ("WardenPlayerDeputize:%s has deputized %s", PlayerObject::getAccountDescription(this).c_str(), newWardenAccountInfo.c_str())); - - // display confirmation message - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "confirm_deputize"); - prosePackage.target.str = Unicode::narrowToWide(newWardenName); - Chat::sendSystemMessage(*this, prosePackage); - } - } - } - else if (message.getMethod() == "C++DeputizeWardenRspCannotDeputize") - { - Chat::sendSystemMessage(*this, StringId("warden", "cannot_deputize"), Unicode::emptyString); - } - else if (message.getMethod() == "C++UndeputizeWardenReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - NetworkId existingWarden; - StationId existingWardenStationId; - bool success = false; - - Unicode::String const delimiters(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector tokens; - if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 2)) - { - existingWarden = NetworkId(Unicode::wideToNarrow(tokens[0])); - - // quick way to convert a string to a uint32 - existingWardenStationId = static_cast(NetworkId(Unicode::wideToNarrow(tokens[1])).getValue()); - - if (existingWarden != getNetworkId()) - { - PlayerObject * po = PlayerCreatureController::getPlayerObject(this); - if (po && po->isWarden() && (po->getStationId() == existingWardenStationId)) - { - // revoke warden - success = true; - po->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)); - - // send success message back to existing warden who undeputized this warden - std::string result = Unicode::wideToNarrow(getAssignedObjectName()); - result += "|"; - result += po->getAccountDescription(); - - MessageToQueue::getInstance().sendMessageToC(existingWarden, - "C++UndeputizeWardenRspSuccess", - result, - 0, - false); - } - } - } - - if (!success) - { - MessageToQueue::getInstance().sendMessageToC(existingWarden, - "C++UndeputizeWardenRspCannotUndeputize", - std::string(), - 0, - false); - } - } - } - else if (message.getMethod() == "C++UndeputizeWardenRspSuccess") - { - if (!message.getPackedDataVector().empty()) - { - std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - std::string::size_type const pos = result.find('|'); - if ((pos != std::string::npos) && (result.size() > (pos + 1))) - { - std::string const priorWardenName(result.substr(0, pos)); - std::string const pirorWardenAccountInfo(result.substr(pos + 1)); - - // log it - LOG("CustomerService", ("WardenPlayerUndeputize:%s has undeputized %s", PlayerObject::getAccountDescription(this).c_str(), pirorWardenAccountInfo.c_str())); - - // display confirmation message - ProsePackage prosePackage; - prosePackage.stringId = StringId("warden", "confirm_undeputize"); - prosePackage.target.str = Unicode::narrowToWide(priorWardenName); - Chat::sendSystemMessage(*this, prosePackage); - } - } - } - else if (message.getMethod() == "C++UndeputizeWardenRspCannotUndeputize") - { - Chat::sendSystemMessage(*this, StringId("warden", "cannot_undeputize"), Unicode::emptyString); - } - else if (message.getMethod() == "C++OnCollectionServerFirst") - { - if (!message.getPackedDataVector().empty()) - { - std::string const collectionName(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - CollectionsDataTable::CollectionInfoCollection const * const collectionInfo = CollectionsDataTable::getCollectionByName(collectionName); - if (collectionInfo && collectionInfo->trackServerFirst) - { - GameScriptObject * gameScriptObject = const_cast(getScriptObject()); - if (gameScriptObject) - { - ScriptParams params; - params.addParam(collectionInfo->page.book.name.c_str()); // book - params.addParam(collectionInfo->page.name.c_str()); // page - params.addParam(collectionInfo->name.c_str()); // collection - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SERVER_FIRST, params)); - } - } - } - } - else if (message.getMethod() == "C++InviteToGroupReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - - bool success = false; - NetworkId actor, actorShip, group; - std::string actorName; - GroupObject const * groupObject = NULL; - StringId responseSid; - - Unicode::String const delimiters(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector tokens; - if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 4)) - { - success = true; - actor = NetworkId(Unicode::wideToNarrow(tokens[0])); - actorShip = NetworkId(Unicode::wideToNarrow(tokens[1])); - group = NetworkId(Unicode::wideToNarrow(tokens[2])); - actorName = Unicode::wideToNarrow(tokens[3]); - - ServerObject const * so = (group.isValid() ? safe_cast(NetworkIdManager::getObjectById(group)) : NULL); - groupObject = (so ? so->asGroupObject() : NULL); - } - - if (success) - { - std::vector targets; - GroupHelpers::findAllTargetsForGroup(this, targets); - - if (!GroupHelpers::roomInGroup(groupObject, targets.size())) - { - responseSid = GroupStringId::SID_GROUP_FULL; - success = false; - } - } - - if (success) - { - if ((this->getGroup()) && (!GroupHelpers::creatureIsContainedInPOBShip(this))) - { - responseSid = GroupStringId::SID_GROUP_ALREADY_GROUPED; - success = false; - } - } - - if (success) - { - GameScriptObject* const gso = getScriptObject(); - if (gso != NULL && gso->hasScript("ai.beast")) - { - responseSid = GroupStringId::SID_GROUP_BEASTS_CANT_JOIN; - success = false; - } - } - - if (success) - { - NetworkId const & oldInviter = getGroupInviterId(); - if (oldInviter.isValid()) - { - if (oldInviter == actor) - responseSid = GroupStringId::SID_GROUP_CONSIDERING_YOUR_GROUP; - else - responseSid = GroupStringId::SID_GROUP_CONSIDERING_OTHER_GROUP; - - success = false; - } - } - - if (success) - { - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject && playerObject->isIgnoring(Unicode::toLower(actorName))) - { - responseSid = GroupStringId::SID_GROUP_INVITE_NO_TARGET_SELF; - success = false; - } - } - - if (success) - { - // cannot be invited if in combat - if (getState(States::Combat) && ConfigServerGame::getGroupInviteInviteeCombatRestriction()) - { - responseSid = GroupStringId::SID_GROUP_INVITE_TARGET_IN_COMBAT; - success = false; - } - } - - if (success) - { - ProsePackage pp; - pp.stringId = GroupStringId::SID_GROUP_INVITE_TARGET; - pp.target.str = Unicode::narrowToWide(actorName); - pp.actor.id = getNetworkId(); - - Chat::sendSystemMessage(*this, pp); - - setGroupInviter(actor, actorName, actorShip); - - responseSid = GroupStringId::SID_GROUP_INVITE_LEADER; - } - - std::string const objectName(Unicode::wideToNarrow(getAssignedObjectName())); - - std::string response = responseSid.getCanonicalRepresentation(); - response += "|"; - - if (!objectName.empty()) - { - response += "nameString|"; - response += objectName; - } - else - { - StringId nameSid = getObjectNameStringId(); - response += "nameStringId|"; - response += nameSid.getCanonicalRepresentation(); - } - - MessageToQueue::getInstance().sendMessageToC(actor, - "C++GroupOperationGenericRsp", - response, - 0, - false); - } - } - else if (message.getMethod() == "C++InviteToGroupRspTargetNotFound") - { - Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_INVITE_NO_TARGET_SELF, NULL); - } - else if (message.getMethod() == "C++GroupOperationGenericRsp") - { - if (!message.getPackedDataVector().empty()) - { - std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - Unicode::String const delimiters(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector tokens; - if ((Unicode::tokenize(Unicode::narrowToWide(result), tokens, &delimiters, NULL)) && (tokens.size() == 3)) - { - std::string const response(Unicode::wideToNarrow(tokens[0])); - std::string const responseParmType(Unicode::wideToNarrow(tokens[1])); - std::string const responseParm(Unicode::wideToNarrow(tokens[2])); - - ProsePackage pp; - pp.stringId = StringId(response); - - if (responseParmType == std::string("nameString")) - { - pp.target.str = Unicode::narrowToWide(responseParm); - } - else - { - pp.target.stringId = StringId(responseParm); - } - - pp.actor.id = getNetworkId(); - - Chat::sendSystemMessage(*this, pp); - } - } - } - else if (message.getMethod() == "C++UninviteFromGroupReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - - bool success = false; - NetworkId actor; - std::string actorName; - StringId responseSid; - - Unicode::String const delimiters(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector tokens; - if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 2)) - { - success = true; - actor = NetworkId(Unicode::wideToNarrow(tokens[0])); - actorName = Unicode::wideToNarrow(tokens[1]); - } - - if (success) - { - if (actor != getGroupInviterId()) - { - responseSid = GroupStringId::SID_GROUP_UNINVITE_NOT_INVITED; - success = false; - } - } - - if (success) - { - ProsePackage pp; - pp.stringId = GroupStringId::SID_GROUP_UNINVITE_TARGET; - pp.target.str = Unicode::narrowToWide(actorName); - pp.actor.id = getNetworkId(); - - Chat::sendSystemMessage(*this, pp); - - setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); - - responseSid = GroupStringId::SID_GROUP_UNINVITE_SELF; - } - - std::string const objectName(Unicode::wideToNarrow(getAssignedObjectName())); - - std::string response = responseSid.getCanonicalRepresentation(); - response += "|"; - - if (!objectName.empty()) - { - response += "nameString|"; - response += objectName; - } - else - { - StringId nameSid = getObjectNameStringId(); - response += "nameStringId|"; - response += nameSid.getCanonicalRepresentation(); - } - - MessageToQueue::getInstance().sendMessageToC(actor, - "C++GroupOperationGenericRsp", - response, - 0, - false); - } - } - else if (message.getMethod() == "C++UninviteFromGroupRspTargetNotFound") - { - Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_UNINVITE_NO_TARGET_SELF, NULL); - } - else if (message.getMethod() == "C++GroupJoinInviterInfoReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - NetworkId const invitee(params); - GroupObject const * const existingGroup = getGroup(); - GroupMemberParam gmp = GroupHelpers::buildGroupMemberParam(this); - - char buffer[1024]; - snprintf(buffer, sizeof(buffer)-1, "%s|%s|%s|%d|%d|%d|%s|%d|%d|%d", - (existingGroup ? existingGroup->getNetworkId().getValueString().c_str() : "0"), - gmp.m_memberId.getValueString().c_str(), - gmp.m_memberName.c_str(), - gmp.m_memberDifficulty, - static_cast(gmp.m_memberProfession), - (gmp.m_memberIsPC ? 1 : 0), - gmp.m_memberShipId.getValueString().c_str(), - (gmp.m_memberShipIsPOB ? 1 : 0), - (gmp.m_memberOwnsPOB ? 1 : 0), - (getState(States::Combat) ? 1 : 0)); - - buffer[sizeof(buffer)-1] = '\0'; - - MessageToQueue::getInstance().sendMessageToC(invitee, - "C++GroupJoinInviterInfoRsp", - buffer, - 0, - false); - - // if the inviter had been invited in the meantime, have them decline - if (getGroupInviterId().isValid()) - setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); - } - } - else if (message.getMethod() == "C++GroupJoinInviterInfoRsp") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - bool success = false; - NetworkId existingGroupId; - NetworkId inviterId; - std::string inviterName; - int inviterDifficulty = 1; - LfgCharacterData::Profession inviterProfession = LfgCharacterData::Prof_Unknown; - bool inviterIsPC = true; - NetworkId inviterShipId; - bool inviterShipIsPOB = false; - bool inviterOwnsPOB = false; - bool inviterInCombat = false; - - Unicode::String const delimiters(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector tokens; - if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 10)) - { - success = true; - existingGroupId = NetworkId(Unicode::wideToNarrow(tokens[0])); - inviterId = NetworkId(Unicode::wideToNarrow(tokens[1])); - inviterName = Unicode::wideToNarrow(tokens[2]); - inviterDifficulty = atoi(Unicode::wideToNarrow(tokens[3]).c_str()); - inviterProfession = static_cast(atoi(Unicode::wideToNarrow(tokens[4]).c_str())); - inviterIsPC = (atoi(Unicode::wideToNarrow(tokens[5]).c_str()) != 0); - inviterShipId = NetworkId(Unicode::wideToNarrow(tokens[6])); - inviterShipIsPOB = (atoi(Unicode::wideToNarrow(tokens[7]).c_str()) != 0); - inviterOwnsPOB = (atoi(Unicode::wideToNarrow(tokens[8]).c_str()) != 0); - inviterInCombat = (atoi(Unicode::wideToNarrow(tokens[9]).c_str()) != 0); - } - - GroupObject * existingGroup = NULL; - if (success) - { - if (existingGroupId.isValid()) - { - ServerObject * so = safe_cast(NetworkIdManager::getObjectById(existingGroupId)); - existingGroup = (so ? so->asGroupObject() : NULL); - if (!existingGroup) - { - success = false; - Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_EXISTING_GROUP_NOT_FOUND, NULL); - } - } - } - - if (success) - { - // make sure inviter hasn't joined another group since the invite - if (existingGroup && (inviterId != existingGroup->getGroupLeaderId())) - { - success = false; - ProsePackage pp; - pp.stringId = GroupStringId::SID_GROUP_JOIN_INVITER_NOT_LEADER; - pp.target.str = Unicode::narrowToWide(inviterName); - pp.actor.id = getNetworkId(); - - Chat::sendSystemMessage(*this, pp); - } - } - - if (success) - { - // cannot join if the inviter is in combat - if (inviterInCombat && ConfigServerGame::getGroupJoinInviterCombatRestriction()) - { - success = false; - ProsePackage pp; - pp.stringId = GroupStringId::SID_GROUP_JOIN_LEADER_IN_COMBAT; - pp.target.str = Unicode::narrowToWide(inviterName); - pp.actor.id = getNetworkId(); - - Chat::sendSystemMessage(*this, pp); - } - } - - std::vector targets; - if (success) - { - GroupHelpers::findAllTargetsForGroup(this, targets); - - if (existingGroup && !GroupHelpers::roomInGroup(existingGroup, targets.size())) - { - success = false; - Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_JOIN_FULL, NULL); - } - } - - if (success) - { - // if we are in a POB group then we need to disband it - GroupObject * const groupFromPOB = getGroup(); - if (groupFromPOB != 0) - { - groupFromPOB->disbandGroup(); - - std::vector::const_iterator ii = targets.begin(); - std::vector::const_iterator iiEnd = targets.end(); - - for (; ii != iiEnd; ++ii) - { - if ((*ii)->getGroup() == groupFromPOB) - (*ii)->getGroup()->onGroupMemberRemoved((*ii)->getNetworkId(), true); - } - - if (getGroup() == groupFromPOB) - getGroup()->onGroupMemberRemoved(getNetworkId(), true); - } - - if (existingGroup) - { - GroupObject::GroupMemberParamVector targetMemberParams; - GroupHelpers::buildGroupMemberParamsFromCreatures(targets, targetMemberParams); - - int const numberOfTargets = static_cast(targetMemberParams.size()); - - for (int i = 0; i < numberOfTargets; ++i) - { - existingGroup->addGroupMember(targetMemberParams[i]); - } - } - else - { - // if the inviter happens to be in the same ship as you then we need to remove - // him from the targets list so that he isn't added to the new group twice - for (std::vector::iterator ii = targets.begin(); ii != targets.end(); ++ii) - { - if ((*ii)->getNetworkId() == inviterId) - { - targets.erase(ii); - break; - } - } - - GroupObject::GroupMemberParamVector targetMemberParams; - GroupHelpers::buildGroupMemberParamsFromCreatures(targets, targetMemberParams); - - // group did not already exist, so form it with the inviter as the leader - if (!targetMemberParams.empty()) - ServerUniverse::getInstance().createGroup(GroupMemberParam(inviterId, inviterName, inviterDifficulty, inviterProfession, inviterIsPC, inviterShipId, inviterShipIsPOB, inviterOwnsPOB), targetMemberParams); - } - - // Until the targets are actually told they are in a group - // (the authoritative group object may be on another server) - // we will keep track of who extended the invitation - std::vector::const_iterator ii = targets.begin(); - std::vector::const_iterator iiEnd = targets.end(); - for (; ii != iiEnd; ++ii) - { - (*ii)->setInviterForPendingGroup(inviterId); - } - } - } - } - else if (message.getMethod() == "C++GroupJoinInviterInfoReqInviterNotFound") - { - Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_MUST_BE_INVITED, NULL); - } - else if (message.getMethod() == "C++LeaveGroupReq") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - GroupObject const * const groupObj = getGroup(); - if (groupObj && (groupObj->getNetworkId() == NetworkId(params)) && (groupObj->getGroupLeaderId() != getNetworkId())) - { - static uint32 const commandHash = Crc::normalizeAndCalculate("leaveGroup"); - const Command &command = CommandTable::getCommand(static_cast(commandHash)); - if (!command.isNull()) - { - commandQueueEnqueue(command, NetworkId::cms_invalid, Unicode::String(), 0, false, static_cast(Command::CP_Front), true); - } - } - } - } - else if (message.getMethod() == "C++GroupPickupPointCreated") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - - Unicode::String const delimiters(Unicode::narrowToWide("|")); - Unicode::UnicodeStringVector tokens; - if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 5)) - { - // tell group member that the group pickup point has been created - if (getClient()) - { - StringId::LocUnicodeString response; - if (StringId("group", "create_group_pickup_success_others").localize(response)) - { - ConsoleMgr::broadcastString(FormattedString<2048>().sprintf(Unicode::wideToNarrow(response).c_str(), Unicode::wideToNarrow(tokens[4]).c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigServerGame::getGroupPickupPointTimeLimitSeconds())).c_str()), - getClient()); - } - } - - // create/update the group member's group pickup point waypoint - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - std::string const planetName = Unicode::wideToNarrow(tokens[0]); - int const x = atoi(Unicode::wideToNarrow(tokens[1]).c_str()); - int const y = atoi(Unicode::wideToNarrow(tokens[2]).c_str()); - int const z = atoi(Unicode::wideToNarrow(tokens[3]).c_str()); - - Location const location(Vector(static_cast(x), static_cast(y), static_cast(z)), NetworkId::cms_invalid, Location::getCrcBySceneName(planetName)); - playerObject->createOrUpdateReusableWaypoint(location, "groupPickupWp", Unicode::narrowToWide("Group Pickup Point"), Waypoint::White); - } - } - } - } - else if (message.getMethod() == "C++OccupyUnlockedSlotRsp") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - LoginUpgradeAccountMessage::OccupyUnlockedSlotResponse const response = static_cast(::atoi(params.c_str())); - - if (response == LoginUpgradeAccountMessage::OUSR_success) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request SUCCESS", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_success"), Unicode::emptyString); - - // let the client know so it can change the character to be properly displayed on the character select screen - Client * const client = getClient(); - if (client) - { - GenericValueTypeMessage > const characterChangedUnlocked("CharacterChangedUnlocked", std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId())); - client->send(characterChangedUnlocked, true); - } - } - else if (response == LoginUpgradeAccountMessage::OUSR_db_error) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - internal db error", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_error"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unlocked_slot) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - account doesn't have an unlocked slot", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_no_unlocked_slot"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unoccupied_unlocked_slot) - { - LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - account has no unoccupied unlocked slot", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_no_unoccupied_unlocked_slot"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::OUSR_cluster_already_has_unlocked_slot_character) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - cluster already has an unlocked slot character", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_has_unlocked_slot"), Unicode::emptyString); - } - else - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - unknown result code (%d)", PlayerObject::getAccountDescription(this).c_str(), static_cast(response))); - } - } - } - else if (message.getMethod() == "C++VacateUnlockedSlotRsp") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - LoginUpgradeAccountMessage::VacateUnlockedSlotResponse const response = static_cast(::atoi(params.c_str())); - - if (response == LoginUpgradeAccountMessage::VUSR_success) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request SUCCESS", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_success"), Unicode::emptyString); - - // let the client know so it can change the character to be properly displayed on the character select screen - Client * const client = getClient(); - if (client) - { - GenericValueTypeMessage > const characterChangedNormal("CharacterChangedNormal", std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId())); - client->send(characterChangedNormal, true); - } - } - else if (response == LoginUpgradeAccountMessage::VUSR_db_error) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - internal db error", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_error"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::VUSR_account_has_no_unlocked_slot) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - account doesn't have an unlocked slot", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_no_unlocked_slot"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::VUSR_not_unlocked_slot_character) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - character is not an unlocked slot character", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_not_unlocked_slot_character"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::VUSR_no_available_normal_character_slot) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - no available normal character slot for the account on this galaxy", PlayerObject::getAccountDescription(this).c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_no_available_normal_character_slot"), Unicode::emptyString); - } - else - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - unknown result code (%d)", PlayerObject::getAccountDescription(this).c_str(), static_cast(response))); - } - } - } - else if (message.getMethod() == "C++SwapUnlockedSlotRsp") - { - if (!message.getPackedDataVector().empty()) - { - Archive::ByteStream bs; - bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); - - Archive::ReadIterator ri = bs.begin(); - GenericValueTypeMessage, std::pair > > > const swapUnlockedSlotRsp(ri); - - LoginUpgradeAccountMessage::SwapUnlockedSlotResponse const response = static_cast(swapUnlockedSlotRsp.getValue().first.first); - if (response == LoginUpgradeAccountMessage::SUSR_success) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s (%s) request SUCCESS", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.second.c_str())); - - ProsePackage prosePackage; - prosePackage.stringId = StringId("unlocked_slot", "swap_unlocked_slot_success"); - prosePackage.target.str = Unicode::narrowToWide(swapUnlockedSlotRsp.getValue().second.second.second); - Chat::sendSystemMessage(*this, prosePackage); - - // let the client know so it can change the character to be properly displayed on the character select screen - Client * const client = getClient(); - if (client) - { - GenericValueTypeMessage > const characterChangedNormal("CharacterChangedNormal", std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId())); - client->send(characterChangedNormal, true); - - GenericValueTypeMessage > const characterChangedUnlocked("CharacterChangedUnlocked", std::make_pair(GameServer::getInstance().getClusterName(), swapUnlockedSlotRsp.getValue().second.second.first)); - client->send(characterChangedUnlocked, true); - } - } - else if (response == LoginUpgradeAccountMessage::SUSR_db_error) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - internal db error", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_error"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::SUSR_account_has_no_unlocked_slot) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - account doesn't have an unlocked slot", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_no_unlocked_slot"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::SUSR_not_unlocked_slot_character) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - source character is not an unlocked slot character", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_not_unlocked_slot_character"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::SUSR_invalid_target_character) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - target character is either not valid, not on the same account, or not on this galaxy", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_invalid_target_character"), Unicode::emptyString); - } - else if (response == LoginUpgradeAccountMessage::SUSR_target_character_already_unlocked_slot_character) - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - target character is already an unlocked slot character", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); - - Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_target_is_already_unlocked_character"), Unicode::emptyString); - } - else - { - // CS log the response - LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - unknown result code (%d)", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().first.first)); - } - } - } - else if (message.getMethod() == "C++AccountFeatureIdResponse") - { - if (!message.getPackedDataVector().empty()) - { - Archive::ByteStream bs; - bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); - - Archive::ReadIterator ri = bs.begin(); - AccountFeatureIdResponse const msg(ri); - - if ((msg.getTarget() == getNetworkId()) && (msg.getResultCode() == RESULT_SUCCESS)) - { - Client * client = getClient(); - if (client) - { - if (msg.getGameCode() == PlatformGameCode::SWG) - client->setAccountFeatureIds(msg.getFeatureIds()); - } - } - - if ((msg.getRequestReason() == AccountFeatureIdRequest::RR_ConsoleCommandReloadRequest) && msg.getRequester().isValid() && (msg.getRequester() == getNetworkId())) - { - if (msg.getResultCode() == RESULT_SUCCESS) - { - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request for feature Id for account (%lu) was successful", msg.getTargetStationId()), - getClient()); - - if (msg.getGameCode() == PlatformGameCode::SWG) - { - ConsoleMgr::broadcastString("you can use the /getAccountInfo command on a targeted character to view the character's account SWG feature Id", - getClient()); - } - - if (msg.getResultCameFromSession()) - { - std::map const & sessionFeatureIdsData = msg.getSessionFeatureIdsData(); - - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("session/Platform reported successful result code (%u, %s:%s), (%d) feature Ids for account (%lu)", msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str(), sessionFeatureIdsData.size(), msg.getTargetStationId()), - getClient()); - - for (std::map::const_iterator iter = sessionFeatureIdsData.begin(); iter != sessionFeatureIdsData.end(); ++iter) - { - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%lu (%s)", iter->first, iter->second.c_str()), - getClient()); - } - } - else if (msg.getGameCode() != PlatformGameCode::SWG) - { - std::map const & featureIds = msg.getFeatureIds(); - - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("(%d) feature Ids for account (%lu)", featureIds.size(), msg.getTargetStationId()), - getClient()); - - for (std::map::const_iterator iter = featureIds.begin(); iter != featureIds.end(); ++iter) - { - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%lu (%d)", iter->first, iter->second), - getClient()); - } - } - } - else - { - if (msg.getResultCameFromSession()) - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request for feature Id for account (%lu) failed with error code (%u, %s:%s)", msg.getTargetStationId(), msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str()), getClient()); - else - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request for feature Id for account (%lu) failed with error code (%u)", msg.getTargetStationId(), msg.getResultCode()), getClient()); - } - } - - if ((msg.getRequestReason() == AccountFeatureIdRequest::RR_ReloadRewardCheck) && msg.getRequester().isValid() && (msg.getRequester() == getNetworkId()) && (msg.getGameCode() == PlatformGameCode::SWG)) - { - // let script know the that account feature id has been - // retrieved so it can resume the rewards claim process - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "veteranAccountFeatureIdResponse", std::vector(), 0, false); - } - } - } - else if (message.getMethod() == "C++FeatureIdTransactionResponse") - { - if (!message.getPackedDataVector().empty()) - { - Archive::ByteStream bs; - bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); - - Archive::ReadIterator ri = bs.begin(); - FeatureIdTransactionResponse const msg(ri); - VeteranRewardManager::verifyFeatureIdTransactions(*this, msg.getTransactions()); - } - } - else if (message.getMethod() == "C++TransferReplyMoveValidation") - { - if (!message.getPackedDataVector().empty()) - { - Archive::ByteStream bs; - bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); - - Archive::ReadIterator ri = bs.begin(); - TransferReplyMoveValidation const msg(ri); - - // we should only be here if the validation failed - TransferRequestMoveValidation::TransferRequestSource const transferRequestSource = msg.getTransferRequestSource(); - if (transferRequestSource == TransferRequestMoveValidation::TRS_console_god_command) - { - TransferReplyMoveValidation::TransferReplyMoveValidationResult const result = msg.getResult(); - - if (result == TransferReplyMoveValidation::TRMVR_cannot_create_regular_character) - { - ConsoleMgr::broadcastString(FormattedString<256>().sprintf("the destination station id (%u) is not allowed to create any more character on the destination galaxy (%s)", msg.getDestinationStationId(), msg.getDestinationGalaxy().c_str()), getClient()); - } - else if (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid) - { - ConsoleMgr::broadcastString(FormattedString<256>().sprintf("either the destination galaxy (%s) is invalid, or the destination galaxy (%s) is not using the same login server as this galaxy", msg.getDestinationGalaxy().c_str(), msg.getDestinationGalaxy().c_str()), getClient()); - } - else if (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected) - { - ConsoleMgr::broadcastString(FormattedString<256>().sprintf("the destination galaxy (%s) is not currently started", msg.getDestinationGalaxy().c_str()), getClient()); - } - else if (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading) - { - ConsoleMgr::broadcastString(FormattedString<256>().sprintf("the destination galaxy (%s) is currently loading", msg.getDestinationGalaxy().c_str()), getClient()); - } - else - { - ConsoleMgr::broadcastString(FormattedString<256>().sprintf("transfer validation failed with error code (%d)", static_cast(result)), getClient()); - } - } - else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_transfer)) - { - TransferReplyMoveValidation::TransferReplyMoveValidationResult const result = msg.getResult(); - if (result == TransferReplyMoveValidation::TRMVR_cannot_create_regular_character) - { - ScriptParams params; - params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateFailCannotCreateCharacter", dictionary->getSerializedData(), 0, false); - } - } - else if ((result == TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid) || - (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected) || - (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading)) - { - ScriptParams params; - params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateFailDestGalaxyUnavailable", dictionary->getSerializedData(), 0, false); - } - } - else - { - LOG("CustomerService", ("CharacterTransfer: transfer validation failed for [%u, %s, %s (%s)] to [%u, %s, %s] with unexpected error code (%d)", msg.getSourceStationId(), msg.getSourceGalaxy().c_str(), msg.getSourceCharacter().c_str(), msg.getSourceCharacterId().getValueString().c_str(), msg.getDestinationStationId(), msg.getDestinationGalaxy().c_str(), msg.getDestinationCharacter().c_str(), static_cast(result))); - } - } - else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_transfer)) - { - TransferReplyMoveValidation::TransferReplyMoveValidationResult const result = msg.getResult(); - if (result == TransferReplyMoveValidation::TRMVR_cannot_create_regular_character) - { - ScriptParams params; - params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateFailCannotCreateCharacter", dictionary->getSerializedData(), 0, false); - } - } - else if ((result == TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid) || - (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected) || - (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading)) - { - ScriptParams params; - params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateFailDestGalaxyUnavailable", dictionary->getSerializedData(), 0, false); - } - } - else - { - LOG("CustomerService", ("CharacterTransfer: transfer validation failed for [%u, %s, %s (%s)] to [%u, %s, %s] with unexpected error code (%d)", msg.getSourceStationId(), msg.getSourceGalaxy().c_str(), msg.getSourceCharacter().c_str(), msg.getSourceCharacterId().getValueString().c_str(), msg.getDestinationStationId(), msg.getDestinationGalaxy().c_str(), msg.getDestinationCharacter().c_str(), static_cast(result))); - } - } - } - } - else if (message.getMethod() == "C++TransferReplyNameValidation") - { - if (!message.getPackedDataVector().empty()) - { - Archive::ByteStream bs; - bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); - - Archive::ReadIterator ri = bs.begin(); - GenericValueTypeMessage > const msg(ri); - - TransferRequestMoveValidation::TransferRequestSource const transferRequestSource = msg.getValue().second.getTransferRequestSource(); - - if (!msg.getValue().second.getIsValidName()) - { - if (transferRequestSource == TransferRequestMoveValidation::TRS_console_god_command) - { - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("the character name (%s) is not available on galaxy (%s) because of reason (%s)", msg.getValue().second.getDestinationCharacterName().c_str(), msg.getValue().second.getDestinationGalaxy().c_str(), msg.getValue().first.c_str()), getClient()); - } - else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_transfer)) - { - ScriptParams params; - params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); - params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); - params.addParam(msg.getValue().first.c_str(), "reason"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateFailNameValidation", dictionary->getSerializedData(), 0, false); - } - } - else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_transfer)) - { - ScriptParams params; - params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); - params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); - params.addParam(msg.getValue().first.c_str(), "reason"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateFailNameValidation", dictionary->getSerializedData(), 0, false); - } - } - } - else if (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_validate) - { - ScriptParams params; - params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); - params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateSuccess", dictionary->getSerializedData(), 0, false); - } - } - else if (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_validate) - { - ScriptParams params; - params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); - params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); - ScriptDictionaryPtr dictionary; - GameScriptObject::makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateSuccess", dictionary->getSerializedData(), 0, false); - } - } - } - } - else if (message.getMethod() == "C++PickupAllRoomItemsIntoInventory") - { - // use while(true) loop to use break to discontinue processing and go to the end of loop to run cleanup code - PlayerObject * playerObject = NULL; - while (true) - { - playerObject = PlayerCreatureController::getPlayerObject(this); - if (!playerObject) - break; - - // player has disconnected - if (!getClient()) - break; - - // don't allow this in god mode because it could be used accidentally and pick up a bunch of stuff, - // and god mode allows stuff to be picked up, which wouldn't normally be allowed to be picked up - if (getClient()->isGod()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you switched into GOD mode."), Unicode::emptyString); - break; - } - - // player is not "active", meaning he's probably doing it with a macro - if (playerObject->getSessionLastActiveTime() == 0) - break; - - int operationId = 0; - if (!getObjVars().getItem("pickupDropAllItemsOperation.operationId", operationId) || (operationId == 0)) - break; - - if (operationId != playerObject->getPickupDropAllItemsOperationId()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an unexpected condition. Please try the operation again."), Unicode::emptyString); - break; - } - - NetworkId const & cellId = playerObject->getPickupDropAllItemsCellId(); - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (!containingCell || !containingCell->asCellObject() || (containingCell->getNetworkId() != cellId)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you have left the room."), Unicode::emptyString); - break; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you have left the room."), Unicode::emptyString); - break; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you have left the room."), Unicode::emptyString); - break; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); - break; - } - - if (!containingPOB->isOnAdminList(*this)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you are no longer the the owner or an admin of the structure or POB ship."), Unicode::emptyString); - break; - } - - ServerObject * const targetInventoryObj = getInventory(); - if (!targetInventoryObj) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); - break; - } - - VolumeContainer * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); - if (!targetInventoryContainer) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); - break; - } - - int const inventoryBaseLimit = targetInventoryContainer->getTotalVolume(); - int const inventoryLimit = (playerObject->getPickupAllItemsAllowInventoryOverload() ? std::max(inventoryBaseLimit, (inventoryBaseLimit + ConfigServerGame::getMoveValidationMaxInventoryOverload() - 11)) : inventoryBaseLimit); - - if (targetInventoryContainer->getCurrentVolume() >= inventoryLimit) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because your inventory is full."), Unicode::emptyString); - - // if they didn't run the command with the -overload - // option, remind them about the -overload option - if (!playerObject->getPickupAllItemsAllowInventoryOverload()) - Chat::sendSystemMessage(*this, Unicode::narrowToWide("If you wish to pick up more items than available inventory space, you can specify the \"overload\" option with the command by typing \"/pickupAllRoomItemsIntoInventory -overload\" which will pick up additional items and overload your inventory, but not so overloaded as to prevent you from moving."), Unicode::emptyString); - - break; - } - - Container const * const cellContainer = ContainerInterface::getContainer(*containingCell); - if (!cellContainer) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); - break; - } - - std::set & processedItemsSoFar = playerObject->getPickupDropAllItemsProcessedItemsSoFar(); - std::list cellContents; - { - for (ContainerConstIterator iter = cellContainer->begin(); iter != cellContainer->end(); ++iter) - { - if ((*iter != getNetworkId()) && (processedItemsSoFar.count(*iter) <= 0)) - cellContents.push_back(*iter); - } - } - - if (cellContents.empty()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because no more items in the room can be picked up or the room is empty."), Unicode::emptyString); - break; - } - - // if necessary, temporary increase the inventory limit to allow overload - if (inventoryLimit > inventoryBaseLimit) - targetInventoryContainer->debugDoNotUseSetCapacity(inventoryLimit); - - int numberOfItemsPickedUpSoFar = playerObject->getPickupDropAllItemsNumItemsSoFar(); - - char buffer[512]; - Vector const pos = Transform::identity.getPosition_p(); - snprintf(buffer, sizeof(buffer)-1, " %s -1 %f %f %f", targetInventoryObj->getNetworkId().getValueString().c_str(), pos.x, pos.y, pos.z); - buffer[sizeof(buffer)-1] = '\0'; - Unicode::String const commandTransferItemMiscParams = Unicode::narrowToWide(buffer); - - static uint32 const hashTransferItemMisc = Crc::normalizeAndCalculate("transferItemMisc"); - Command const & commandTransferItemMisc = CommandTable::getCommand(hashTransferItemMisc); - ServerObject const * cellContent; - bool blockedByNoTrade; - bool showPickUpMenu; - Container::ContainerErrorCode cec; - int previousVolume, newVolume; - int numberOfItemsToProcessThisRound = ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound(); - for (std::list::const_iterator iter = cellContents.begin(); iter != cellContents.end(); ++iter) - { - --numberOfItemsToProcessThisRound; - processedItemsSoFar.insert(*iter); - - cellContent = safe_cast(iter->getObject()); - if (!cellContent) - continue; - - if (ContainerInterface::getContainedByObject(*cellContent) != containingCell) - continue; - - // see if the item would normally have the "Pick Up" menu item on it - if (!PlayerCreatureController::objectMenuRequestCanManipulateObject(*this, *cellContent, blockedByNoTrade, showPickUpMenu)) - continue; - - if (!showPickUpMenu) - continue; - - // see if item would fit in inventory - if (!targetInventoryContainer->mayAdd(*cellContent, cec)) - continue; - - // "Pick Up" the item, just as if the player had used the "Pick Up" radial or /pickup command - previousVolume = targetInventoryContainer->getCurrentVolume(); - CommandCppFuncs::commandFuncTransferMisc(commandTransferItemMisc, getNetworkId(), cellContent->getNetworkId(), commandTransferItemMiscParams); - - // stop trying when inventory is full - newVolume = targetInventoryContainer->getCurrentVolume(); - if (newVolume >= inventoryLimit) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because your inventory is full."), Unicode::emptyString); - - // if they didn't run the command with the -overload - // option, remind them about the -overload option - if (!playerObject->getPickupAllItemsAllowInventoryOverload()) - Chat::sendSystemMessage(*this, Unicode::narrowToWide("If you wish to pick up more items than available inventory space, you can specify the \"overload\" option with the command by typing \"/pickupAllRoomItemsIntoInventory -overload\" which will pick up additional items and overload your inventory, but not so overloaded as to prevent you from moving."), Unicode::emptyString); - - break; - } - - // update count of how many items have been picked up for the operation - numberOfItemsPickedUpSoFar += std::max(0, (newVolume - previousVolume)); - - // stop trying when enough items have been picked up for the operation - if (numberOfItemsPickedUpSoFar > inventoryLimit) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because \"enough\" items have been picked up."), Unicode::emptyString); - break; - } - - // only do so many items each round, to spread out the load - if (numberOfItemsToProcessThisRound <= 0) - break; - } - - // if necessary, restore the inventory limit - if (inventoryLimit > inventoryBaseLimit) - targetInventoryContainer->debugDoNotUseSetCapacity(inventoryBaseLimit); - - // stop if inventory is full - if (targetInventoryContainer->getCurrentVolume() >= inventoryLimit) - break; - - // stop if enough items have been picked up for the operation - if (numberOfItemsPickedUpSoFar > inventoryLimit) - break; - else - playerObject->setPickupDropAllItemsNumItemsSoFar(numberOfItemsPickedUpSoFar); - - // stop if no more items can be picked up - if (numberOfItemsToProcessThisRound > 0) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because no more items in the room can be picked up or the room is empty."), Unicode::emptyString); - break; - } - - // queue up the next round of pickup - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++PickupAllRoomItemsIntoInventory", - "", - 1, - false); - - return; - } - - // if we reach this point, it means we are stopping the operation, so cleanup - removeObjVarItem("pickupDropAllItemsOperation"); - - if (playerObject) - { - playerObject->setPickupDropAllItemsOperationId(0); - playerObject->setPickupDropAllItemsCellId(NetworkId::cms_invalid); - playerObject->setPickupAllItemsAllowInventoryOverload(false); - playerObject->setPickupDropAllItemsNumItemsSoFar(0); - playerObject->getPickupDropAllItemsProcessedItemsSoFar().clear(); - } - } - else if (message.getMethod() == "C++DropAllInventoryItemsIntoRoom") - { - // use while(true) loop to use break to discontinue processing and go to the end of loop to run cleanup code - PlayerObject * playerObject = NULL; - while (true) - { - playerObject = PlayerCreatureController::getPlayerObject(this); - if (!playerObject) - break; - - // player has disconnected - if (!getClient()) - break; - - // don't allow this in god mode because it could be used accidentally and drop a bunch of stuff, - // and god mode allows stuff to be dropped, which wouldn't normally be allowed to be dropped - if (getClient()->isGod()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you switched into GOD mode."), Unicode::emptyString); - break; - } - - // player is not "active", meaning he's probably doing it with a macro - if (playerObject->getSessionLastActiveTime() == 0) - break; - - int operationId = 0; - if (!getObjVars().getItem("pickupDropAllItemsOperation.operationId", operationId) || (operationId == 0)) - break; - - if (operationId != playerObject->getPickupDropAllItemsOperationId()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an unexpected condition. Please try the operation again."), Unicode::emptyString); - break; - } - - NetworkId const & cellId = playerObject->getPickupDropAllItemsCellId(); - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (!containingCell || !containingCell->asCellObject() || (containingCell->getNetworkId() != cellId)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you have left the room."), Unicode::emptyString); - break; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you have left the room."), Unicode::emptyString); - break; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you have left the room."), Unicode::emptyString); - break; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an internal error."), Unicode::emptyString); - break; - } - - if (!containingPOB->isOnAdminList(*this)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you are no longer the the owner or an admin of the structure or POB ship."), Unicode::emptyString); - break; - } - - int pobBaseItemLimit = 0; - int pobAdditionalItems = 0; - const int pobItemLimit = containingPOB->getPobTotalItemLimit(pobBaseItemLimit, pobAdditionalItems); - - if (containingPOB->getPobItemCount() >= pobItemLimit) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because the structure or POB ship is full."), Unicode::emptyString); - break; - } - - ServerObject const * const targetInventoryObj = getInventory(); - if (!targetInventoryObj) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an internal error."), Unicode::emptyString); - break; - } - - VolumeContainer const * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); - if (!targetInventoryContainer) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an internal error."), Unicode::emptyString); - break; - } - - int const inventoryOverloadLimit = targetInventoryContainer->getTotalVolume() + ConfigServerGame::getMoveValidationMaxInventoryOverload(); - - std::set & processedItemsSoFar = playerObject->getPickupDropAllItemsProcessedItemsSoFar(); - std::list inventoryContents; - { - for (ContainerConstIterator iter = targetInventoryContainer->begin(); iter != targetInventoryContainer->end(); ++iter) - { - if (processedItemsSoFar.count(*iter) <= 0) - inventoryContents.push_back(*iter); - } - } - - if (inventoryContents.empty()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because no more items in your inventory can be dropped or your inventory is empty."), Unicode::emptyString); - break; - } - - int numberOfItemsDroppedSoFar = playerObject->getPickupDropAllItemsNumItemsSoFar(); - - char buffer[512]; - Vector const pos = getTransform_o2c().getPosition_p(); - snprintf(buffer, sizeof(buffer)-1, " %s -1 %f %f %f", containingCell->getNetworkId().getValueString().c_str(), pos.x, pos.y, pos.z); - buffer[sizeof(buffer)-1] = '\0'; - Unicode::String const commandTransferItemMiscParams = Unicode::narrowToWide(buffer); - - static uint32 const hashTransferItemMisc = Crc::normalizeAndCalculate("transferItemMisc"); - Command const & commandTransferItemMisc = CommandTable::getCommand(hashTransferItemMisc); - ServerObject const * inventoryContent; - int previousVolume, newVolume; - int numberOfItemsToProcessThisRound = ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound(); - for (std::list::const_iterator iter = inventoryContents.begin(); iter != inventoryContents.end(); ++iter) - { - --numberOfItemsToProcessThisRound; - processedItemsSoFar.insert(*iter); - - inventoryContent = safe_cast(iter->getObject()); - if (!inventoryContent) - continue; - - if (ContainerInterface::getContainedByObject(*inventoryContent) != targetInventoryObj) - continue; - - previousVolume = containingPOB->getPobItemCount(); - if ((previousVolume + inventoryContent->getVolume()) > pobItemLimit) - continue; - - // "Drop" the item, just as if the player had used the "Drop" radial - CommandCppFuncs::commandFuncTransferMisc(commandTransferItemMisc, getNetworkId(), inventoryContent->getNetworkId(), commandTransferItemMiscParams); - - // stop trying when POB is full - newVolume = containingPOB->getPobItemCount(); - if (newVolume >= pobItemLimit) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because the structure or POB ship is full."), Unicode::emptyString); - break; - } - - // update count of how many items have been dropped for the operation - numberOfItemsDroppedSoFar += std::max(0, (newVolume - previousVolume)); - - // stop trying when enough items have been dropped for the operation - if ((numberOfItemsDroppedSoFar > inventoryOverloadLimit) && (numberOfItemsDroppedSoFar > ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound())) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because \"enough\" items have been dropped."), Unicode::emptyString); - break; - } - - // only do so many items each round, to spread out the load - if (numberOfItemsToProcessThisRound <= 0) - break; - } - - // stop if POB is full - if (containingPOB->getPobItemCount() >= pobItemLimit) - break; - - // stop if enough items have been dropped for the operation - if ((numberOfItemsDroppedSoFar > inventoryOverloadLimit) && (numberOfItemsDroppedSoFar > ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound())) - break; - else - playerObject->setPickupDropAllItemsNumItemsSoFar(numberOfItemsDroppedSoFar); - - // stop if no more items can be dropped - if (numberOfItemsToProcessThisRound > 0) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because no more items in your inventory can be dropped or your inventory is empty."), Unicode::emptyString); - break; - } - - // queue up the next round of drop - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++DropAllInventoryItemsIntoRoom", - "", - 1, - false); - - return; - } - - // if we reach this point, it means we are stopping the operation, so cleanup - removeObjVarItem("pickupDropAllItemsOperation"); - - if (playerObject) - { - playerObject->setPickupDropAllItemsOperationId(0); - playerObject->setPickupDropAllItemsCellId(NetworkId::cms_invalid); - playerObject->setPickupAllItemsAllowInventoryOverload(false); - playerObject->setPickupDropAllItemsNumItemsSoFar(0); - playerObject->getPickupDropAllItemsProcessedItemsSoFar().clear(); - } - } - else if (message.getMethod() == "C++RestoreDecorationLayout") - { - // use while(true) loop to use break to discontinue processing and go to the end of loop to run cleanup code - PlayerObject * playerObject = NULL; - while (true) - { - playerObject = PlayerCreatureController::getPlayerObject(this); - if (!playerObject) - break; - - // player has disconnected - if (!getClient()) - break; - - // player is not "active", meaning he's probably doing it with a macro - if (playerObject->getSessionLastActiveTime() == 0) - break; - - int operationId = 0; - if (!getObjVars().getItem("restoreDecorationOperation.operationId", operationId) || (operationId == 0)) - break; - - if (operationId != playerObject->getRestoreDecorationOperationId()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because of an unexpected condition. Please try the operation again."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - ServerObject * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - ServerObject * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - if (containingPOBso->getNetworkId() != playerObject->getRestoreDecorationPobId()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - TangibleObject * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because of an internal error."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - if (!containingPOB->isOnAdminList(*this)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you are no longer the the owner or an admin of the structure or POB ship."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - int numberOfItemsToProcessThisRound = ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound(); - std::list, std::pair > > & restoreDecorationLayoutList = playerObject->getRestoreDecorationLayoutList(); - while (!restoreDecorationLayoutList.empty() && (numberOfItemsToProcessThisRound > 0)) - { - std::pair, std::pair > const & front = restoreDecorationLayoutList.front(); - restoreItemDecorationLayout(*this, *playerObject, front.first.first, *containingPOB, front.first.second, front.second.first, front.second.second); - playerObject->setRestoreDecorationAttemptedCount(playerObject->getRestoreDecorationAttemptedCount() + 1); - --numberOfItemsToProcessThisRound; - restoreDecorationLayoutList.pop_front(); - } - - if (restoreDecorationLayoutList.empty()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been completed."), Unicode::emptyString); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); - break; - } - - // queue up the next round of restore - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++RestoreDecorationLayout", - "", - 1, - false); - - return; - } - - // if we reach this point, it means we are stopping the operation, so cleanup - removeObjVarItem("restoreDecorationOperation"); - - if (playerObject) - { - playerObject->setRestoreDecorationOperationId(0); - playerObject->setRestoreDecorationPobId(NetworkId::cms_invalid); - playerObject->setRestoreDecorationTotalCount(0); - playerObject->setRestoreDecorationAttemptedCount(0); - playerObject->setRestoreDecorationSuccessCount(0); - playerObject->getRestoreDecorationLayoutList().clear(); - } - } - else if (message.getMethod() == "C++CityAddCitizen") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - const int cityId = atoi(params.c_str()); - if (cityId > 0) - CityInterface::enterCityChatRoom(cityId, *this); - } - } - else if (message.getMethod() == "C++CityRemoveCitizen") - { - if (!message.getPackedDataVector().empty()) - { - std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); - const int cityId = atoi(params.c_str()); - if (cityId > 0) - CityInterface::leaveCityChatRoom(cityId, *this); - } - } - else - { - TangibleObject::handleCMessageTo(message); - } -} - -//----------------------------------------------------------------------- - -bool CreatureObject::alwaysSendReliableTransform() const -{ - return false; -} - -//----------------------------------------------------------------------- - -bool CreatureObject::immediateLogoutAllowed() -{ - // Notes: - // 1. This should only be called on authoritative objects. - // 2. This call is triggered by a client disconnect that we will only see if a client is - // already associated with this object. - // 3. A client is only associated with an object when the object has finished baselines and - // is authoritative; therefore, we should never hit a case where a player that is logging - // in gets disconnected and causes this function to get called. - // 4. Even though this function is phrased as a query, it has some serious side effects. - // Calling it should be treated as if the caller is saying "Prepare for a disconnect" even - // though script can override and prevent an immediate logout. - DEBUG_FATAL(!isAuthoritative(), ("CreatureObject::immediateLogoutAllowed() should only be called on authoritative objects.")); - - // if we are in an npc conversation, end it - if (isInNpcConversation()) - endNpcConversation(); - - // if we are mounted, dismount. - if (getState(States::RidingMount)) - { - CreatureObject *const mountedCreature = getMountedCreature(); - if (mountedCreature) - mountedCreature->detachRider(getNetworkId()); - } - - virtualOnLogout(); - - LOG("CustomerService", ("Money:%s logging out with %d money", PlayerObject::getAccountDescription(getNetworkId()).c_str(), getTotalMoney())); - - ScriptParams params; - return (getScriptObject()->trigAllScripts(Scripting::TRIG_IMMEDIATE_LOGOUT, params) == SCRIPT_CONTINUE); -} - -//----------------------------------------------------------------------- - -float CreatureObject::getStepHeight() const -{ - return static_cast(getSharedTemplate())->getStepHeight(); -} - -//---------------------------------------------------------------------- - -float CreatureObject::getApproachTriggerRange() const -{ - return static_cast(getObjectTemplate())->getApproachTriggerRange(); -} - -//---------------------------------------------------------------------- - -void CreatureObject::setIsBeast(bool newValue) -{ - if(m_isBeast.get() != newValue) - { - m_isBeast.set(newValue); - } -} - -//---------------------------------------------------------------------- - -bool CreatureObject::setForceShowHam(bool show) -{ - if(!isAuthoritative()) - { - return false; - } - - m_forceShowHam.set(show); - return true; -} - -//---------------------------------------------------------------------- - -void CreatureObject::setIsStatic(bool newValue) -{ - if(m_isStatic.get() != newValue) - { - m_isStatic = newValue; - if (newValue) - { - TerrainObject* const terrain = TerrainObject::getInstance(); - if (terrain && terrain->isReferenceObject(this)) - terrain->removeReferenceObject(this); - // don't alter static creatures - if (!isPlayerControlled()) - setDefaultAlterTime(AlterResult::cms_keepNoAlter); - } - else - { - potentiallyAddToTerrain(); - if (!isPlayerControlled()) - setDefaultAlterTime(AlterResult::cms_alterQuickly); - } - } -} - -//---------------------------------------------------------------------- - -bool CreatureObject::potentiallyAddToTerrain() -{ - //@todo don't make reference object if any of the following are true: - // check is "asleep" (must add when woken up) - - TerrainObject* const terrain = TerrainObject::getInstance (); - if ( isAuthoritative() && !getIsStatic() && !getCreatureController()->getHibernate() && terrain && !terrain->isReferenceObject(this) && isInWorldCell() ) - { - terrain->addReferenceObject(this); - return true; - } - return false; -} - -//---------------------------------------------------------------------- - -void CreatureObject::virtualOnAddedToWorldCell() -{ - TangibleObject::virtualOnAddedToWorldCell(); - potentiallyAddToTerrain(); - m_lastRegionNotifyPosition = getPosition_w(); - m_lastRegionNotifyPosition.x += 1.0f; // force a check - checkNotifyRegions(); -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::virtualOnRemovedFromWorldCell() -{ - TangibleObject::virtualOnRemovedFromWorldCell(); - - TerrainObject* const terrain = TerrainObject::getInstance(); - if (terrain && terrain->isReferenceObject(this)) - terrain->removeReferenceObject(this); -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::virtualOnSetAuthority() -{ - TangibleObject::virtualOnSetAuthority(); - - potentiallyAddToTerrain(); - - for (int i = 0; i < Attributes::NumberOfAttributes; ++i) - m_regeneration[i] = 0; - - if (isPlayerControlled()) - { - setNumberOfMissionsWantedInMissionBag(ConfigServerGame::getNumberOfMissionsWantedInMissionBag()); - - if (isInitialized()) - { - Client *client = GameServer::getInstance().getClient(getNetworkId()); - if (client) - client->onLoadPlayer(*this); - } - } - - AICreatureController * const controller = AICreatureController::asAiCreatureController(getController()); - - if (controller) - controller->setAuthority(true); - - //-- Update the creature's group mission critical object set - GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::virtualOnReleaseAuthority() -{ - TangibleObject::virtualOnReleaseAuthority(); - TerrainObject* const terrain = TerrainObject::getInstance(); - if (terrain && terrain->isReferenceObject(this)) - terrain->removeReferenceObject(this); - - AICreatureController * const controller = AICreatureController::asAiCreatureController(getController()); - - if(controller) - { - if (getProperty(SlopeEffectProperty::getClassPropertyId()) != NULL) - removeProperty(SlopeEffectProperty::getClassPropertyId()); - controller->setAuthority(false); - } -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::virtualOnLogout() -{ - TangibleObject::virtualOnLogout(); - PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); - if (player != NULL) - player->virtualOnLogout(); -} - -//------------------------------------------------------------------------------------------ - -bool CreatureObject::wantSawAttackTriggers() const -{ - if (isDisabled()) - return false; - return TangibleObject::wantSawAttackTriggers(); -} - -//---------------------------------------------------------------------- - -void CreatureObject::addPackedWearable(std::string const &appearanceData, int arrangementIndex, NetworkId const &networkId, uint32 sharedTemplateCrcValue, const BaselinesMessage * weaponSharedBaselines, const BaselinesMessage * weaponSharedNpBaselines) -{ - //-- Check if this network id already exists in the wearable list. - size_t const length = m_wearableData.size(); - for (size_t i = 0; i < length; ++i) - { - WearableEntry const &entry = m_wearableData[i]; - if (entry.m_networkId == networkId) - { - // Check if this entry exists but in a different configuration. - WARNING((entry.m_arrangement != arrangementIndex), ("attempted to add object id=[%s] in packed wearable list multiple times in different arrangements, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_arrangement, arrangementIndex)); - WARNING((static_cast(entry.m_objectTemplate) != sharedTemplateCrcValue), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by shared object template crc value, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_objectTemplate, static_cast(sharedTemplateCrcValue))); - DEBUG_WARNING((entry.m_appearanceString != appearanceData), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by appearance customization data.", appearanceData.c_str())); - - // Done, this entry is already in the wearable data list. - - // we own the weaponSharedBaselines and weaponSharedBaselines pointers, so if - // we are not going to add them to the wearables list, we must delete them - if (weaponSharedBaselines) - delete weaponSharedBaselines; - if (weaponSharedNpBaselines) - delete weaponSharedNpBaselines; - - return; - } - } - - //-- Add the new entry. - m_wearableData.push_back(WearableEntry(appearanceData, arrangementIndex, networkId, sharedTemplateCrcValue, weaponSharedBaselines, weaponSharedNpBaselines)); -} - -//---------------------------------------------------------------------- - -void CreatureObject::packWearables() -{ - // Pack wearables data - - SlottedContainer const * const myContainer = ContainerInterface::getSlottedContainer(*this); - - if (myContainer) - { - Object const * inventory = 0; - Object const * datapad = 0; - Object const * appearance = 0; - Container::ContainerErrorCode tmp = Container::CEC_Success; - static SlotId const inventorySlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); - if (inventorySlot != SlotId::invalid) - { - Container::ContainedItem itemId = myContainer->getObjectInSlot(inventorySlot, tmp); - inventory = itemId.getObject(); - } - SlotId datapadSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::datapad); - if (datapadSlot != SlotId::invalid) - { - Container::ContainedItem itemId = myContainer->getObjectInSlot(datapadSlot, tmp); - datapad = itemId.getObject(); - } - SlotId appearanceInvSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); - if (appearanceInvSlot != SlotId::invalid) - { - Container::ContainedItem itemId = myContainer->getObjectInSlot(appearanceInvSlot, tmp); - appearance = itemId.getObject(); - } - - for (ContainerConstIterator iter = myContainer->begin(); iter != myContainer->end(); ++iter) - { - Object const * const o = (*iter).getObject(); - if (o) - { - ServerObject const * const so = o->asServerObject(); - if (so) - { - TangibleObject const * const tang = so->asTangibleObject(); - if (tang) - { - SlottedContainmentProperty const * const scp = ContainerInterface::getSlottedContainmentProperty(*tang); - if (scp) - { - if (scp->isInAppearanceSlot() || tang == inventory || tang == datapad ) - { - ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tang->getClientSharedTemplateName()); - if (clientSharedTemplateNameCrcString.isEmpty()) - WARNING(true, ("Could not find crc for [%s]. Wearable will not be streamed to client", tang->getClientSharedTemplateName())); - else if (so->asWeaponObject() != NULL) - { - addPackedWearable(tang->getAppearanceData(), scp->getCurrentArrangement(), tang->getNetworkId(), clientSharedTemplateNameCrcString.getCrc(), - tang->createSharedBaselinesMessage(), tang->createSharedNpBaselinesMessage()); - } - else - addPackedWearable(tang->getAppearanceData(), scp->getCurrentArrangement(), tang->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); - } - } - } - } - } - } - - if(appearance) - { - SlottedContainer const * const myAppearanceContainer = ContainerInterface::getSlottedContainer(*appearance); - for(ContainerConstIterator iter = myAppearanceContainer->begin(); iter!= myAppearanceContainer->end(); ++iter) - { - Object const * const o = (*iter).getObject(); - if (o) - { - ServerObject const * const so = o->asServerObject(); - if (so) - { - TangibleObject const * const tang = so->asTangibleObject(); - if (tang) - { - SlottedContainmentProperty const * const scp = ContainerInterface::getSlottedContainmentProperty(*tang); - if (scp) - { - if (scp->isInAppearanceSlot()) - { - ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tang->getClientSharedTemplateName()); - if (clientSharedTemplateNameCrcString.isEmpty()) - WARNING(true, ("Could not find crc for [%s]. Wearable will not be streamed to client", tang->getClientSharedTemplateName())); - else - addPackedAppearanceWearable(tang->getAppearanceData(), scp->getCurrentArrangement(), tang->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); - } - } - } - } - } - } - } - } -} - -// ---------------------------------------------------------------------- - -/** - * Called when we get an ack back that a Jedi slot has been added to our account. - * This function should only be called by PlayerObject::addJediToAccountAck()! - */ -void CreatureObject::addJediToAccountAck() -{ - // flag success via an objvar so we can end the timed callback C++AddJediSlot - setObjVarItem(OBJVAR_ADD_JEDI_ACK, 1); -} // CreatureObject::addJediToAccountAck - - -//---------------------------------------------------------------------- - -void CreatureObject::setNumberOfMissionsWantedInMissionBag(int n) -{ - int i = 0; - ServerObject * const missionBag = getMissionBag(); - if(missionBag) - { - Container * const container = ContainerInterface::getContainer(*missionBag); - ContainerIterator iter; - for(iter = container->begin(); iter != container->end(); ++iter) - { - Object * const o = (*iter).getObject(); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so && so->asMissionObject()) - ++i; - } - } - - if (n - i > 0) - { - if (m_numberOfMissionsWantedInMissionBag <= 0) - { - // place object on mission object create queue - s_missionQueue.push_back(getNetworkId()); - } - m_numberOfMissionsWantedInMissionBag = n - i; - } - else if (i - n > 0) - { - // remove mission objects from the bag - int j = 0; - for (iter = container->begin(), j = 0; iter != container->end(), j < i - n; ++iter, ++j) - { - Object * const o = (*iter).getObject(); - if (o) - { - ServerObject * const so = o->asServerObject(); - if (so && so->asMissionObject()) - so->kill(); - } - } - } - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::runMissionCreationQueue() -{ - int i = ConfigServerGame::getMissionCreationQueueSize(); - while(i > 0 && !s_missionQueue.empty()) - { - const NetworkId id = s_missionQueue.front(); - s_missionQueue.pop_front(); - CreatureObject * creature = safe_cast(NetworkIdManager::getObjectById(id)); - if(creature) - { - if(creature->isAuthoritative()) - { - if(MissionObject::createMissionObjectInCreatureMissionBag(creature)) - creature->m_numberOfMissionsWantedInMissionBag--; - if(creature->m_numberOfMissionsWantedInMissionBag > 0) - s_missionQueue.push_back(id); - } - } - i--; - } -} - -//---------------------------------------------------------------------- - -int CreatureObject::getMaxNumberOfLots() const -{ - return HOUSING_MAX_LOTS; -} - -//---------------------------------------------------------------------- - -NetworkId CreatureObject::getHouse() const -{ - NetworkId houseId; - - // the objvar houseId is per player and is used if it exists - if (getObjVars().getItem(OBJVAR_PLAYER_HOUSE_ID, houseId)) - return houseId; - - return NetworkId::cms_invalid; -} - -//---------------------------------------------------------------------- - -void CreatureObject::setHouse(const CachedNetworkId & houseId) -{ - if (isAuthoritative()) - { - // store as an objvar to keep this id per player vs. per account - setObjVarItem(OBJVAR_PLAYER_HOUSE_ID, houseId); - } - else - { - sendControllerMessageToAuthServer(CM_setHouse, new MessageQueueGenericValueType(houseId)); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::getAvailableLocomotions() -{ - getMovementTable()->getAllLocomotions(m_posture.get(), m_states.get(), m_fastLocomotion, m_slowLocomotion, m_stationaryLocomotion); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::calcPvpableState() -{ - setPvpable(true); -} - -// ---------------------------------------------------------------------- - -float CreatureObject::getBaseWalkSpeed() const -{ - float speed = m_baseWalkSpeed.get(); - if (speed < 0.0f) - return safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_walk); - return speed; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setBaseWalkSpeed(float speed) -{ - if (isAuthoritative()) - { - if (m_baseWalkSpeed.get() != speed) - { - m_baseWalkSpeed = speed; - requestMovementInfoUpdate(); - } - } - else - { - Controller *controller = getController(); - if (controller) - controller->appendMessage( - CM_creatureSetBaseWalkSpeed, - speed, - 0, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -// ---------------------------------------------------------------------- - -float CreatureObject::getBaseRunSpeed() const -{ - float speed = m_baseRunSpeed.get(); - if (speed < 0.0f) - return safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_run); - return speed; -} - -// ---------------------------------------------------------------------- - -int CreatureObject::loadPackedHouses() -{ - int numHouses = 0; - ServerObject *datapad = getDatapad(); - if (datapad) - { - VolumeContainer const * datapadContainer = ContainerInterface::getVolumeContainer(*datapad); - if (datapadContainer) - { - // iterate over contents. - for(ContainerConstIterator iter(datapadContainer->begin()); - iter != datapadContainer->end(); - ++iter) - { - const CachedNetworkId & objId = (*iter); - const ServerObject * obj = safe_cast(objId.getObject()); - if (obj && (obj->getGameObjectType() == SharedObjectTemplate::GOT_data_house_control_device)) - { - // if object is a house control device, then go ahead and get the first contained item - - // should be the house itself. - SlottedContainer const *hcdContainer = ContainerInterface::getSlottedContainer(*obj); - if (hcdContainer && hcdContainer->getNumberOfItems() > 0) - { - //load the contents for the house. - for(ContainerConstIterator hcdIter(hcdContainer->begin()); - hcdIter != hcdContainer->end(); - ++hcdIter) - { - Object * const houseId = (*hcdIter).getObject(); - BuildingObject * const house = (houseId ? houseId->asServerObject()->asBuildingObject() : NULL); - if (house && !house->getContentsLoaded()) - { - LOG("CustomerService", ("CharacterTransfer: starting packed house load (%s) for CTS character %s", house->getNetworkId().getValueString().c_str(), PlayerObject::getAccountDescription(this).c_str())); - - numHouses++; - house->loadContents(); - setLoadCTSPackedHouses(true); - } - } - } - } - } - } - } - - return numHouses; -} - -// ---------------------------------------------------------------------- - -std::vector CreatureObject::uploadCharacterData(const bool withItems, const bool allowOverride) -{ - std::vector result; - - if(getClient()) - { - GameScriptObject * scriptObject = getScriptObject(); - if(scriptObject) - { - int resultSize = 0; - std::vector tmp; - tmp.resize(ConfigServerGame::getCtsDefaultScriptDictionarySizeBytes()); - - ScriptParams p; - p.addParam(tmp); - p.addParam(resultSize); - p.addParam(withItems); - p.addParam(allowOverride); - REPORT_LOG(true, ("Calling OnStartCharacterUpload from CreatureObject.cpp\n")); - IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_START_CHARACTER_UPLOAD, p)); - - resultSize = p.getIntParam(1); - tmp = p.getByteArrayParam(0); - int i; - for(i=0; i < resultSize; ++i) - { - result.push_back(tmp[static_cast(i)]); - } - LOG("CustomerService", ("CharacterTransfer: CreatureObject::uploadCharacterData() yields a buffer %d bytes long", result.size())); - } - } - return result; -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::receiveCharacterTransferMessage(const std::vector & packedCharacterData) -{ - bool result = false; - GameScriptObject * scriptObject = getScriptObject(); - if(scriptObject) - { - ScriptParams p; - p.addParam(packedCharacterData); - if(scriptObject->trigAllScripts(Scripting::TRIG_DOWNLOAD_CHARACTER, p)) - { - result = true; - } - } - - if (result) - { - // tell CentralServer to not allow login for this character - // until the character has been persisted and unloaded - GenericValueTypeMessage > > const msg( - "SetSceneForPlayer", - std::make_pair( - getNetworkId(), - std::make_pair(ServerWorld::getSceneId(), true))); - - GameServer::getInstance().sendToCentralServer(msg); - - // set the idle time so that the character will be disconnected - // in ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec() - // so that the character will get unloaded after the next save cycle, - // so that the player can log in the character; this should be much - // faster than the default idle disconnect behavior where the character - // would get disconnected in ConfigServerGame::getIdleLogoutTimeSec() - if (getClient()) - getClient()->resetIdleTimeAfterCharacterTransfer(); - } - - return result; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::receiveCharacterTransferStatusMessage(const std::string & statusMessage) -{ - GameScriptObject * scriptObject = getScriptObject(); - if(scriptObject) - { - ScriptParams p; - p.addParam(statusMessage.c_str()); - scriptObject->trigAllScripts(Scripting::TRIG_RECEIVE_CHARACTER_TRANSFER_STATUS_MESSAGE, p); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setBaseRunSpeed(float speed) -{ - if (isAuthoritative()) - { - if (m_baseRunSpeed.get() != speed) - { - m_baseRunSpeed = speed; - requestMovementInfoUpdate(); - } - } - else - { - Controller *controller = getController(); - if (controller) - controller->appendMessage( - CM_creatureSetBaseRunSpeed, - speed, - 0, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -// ---------------------------------------------------------------------- - -/** - * Tests if this creature has a bounty on another creature. - * (Virtual function, overriden in SwgCreatureObject) - * - * @param target the creature to test if we have a bounty on - * - * @return true if we have a bounty on the target, false if not - */ -bool CreatureObject::hasBounty(const CreatureObject & target) const -{ - //@todo: this should really be a function of the pvp classes, but we - // need this to be virtual - return false; -} // CreatureObject::hasBounty - -// ---------------------------------------------------------------------- - -/** - * Tests if this creature has a bounty on anything. - * (Virtual function, overriden in SwgCreatureObject, can't be pure virtual - * because ServerCreatureObjectTemplate has a function that instantiates a CreatureObject) - */ -bool CreatureObject::hasBounty() const -{ - return false; -} - -// ---------------------------------------------------------------------- - -/** - * Return a list of all the bounty hunters targeting this creature. - * - * Overriden in SwgCreatureObject. - */ -std::vector const & CreatureObject::getJediBountiesOnMe() const -{ - static const std::vector nothing; - return nothing; -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::hasBountyMissionForTarget(const NetworkId & targetId) const -{ - const ServerObject * const datapad = getDatapad(); - if (!datapad) - return false; - - const Container * const container = ContainerInterface::getContainer(*datapad); - if (!container) - return false; - - for (ContainerConstIterator iter = container->begin(); iter != container->end(); ++iter) - { - const ServerObject * const serverMissionObject = safe_cast((*iter).getObject()); - if (serverMissionObject) - { - const MissionObject * const missionObject = serverMissionObject->asMissionObject(); - if (missionObject) - { - static const unsigned int bounty = CrcLowerString::calculateCrc("bounty"); - NetworkId bountyTargetId; - - if ((missionObject->getMissionType() == bounty) && (missionObject->getObjVars().getItem("objTarget", bountyTargetId)) && (bountyTargetId == targetId)) - return true; - } - } - } - - return false; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setAlternateAppearance(std::string const &sharedObjectTemplateName) -{ - //-- Ensure we're authoritative. - if (!isAuthoritative()) - { - WARNING(true, - ("CreatureObject::setAppearanceFromObjectTemplate(): called on non-authoritative object id=[%s], server id=[%d]", - getNetworkId().getValueString().c_str(), - static_cast(GameServer::getInstance().getProcessId()) - )); - return; - } - - // See if we're trying to turn off our alt appearance - std::string const none("none"); - if(sharedObjectTemplateName.find(none) != std::string::npos && sharedObjectTemplateName.size() == none.size()) - { - GameScriptObject * const scriptObject = this->getScriptObject(); - if(scriptObject) - { - ScriptParams params; - params.addParam(getNetworkId()); - if(scriptObject->trigAllScripts(Scripting::TRIG_ON_ABOUT_TO_REVERT_APPEARANCE, params) == SCRIPT_OVERRIDE) - return; - m_alternateAppearanceSharedObjectTemplateName.set(sharedObjectTemplateName); - - setState(States::Disguised, false); - - params.clear(); - params.addParam(getNetworkId()); - - IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_REVERTED_APPEARANCE, params)); - - } - - return; - } - - //-- Ensure the serverObjectTemplateName exists. - if (sharedObjectTemplateName.empty() || !TreeFile::exists(sharedObjectTemplateName.c_str())) - { - WARNING(true, - ("CreatureObject::setAppearanceFromObjectTemplate(): called on id=[%s], server id=[%d]: invalid serverObjectTemplateName [%s]", - getNetworkId().getValueString().c_str(), - static_cast(GameServer::getInstance().getProcessId()), - sharedObjectTemplateName.c_str() - )); - return; - } - - - ObjectTemplate const *sharedObjectTemplate = ObjectTemplateList::fetch(sharedObjectTemplateName); - SharedCreatureObjectTemplate const *const sharedObjectTemplateAsCreature = dynamic_cast(sharedObjectTemplate); - - if (sharedObjectTemplate && sharedObjectTemplateAsCreature) - { - //-- Ensure there is an appearance filename. - if (!sharedObjectTemplateAsCreature->getAppearanceFilename().empty()) - { - GameScriptObject * const scriptObject = this->getScriptObject(); - if(scriptObject) - { - ScriptParams params; - params.addParam(getNetworkId()); - params.addParam(sharedObjectTemplateName.c_str()); - - if(scriptObject->trigAllScripts(Scripting::TRIG_ON_ABOUT_TO_CHANGE_APPEARANCE, params) == SCRIPT_OVERRIDE) - return; - - //-- Set the alternate shared object template name since it is different from the natural shared object template name. - m_alternateAppearanceSharedObjectTemplateName.set(sharedObjectTemplateAsCreature->getAppearanceFilename()); - - setState(States::Disguised, true); - - params.clear(); - params.addParam(getNetworkId()); - - IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_CHANGED_APPEARANCE, params)); - } - - } - - // Release resources. - sharedObjectTemplate->releaseReference(); - sharedObjectTemplate = 0; - } - -} - -// ====================================================================== - -bool operator!=(CreatureMod const &a, CreatureMod const &b) -{ - return a.mod != b.mod - || a.startTime != b.startTime - || a.maxVal != b.maxVal - || a.currentVal != b.currentVal; -} - -// ====================================================================== - -namespace Archive -{ - void put(Archive::ByteStream &target, CreatureAttitude const &state) - { - target.put(&state.m_behavior, 4); - target.put(&state.m_angerState, 4); - target.put(&state.m_fearState, 4); - for (int i = 0; i < MentalStates::NumberOfMentalStates; ++i) - target.put(&state.m_currentValues[i], 4); - } - - void get(Archive::ReadIterator &source, CreatureAttitude &state) - { - source.get(&state.m_behavior, 4); - source.get(&state.m_angerState, 4); - source.get(&state.m_fearState, 4); - for (int i = 0; i < MentalStates::NumberOfMentalStates; ++i) - source.get(&state.m_currentValues[i], 4); - } - - //---------------------------------------------------------------------- - - void put(Archive::ByteStream &target, MonitoredCreatureMovement const &state) - { - target.put(&state.m_lastDistance, sizeof(state.m_lastDistance)); - target.put(&state.m_skittishness, sizeof(state.m_skittishness)); - target.put(&state.m_curve, sizeof(state.m_curve)); - } - - void get(Archive::ReadIterator &source, MonitoredCreatureMovement &state) - { - source.get(&state.m_lastDistance, sizeof(state.m_lastDistance)); - source.get(&state.m_skittishness, sizeof(state.m_skittishness)); - source.get(&state.m_curve, sizeof(state.m_curve)); - } - - //---------------------------------------------------------------------- - - void put(Archive::ByteStream &target, CreatureMod const &mod) - { - target.put(&mod.startTime, sizeof(mod.startTime)); - target.put(&mod.maxVal, sizeof(mod.maxVal)); - target.put(&mod.currentVal, sizeof(mod.currentVal)); - put(target, mod.mod); - } - - void get(Archive::ReadIterator &source, CreatureMod &mod) - { - source.get(&mod.startTime, sizeof(mod.startTime)); - source.get(&mod.maxVal, sizeof(mod.maxVal)); - source.get(&mod.currentVal, sizeof(mod.currentVal)); - get(source, mod.mod); - } -}; - -//---------------------------------------------------------------------- - -float CreatureObject::getWalkSpeed () const -{ - float walkSpeed = m_walkSpeed.get(); - - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - if (m_vehiclePhysicsData) - { - walkSpeed = m_vehiclePhysicsData->m_walkSpeed; - } - } - - return walkSpeed * getMovementScale() * getMovementPercent(); -} - -//---------------------------------------------------------------------- - -float CreatureObject::getRunSpeed () const -{ - float runSpeed = m_runSpeed.get(); - - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - if (m_vehiclePhysicsData) - { - runSpeed = m_vehiclePhysicsData->m_runSpeed; - } - } - - return runSpeed * getMovementScale() * getMovementPercent(); -} - -//---------------------------------------------------------------------- - -float CreatureObject::getAccelerationForSpeed (float currentSpeed) const -{ - float accel = 0.0f; - - if (currentSpeed <= getWalkSpeed ()) - accel = safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_walk); - else - accel = safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_run); - - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - if (m_vehiclePhysicsData) - { - if (m_vehiclePhysicsData->m_runSpeed) - { - const float speedPercent = std::min (1.0f, currentSpeed / m_vehiclePhysicsData->m_runSpeed); - accel = m_vehiclePhysicsData->m_accelerationMin + (m_vehiclePhysicsData->m_accelerationMax - m_vehiclePhysicsData->m_accelerationMin) * speedPercent; - } - } - } - - return accel * getAccelScale() * getAccelPercent(); -} - -//---------------------------------------------------------------------- - -float CreatureObject::getTurnRateForSpeed (float currentSpeed) const -{ - float turnRate = 0.0f; - - if (currentSpeed <= getWalkSpeed ()) - turnRate = safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_walk); - else - turnRate = safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_run); - - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - if (m_vehiclePhysicsData) - { - if (m_vehiclePhysicsData->m_runSpeed) - { - const float speedPercent = std::min (1.0f, currentSpeed / m_vehiclePhysicsData->m_runSpeed); - turnRate = convertRadiansToDegrees (m_vehiclePhysicsData->m_turnRateMin + (m_vehiclePhysicsData->m_turnRateMax - m_vehiclePhysicsData->m_turnRateMin) * speedPercent); - } - } - } - - return turnRate; -} - -//---------------------------------------------------------------------- - -float CreatureObject::getSlopeMod () const -{ - return 1.0f; -} - -//----------------------------------------------------------------------- - -float CreatureObject::getAcceleration(SharedCreatureObjectTemplate::MovementTypes movementType) const -{ - float walk = getAccelerationForSpeed (getWalkSpeed ()); - float run = getAccelerationForSpeed (getRunSpeed ()); - - if (walk < 0.1f) - walk = 0.1f; - if (walk < run) - { - run = walk; - } - if (movementType == SharedCreatureObjectTemplate::MT_walk) - return walk; - else - return run; -} - -//----------------------------------------------------------------------- - -float CreatureObject::getTurnRate(SharedCreatureObjectTemplate::MovementTypes movementType) const -{ - float walk = getTurnRateForSpeed (getWalkSpeed ()); - float run = getTurnRateForSpeed (getRunSpeed ()); - - if (walk < 30.0f) - walk = 30.0f; - if (walk < run) - { - run = walk * 0.5f; - } - if (movementType == SharedCreatureObjectTemplate::MT_walk) - return walk; - else - return run; -} - -//---------------------------------------------------------------------- - -void CreatureObject::updateVehiclePhysicsData () -{ - if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) - { - if (!m_vehiclePhysicsData) - m_vehiclePhysicsData = new VehiclePhysicsData; - - const CustomizationData *const cd = fetchCustomizationData(); - if (cd) - { - VehicleHoverDynamics::readParamsFromCustomizationData (*cd, - m_vehiclePhysicsData->m_minMoveSpeed, - m_vehiclePhysicsData->m_runSpeed, - m_vehiclePhysicsData->m_turnRateMin, - m_vehiclePhysicsData->m_turnRateMax, - m_vehiclePhysicsData->m_accelerationMin, - m_vehiclePhysicsData->m_accelerationMax); - - cd->release (); - m_vehiclePhysicsData->m_walkSpeed = 0.5f * m_vehiclePhysicsData->m_runSpeed; - return; - } - } - - if (m_vehiclePhysicsData) - { - delete m_vehiclePhysicsData; - m_vehiclePhysicsData = 0; - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::unequipAllItems() -{ - //-- Ensure we're authoritative. - if (!isAuthoritative()) - { - WARNING(true, - ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d] but this object is not authoritative.", - getNetworkId().getValueString().c_str(), - getObjectTemplateName(), - static_cast(GameServer::getInstance().getProcessId()) - )); - return; - } - - //-- Get the equipment container for the creature. - SlottedContainer * const equipmentContainer = ContainerInterface::getSlottedContainer(*this); - if (!equipmentContainer) - { - WARNING(true, - ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d]: failed to get equipment slotted container, error code=[%d].", - getNetworkId().getValueString().c_str(), - getObjectTemplateName(), - static_cast(GameServer::getInstance().getProcessId()) - )); - return; - } - - //-- Get the inventory container for the creature. - Container::ContainerErrorCode errorCode = Container::CEC_Success; - Container::ContainedItem inventoryContainedItem = equipmentContainer->getObjectInSlot(s_inventorySlotId, errorCode); - Object *const inventoryObjectBase = inventoryContainedItem.getObject(); - ServerObject *const inventoryObject = inventoryObjectBase ? inventoryObjectBase->asServerObject() : NULL; - if (!inventoryObject || (errorCode != Container::CEC_Success)) - { - WARNING(true, - ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d]: failed to get inventory object from equipment, error code=[%d].", - getNetworkId().getValueString().c_str(), - getObjectTemplateName(), - static_cast(GameServer::getInstance().getProcessId()), - static_cast(errorCode) - )); - return; - } - - VolumeContainer *const inventoryContainer = ContainerInterface::getVolumeContainer(*inventoryObject); - if (!inventoryContainer) - { - WARNING(true, - ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d]: inventory object is NULL.", - getNetworkId().getValueString().c_str(), - getObjectTemplateName(), - static_cast(GameServer::getInstance().getProcessId()) - )); - return; - } - - //-- Collect items to move into inventory. This includes items in all slots that players can manipulate. - typedef std::vector ServerObjectVector; - ServerObjectVector itemsToTransfer; - - { - ContainerIterator const endIt = equipmentContainer->end(); - for (ContainerIterator it = equipmentContainer->begin(); it != endIt; ++it) - { - // Get the equipment item. - Container::ContainedItem containedItem = *it; - Object *const objectBase = containedItem.getObject(); - ServerObject *const object = objectBase ? objectBase->asServerObject() : NULL; - if (!object) - { - WARNING(true, - ("null object in equipment container for object id=[%s]: equipment item id=[%s].", - getNetworkId().getValueString().c_str(), - containedItem.getValueString().c_str() - )); - continue; - } - - // Get the slotted containment property so we can check the slot characteristics. - SlottedContainmentProperty const *const property = ContainerInterface::getSlottedContainmentProperty(*object); - if (!property) - { - WARNING(true, - ("object in equipment container for object id=[%s], equipment item id=[%s] has no SlottedContainmentProperty.", - getNetworkId().getValueString().c_str(), - containedItem.getValueString().c_str() - )); - continue; - } - - // Check if any of the current arrangement's slots are not player manipulatable. - if (property->canManipulateArrangement(property->getCurrentArrangement())) - itemsToTransfer.push_back(object); - } - } - - //-- Transfer selected equipped items to inventory. - { - ServerObjectVector::iterator const endIt = itemsToTransfer.end(); - for (ServerObjectVector::iterator it = itemsToTransfer.begin(); it != endIt; ++it) - { - ServerObject *const object = *it; - if (!object) - continue; - - ContainerInterface::transferItemToVolumeContainer(*inventoryObject, *object, NULL, errorCode); - WARNING(errorCode != Container::CEC_Success, - ("unequipAllItems(): CreatureObject id=[%s] failed to transfer item id=[%s], template=[%s] from equipment to inventory container, container error code [%d].", - getNetworkId().getValueString().c_str(), - object->getNetworkId().getValueString().c_str(), - object->getObjectTemplateName(), - static_cast(errorCode) - )); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::virtualOnSetClient() -{ - TangibleObject::virtualOnSetClient(); - - handleTutorialTransition(); - - setNumberOfMissionsWantedInMissionBag(ConfigServerGame::getNumberOfMissionsWantedInMissionBag()); -} - -//---------------------------------------------------------------------- - -std::vector CreatureObject::getWearableData() -{ - return m_wearableData.get(); -} - -//---------------------------------------------------------------------- - -void CreatureObject::setWearableData(std::vector const & packedWearables) -{ - m_wearableData.set(packedWearables); -} - -//---------------------------------------------------------------------- - -void CreatureObject::onContainedItemAppearanceDataModified(TangibleObject const & target, std::string const & oldValue, std::string const & value) -{ - TangibleObject::onContainedItemAppearanceDataModified(target, oldValue, value); - - if(oldValue != value) - { - std::vector wearableData = getWearableData(); - for(std::vector::iterator i = wearableData.begin(); i != wearableData.end(); ++i) - { - if(target.getNetworkId() == i->m_networkId) - { - i->m_appearanceString = value; - setWearableData(wearableData); - //there will only be one object with the target's networkid, so we can return - return; - } - } - } -} - -//---------------------------------------------------------------------- - -void CreatureObject::updateGroup() -{ - GroupObject * group = getGroup(); - if(group) - { - const std::vector > & groupMembers = group->getGroupMembers(); - - // if there are members that might need an update - if(! groupMembers.empty()) - { - // setup the update status message that is sent to the client - if(! m_clientMfdStatusUpdateMessage) - { - // this is the first time an update might need to have been sent - m_clientMfdStatusUpdateMessage = new ClientMfdStatusUpdateMessage(getNetworkId(), ServerWorld::getSceneId(), findPosition_w(), ConfigFile::getKeyFloat("ServerGame", "groupLocationUpdateTimer", 1.0f), ConfigFile::getKeyFloat("ServerGame", "groupLocationUpdateMinimumMoveDistance", 64.0f)); - } - else - { - // it's already been constructed, update members - m_clientMfdStatusUpdateMessage->setSceneName(ServerWorld::getSceneId()); - m_clientMfdStatusUpdateMessage->setWorldCoordinates(findPosition_w()); - } - - // if there are still members to update since the last calculation, select - // the first one in the list and send the message - if(! m_clientMfdStatusUpdateMessage->getMembersToUpdate().empty()) - { - if(m_clientMfdStatusUpdateMessage->updateMemberUpdateTimer(Clock::frameTime())) - { - // default, assume that the object is observed and no messageTo - // is needed - bool sendMessageTo = false; - - while(! sendMessageTo && (!m_clientMfdStatusUpdateMessage->getMembersToUpdate().empty())) - { - static Archive::ByteStream bs; - bs.clear(); - NetworkId memberId = m_clientMfdStatusUpdateMessage->getMembersToUpdate().back(); - m_clientMfdStatusUpdateMessage->getMembersToUpdate().pop_back(); - - if(memberId != getNetworkId()) - { - // cull bad network id's - if(memberId != NetworkId::cms_invalid) - { - Object * obj = NetworkIdManager::getObjectById(memberId); - if(obj) - { - ServerObject * target = obj->asServerObject(); - if(target && target->getClient()) - { - // check to see whether the target observing this creature - // if it is, then the client will be updated automatically - if(! ObserveTracker::isObserving(*target->getClient(), *this)) - { - // this creature is not being observed by the target player - // if it is authoritative on this server, however, send - // the message directly. - if(target->isAuthoritative()) - { - target->getClient()->send(*m_clientMfdStatusUpdateMessage, false); - } - else - { - // the object is valid, but - // not authoritative on this - // server, send a messageTO - sendMessageTo = true; - } - } // else normal game operation will take care of updating the client MFD status window - } - else if(target && !target->getClient() && !target->isAuthoritative()) - { - // target is valid, but probably a proxy of a player - // controlled object. Send a message to the remote - // server - sendMessageTo = true; - } - else if(! target) - { - WARNING_STRICT_FATAL(true, ("While updating group locations, group member ID %s refers to an object that is not a server object!", memberId.getValueString().c_str())); - } - } - else - { - // not on this server, send a message - sendMessageTo = true; - } - } // else memberId is an invalid NetworkId - } // else memberId is self - if(sendMessageTo) - { - // the group member is not locally authoritative - // on this server and is not being observed, the only - // way to get data to the group member is by sending - // a message to. - - bs.clear(); - m_clientMfdStatusUpdateMessage->pack(bs); - // send the messageTo to the target object - MessageToQueue::getInstance().sendMessageToC(memberId, "ClientMfdStatusUpdateMessage", std::string(reinterpret_cast(bs.getBuffer()), bs.getSize()), 0, false); - } - } - } - } - // If the message hasn't changed since the last attempt, don't - // bother sending the update - else if(m_clientMfdStatusUpdateMessage->getHasChanged()) - { - // add group members to the mfs status update member id list - m_clientMfdStatusUpdateMessage->getMembersToUpdate().clear(); - std::vector >::const_iterator i; - for(i = groupMembers.begin(); i != groupMembers.end(); ++i) - { - if(i->first != NetworkId::cms_invalid && i->first != getNetworkId()) - m_clientMfdStatusUpdateMessage->addMemberToUpdate(i->first); - } - } - } - else - { - // the group is empty, clean up any memory that might have been used before - delete m_clientMfdStatusUpdateMessage; - m_clientMfdStatusUpdateMessage = 0; - } - } - else - { - // the group is empty, clean up any memory that might have been used before - delete m_clientMfdStatusUpdateMessage; - m_clientMfdStatusUpdateMessage = 0; - } - - if(m_clientMfdStatusUpdateMessage) - { - m_clientMfdStatusUpdateMessage->setHasChanged(false); - } -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::handleTutorialTransition() -{ - // this is where all the code lives for the special transitions for the tutorial... - // much of the implementation is implemented in NewbieTutorial and is called through here - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - - if (playerObject) - { - // check if this player is coming from the character creation / selection screen - bool isFromLogin = playerObject->getIsFromLogin(); - playerObject->setIsFromLogin(false); - bool startTutorial = !ConfigServerGame::getSkipTutorial(); - if (startTutorial) - { - // let the npe phase determine whether or not to do the tutorial - startTutorial = (NewbieTutorial::shouldStartTutorial(this)); - } - - const std::string currentScene = ServerWorld::getSceneId(); - if (NewbieTutorial::isInTutorialArea(this)) - { - LOG("npe", ("handleTutorialTransition called for object %s in scene %s at location %f %f %f\n", getNetworkId().getValueString().c_str(), currentScene.c_str(), getPosition_w().x, getPosition_w().y, getPosition_w().z)); - - // check and see if they are loading into a tutorial area. If so, make sure they only have objects in the FileManifest - if (ConfigServerGame::getStripNonFreeAssetsFromPlayersInTutorial()) - { - LOG("npe", ("handleTutorialTransition removing any non-free assets from object %s\n", getNetworkId().getValueString().c_str())); - NewbieTutorial::stripNonFreeAssetsFromPlayerInTutorial(this); - } - } - - if (startTutorial && currentScene == NewbieTutorial::getSceneId()) - { - // if we are in the tutorial scene, force a teleportFixup here so we can determine if we are in a container - handleTeleportFixup(false); - - ServerObject const * container = safe_cast(ContainerInterface::getContainedByObject(*this)); - - // if they are on the tutorial planet, but not in a valid container, create a tutorial instance for them - if (!container || !container->isAuthoritative() || isFromLogin) - { - // the player should be in the tutorial and is in the right place, go ahead and place them - NewbieTutorial::setupCharacterForTutorial(this); - Vector newLocation = getPosition_w(); - if (newLocation == Vector(0,0,0)) - { - LOG("npe", ("handleTutorialTransition setup tutorial at the origin for object %s\n", getNetworkId().getValueString().c_str())); - } - ServerObject *tutorial = NewbieTutorial::createTutorial(newLocation); - - FATAL(!tutorial, ("failed to create tutorial for player which already exists.")); - std::string startCellName = NewbieTutorial::getStartCellName(); - - Vector startCoords = NewbieTutorial::getStartCoords(); - LOG("npe", ("handleTutorialTransition created newbie tutorial %s (%s authoritative) for %s (%s authoritative)\n", tutorial->getNetworkId().getValueString().c_str(), (tutorial->isAuthoritative()) ? "is" : "not", getNetworkId().getValueString().c_str(), (isAuthoritative()) ? "is" : "not")); - - teleportObject(newLocation, tutorial->getNetworkId(), startCellName, startCoords, "", true); - } - } - else if ( - (startTutorial && isFromLogin) - ) - { - // if the creature object is coming from login, and they should start the tutorial - // or if the player is on a free trial account, but is on a non-free trial planet or location (NOT GOOD!) - // warp them to the tutorial planet - LOG("npe", ("Warping player (%s) back to tutorial because they are coming from login (%i) or because they are on a free trial account (%i) and trying to get to a non-free trial planet (%s: %f %f %f)\n", getNetworkId().getValueString().c_str(), isFromLogin, (getClient() && getClient()->isFreeTrialAccount()), ServerWorld::getSceneId().c_str(), getPosition_w().x, getPosition_w().y, getPosition_w().z)); - NewbieTutorial::setupCharacterForTutorial(this); - GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this), NewbieTutorial::getSceneId(), NewbieTutorial::getTutorialLocation(), NetworkId::cms_invalid, Vector(0,0,0)); - } - } -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::onContainerChildLostItem(ServerObject * destination, ServerObject& item, ServerObject* source, ServerObject* transferer) -{ - ServerObject::onContainerChildLostItem(destination, item, source, transferer); - - GameScriptObject * gameScriptObject = getScriptObject(); - if(gameScriptObject) - { - NetworkId itemId = item.getNetworkId(); - NetworkId sourceId; - if(source) - sourceId = source->getNetworkId(); - NetworkId transfererId; - if(transferer) - transfererId = transferer->getNetworkId(); - NetworkId destinationId; - if(destination) - destinationId = destination->getNetworkId(); - - ScriptParams params; - params.addParam (itemId); - params.addParam (sourceId); - params.addParam (transfererId); - params.addParam (destinationId); - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_CONTAINER_CHILD_LOST_ITEM, params)); - } - - if(isPlayerControlled()) // Source == Appearance Inventory - { - //Update wearble appearance data - SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); - if (scp) - { - WearableEntry e("", scp->getCurrentArrangement(), item.getNetworkId(), 0); - int index = m_wearableAppearanceData.find(e); - if (index >= 0) - { - m_wearableAppearanceData.erase(index); - } - } - } - -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::onContainerChildGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) -{ - ServerObject::onContainerChildGainItem(item, source, transferer); - - GameScriptObject * gameScriptObject = getScriptObject(); - if(gameScriptObject) - { - NetworkId itemId = item.getNetworkId(); - NetworkId sourceId; - if(source) - sourceId = source->getNetworkId(); - NetworkId transfererId; - if(transferer) - transfererId = transferer->getNetworkId(); - - ScriptParams params; - params.addParam (itemId); - params.addParam (sourceId); - params.addParam (transfererId); - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_CONTAINER_CHILD_GAIN_ITEM, params)); - } - - if(isPlayerControlled()) - { - TangibleObject* tangibleObject = item.asTangibleObject(); - - if(!tangibleObject) - return; - - //Update wearables data - SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); - if (scp) - { - Object const * appearance = 0; - - SlottedContainer const * const myContainer = ContainerInterface::getSlottedContainer(*this); - - if (myContainer) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - SlotId appearanceInvSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); - if (appearanceInvSlot != SlotId::invalid) - { - Container::ContainedItem itemId = myContainer->getObjectInSlot(appearanceInvSlot, tmp); - appearance = itemId.getObject(); - } - } - - Object const * container = ContainerInterface::getContainedByObject(*tangibleObject); - bool const inAppearanceInv = (container == appearance); - if (scp->getCurrentArrangement() >= 0 && scp->isInAppearanceSlot() && inAppearanceInv) - { - ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tangibleObject->getClientSharedTemplateName()); - if (clientSharedTemplateNameCrcString.isEmpty()) - WARNING(true, ("Could not find crc for %s. Wearable will not be streamed to client", tangibleObject->getClientSharedTemplateName())); - else - addPackedAppearanceWearable(tangibleObject->getAppearanceData(), scp->getCurrentArrangement(), tangibleObject->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); - } - } - } - -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::forceNotifyRegionsCheck() -{ - m_lastRegionNotifyPosition.x += 1.0f; // force a check -} - -//------------------------------------------------------------------------------------------ - -void CreatureObject::checkNotifyRegions() -{ - // if the object is player controlled, check for a change of regions that have their - // notify field set to true. - static const bool allowChecks = ConfigServerGame::getCheckNotifyRegions(); - if(! allowChecks) - return; - - if(! isPlayerControlled() || !isAuthoritative()) - return; - - if (! isInWorld()) - return; - bool forceCheckRegions = m_regionFlagTimer.isExpired(); - - if(m_lastRegionNotifyPosition == getPosition_w() && !forceCheckRegions) - return; - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if(! playerObject) - return; - - PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::checkNotifyRegions()"); - // region containers populated by region master getRegionsAtPoint() - - static std::vector newRegions; - newRegions.clear(); - RegionMaster::getRegionsAtPoint(ServerWorld::getSceneId(), getPosition_w().x, getPosition_w().z, newRegions); - - if(forceCheckRegions) - { - m_regionFlagTimer.reset(); - - std::vector::iterator regionIter = newRegions.begin(); - EnvironmentInfo flags = static_cast(0); - for(; regionIter != newRegions.end(); ++regionIter) - { - if((*regionIter)->getNotify()) - flags = flags | (*regionIter)->getEnvironmentFlags(); - } - - playerObject->setEnvironmentFlags(flags); - - if(m_lastRegionNotifyPosition == getPosition_w()) - return; - } - - static std::vector newNotifyRegions; - newNotifyRegions.clear(); - - static std::vector newNotifyRegionsEntered; - newNotifyRegionsEntered.clear(); - - static std::vector > notifyRegionsExited; - notifyRegionsExited.clear(); - - // look for region enter events - std::vector::const_iterator i; - - bool teleport = false; - static const bool allowOverride = ConfigServerGame::getAllowRegionTriggerOverride(); - - // iterate through the new regions looking for a "notify" region that is not in the - // list of regions found during the last check. - for(i = newRegions.begin(); i != newRegions.end(); ++i) - { - if((*i)->getNotify()) - { - // this is a region that requires a notification be sent - // to scripts on the player's creature object - std::string regionName = Unicode::wideToNarrow((*i)->getName()); - newNotifyRegions.push_back(regionName); - - // check the notify regions from the last pass - // to see if this is a new region - if (!m_notifyRegions.contains(std::make_pair(ServerWorld::getSceneId(), regionName))) - { - // the region was not in the list, this is a new region - // and TRIG_ENTER_REGION should be generated - ScriptParams params; - params.addParam(ServerWorld::getSceneId().c_str()); - params.addParam(regionName.c_str()); - if(getScriptObject()) - { - // allow scripts to prevent entry into the region if they - // return SCRIPT_OVERRIDE - if (getScriptObject()->trigAllScripts(Scripting::TRIG_ENTER_REGION, params) == SCRIPT_OVERRIDE) - { - // don't disallow admins, don't disallow if the server - // config has it disabled - if((!getClient() || !getClient()->isGod()) && allowOverride) - { - teleport = true; - - Vector teleportTarget = getPosition_w(); - Vector regionCenter = (*i)->getCenter(); - - // if, somehow, a player starts in a forbidden region, allow them to walk out - if(teleportTarget.magnitudeXZBetweenSquared(regionCenter) < m_lastRegionNotifyPosition.magnitudeXZBetweenSquared(regionCenter)) - { - // the current position is further into the region, - // push the player back - teleportObject(m_lastRegionNotifyPosition, NetworkId::cms_invalid, "", Vector(), ""); - } - else - { - // the current position is closer to the region edge, - // allow the player to move normally in this direction - m_lastRegionNotifyPosition = teleportTarget; - } - - // if the player is on a mount/vehicle but is - // not the driver of the mount/vehicle, then - // eject the (passenger) player so he doesn't - // keep trying to enter the region because the - // mount/vehicle will keep taking him into the - // region as long as he remains mounted - CreatureObject const * const mountedCreature = getMountedCreature(); - if (mountedCreature && (this != mountedCreature->getPrimaryMountingRider())) - { - static uint32 const commandHash = Crc::normalizeAndCalculate("dismount"); - const Command &command = CommandTable::getCommand(static_cast(commandHash)); - if (!command.isNull()) - { - commandQueueEnqueue(command, mountedCreature->getNetworkId(), mountedCreature->getObjectName(), 0, false, static_cast(Command::CP_Front), true); - } - } - } - } - } - - // if a teleport didn't happen, - // keep this region on the list - // of notify regions the client - // just entered - if(! teleport) - newNotifyRegionsEntered.push_back(regionName); - } - } - } - - // look for for region exit events. If a region from the last pass - // is not in the new region list, the player has left the region - Archive::AutoDeltaSet >::const_iterator i2; - for(i2 = m_notifyRegions.begin(); i2 != m_notifyRegions.end(); ++i2) - { - if((i2->first != ServerWorld::getSceneId()) || (std::find(newNotifyRegions.begin(), newNotifyRegions.end(), i2->second) == newNotifyRegions.end())) - { - // the player is exiting the region, send a TRIG_EXIT_REGION - // to all scripts attached to the player's creature object - ScriptParams params; - params.addParam(i2->first.c_str()); - params.addParam(i2->second.c_str()); - if(getScriptObject()) - { - if(getScriptObject()->trigAllScripts(Scripting::TRIG_EXIT_REGION, params) == SCRIPT_OVERRIDE) - { - // don't override movement of god characters, or if the - // server config disables move overrides - if((!getClient() || !getClient()->isGod()) && allowOverride && (i2->first == ServerWorld::getSceneId())) - { - teleport = true; - - Vector teleportTarget = getPosition_w(); - - // if the current position is outside the region, fix the - // teleport target to prevent the player from exiting - Region * r = RegionMaster::getRegionByName(i2->first, Unicode::narrowToWide(i2->second)); - if (r) - { - if(! r->getBounds().isPointIn(teleportTarget.x, teleportTarget.z)) - { - // find a point along the path that is in the retion - Vector heading = r->getCenter() - teleportTarget; - heading.normalize(); - - int tries = 0; - while(! r->getBounds().isPointIn(teleportTarget.x, teleportTarget.z) && tries < 300) - { - ++tries; - teleportTarget += heading; - } - teleportObject(teleportTarget, NetworkId::cms_invalid, "", Vector(), ""); - } - } - m_lastRegionNotifyPosition = teleportTarget; - } - } - else - { - notifyRegionsExited.push_back(std::make_pair(i2->first, i2->second)); - } - } - } - } - - if(!teleport) - { - m_lastRegionNotifyPosition = getPosition_w(); - } - - std::vector >::const_iterator i3; - for(i3 = notifyRegionsExited.begin(); i3 != notifyRegionsExited.end(); ++i3) - { - m_notifyRegions.erase(*i3); - } - - std::vector::const_iterator i4; - for(i4 = newNotifyRegionsEntered.begin(); i4 != newNotifyRegionsEntered.end(); ++i4) - { - m_notifyRegions.insert(std::make_pair(ServerWorld::getSceneId(), *i4)); - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::hasCertificationsForItem(const TangibleObject & item) const -{ - std::vector requiredCerts; - item.getRequiredCertifications(requiredCerts); - - for (std::vector::const_iterator i=requiredCerts.begin(); i!=requiredCerts.end(); ++i) - { - if (!hasCommand(*i)) - return false; - } - - return true; -} - -//----------------------------------------------------------------------- - -CreatureObject * CreatureObject::getCreatureObject(NetworkId const & networkId) -{ - return asCreatureObject(NetworkIdManager::getObjectById(networkId)); -} - -// ---------------------------------------------------------------------- - -CreatureObject const * CreatureObject::asCreatureObject(Object const * object) -{ - ServerObject const * const serverObject = (object != NULL) ? object->asServerObject() : NULL; - - return (serverObject != NULL) ? serverObject->asCreatureObject() : NULL; -} - -// ---------------------------------------------------------------------- - -CreatureObject * CreatureObject::asCreatureObject(Object * object) -{ - ServerObject * serverObject = (object != NULL) ? object->asServerObject() : NULL; - - return (serverObject != NULL) ? serverObject->asCreatureObject() : NULL; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::addMissionCriticalObject(NetworkId const & networkId) -{ - if (isAuthoritative()) - { - if (m_missionCriticalObjectSet.find(networkId) == m_missionCriticalObjectSet.end()) - { - m_missionCriticalObjectSet.insert(networkId); - GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); - ServerObject * const serverObject = safe_cast(NetworkIdManager::getObjectById(networkId)); - if (serverObject) - ObserveTracker::onMissionCriticalObjectAdded(*this, *serverObject); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::removeMissionCriticalObject(NetworkId const & networkId) -{ - if (isAuthoritative()) - { - MissionCriticalObjectSet::const_iterator iter = m_missionCriticalObjectSet.find(networkId); - if (iter != m_missionCriticalObjectSet.end()) - { - m_missionCriticalObjectSet.erase(iter); - GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::clearMissionCriticalObjects() -{ - if (isAuthoritative()) - { - m_missionCriticalObjectSet.clear(); - GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::isMissionCriticalObject(NetworkId const & networkId) const -{ - if (isAuthoritative()) - return m_missionCriticalObjectSet.find(networkId) != m_missionCriticalObjectSet.end(); - - return false; -} - -// ---------------------------------------------------------------------- - -CreatureObject::MissionCriticalObjectSet const & CreatureObject::getMissionCriticalObjects() const -{ - return m_missionCriticalObjectSet.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setGroupMissionCriticalObjects(GroupMissionCriticalObjectSet const & groupMissionCriticalObjectSet) -{ - DEBUG_FATAL(!isAuthoritative(), ("CreatureObject::setGroupMissionCriticalObjects: called on non-authoritative object %s", getDebugInformation(true).c_str())); - if (isAuthoritative()) - { - //-- Anything that is not in our set, we need to add - { - for (GroupMissionCriticalObjectSet::const_iterator iter = groupMissionCriticalObjectSet.begin(); iter != groupMissionCriticalObjectSet.end(); ++iter) - if (!m_groupMissionCriticalObjectSet.contains(*iter)) - m_groupMissionCriticalObjectSet.insert(*iter); - } - - //-- Anything that is not in the original set, we need to remove - { - for (GroupMissionCriticalObjectSet::const_iterator iter(m_groupMissionCriticalObjectSet.begin()); iter != m_groupMissionCriticalObjectSet.end(); ++iter) - if (groupMissionCriticalObjectSet.find(*iter) == groupMissionCriticalObjectSet.end()) - m_groupMissionCriticalObjectSet.erase(*iter); - } - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::getCoverVisibility() const -{ - return m_coverVisibility.get(); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setCoverVisibility(bool isVisible) -{ - if (isAuthoritative()) - { - m_coverVisibility.set(isVisible); - } - else - { - sendControllerMessageToAuthServer(CM_setCoverVisibility, new MessageQueueGenericValueType(isVisible)); - } -} - -// ---------------------------------------------------------------------- - -/** - * Called when an attack pushes us away from the attacker. This gets called - * due to a message from the client (which sucks, btw). - * - * @param attackerId the attacker - * @param attackerPos where the client thought the attacker was - * @param defenderPos where the client thought the defender (us) was - * @param distance the distance we are pushed away from the attacker - */ -void CreatureObject::pushedMe(const NetworkId & attackerId, - const Vector & attackerPos, const Vector & defenderPos, float distance) -{ - if (isAuthoritative()) - { - const ServerObject * attacker = safe_cast(NetworkIdManager::getObjectById(attackerId)); - - //@todo: add a whole bunch of security checks here - // for now, push us away from the defender, using the server positions - - // do a bare minimum sanity check - static const float MAX_DISTANCE = 20.0f; - if (distance > MAX_DISTANCE) - { - WARNING(true, ("CreatureObject::pushedMe told defender %s was pushed by %s %f meters (max = %f)", - getNetworkId().getValueString().c_str(), attackerId.getValueString().c_str(), distance, MAX_DISTANCE)); - return; - } - - - UNREF(defenderPos); - - Vector offset(getPosition_w()); - if (attacker != NULL) - offset -= attacker->getPosition_w(); - else - offset -= attackerPos; - offset.normalize(); - offset *= distance; - - // this is a hack due to the controller move command needing to know the destination cell - // @todo: change creature movement to always use the CellProperty notification system for moving across cell boundaries - const Vector oldPos(getPosition_p()); - - // note: unlike the client, this call will not cause us to change cells - move_p(rotate_w2p(offset)); - - AICreatureController *controller = dynamic_cast(getController()); - if (controller != NULL) - { - // we only need to do this for npcs, because we'll use the update from a player's client for players - // we need to do this for npcs to prevent the ai from moving them back to their previous position - const Vector newPos(getPosition_p()); - float closestPortalT = 0.0f; - const CellProperty * destinationCell = getParentCell()->getDestinationCell(oldPos, newPos, closestPortalT); - if (destinationCell == NULL || destinationCell == getParentCell()) - { - // no cell change - controller->warpTo(getParentCell(), newPos); - } - else - { - Vector warpPos(destinationCell->getOwner().rotateTranslate_w2p(rotateTranslate_p2w(newPos))); - controller->warpTo(destinationCell, warpPos); - } - } - } - else - { - sendControllerMessageToAuthServer(CM_pushCreature, - new MessageQueuePushCreature(attackerId, getNetworkId(), attackerPos, defenderPos, distance)); - } -} - -// ---------------------------------------------------------------------- - -/** - * Creates a "slow down" effect between this creature and a defender. The effect acts as if - * there was a hill between the combatants, with the attacker at the top and the defender - * at the bottom. The area of the effect is a cone between the attacker and defender. - * The "hill" will be maintained between the combatants even if they move. - * - * @param defender the target that defines the direction of the "hill" - * @param coneLength the length of the effect cone - * @param coneAngle the angle of the effect cone, in radians - * @param slopeAngle the angle of the "hill", in radians - * @param expireTime the game time when the effect expires - */ -void CreatureObject::addSlowDownEffect(const TangibleObject & defender, float coneLength, float coneAngle, float slopeAngle, unsigned long expireTime) -{ - if (isAuthoritative()) - { - if (addSlowDownEffectProxy(defender, coneLength, coneAngle, slopeAngle, expireTime)) - { - // tell everyone who can see us that we are doing the effect - Controller * const controller = getController(); - if (controller) - { - controller->appendMessage(CM_slowDownEffect, - 0, - new MessageQueueSlowDownEffect(defender.getNetworkId(), coneLength, coneAngle, slopeAngle, expireTime), - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_PROXY_SERVER | - GameControllerMessageFlags::DEST_ALL_CLIENT); - } - } - } - else - { - sendControllerMessageToAuthServer(CM_slowDownEffect, - new MessageQueueSlowDownEffect(defender.getNetworkId(), coneLength, coneAngle, slopeAngle, expireTime)); - } -} - -// ---------------------------------------------------------------------- - -/** - * Creates a "slow down" effect between this creature and a defender. The effect acts as if - * there was a hill between the combatants, with the attacker at the top and the defender - * at the bottom. The area of the effect is a cone between the attacker and defender. - * The "hill" will be maintained between the combatants even if they move. - * - * @param defender the target that defines the direction of the "hill" - * @param coneLength the length of the effect cone - * @param coneAngle the angle of the effect cone, in radians - * @param slopeAngle the angle of the "hill", in radians - * @param expireTime the game time when the effect expires - * - * @return true if the effect was added, false if the creature already had a slow down effect - */ -bool CreatureObject::addSlowDownEffectProxy(const TangibleObject & defender, float coneLength, float coneAngle, float slopeAngle, unsigned long expireTime) -{ - // if we already are doing a slowdown, don't do another - Property * property = getProperty(SlowDownProperty::getClassPropertyId()); - if (property != NULL) - return false; - - property = new SlowDownProperty(*this, CachedNetworkId(defender), coneLength, coneAngle, slopeAngle, expireTime); - addProperty(*property, true); - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Causes any slow down effect being used by us to be canceled early. - */ -void CreatureObject::removeSlowDownEffect() -{ - if (isAuthoritative()) - { - removeSlowDownEffectProxy(); - - // tell all my proxies (client and server) to remove the effect - Controller * const controller = getController(); - if (controller) - controller->appendMessage(CM_removeSlowDownEffectProxy, 0, NULL, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT | GameControllerMessageFlags::DEST_PROXY_SERVER); - } - else - { - sendControllerMessageToAuthServer(CM_removeSlowDownEffect, NULL); - } -} - -// ---------------------------------------------------------------------- - -/** - * Causes any slow down effect being used by us to be canceled early. - */ -void CreatureObject::removeSlowDownEffectProxy() -{ - if (getProperty(SlowDownProperty::getClassPropertyId()) != NULL) - removeProperty(SlowDownProperty::getClassPropertyId()); -} - -// ---------------------------------------------------------------------- - -/** - * Adds an additional terrain slope effect that will be taken into account the - * next time we alter this creature. Note that this function only affects non-player - * creatures. - * - * @param normal the normal vector of the "terrain" that is affecting us - */ -void CreatureObject::addTerrainSlopeEffect(const Vector & normal) -{ - if (isAuthoritative() && !isPlayerControlled()) - { - Property * property = getProperty(SlopeEffectProperty::getClassPropertyId()); - if (property == NULL) - { - property = new SlopeEffectProperty(*this); - addProperty(*property, true); - } - safe_cast(property)->addNormal(normal); - } -} - -// ---------------------------------------------------------------------- - -char const * CreatureObject::getMentalStateString(MentalStates::Enumerator const mentalState) -{ - switch (mentalState) - { - case MentalStates::Fear: { return "FEAR"; } - case MentalStates::Anger: { return "ANGER"; } - case MentalStates::Interest: { return "INTEREST"; } - case MentalStates::Distress: { return "DISTRESS"; } - default: {} - } - - return "ERROR"; -} - -// ---------------------------------------------------------------------- - -char const * CreatureObject::getBehaviorString(Behaviors::Enumerator const behavior) -{ - switch (behavior) - { - case Behaviors::Calm: { return "CALM"; } - case Behaviors::Alert: { return "ALERT"; } - case Behaviors::Threaten: { return "THREATEN"; } - case Behaviors::Retreat: { return "RETREAT"; } - case Behaviors::Flee: { return "FLEE"; } - case Behaviors::Attack: { return "ATTACK"; } - case Behaviors::Frenzy: { return "FRENZY"; } - default: {} - } - - return "ERROR"; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::alterPseudoPlayedTime(float time) -{ - if (isAuthoritative()) - { - m_pseudoPlayedTime += time; - } - else - { - WARNING(true, ("CreatureObject::alterPlayedTime called on non-authoritative creature")); - } -} // updatePlayedTime - -// ---------------------------------------------------------------------- - -void CreatureObject::setPseudoPlayedTime(float playedTime) -{ - m_pseudoPlayedTime = playedTime; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::addBuff(uint32 buffNameCrc, float duration, float dynamicValue, NetworkId caster, uint32 stackCount) -{ - addBuff( buffNameCrc, duration, dynamicValue, duration, caster, stackCount); -} - -void CreatureObject::addBuff(uint32 buffNameCrc, float timeTillRemoval, float dynamicValue, float totalDuration, NetworkId caster, uint32 stackCount) -{ - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_addBuff, new MessageQueueGenericValueType > > > >(std::make_pair(static_cast(buffNameCrc), std::make_pair(timeTillRemoval, std::make_pair(dynamicValue, std::make_pair(totalDuration, caster)))))); - return; - } - uint32 timestamp = internalGetPlayedTime(); - - if (BuffManager::getBuffIsCelestial(buffNameCrc)) - { - timestamp = ServerClock::getInstance().getGameTimeSeconds(); - } - - int newStackCount = stackCount; - - if(timeTillRemoval < 0.0f) - timestamp = 0xFFFFFFFF; - else if (timeTillRemoval == 0.0f) - { - float defaultDuration = BuffManager::getBuffDefaultDuration(buffNameCrc); - if(defaultDuration < 0.0f) - timestamp = 0xFFFFFFFF; - else - { - timestamp += static_cast(defaultDuration); - totalDuration = defaultDuration; - } - } - else - { - timestamp += static_cast(timeTillRemoval); - } - bool reapply = false; - if(hasBuff(buffNameCrc)) - { - Buff b; - getBuff(buffNameCrc, b); - - newStackCount += b.m_stackCount; - - if((timestamp != 0xFFFFFFFF) && (b.m_timestamp > timestamp)) - { - //We don't need to do anything; the buff we're adding has less time than the one we have - return; - } - std::map::const_iterator i = m_buffs.find(buffNameCrc); - if (i != m_buffs.end()) - { - m_buffs.erase(i); - } - m_persistedBuffs.erase(buffNameCrc); - reapply = true; - } - - newStackCount = std::max(0, std::min(newStackCount, static_cast(BuffManager::getBuffMaxStacks(buffNameCrc)))); - - Buff::PackedBuff packedValue = Buff(buffNameCrc, timestamp, dynamicValue, static_cast(totalDuration), caster, newStackCount).getPackedBuffValue(); - - m_buffs.insert(buffNameCrc, packedValue); - if (BuffManager::getIsBuffPersisted(buffNameCrc)) - { - m_persistedBuffs.insert(buffNameCrc, packedValue); - } - if(reapply) - BuffManager::reapplyBuffEffects(this, buffNameCrc, timeTillRemoval, dynamicValue, newStackCount, caster); - else - BuffManager::applyBuffEffects(this, buffNameCrc, timeTillRemoval, dynamicValue, newStackCount, caster); - //If there was a state, add that state to this creature - int buffState = BuffManager::getBuffState(buffNameCrc); - if(buffState != -1) - setState(static_cast(buffState), true); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::removeBuff(uint32 buffNameCrc) -{ - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_removeBuff, new MessageQueueGenericValueType(static_cast(buffNameCrc))); - return; - } - - std::map::const_iterator i = m_buffs.find(buffNameCrc); - if (i != m_buffs.end()) - { - NetworkId caster = (*i).second.caster; - m_buffs.erase(i); - int buffState = BuffManager::getBuffState(buffNameCrc); - BuffManager::removeBuffEffects(this, buffNameCrc, caster); - if (!stillHasBuffState(buffNameCrc, buffState)) - setState(static_cast(buffState), false); - std::string const &callback = BuffManager::getBuffCallback(buffNameCrc); - ScriptParams params; - params.addParam(static_cast(buffNameCrc), "buffCrc"); - ScriptDictionaryPtr dictionary; - getScriptObject()->makeScriptDictionary(params, dictionary); - dictionary->serialize(); - getScriptObject()->handleMessage(callback, dictionary); - } - - // clean up any persistance - m_persistedBuffs.erase(buffNameCrc); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::decrementBuff(uint32 const buffNameCrc, uint32 const stacksToRemove) -{ - std::map::const_iterator i = m_buffs.find(buffNameCrc); - if (i != m_buffs.end()) - { - - Buff::PackedBuff b = (*i).second; - - b.stackCount -= stacksToRemove; - - removeBuff(buffNameCrc); - - if (static_cast(b.stackCount) > 0) - { - uint32 currentTime = internalGetPlayedTime(); - - if (BuffManager::getBuffIsCelestial(buffNameCrc)) - { - currentTime = ServerClock::getInstance().getGameTimeSeconds(); - } - - float endTime = static_cast (b.endtime) - static_cast (currentTime); - addBuff( buffNameCrc, endTime , b.value, static_cast (b.duration), b.caster, b.stackCount); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::decayBuff(uint32 buffNameCrc, float decayPercentage) -{ - std::map::const_iterator i = m_buffs.find(buffNameCrc); - if (i != m_buffs.end()) - { - Buff::PackedBuff b = (*i).second; - - float decayValue = b.duration * decayPercentage; // decayPercentage should be a value between 0.0 and 1.0 - - removeBuff(buffNameCrc); - - uint32 currentTime = internalGetPlayedTime(); - - float endTime = (static_cast (b.endtime) - decayValue) - static_cast (currentTime); - - if(endTime > 0.0f) - addBuff( buffNameCrc, endTime , b.value, static_cast (b.duration), b.caster, b.stackCount); - } -} - -uint32 CreatureObject::internalGetPlayedTime() const -{ - if (isPlayerControlled()) - { - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - return static_cast(playerObject->getPlayedTime()); - } - } - return static_cast(ServerClock::getInstance().getGameTimeSeconds()); -} - -// ---------------------------------------------------------------------- - -// This functions expires buffs as needed -void CreatureObject::updateBuffs() -{ - uint32 timestamp = internalGetPlayedTime(); - std::list< Buff > buffsToRemove; - - for (std::map::const_iterator i = m_buffs.begin(); i != m_buffs.end(); ) - { - const std::pair & p = *i++; - Buff b(p.first, p.second); - - if (BuffManager::getBuffIsCelestial(b.m_nameCrc)) - { - timestamp = ServerClock::getInstance().getGameTimeSeconds(); - } - else - { - timestamp = internalGetPlayedTime(); - } - - if (b.m_timestamp < timestamp) - { - buffsToRemove.push_back(b); - } - } - - std::list< Buff >::iterator iter = buffsToRemove.begin(); - for( ; iter != buffsToRemove.end(); ++iter) - { - removeBuff((*iter).m_nameCrc); - } - -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::stillHasBuffState(uint32 buffNameCrc, int state) const -{ - for (std::map::const_iterator i = m_buffs.begin(); i != m_buffs.end(); ++i) - { - const std::pair & p = *i; - if ((p.first != buffNameCrc) && (BuffManager::getBuffState(p.first) == state)) - return true; - } - return false; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::getAllBuffs(stdvector::fwd & buffCrcs) const -{ - buffCrcs.clear(); - buffCrcs.reserve(m_buffs.size()); - for (std::map::const_iterator i = m_buffs.begin(); i != m_buffs.end(); ++i) - { - const std::pair & p = *i; - buffCrcs.push_back(p.first); - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::getBuff(uint32 buffNameCrc, Buff & buff) const -{ - std::map::const_iterator found = m_buffs.find(buffNameCrc); - if (found == m_buffs.end()) - return false; - - buff.set((*found).first, (*found).second); - return true; -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::hasBuff(uint32 buffNameCrc) const -{ - std::map::const_iterator found = m_buffs.find(buffNameCrc); - return (found != m_buffs.end()); -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::isInTutorial() const -{ - return NewbieTutorial::isInTutorial(this); -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::isJedi() const -{ - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - return playerObject->isJedi(); - else - return false; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setLevel(int level) -{ - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - controller->appendMessage( - CM_setLevel, - 0.0f, - new MessageQueueGenericValueType(level), - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - } - else - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject == NULL) - { - // this is an ai, so just set the level - m_level = (int16) level; - } - else - { - LevelManager::LevelData levelData; - LevelManager::setLevelDataFromLevel(levelData, level); - - setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::recalculateLevel() -{ - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - { - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - controller->appendMessage( - CM_recalculateLevel, - 0.0f, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - } - else - { - LevelManager::LevelData levelData; - LevelManager::calculateLevelData(getLevelXp(), levelData); - - setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setLevelData(int16 level, int levelXp, int health) -{ - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - { - m_totalLevelXp = levelXp; - - m_levelHealthGranted = health; - - m_level = level; - - GroupObject *group = getGroup(); - if (group != 0) - { - group->setMemberLevel(getNetworkId(), level); - } - - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); - if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.level != static_cast(level))) - ServerUniverse::setConnectedCharacterLevelData(getNetworkId(), static_cast(level)); - - // update and sync - computeTotalAttributes(); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::levelChanged() const -{ - return; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setClientUsesAnimationLocomotion(bool const enabled) -{ - m_clientUsesAnimationLocomotion = enabled; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::fixupPersistentBuffsAfterLoading() -{ - // initialize persisted buffs - if(m_fixedupPersistentBuffsAfterLoading) - return; // don't want to do it twice - m_fixedupPersistentBuffsAfterLoading = true; - DEBUG_WARNING(isPlayerControlled() && PlayerCreatureController::getPlayerObject(this) && !PlayerCreatureController::getPlayerObject(this)->isInitialized(), - ("CreatureObject::fixupPersistentBuffsAfterLoading trying to use an uninitialized player object")); - uint32 currentTime = internalGetPlayedTime(); - std::vector tempPersistedHolder; - for (std::map::const_iterator ip = m_persistedBuffs.begin(); ip != m_persistedBuffs.end(); ++ip) - { - Buff b((*ip).first, (*ip).second); - tempPersistedHolder.push_back(b); - } - m_persistedBuffs.clear(); - for (std::vector::const_iterator i = tempPersistedHolder.begin(); i != tempPersistedHolder.end(); ++i) - { - const Buff & b = (*i); - - if (BuffManager::getBuffIsCelestial(b.m_nameCrc)) - { - currentTime = ServerClock::getInstance().getGameTimeSeconds(); - } - else - currentTime = internalGetPlayedTime(); - - if (b.m_timestamp > currentTime || b.m_timestamp == 0xFFFFFFFF) - { - float timeTillRemoval = -1.0f; - if (b.m_timestamp != 0xFFFFFFFF) - timeTillRemoval = static_cast(b.m_timestamp - currentTime); - - - addBuff(b.m_nameCrc, timeTillRemoval, b.m_value, static_cast(b.m_duration), b.m_caster, b.m_stackCount); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::fixupLevelXpAfterLoading() -{ - // initialize persisted buffs - if(m_fixedupLevelXpAfterLoading) - return; // don't want to do it twice - - m_fixedupLevelXpAfterLoading = true; - - DEBUG_FATAL(!isPlayerControlled(), - ("CreatureObject::fixupLevelXpAfterLoading trying to be called for a non-player controlled object")); - - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - - DEBUG_FATAL(!playerObject, - ("CreatureObject::fixupLevelXpAfterLoading trying to use a non-existent player object")); - - DEBUG_FATAL(playerObject && !playerObject->isInitialized(), - ("CreatureObject::fixupLevelXpAfterLoading trying to use an uninitialized player object")); - - // The level XP and level are not persisted in the database, so when we - // are done loading, we will calculate the current level XP and level - if (playerObject && playerObject->isInitialized()) - { - LevelManager::LevelData levelData; - - // Level XP due to experience points - std::map const & experienceMap = playerObject->getExperiencePoints(); - std::map::const_iterator i; - for (i = experienceMap.begin(); i != experienceMap.end(); ++i) - { - LevelManager::addXpToLevelData(levelData, i->first, i->second); - } - - // Level XP due to skills - for (SkillList::const_iterator skillIter = m_skills.begin(); skillIter != m_skills.end(); ++skillIter) - { - SkillObject const * skill = *skillIter; - if (skill) - { - LevelManager::addSkillToLevelData(levelData, skill->getSkillName()); - } - } - - // Update the skill info directly (we do not want scripts triggered) - m_level = levelData.currentLevel; - m_previousLevel = levelData.currentLevel; - m_totalLevelXp = levelData.currentLevelXp; - m_levelHealthGranted = levelData.currentHealth; - - levelChanged(); - } -} - -// ---------------------------------------------------------------------- - -CreatureObject::Difficulty CreatureObject::getDifficulty() const -{ - return static_cast(m_difficulty.get()); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setDifficulty(Difficulty const difficulty) -{ - m_difficulty = static_cast(difficulty); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setHologramType(int32 const newHologramType) -{ - if (isAuthoritative()) - { - m_hologramType = newHologramType; - } - else - { - sendControllerMessageToAuthServer(CM_modifyHologramType, new MessageQueueGenericValueType(newHologramType)); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setVisibleOnMapAndRadar(bool const newVal) -{ - if (isAuthoritative()) - { - m_visibleOnMapAndRadar = newVal; - } - else - { - sendControllerMessageToAuthServer(CM_modifyVisibleOnMapAndRadar, new MessageQueueGenericValueType(newVal)); - } -} - -// ---------------------------------------------------------------------- - -float CreatureObject::getRegenRate(Attributes::Enumerator poolAttrib) const -{ - if (!Attributes::isAttribPool(poolAttrib)) - return 0; - - // we've stored the rate as an int, convert back to float - int fixedFloatRate = m_attributes[poolAttrib+1]; - return static_cast(fixedFloatRate); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setRegenRate(Attributes::Enumerator poolAttrib, float value) -{ - if (Attributes::isAttribPool(poolAttrib)) - { - if (value < 0) - value = 0; - if (isAuthoritative()) - { - // store the value as an int - m_attributes.set(poolAttrib+1, static_cast(floor(value))); - } - else - { - sendControllerMessageToAuthServer(CM_setRegenRate, new MessageQueueGenericValueType >(std::make_pair(static_cast(poolAttrib), value))); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::setLastWaterDamageTime(unsigned long newTime) -{ - m_lastWaterDamageTime = newTime; -} - -// ---------------------------------------------------------------------- - -bool CreatureObject::doesLocomotionInvalidateCommand(Command const &cmd) const -{ - Locomotions::Enumerator locomotion = getLocomotion(); - if((locomotion != Locomotions::Running) || cmd.m_locomotionPermissions[locomotion]) - return !cmd.m_locomotionPermissions[locomotion]; - if(!isPlayerControlled()) - return true; - PlayerCreatureController const *playerCreatureController = safe_cast(getController()); - if(playerCreatureController) - return (playerCreatureController->getLastSpeed() > ConfigSharedGame::getMovementThresholdForActionValidation()); - return true; -} - -// ---------------------------------------------------------------------- - -CommandQueue * CreatureObject::getCommandQueue() const -{ - if (m_commandQueue == NULL) - { - m_commandQueue = CommandQueue::getCommandQueue(*const_cast(this)); - } - - return m_commandQueue; -} - -// ---------------------------------------------------------------------- - -void CreatureObject::clearCommands() -{ - m_commands.clear(); -} - -// ---------------------------------------------------------------------- - -std::map const & CreatureObject::getCommandList() const -{ - return m_commands.getMap(); -} - -// ---------------------------------------------------------------------- - -/** - Multiple skills can grant the same command. Commands can be granted - apart from skills. When a skill is removed, it must remove the command - it granted, but it probably shouldn't remove the command if is granted - by another skill or commands granted via other methods - (items/quests, etc...) -*/ -bool CreatureObject::grantCommand(std::string const & commandName, bool const fromSkill) -{ - bool result = false; - if(isAuthoritative()) - { - result = true; - // check if we already have the command - Archive::AutoDeltaMap::const_iterator found = m_commands.find(commandName); - if (found == m_commands.end()) - { - m_commands.set(commandName, 1); - - if(getClient()) - { - GrantCommand grant(commandName); - getClient()->send(grant, true); - } - if (!fromSkill) - { - // save command as objvar - setObjVarItem(OBJVAR_NOT_SKILL_COMMANDS + "." + commandName, 1); - } - } - else - { - m_commands.set(commandName, (*found).second + 1); - } - } - else - { - result = true; - sendControllerMessageToAuthServer(CM_grantCommand, new MessageQueueGenericValueType(commandName)); - } - return result; -} - -//----------------------------------------------------------------------- - -void CreatureObject::revokeCommand(std::string const & command, bool const fromSkill, bool const ignoreCount) -{ - if(isAuthoritative()) - { - Archive::AutoDeltaMap::const_iterator found = m_commands.find(command); - if (found != m_commands.end()) - { - if ((*found).second > 1 && !ignoreCount) - { - m_commands.set(command, (*found).second - 1); - } - else - { - m_commands.erase(found); - - if(getClient()) - { - RevokeCommand revoke(command); - getClient()->send(revoke, true); - } - if (!fromSkill) - { - // remove commands from objvars - removeObjVarItem(OBJVAR_NOT_SKILL_COMMANDS + "." + command); - } - } - } - } - else - { - sendControllerMessageToAuthServer(CM_revokeCommand, new MessageQueueGenericValueType(command)); - } -} - -//----------------------------------------------------------------------- - -bool CreatureObject::hasCommand(std::string const & commandName) const -{ - bool result = false; - if (commandName == "unskilled") - result = true; - else - { - const Archive::AutoDeltaMap::const_iterator f = m_commands.find(commandName); - result = (f != m_commands.end()); - } - return result; -} - -//----------------------------------------------------------------------- - -/** - * Called when our observer count changes. Will bring us into or out of hibernation - * if needed. - */ -void CreatureObject::observersCountChanged() -{ - if (isAuthoritative()) - { - CreatureController * controller = getCreatureController(); - int observers = getObserversCount(); - bool hibernating = controller->getHibernate(); - if ((observers > 0 && hibernating) || - (observers <= 0 && !hibernating)) - { - // attempt to change our hibernate state - controller->updateHibernate(); - } - } -} - -//----------------------------------------------------------------------- - -bool CreatureObject::isStopped() const -{ - return (m_stopWalkRun.get() == 0); -} - -//----------------------------------------------------------------------- - -bool CreatureObject::isWalking() const -{ - return (m_stopWalkRun.get() == 1); -} - -//----------------------------------------------------------------------- - -bool CreatureObject::isRunning() const -{ - return (m_stopWalkRun.get() == 2); -} - -//----------------------------------------------------------------------- - -void CreatureObject::setLookAtYaw(const float lookAtYaw, bool useLookAtYaw) -{ - if(useLookAtYaw && (m_lookAtYaw != lookAtYaw)) - setTransformChanged(true); - m_lookAtYaw = lookAtYaw; - m_useLookAtYaw = useLookAtYaw; -} - -//----------------------------------------------------------------------- - -float CreatureObject::getLookAtYaw() const -{ - return m_lookAtYaw; -} - -//----------------------------------------------------------------------- - -bool CreatureObject::getUseLookAtYaw() const -{ - return m_useLookAtYaw; -} - -//----------------------------------------------------------------------- - -int CreatureObject::getExpertiseRankForPlayer(std::string const & expertiseName) -{ - int result = 0; - - int rankMax = ExpertiseManager::getExpertiseRankMax(expertiseName); - - int tree = ExpertiseManager::getExpertiseTree(expertiseName); - int tier = ExpertiseManager::getExpertiseTier(expertiseName); - int grid = ExpertiseManager::getExpertiseGrid(expertiseName); - int rank = 1; - - while (rank <= rankMax) - { - SkillObject const * skill = ExpertiseManager::getExpertiseSkillAt(tree, tier, grid, rank); - if (skill && hasSkill(*skill)) - { - result = rank; - rank++; - } - else - { - break; - } - } - return result; -} - -//----------------------------------------------------------------------- - -void CreatureObject::getExpertisesForPlayer(SkillList & expertiseList) const -{ - expertiseList.clear(); - - SkillList const & skillList = this->getSkillList(); - - for (SkillList::const_iterator i = skillList.begin(); i != skillList.end(); ++i) - { - if (*i) - { - if (ExpertiseManager::isExpertise(*i)) - { - expertiseList.insert(*i); - } - } - } -} - -//----------------------------------------------------------------------- - -int CreatureObject::getExpertisePointsSpentForPlayerInTree(int tree) -{ - int spentPoints = 0; - - SkillList expertiseList; - getExpertisesForPlayer(expertiseList); - - for (SkillList::const_iterator i = expertiseList.begin(); i != expertiseList.end(); ++i) - { - SkillObject const * expertise = *i; - if (expertise) - { - std::string const & expertiseName = expertise->getSkillName(); - if (ExpertiseManager::getExpertiseTree(expertiseName) == tree) - { - spentPoints += getExpertiseRankForPlayer(expertiseName); - } - } - } - return spentPoints; -} - -//---------------------------------------------------------------------- - -int CreatureObject::getRemainingExpertisePoints() const -{ - int const numPointsAvail = ExpertiseManager::getExpertisePointsForLevel(getLevel()); - - CreatureObject::SkillList expertiseList; - getExpertisesForPlayer(expertiseList); - int const numPointsUsed = expertiseList.size() - 1; // subtract 1 for skill "expertise" - - return numPointsAvail - numPointsUsed; -} - -//----------------------------------------------------------------------- - -bool CreatureObject::processExpertiseRequest(std::vector const &addExpertisesNamesList, bool clearAllExpertisesFirst) -{ - for(std::vector::const_iterator i = addExpertisesNamesList.begin(); i != addExpertisesNamesList.end(); ++i) - { - std::string const &s = *i; - const SkillObject *skill = SkillManager::getInstance().getSkill(s); - if(skill) - { - //Check prerequisites - SkillObject::SkillVector const prereqs = skill->getPrerequisiteSkills(); - for (SkillObject::SkillVector::const_iterator i = prereqs.begin(); i != prereqs.end(); ++i) - { - SkillObject const * prereq = (*i); - if (!prereq || !hasSkill(*prereq)) - { - DEBUG_WARNING(true, ("player %s tried to get expertise %s but doesn't have expertise %s", getNetworkId().getValueString().c_str(), - skill->getSkillName().c_str(), prereq->getSkillName().c_str())); - return false; - } - } - //Check tier points - //Check if the player has enough points for a skill of this tier - int tree = ExpertiseManager::getExpertiseTree(s); - int pointsInTree = getExpertisePointsSpentForPlayerInTree(tree); - int tier = ExpertiseManager::getExpertiseTier(s); - if (pointsInTree < (tier - 1) * POINTS_PER_TIER) - { - DEBUG_WARNING(true, ("player %s tried to get expertise %s but only has %d points in tree %d, needs %d", getNetworkId().getValueString().c_str(), - s.c_str(), pointsInTree, tree, (tier - 1) * POINTS_PER_TIER - )); - return false; - } - - if (getRemainingExpertisePoints() < 1) - { - LOG("CustomerService", - ("SuspectedCheaterChannel: %s attempted to gain more expertise than allowed.", - PlayerObject::getAccountDescription(this).c_str()) - ); - - return false; - } - - //Check faction column - - //Grant skill - grantSkill(*skill); - } - } - return true; -} - -//----------------------------------------------------------------------- - -bool CreatureObject::clearAllExpertises() -{ - int numTries = 0; - while(numTries < 50) - { - //@TODO: guard this however design wants - const SkillList &skills = getSkillList(); - std::vector skillsToRevoke; - for(std::set::const_iterator i(skills.begin()); i != skills.end(); ++i) - { - const SkillObject *skill = *i; - if(skill && ExpertiseManager::isExpertise(skill)) - skillsToRevoke.push_back(skill); - } - if(skillsToRevoke.empty()) - return true; - for(std::vector::iterator i2 = skillsToRevoke.begin(); i2 != skillsToRevoke.end(); ++i2) - { - const SkillObject *skill = *i2; - revokeSkill(*skill, true); - } - numTries++; - } - return false; -} - -//----------------------------------------------------------------------- - -void CreatureObject::recomputeCommandSeries() -{ - for(std::vector::iterator i = s_commandSeriesRecords.begin(); i != s_commandSeriesRecords.end(); ++i) - { - CommandSeriesRecord const & csr = *i; - bool hasLevel = getLevel() >= csr.level; - if(csr.baseCommandName.empty()) - { - if(!hasLevel) - LOG("CustomerService",("Player %s of level %d has command %s from command series, but should not have it until level %d", - getNetworkId().getValueString().c_str(), getLevel(), csr.baseCommandName.c_str(), csr.level)); - } - else - { - if(hasCommand(csr.commandName) && (!hasCommand(csr.baseCommandName) || !hasLevel)) - { - revokeCommand(csr.commandName, true); - } - else if(!hasCommand(csr.commandName) && hasCommand(csr.baseCommandName) && hasLevel) - { - grantCommand(csr.commandName, true); - } - } - - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::incrementKillMeter(int amount) -{ - if (isPlayerControlled()) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject != NULL) - { - playerObject->incrementKillMeter(amount); - } - } -} - -//----------------------------------------------------------------------- - -void CreatureObject::getLfgCharacterData(LfgCharacterData & lfgCharacterData) const -{ - lfgCharacterData.characterId = getNetworkId(); - lfgCharacterData.characterName = getAssignedObjectName(); - lfgCharacterData.characterLowercaseFirstName = Unicode::wideToNarrow(Unicode::toLower(getAssignedObjectFirstName())); - - lfgCharacterData.species = getSpecies(); - lfgCharacterData.gender = getGender(); - - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); - if (iterFind != connectedCharacterLfgData.end()) - { - lfgCharacterData.characterInterests = iterFind->second.characterInterests; - lfgCharacterData.characterCreateTime = iterFind->second.characterCreateTime; - lfgCharacterData.characterAge = iterFind->second.characterAge; - } - else - { - lfgCharacterData.characterInterests.clear(); - lfgCharacterData.characterCreateTime = -1; - lfgCharacterData.characterAge = -1; - } - - if (lfgCharacterData.characterCreateTime <= 0) - lfgCharacterData.characterCreateTime = static_cast(NameManager::getInstance().getPlayerCreateTime(getNetworkId())); - - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); - if (playerObject) - { - lfgCharacterData.characterAge = playerObject->getAgeInDays(); - - lfgCharacterData.profession = LfgCharacterData::convertSkillTemplateToProfession(playerObject->getSkillTemplate()); - - MatchMakingId const & id = playerObject->getMatchMakingCharacterProfileId(); - lfgCharacterData.anonymous = id.isBitSet(MatchMakingId::B_anonymous); - lfgCharacterData.searchableByCtsSourceGalaxy = id.isBitSet(MatchMakingId::B_searchableByCtsSourceGalaxy); - lfgCharacterData.displayLocationInSearchResults = id.isBitSet(MatchMakingId::B_displayLocationInSearchResults); - - if (id.isBitSet(MatchMakingId::B_lookingForGroup)) - LfgDataTable::setBit("lfg", lfgCharacterData.characterInterests); - else - LfgDataTable::clearBit("lfg", lfgCharacterData.characterInterests); - - if (id.isBitSet(MatchMakingId::B_helper)) - LfgDataTable::setBit("helper", lfgCharacterData.characterInterests); - else - LfgDataTable::clearBit("helper", lfgCharacterData.characterInterests); - - if (id.isBitSet(MatchMakingId::B_rolePlay)) - LfgDataTable::setBit("rp", lfgCharacterData.characterInterests); - else - LfgDataTable::clearBit("rp", lfgCharacterData.characterInterests); - - if (id.isBitSet(MatchMakingId::B_lookingForWork)) - LfgDataTable::setBit("lfw", lfgCharacterData.characterInterests); - else - LfgDataTable::clearBit("lfw", lfgCharacterData.characterInterests); - - lfgCharacterData.active = (playerObject->getSessionLastActiveTime() != 0); - lfgCharacterData.sessionActivity = playerObject->getSessionActivity(); - } - else - { - lfgCharacterData.profession = LfgCharacterData::Prof_Unknown; - lfgCharacterData.anonymous = false; - lfgCharacterData.displayLocationInSearchResults = false; - lfgCharacterData.active = false; - lfgCharacterData.sessionActivity = 0; - } - - SkillObject const * skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_novice"); - if (skill && hasSkill(*skill)) - { - lfgCharacterData.pilot = LfgCharacterData::Pilot_Rebel; - } - else - { - skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_novice"); - if (skill && hasSkill(*skill)) - { - lfgCharacterData.pilot = LfgCharacterData::Pilot_Imperial; - } - else - { - skill = SkillManager::getInstance().getSkill("pilot_neutral_novice"); - if (skill && hasSkill(*skill)) - { - lfgCharacterData.pilot = LfgCharacterData::Pilot_Neutral; - } - else - { - lfgCharacterData.pilot = LfgCharacterData::Pilot_None; - } - } - } - - lfgCharacterData.level = getLevel(); - lfgCharacterData.faction = getPvpFaction(); - - int const guildId = getGuildId(); - if (guildId == 0) - { - lfgCharacterData.guildName.clear(); - lfgCharacterData.guildAbbrev.clear(); - } - else - { - lfgCharacterData.guildName = GuildInterface::getGuildName(guildId); - lfgCharacterData.guildAbbrev = GuildInterface::getGuildAbbrev(guildId); - } - - std::vector const & cityIds = CityInterface::getCitizenOfCityId(getNetworkId()); - if (!cityIds.empty()) - { - lfgCharacterData.citizenOfCity = CityInterface::getCityInfo(cityIds.front()).getCityName(); - } - else - { - lfgCharacterData.citizenOfCity.clear(); - } - - lfgCharacterData.groupId = m_group.get(); - lfgCharacterData.locationPlanet = ServerWorld::getSceneId(); - - lfgCharacterData.locationRegion.clear(); - lfgCharacterData.locationFactionalPresenceGcwRegion.clear(); - lfgCharacterData.locationFactionalPresenceGridX = 0; - lfgCharacterData.locationFactionalPresenceGridZ = 0; - lfgCharacterData.locationPlayerCity.clear(); - PlanetObject const * const planetObject = ServerUniverse::getInstance().getPlanetByName(lfgCharacterData.locationPlanet); - if (planetObject) - { - Vector const creaturePosition = findPosition_w(); - Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(planetObject->getName(), creaturePosition.x, creaturePosition.z); - - if (region != NULL) - lfgCharacterData.locationRegion = Unicode::wideToNarrow(region->getName()); - - // handle factional presence - Client const * const client = getClient(); - if (client && (!ConfigServerGame::getGcwFactionalPresenceDisableForSecuredLogin() || !client->isGodValidated())) - { - std::string const & playerCurrentGcwRegion = playerObject->getCurrentGcwRegion(); - if (!playerCurrentGcwRegion.empty()) - { - if (!ServerWorld::isSpaceScene()) - { - // ground factional presence - // - // character contributes to ground GCW factional presence if he is actively - // playing the game, is declared factional, is not in a cell, is not - // cloaked/incapped/dead/swimming, and is not hidden from the overhead map/radar - if (lfgCharacterData.active && !PvpData::isNeutralFactionId(lfgCharacterData.faction) && PvpInternal::isDeclared(*this) && !isHidden() && isVisible() && getCoverVisibility() && !isIncapacitated() && !isDead() && !getState(States::Swimming) && getVisibleOnMapAndRadar()) - { - bool inCell = false; - ServerObject const * o = safe_cast(ContainerInterface::getContainedByObject(*this)); - while (o) - { - if (o->asCellObject()) - { - inCell = true; - break; - } - - o = safe_cast(ContainerInterface::getContainedByObject(*o)); - } - - if (!inCell) - { - // make sure he (or his vehicle/mount) is standing on the - // ground, and not on a roof/balcony/storyteller platform/etc - Object const * playerOrMount = getMountedCreature(); - if (playerOrMount) - { - // is factional presence allowed while mounted? - if (ConfigServerGame::getGcwFactionalPresenceMountedPct() <= 0) - playerOrMount = NULL; - } - else - { - playerOrMount = this; - } - - if (playerOrMount) - { - CollisionProperty const * const collisionProperty = playerOrMount->getCollisionProperty(); - Footprint const * const footprint = (collisionProperty ? collisionProperty->getFootprint() : NULL); - bool isOnSolidFloor = (footprint && footprint->isOnSolidFloor()); - if (isOnSolidFloor) - { - // make sure the player/mount is actually standing on the floor for it to count - float groundHeight, floorHeight; - if (footprint->getGroundHeight(groundHeight) && footprint->getFloorHeight(floorHeight) && (groundHeight == floorHeight)) - { - // really standing on the floor - } - else - { - // not really standing on the floor - isOnSolidFloor = false; - } - } - - // standing on the ground - if (!isOnSolidFloor) - { - lfgCharacterData.locationFactionalPresenceGcwRegion = playerCurrentGcwRegion; - - // if there's factional presence, calculate the grid in which it is occurring - // clamp to -8000 - 7999 - int posX = std::min(std::max(static_cast(creaturePosition.x), -8000), 7999); - - // clamp to -8000 - 7999 - int posZ = std::min(std::max(static_cast(creaturePosition.z), -8000), 7999); - - if (posX < 0) - posX -= (PvpData::getGcwFactionalPresenceGridSize() - 1); - - if (posZ < 0) - posZ -= (PvpData::getGcwFactionalPresenceGridSize() - 1); - - lfgCharacterData.locationFactionalPresenceGridX = ((posX / PvpData::getGcwFactionalPresenceGridSize()) * PvpData::getGcwFactionalPresenceGridSize()) + (PvpData::getGcwFactionalPresenceGridSize() / 2); - lfgCharacterData.locationFactionalPresenceGridZ = ((posZ / PvpData::getGcwFactionalPresenceGridSize()) * PvpData::getGcwFactionalPresenceGridSize()) + (PvpData::getGcwFactionalPresenceGridSize() / 2); - } - } - } - } - } - else if (lfgCharacterData.active && !isIncapacitated() && !isDead()) - { - // space factional presence - // - // character contributes to space GCW factional presence if he is actively playing the - // game, is not incapped/dead, is on board a player ship that's open to attack from - // other player ships, and is the same faction as the ship - ShipObject const * const ship = ShipObject::getContainingShipObject(this); - if (ship && ship->isPlayerShip() && !ship->isInvulnerable() && PvpInternal::isDeclared(*ship)) - { - uint32 const shipFaction = ship->getSpaceFaction(); - if ((PvpData::isImperialFactionId(shipFaction) || PvpData::isRebelFactionId(shipFaction)) && (lfgCharacterData.faction == shipFaction)) - lfgCharacterData.locationFactionalPresenceGcwRegion = playerCurrentGcwRegion; - } - } - } - } - - int const cityId = CityInterface::getCityAtLocation(planetObject->getName(), static_cast(creaturePosition.x), static_cast(creaturePosition.z), 0); - if (cityId > 0) - lfgCharacterData.locationPlayerCity = CityInterface::getCityInfo(cityId).getCityName(); - } - - // CTS transferred from galaxy - lfgCharacterData.ctsSourceGalaxy.clear(); - if (getObjVars().hasItem("ctsHistory")) - { - DynamicVariableList::NestedList const ctsTransactions(getObjVars(), "ctsHistory"); - for (DynamicVariableList::NestedList::const_iterator i = ctsTransactions.begin(); i != ctsTransactions.end(); ++i) - { - Unicode::String ctsTransactionDetail; - if (i.getValue(ctsTransactionDetail)) - { - Unicode::UnicodeStringVector tokens; - if (Unicode::tokenize(ctsTransactionDetail, tokens, NULL, NULL) && (tokens.size() >= 4)) - { - IGNORE_RETURN(lfgCharacterData.ctsSourceGalaxy.insert(Unicode::wideToNarrow(tokens[1]))); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObjectNamespace::GroupHelpers::creatureIsContainedInPOBShip(CreatureObject const * const creatureObject) -{ - NOT_NULL(creatureObject); - - ShipObject const * const shipObject = ShipObject::getContainingShipObject(creatureObject); - return shipObject && shipObject->getPortalProperty(); -} - -// ---------------------------------------------------------------------- - -void CreatureObjectNamespace::GroupHelpers::findAllTargetsForGroup(CreatureObject * const targetObj, std::vector & targets) -{ - typedef std::vector Targets; - - NOT_NULL(targetObj); - - ShipObject * const shipObject = ShipObject::getContainingShipObject(targetObj); - GroupObject const * const groupObject = targetObj->getGroup(); - - if ((shipObject != 0) && (groupObject != 0)) - { - Targets passengers; - - shipObject->findAllPassengers(passengers, true); - - Targets::const_iterator ii = passengers.begin(); - Targets::const_iterator iiEnd = passengers.end(); - - for (; ii != iiEnd; ++ii) - { - CreatureObject * const passenger = *ii; - - if (passenger != 0) - { - NetworkId const & passengerId = passenger->getNetworkId(); - - if (groupObject->isGroupMember(passengerId)) - { - targets.push_back(passenger); - } - } - NOT_NULL(passenger); - } - } - else - { - targets.push_back(targetObj); - } -} - -// ---------------------------------------------------------------------- - -bool CreatureObjectNamespace::GroupHelpers::roomInGroup(GroupObject const * groupObj, int additionalMembers) -{ - if (groupObj != 0) - { - return groupObj->doesGroupHaveRoomFor(additionalMembers); - } - - additionalMembers = std::max(0, additionalMembers); - return additionalMembers < GroupObject::maximumMembersInGroup(); -} - -// ---------------------------------------------------------------------- - -GroupMemberParam const CreatureObjectNamespace::GroupHelpers::buildGroupMemberParam(CreatureObject const * const creatureObject) -{ - NOT_NULL(creatureObject); - - ShipObject const * const shipObject = ShipObject::getContainingShipObject(creatureObject); - NetworkId const & memberId = creatureObject->getNetworkId(); - std::string const & name = Unicode::wideToNarrow(creatureObject->getEncodedObjectName()); - int const level = creatureObject->getLevel(); - bool const memberIsPC = creatureObject->isPlayerControlled(); - LfgCharacterData::Profession profession = LfgCharacterData::Prof_Unknown; - if (!memberIsPC) - { - profession = LfgCharacterData::Prof_NPC; - } - else - { - PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if (playerObject) - profession = LfgCharacterData::convertSkillTemplateToProfession(playerObject->getSkillTemplate()); - } - - NetworkId const & shipId = (shipObject != 0) ? shipObject->getNetworkId() : NetworkId::cms_invalid; - bool const shipIsPOB = shipObject != 0 && shipObject->getPortalProperty() != 0; - bool const ownsPOB = shipObject != 0 && shipObject->getOwnerId() == memberId; - - return GroupMemberParam(memberId, name, level, profession, memberIsPC, shipId, shipIsPOB, ownsPOB); -} - -// ---------------------------------------------------------------------- - -void CreatureObjectNamespace::GroupHelpers::buildGroupMemberParamsFromCreatures(std::vector const & targets, GroupObject::GroupMemberParamVector & targetMemberParams) -{ - std::vector::const_iterator ii = targets.begin(); - std::vector::const_iterator iiEnd = targets.end(); - - for (; ii != iiEnd; ++ii) - { - CreatureObject const * const creatureObject = *ii; - if (creatureObject != 0) - { - targetMemberParams.push_back(GroupHelpers::buildGroupMemberParam(creatureObject)); - } - } -} - -// ---------------------------------------------------------------------- - -void CreatureObjectNamespace::restoreItemDecorationLayout(CreatureObject & decorator, PlayerObject & decoratorPlayerObject, CachedNetworkId const & item, TangibleObject const & pob, CachedNetworkId const & cell, Vector const & position, Quaternion const & orientation) -{ - // make sure item is around - ServerObject const * const itemSo = safe_cast(item.getObject()); - if (!itemSo) - return; - - // make sure item is immediately in a cell/room - ServerObject const * const itemContainingCell = safe_cast(ContainerInterface::getContainedByObject(*itemSo)); - if (!itemContainingCell || !itemContainingCell->asCellObject()) - return; - - // make sure item is in the pob - if (&pob != ContainerInterface::getContainedByObject(*itemContainingCell)) - return; - - // make sure the cell is around - ServerObject const * const cellSo = safe_cast(cell.getObject()); - if (!cellSo) - return; - - CellObject const * const cellCo = cellSo->asCellObject(); - if (!cellCo) - return; - - // make sure cell is in the pob - if (&pob != ContainerInterface::getContainedByObject(*cellCo)) - return; - - // item is not currently in the target room, need to move it - bool needToMoveItem = false; - bool needToRotateItem = false; - Transform const * itemCurrentTransform = NULL; - if (itemContainingCell->getNetworkId() != cellSo->getNetworkId()) - { - needToMoveItem = true; - } - else - { - // if the item is not currently at the desired position, need to move it - itemCurrentTransform = &(itemSo->getTransform_o2p()); - Vector const currentPosition = itemCurrentTransform->getPosition_p(); - if (currentPosition.magnitudeBetweenSquared(position) > 0.0025) // not within 0.05m - { - needToMoveItem = true; - } - else - { - // if the item is not currently at the desired orientation, need to rotate it - Quaternion const currentOrientation(*itemCurrentTransform); - if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) - { - needToRotateItem = true; - } - } - } - - if (!needToMoveItem && !needToRotateItem) - return; - - // if the item needs to be moved, check to see if it needs to be rotated as well - if (needToMoveItem) - { - if (!itemCurrentTransform) - itemCurrentTransform = &(itemSo->getTransform_o2p()); - - Quaternion const currentOrientation(*itemCurrentTransform); - if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) - { - needToRotateItem = true; - } - } - - // if the item needs to be moved, find the "best" valid position for the item - if (needToMoveItem) - { - CellProperty const * const cellProperty = cellCo->getCellProperty(); - if (!cellProperty) - return; - - Floor const * const floor = cellProperty->getFloor(); - if (!floor) - return; - - BaseExtent const * const floorExtent = floor->getExtent_l(); - if (!floorExtent) - return; - - AxialBox const floorExtentBoundingBox = floorExtent->getBoundingBox(); - Vector floorExtentBoundingBoxCenter = floorExtentBoundingBox.getCenter(); - floorExtentBoundingBoxCenter.y = position.y + 1.0f; - - Vector goodLocation(position); - goodLocation.y = floorExtentBoundingBoxCenter.y; - - bool foundGoodPoint = true; - FloorLocator flResult; - if (!floor->intersectClosest(Ray3d(goodLocation, Vector::negativeUnitY), flResult)) - { - // do a "binary" search of points on the line starting at the floor bounding - // box center location (which may be a good location) and ending at the target - // location (which is a bad location) until a point on the line is found - // that is a good location, and that point is "up against" the wall of the cell - Vector badLocation(goodLocation); - goodLocation = floorExtentBoundingBoxCenter; - foundGoodPoint = floor->intersectClosest(Ray3d(goodLocation, Vector::negativeUnitY), flResult); - - Vector midpointPosition; - while (true) - { - // stop when the 2 closest "good" and "bad" location points are .2m apart, - // meaning we have gotten close enough to "up against" the wall of the cell - if (goodLocation.magnitudeXZBetweenSquared(badLocation) <= 0.04f) - break; - - midpointPosition = Vector::midpoint(goodLocation, badLocation); - midpointPosition.y = floorExtentBoundingBoxCenter.y; - if (floor->intersectClosest(Ray3d(midpointPosition, Vector::negativeUnitY), flResult)) - { - foundGoodPoint = true; - goodLocation = midpointPosition; - } - else - { - badLocation = midpointPosition; - } - } - } - - // couldn't find any valid position for the item - if (!foundGoodPoint) - return; - - // set the height of the item - goodLocation.y = position.y; - - // trigger script to move the item, which will perform the remaining validation - GameScriptObject * const gameScriptObject = decorator.getScriptObject(); - if (!gameScriptObject) - return; - - ScriptParams sp; - sp.addParam(itemSo->getNetworkId()); - sp.addParam(cellSo->getNetworkId()); - sp.addParam(goodLocation); - sp.addParam(needToRotateItem); - sp.addParam(orientation.w); - sp.addParam(orientation.x); - sp.addParam(orientation.y); - sp.addParam(orientation.z); - - // set the id of the object being restored, so that we can bypass the LOS check for it - decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(itemSo->getNetworkId()); - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_DO_RESTORE_ITEM_DECORATION_LAYOUT, sp)); - decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(NetworkId::cms_invalid); - - // check to see if the item got restored - bool itemGotRestored = true; - if (itemContainingCell->getNetworkId() == cellSo->getNetworkId()) - { - Transform const & itemCurrentTransform = itemSo->getTransform_o2p(); - Vector const currentPosition = itemCurrentTransform.getPosition_p(); - if (currentPosition.magnitudeBetweenSquared(goodLocation) > 0.0025) // not within 0.05m - { - itemGotRestored = false; - } - else if (needToRotateItem) - { - Quaternion const currentOrientation(itemCurrentTransform); - if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) - { - itemGotRestored = false; - } - } - } - else if (cellSo != ContainerInterface::getContainedByObject(*itemSo)) - { - itemGotRestored = false; - } - - if (itemGotRestored) - decoratorPlayerObject.setRestoreDecorationSuccessCount(decoratorPlayerObject.getRestoreDecorationSuccessCount() + 1); - } - else if (needToRotateItem) - { - // trigger script to rotate the item, which will perform the remaining validation - GameScriptObject * const gameScriptObject = decorator.getScriptObject(); - if (!gameScriptObject) - return; - - ScriptParams sp; - sp.addParam(itemSo->getNetworkId()); - sp.addParam(orientation.w); - sp.addParam(orientation.x); - sp.addParam(orientation.y); - sp.addParam(orientation.z); - - // set the id of the object being restored, so that we can bypass the LOS check for it - decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(itemSo->getNetworkId()); - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_DO_RESTORE_ITEM_DECORATION_LAYOUT_ROTATION_ONLY, sp)); - decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(NetworkId::cms_invalid); - - // check to see if the item got restored - bool itemGotRestored = true; - Transform const & itemCurrentTransform = itemSo->getTransform_o2p(); - Quaternion const currentOrientation(itemCurrentTransform); - if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) - { - itemGotRestored = false; - } - - if (itemGotRestored) - decoratorPlayerObject.setRestoreDecorationSuccessCount(decoratorPlayerObject.getRestoreDecorationSuccessCount() + 1); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::clientMinigameOpen(ValueDictionary const & messageData) -{ - typedef ValueDictionary Payload; - MessageQueueGenericValueType * msg = new MessageQueueGenericValueType(messageData); - - if (isAuthoritative()) - { - appendMessage(CM_clientMinigameOpen, 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - else - { - sendControllerMessageToAuthServer(CM_clientMinigameOpen, msg); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::clientMinigameClose(ValueDictionary const & messageData) -{ - typedef ValueDictionary Payload; - MessageQueueGenericValueType * msg = new MessageQueueGenericValueType(messageData); - - if (isAuthoritative()) - { - appendMessage(CM_clientMinigameClose, 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - else - { - sendControllerMessageToAuthServer(CM_clientMinigameClose, msg); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::addPackedAppearanceWearable(std::string const &appearanceData, int arrangementIndex, NetworkId const &networkId, uint32 sharedTemplateCrcValue) -{ - //-- Check if this network id already exists in the wearable list. - size_t const length = m_wearableAppearanceData.size(); - for (size_t i = 0; i < length; ++i) - { - WearableEntry const &entry = m_wearableAppearanceData[i]; - if (entry.m_networkId == networkId) - { - // Check if this entry exists but in a different configuration. - WARNING((entry.m_arrangement != arrangementIndex), ("attempted to add object id=[%s] in packed wearable list multiple times in different arrangements, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_arrangement, arrangementIndex)); - WARNING((static_cast(entry.m_objectTemplate) != sharedTemplateCrcValue), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by shared object template crc value, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_objectTemplate, static_cast(sharedTemplateCrcValue))); - DEBUG_WARNING((entry.m_appearanceString != appearanceData), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by appearance customization data.", appearanceData.c_str())); - - return; - } - } - //-- Add the new entry. - m_wearableAppearanceData.push_back(WearableEntry(appearanceData, arrangementIndex, networkId, sharedTemplateCrcValue, NULL, NULL)); -} - -// ---------------------------------------------------------------------- - -void CreatureObject::saveDecorationLayout(ServerObject const & pobSourceObject, int saveSlotNumber, std::string const & description) -{ - int debugNumItems = 0; - const unsigned long debugStartTimeMs = Clock::timeMs(); - - if (!isAuthoritative()) - return; - - if (!getClient()) - return; - - // only slots 1-3 are currently supported - if ((saveSlotNumber < 1) || (saveSlotNumber > 3)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - if (!pobSourceObject.isAuthoritative()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(this); - if (!playerObj) - return; - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (containingPOBso != &pobSourceObject) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); - return; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - if (!containingPOB->isOnAdminList(*this)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - Container const * const pobContainer = ContainerInterface::getContainer(*containingPOB); - if (pobContainer) - { - std::string objvarValue; - int objvarValueIndex = 0; - - char buffer1[64]; - buffer1[sizeof(buffer1)-1] = '\0'; - - char buffer2[1024]; - buffer2[sizeof(buffer2)-1] = '\0'; - - std::set rooms; - - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d", saveSlotNumber); - playerObj->removeObjVarItem(buffer1); - - for (ContainerConstIterator i = pobContainer->begin(); i != pobContainer->end(); ++i) - { - ServerObject const * const cell = safe_cast((*i).getObject()); - if (cell && cell->asCellObject()) - { - CellProperty const * const cellContainer = cell->getCellProperty(); - if (cellContainer) - { - std::map, std::pair >::const_iterator const iterFindCellHeight = s_mapCellHeightRestriction.find(std::make_pair(containingPOB->getTemplateCrc(), cellContainer->getCellNameCrc())); - if (iterFindCellHeight == s_mapCellHeightRestriction.end()) - continue; - - Floor const * const floor = cellContainer->getFloor(); - if (!floor) - continue; - - BaseExtent const * const floorExtent = floor->getExtent_l(); - if (!floorExtent) - continue; - - AxialBox const floorExtentBoundingBox = floorExtent->getBoundingBox(); - Vector const floorExtentBoundingBoxCenter = floorExtentBoundingBox.getCenter(); - - for (ContainerConstIterator j = cellContainer->begin(); j != cellContainer->end(); ++j) - { - ServerObject const * const cellContent = safe_cast((*j).getObject()); - if (cellContent && cellContent->isPersisted() && !cellContent->asCreatureObject() && !cellContent->isVendor()) - { - ++debugNumItems; - IGNORE_RETURN(rooms.insert(cellContainer->getCellName())); - - Transform const & transform = cellContent->getTransform_o2p(); - Vector const position = transform.getPosition_p(); - Quaternion const quaternion(transform); - - snprintf(buffer2, sizeof(buffer2)-1, "%s~%s~%.10g~%.10g~%.10g~%.10g~%.10g~%.10g~%.10g", cellContent->getNetworkId().getValueString().c_str(), cellContainer->getCellName(), position.x - floorExtentBoundingBoxCenter.x, position.y - iterFindCellHeight->second.first, position.z - floorExtentBoundingBoxCenter.z, quaternion.w, quaternion.x, quaternion.y, quaternion.z); - if ((objvarValue.size() + ::strlen(buffer2) + 2) > DynamicVariable::MAX_DYNAMIC_VARIABLE_UTF8_LENGTH) - { - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); - playerObj->setObjVarItem(buffer1, objvarValue); - ++objvarValueIndex; - objvarValue = buffer2; - } - else - { - if (!objvarValue.empty()) - objvarValue += "~"; - - objvarValue += buffer2; - } - } - } - } - } - } - - if (rooms.empty()) - { - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d", saveSlotNumber); - playerObj->removeObjVarItem(buffer1); - - Chat::sendSystemMessage(*this, Unicode::narrowToWide("There is currently no decoration in the structure or POB ship to save."), Unicode::emptyString); - } - else - { - if (!objvarValue.empty()) - { - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); - playerObj->setObjVarItem(buffer1, objvarValue); - } - - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.saveTime", saveSlotNumber); - playerObj->setObjVarItem(buffer1, static_cast(::time(NULL))); - - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.pobName", saveSlotNumber); - playerObj->setObjVarItem(buffer1, containingPOB->getObjectNameStringId().localize()); - - std::vector roomsVector; - for (std::set::const_iterator iterRoom = rooms.begin(); iterRoom != rooms.end(); ++iterRoom) - roomsVector.push_back(Unicode::narrowToWide(*iterRoom)); - - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.rooms", saveSlotNumber); - playerObj->setObjVarItem(buffer1, roomsVector); - - std::string validatedDescription = description; - if (!validatedDescription.empty()) - { - if (validatedDescription.size() > 40) - validatedDescription = validatedDescription.substr(0, 40); - - snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.description", saveSlotNumber); - playerObj->setObjVarItem(buffer1, validatedDescription); - } - - if (validatedDescription.empty()) - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("The decoration layout of the structure or POB ship has been saved in slot %d.", saveSlotNumber)), Unicode::emptyString); - else - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("The decoration layout of the structure or POB ship has been saved in slot %d (%s).", saveSlotNumber, validatedDescription.c_str())), Unicode::emptyString); - } - } - else - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - } - - if ((debugNumItems > 0) && getClient()->isGod()) - { - const unsigned long debugEndTimeMs = Clock::timeMs(); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("!!!GOD MODE STATISTICS!!! %d items saved in %lums", debugNumItems, (debugEndTimeMs - debugStartTimeMs))), Unicode::emptyString); - } -} - -// ---------------------------------------------------------------------- - -void CreatureObject::restoreDecorationLayout(ServerObject const & pobTargetObject, int saveSlotNumber) -{ - const unsigned long debugStartTimeMs = Clock::timeMs(); - - if (!isAuthoritative()) - return; - - if (!getClient()) - return; - - // only slots 1-3 are currently supported - if ((saveSlotNumber < 1) || (saveSlotNumber > 3)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - if (!pobTargetObject.isAuthoritative()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(this); - if (!playerObj) - return; - - ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (!containingCell || !containingCell->asCellObject()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); - if (!containingPOBso) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (!containingPOBso->isInWorldCell()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - if (containingPOBso != &pobTargetObject) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - // don't allow another restore on the pob while one is still in progress - int const timeNow = static_cast(::time(NULL)); - int restoreDecorationOperationTimeout = 0; - if (getObjVars().getItem("restoreDecorationOperation.timeout", restoreDecorationOperationTimeout) && (restoreDecorationOperationTimeout > timeNow)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing a restore decoration layout operation. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(restoreDecorationOperationTimeout - timeNow)).c_str())), Unicode::emptyString); - return; - } - - if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); - return; - } - - TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); - if (!containingPOB) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - // check for lot overlimit drop restriction - if ((playerObj->getAccountNumLots() > getMaxNumberOfLots()) && getObjVars().hasItem("lotOverlimit.structure_id")) - { - NetworkId lotOverlimitStructure; - if (getObjVars().getItem("lotOverlimit.structure_id", lotOverlimitStructure) && lotOverlimitStructure.isValid()) - { - if (GameObjectTypes::isTypeOf(containingPOB->getGameObjectType(), SharedObjectTemplate::GOT_building) && (containingPOB->getNetworkId() != lotOverlimitStructure)) - { - std::string lotOverlimitStructureName; - std::string lotOverlimitStructureLocation; - - IGNORE_RETURN(getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); - IGNORE_RETURN(getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); - - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are currently over the lot limit, and cannot drop any item into (or move around items within) any factory or structure, other than the %s structure located at %s that caused you to exceed the lot limit.", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); - return; - } - } - } - - if (!containingPOB->isOnAdminList(*this)) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); - return; - } - - // build the list of rooms in the target pob - std::map, std::pair > > > pobTargetObjectRoomsToCells; - Container const * const pobContainer = ContainerInterface::getContainer(*containingPOB); - if (pobContainer) - { - for (ContainerConstIterator i = pobContainer->begin(); i != pobContainer->end(); ++i) - { - ServerObject const * const cell = safe_cast((*i).getObject()); - if (!cell || !cell->asCellObject()) - continue; - - CellProperty const * const cellContainer = cell->getCellProperty(); - if (!cellContainer) - continue; - - std::map, std::pair >::const_iterator const iterFindCellHeight = s_mapCellHeightRestriction.find(std::make_pair(containingPOB->getTemplateCrc(), cellContainer->getCellNameCrc())); - if (iterFindCellHeight == s_mapCellHeightRestriction.end()) - continue; - - Floor const * const floor = cellContainer->getFloor(); - if (!floor) - continue; - - BaseExtent const * const floorExtent = floor->getExtent_l(); - if (!floorExtent) - continue; - - AxialBox const floorExtentBoundingBox = floorExtent->getBoundingBox(); - Vector const floorExtentBoundingBoxCenter = floorExtentBoundingBox.getCenter(); - - pobTargetObjectRoomsToCells[cellContainer->getCellName()] = std::make_pair(cell->asCellObject(), std::make_pair(std::make_pair(iterFindCellHeight->second.first, iterFindCellHeight->second.second), std::make_pair(floorExtentBoundingBoxCenter.x, floorExtentBoundingBoxCenter.z))); - } - } - else - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - // build the list of source room to target room mapping, telling us where to move/restore the items - DynamicVariableList const & objVars = playerObj->getObjVars(); - char buffer[64]; - buffer[sizeof(buffer)-1] = '\0'; - - std::vector savedSourceRooms; - snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.rooms", saveSlotNumber); - if (!objVars.getItem(buffer, savedSourceRooms) || savedSourceRooms.empty()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - std::vector savedTargetRooms; - snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.targetRooms", saveSlotNumber); - if (!objVars.getItem(buffer, savedTargetRooms) || savedTargetRooms.empty()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - if (savedSourceRooms.size() != savedTargetRooms.size()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - std::map sourceRoomToTargetRoomMapping; - for (size_t i = 0, size = savedSourceRooms.size(); i < size; ++i) - { - if (savedTargetRooms[i].empty()) - continue; - - std::string savedTargetRoomNarrow = Unicode::wideToNarrow(savedTargetRooms[i]); - if (pobTargetObjectRoomsToCells.count(savedTargetRoomNarrow) <= 0) - continue; - - sourceRoomToTargetRoomMapping[Unicode::wideToNarrow(savedSourceRooms[i])] = savedTargetRoomNarrow; - } - - if (sourceRoomToTargetRoomMapping.empty()) - { - Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); - return; - } - - int debugNumItems = 0; - int numItemsToBeMoved = 0; - - unsigned int pos; - NetworkId itemId; - ServerObject const * itemObj; - ServerObject const * itemObjContainingCell; - std::string room; - Vector position, currentPosition; - Quaternion orientation; - std::map::const_iterator iterFindSourceRoomToTargetRoomMapping; - std::map, std::pair > > >::const_iterator iterFindPobTargetObjectRoomsToCells; - - std::string objvarValue; - int objvarValueIndex = 0; - - std::list, std::pair > > & restoreDecorationLayoutList = playerObj->getRestoreDecorationLayoutList(); - restoreDecorationLayoutList.clear(); - - snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); - while (objVars.getItem(buffer, objvarValue) && !objvarValue.empty()) - { - pos = 0; - while (objvarValue[pos]) - { - ++debugNumItems; - - nextOid(objvarValue, pos, itemId); - nextString(objvarValue, pos, room); - nextFloat(objvarValue, pos, position.x); - nextFloat(objvarValue, pos, position.y); - nextFloat(objvarValue, pos, position.z); - nextFloat(objvarValue, pos, orientation.w); - nextFloat(objvarValue, pos, orientation.x); - nextFloat(objvarValue, pos, orientation.y); - nextFloat(objvarValue, pos, orientation.z); - - itemObj = ServerWorld::findObjectByNetworkId(itemId); - if (!itemObj) - continue; - - itemObjContainingCell = safe_cast(ContainerInterface::getContainedByObject(*itemObj)); - if (!itemObjContainingCell || !itemObjContainingCell->asCellObject()) - continue; - - if (ContainerInterface::getContainedByObject(*itemObjContainingCell) != containingPOB) - continue; - - // what destination room should this item go in? - iterFindSourceRoomToTargetRoomMapping = sourceRoomToTargetRoomMapping.find(room); - if (iterFindSourceRoomToTargetRoomMapping == sourceRoomToTargetRoomMapping.end()) - { - // no destination room specified, item should not be moved - continue; - } - - // find the cell in the target structure corresponding to the target room - iterFindPobTargetObjectRoomsToCells = pobTargetObjectRoomsToCells.find(iterFindSourceRoomToTargetRoomMapping->second); - if (iterFindPobTargetObjectRoomsToCells == pobTargetObjectRoomsToCells.end()) - { - // target room not found, cannot move the item - continue; - } - - // the height is saved as the offset from the floor - position.y += iterFindPobTargetObjectRoomsToCells->second.second.first.first; - - if (position.y < iterFindPobTargetObjectRoomsToCells->second.second.first.first) - position.y = iterFindPobTargetObjectRoomsToCells->second.second.first.first; - else if (position.y > iterFindPobTargetObjectRoomsToCells->second.second.first.second) - position.y = iterFindPobTargetObjectRoomsToCells->second.second.first.second; - - // x and z are saved as offset from the "center" - position.x += iterFindPobTargetObjectRoomsToCells->second.second.second.first; - position.z += iterFindPobTargetObjectRoomsToCells->second.second.second.second; - - // item is not currently in the target room, need to move it - if (itemObjContainingCell->getNetworkId() != iterFindPobTargetObjectRoomsToCells->second.first->getNetworkId()) - { - ++numItemsToBeMoved; - restoreDecorationLayoutList.push_back(std::make_pair(std::make_pair(CachedNetworkId(*itemObj), CachedNetworkId(*iterFindPobTargetObjectRoomsToCells->second.first)), std::make_pair(position, orientation))); - continue; - } - - // if the item is not currently at the desired position, need to move it - Transform const & itemCurrentTransform = itemObj->getTransform_o2p(); - currentPosition = itemCurrentTransform.getPosition_p(); - if (currentPosition.magnitudeBetweenSquared(position) > 0.0025) // not within 0.05m - { - ++numItemsToBeMoved; - restoreDecorationLayoutList.push_back(std::make_pair(std::make_pair(CachedNetworkId(*itemObj), CachedNetworkId(*iterFindPobTargetObjectRoomsToCells->second.first)), std::make_pair(position, orientation))); - continue; - } - - // if the item is not currently at the desired orientation, need to move it - Quaternion const currentOrientation(itemCurrentTransform); - if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || - !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) - { - ++numItemsToBeMoved; - restoreDecorationLayoutList.push_back(std::make_pair(std::make_pair(CachedNetworkId(*itemObj), CachedNetworkId(*iterFindPobTargetObjectRoomsToCells->second.first)), std::make_pair(position, orientation))); - continue; - } - } - - ++objvarValueIndex; - snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); - } - - snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.description", saveSlotNumber); - std::string saveSlotDescription; - IGNORE_RETURN(objVars.getItem(buffer, saveSlotDescription)); - if (restoreDecorationLayoutList.empty()) - { - if (saveSlotDescription.empty()) - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("No items in the structure or POB ship could be (or need to be) moved/restored using the saved decoration layout in slot %d.", saveSlotNumber)), Unicode::emptyString); - else - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("No items in the structure or POB ship could be (or need to be) moved/restored using the saved decoration layout in slot %d (%s).", saveSlotNumber, saveSlotDescription.c_str())), Unicode::emptyString); - } - else - { - if (saveSlotDescription.empty()) - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("Please remain in the structure or POB ship while the system attempts to move/restore %d items using the saved decoration layout in slot %d. You will be notified when the operation is complete.", numItemsToBeMoved, saveSlotNumber)), Unicode::emptyString); - else - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("Please remain in the structure or POB ship while the system attempts to move/restore %d items using the saved decoration layout in slot %d (%s). You will be notified when the operation is complete.", numItemsToBeMoved, saveSlotNumber, saveSlotDescription.c_str())), Unicode::emptyString); - - // start messageTo loop to do the decoration layout restore, - // spread out over a period of time so it doesn't lag out the server - int restoreDecorationOperationId = ::rand(); - while (restoreDecorationOperationId == 0) - restoreDecorationOperationId = ::rand(); - - playerObj->setRestoreDecorationOperationId(restoreDecorationOperationId); - playerObj->setRestoreDecorationPobId(containingPOB->getNetworkId()); - playerObj->setRestoreDecorationTotalCount(numItemsToBeMoved); - playerObj->setRestoreDecorationAttemptedCount(0); - playerObj->setRestoreDecorationSuccessCount(0); - - IGNORE_RETURN(setObjVarItem("restoreDecorationOperation.timeout", timeNow + (5 * 60))); - IGNORE_RETURN(setObjVarItem("restoreDecorationOperation.operationId", restoreDecorationOperationId)); - - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++RestoreDecorationLayout", - "", - 0, - false); - } - - if ((debugNumItems > 0) && getClient()->isGod()) - { - const unsigned long debugEndTimeMs = Clock::timeMs(); - Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("!!!GOD MODE STATISTICS!!! %d items read (%d will be moved) in %lums", debugNumItems, numItemsToBeMoved, (debugEndTimeMs - debugStartTimeMs))), Unicode::emptyString); - } -} - -// ====================================================================== +//======================================================================== +// +// CreatureObject.cpp +// Copyright 2001-2005, Sony Online Entertainment, Inc. +// All rights reserved. +// +//======================================================================== + +#include "serverGame/FirstServerGame.h" +#pragma warning(disable : 4100 4514) +#include "serverGame/CreatureObject.h" + +#include "SwgGameServer/CombatEngine.h" +#include "SwgGameServer/ConfigCombatEngine.h" +#include "UnicodeUtils.h" +#include "serverGame/AiCreatureController.h" +#include "serverGame/AttribModNameManager.h" +#include "serverGame/BiographyManager.h" +#include "serverGame/BuffManager.h" +#include "serverGame/BuildingObject.h" +#include "serverGame/CellObject.h" +#include "serverGame/Chat.h" +#include "serverGame/CitizenInfo.h" +#include "serverGame/CityInfo.h" +#include "serverGame/CityInterface.h" +#include "serverGame/Client.h" +#include "serverGame/CommandCppFuncs.h" +#include "serverGame/CommandQueue.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ConsoleManager.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/DraftSchematicObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/GroupObject.h" +#include "serverGame/GroupMissionCriticalObjectsBuilder.h" +#include "serverGame/GroupStringId.h" +#include "serverGame/GuildInterface.h" +#include "serverGame/GuildMemberInfo.h" +#include "serverGame/GuildObject.h" +#include "serverGame/ServerImageDesignerManager.h" +#include "serverGame/ManufactureSchematicObject.h" +#include "serverGame/MessageToQueue.h" +#include "serverGame/MissionObject.h" +#include "serverGame/MoveSimManager.h" +#include "serverGame/NameManager.h" +#include "serverGame/NewbieTutorial.h" +#include "serverGame/NpcConversation.h" +#include "serverGame/ObjectTracker.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/PvpInternal.h" +#include "serverGame/Region.h" +#include "serverGame/RegionMaster.h" +#include "serverGame/ReportManager.h" +#include "serverGame/ServerCreatureObjectTemplate.h" +#include "serverGame/ServerMessageForwarding.h" +#include "serverGame/ServerMissionObjectTemplate.h" +#include "serverGame/ServerSecureTrade.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWeaponObjectTemplate.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/ShipObject.h" +#include "serverGame/SpaceVisibilityManager.h" +#include "serverGame/TriggerVolume.h" +#include "serverGame/VeteranRewardManager.h" +#include "serverGame/WeaponObject.h" +#include "serverNetworkMessages/AccountFeatureIdResponse.h" +#include "serverNetworkMessages/FeatureIdTransactionRequest.h" +#include "serverNetworkMessages/FeatureIdTransactionResponse.h" +#include "serverNetworkMessages/GroupMemberParam.h" +#include "serverNetworkMessages/LoginUpgradeAccountMessage.h" +#include "serverNetworkMessages/MessageQueueAlterAttribute.h" +#include "serverNetworkMessages/MessageQueueCommandQueueEnqueueFwd.h" +#include "serverNetworkMessages/MessageQueueSetState.h" +#include "serverNetworkMessages/MessageToPayload.h" +#include "serverNetworkMessages/TransferReplyMoveValidation.h" +#include "serverNetworkMessages/UnloadedPlayerMessage.h" +#include "serverNetworkMessages/UpdateObjectOnPlanetMessage.h" +#include "serverNetworkMessages/UploadCharacterMessage.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/JavaLibrary.h" +#include "serverScript/ScriptDictionary.h" +#include "serverScript/ScriptParameters.h" +#include "serverUtility/AdminAccountManager.h" +#include "serverUtility/ServerClock.h" +#include "Session/CommonAPI/CommonAPI.h" +#include "sharedCollision/BaseExtent.h" +#include "sharedCollision/CollisionProperty.h" +#include "sharedCollision/CollisionWorld.h" +#include "sharedCollision/Floor.h" +#include "sharedCollision/Footprint.h" +#include "sharedDebug/Profiler.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/DynamicVariableListNestedList.h" +#include "sharedFoundation/DynamicVariableLocationData.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedFoundation/TemporaryCrcString.h" +#include "sharedGame/AppearanceManager.h" +#include "sharedGame/AttribModArchive.h" +#include "sharedGame/Buff.h" +#include "sharedGame/CityData.h" +#include "sharedGame/CommandTable.h" +#include "sharedGame/ConfigSharedGame.h" +#include "sharedGame/CraftingData.h" +#include "sharedGame/CustomizationManager.h" +#include "sharedGame/CustomizationManager_MorphParameter.h" +#include "sharedGame/GameObjectTypes.h" +#include "sharedGame/LfgDataTable.h" +#include "sharedGame/MatchMakingCharacterResult.h" +#include "sharedGame/OutOfBandPackager.h" +#include "sharedGame/PlatformFeatureBits.h" +#include "sharedGame/PlayerCreationManager.h" +#include "sharedGame/ProsePackage.h" +#include "sharedGame/PvpData.h" +#include "sharedGame/SharedCreatureObjectTemplate.h" +#include "sharedGame/SharedStringIds.h" +#include "sharedGame/ShipSlotIdManager.h" +#include "sharedGame/SlopeEffectProperty.h" +#include "sharedGame/SlowDownProperty.h" +#include "sharedGame/SpatialChatManager.h" +#include "sharedGame/VehicleHoverDynamics.h" +#include "sharedLog/Log.h" +#include "sharedMath/AxialBox.h" +#include "sharedMath/MxCifQuadTreeBounds.h" +#include "sharedMath/Ray3d.h" +#include "sharedNetworkMessages/ClientMfdStatusUpdateMessage.h" +#include "sharedNetworkMessages/ErrorMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/GrantCommand.h" +#include "sharedNetworkMessages/MessageQueueCombatSpam.h" +#include "sharedNetworkMessages/MessageQueueCommandTimer.h" +#include "sharedNetworkMessages/MessageQueueDataTransformWithParent.h" +#include "sharedNetworkMessages/MessageQueueGenericValueType.h" +#include "sharedNetworkMessages/MessageQueueMissionListResponse.h" +#include "sharedNetworkMessages/MessageQueueOpponentInfo.h" +#include "sharedNetworkMessages/MessageQueuePosture.h" +#include "sharedNetworkMessages/MessageQueuePushCreature.h" +#include "sharedNetworkMessages/MessageQueueSitOnObject.h" +#include "sharedNetworkMessages/MessageQueueSlowDownEffect.h" +#include "sharedNetworkMessages/MessageQueueSpatialChat.h" +#include "sharedNetworkMessages/MessageQueueStringList.h" +#include "sharedNetworkMessages/RevokeCommand.h" +#include "sharedNetworkMessages/SceneChannelMessages.h" +#include "sharedNetworkMessages/SlowDownEffectMessage.h" +#include "serverNetworkMessages/TransferCharacterData.h" +#include "serverNetworkMessages/TransferCharacterDataArchive.h" +#include "sharedNetworkMessages/UpdatePostureMessage.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/CustomizationData.h" +#include "sharedObject/MovementTable.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/SlotId.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedObject/SlottedContainmentProperty.h" +#include "sharedObject/VolumeContainer.h" +#include "sharedSkillSystem/ExpertiseManager.h" +#include "sharedSkillSystem/LevelManager.h" +#include "sharedSkillSystem/SkillManager.h" +#include "sharedSkillSystem/SkillObject.h" +#include "sharedTerrain/TerrainObject.h" +#include "sharedTerrain/WaterTypeManager.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" +#include "swgSharedNetworkMessages/MessageQueueCombatAction.h" +#include "swgSharedUtility/Attributes.h" +#include "swgSharedUtility/States.h" +#include "sharedUtility/ValueDictionary.h" +#include +#include +#include +#include +#include + +//---------------------------------------------------------------------- +// static CreatureObject vars + +const SharedObjectTemplate * CreatureObject::m_defaultSharedTemplate = NULL; + +//---------------------------------------------------------------------- + +// The max number of lots available to a player. This value is also defined in base_class.java +static const int HOUSING_MAX_LOTS = 10; + +// Slot names +static const ConstCharCrcLowerString DATAPAD_SLOT_NAME("datapad"); + +// Crafting objvar names +static const std::string OBJVAR_DISABLE_SCHEMATIC_FILTER("crafting.disableSchematicFiltering"); + +//objvar for banking +static const std::string OBJVAR_BANK_ID("banking_bankid"); +static const std::string OBJVAR_OPEN_BANK_TERMINAL_ID("open_bank_location"); + +//slot names +static const ConstCharCrcLowerString BANK_SLOT_NAME("bank"); +static const ConstCharCrcLowerString MISSION_BAG_SLOT_NAME("mission_bag"); + +// skill data granted independently from skills +static const std::string OBJVAR_NOT_SKILL_MODS("_notskill.mods"); +static const std::string OBJVAR_NOT_SKILL_COMMANDS("_notskill.commands"); +static const std::string OBJVAR_NOT_SKILL_SCHEMATICS("_notskill.schematics"); + +// special skill mods +static const std::string SLOPE_MOD("slope_move"); +static const std::string GROUP_SLOPE_MOD("group_slope_move"); + +// jedi/force power objvars +static const std::string OBJVAR_NEW_JEDI_FORCE("_start_force"); +static const std::string OBJVAR_JEDI("jedi"); +static const std::string OBJVAR_ADD_JEDI_ACK("jediAddedAcknowlege"); +//static const std::string OBJVAR_FORCE_REGEN_RATE("jedi.regenrate"); +//static const std::string OBJVAR_FORCE_REGEN_VALUE("jedi.regenvalue"); +static const std::string OBJVAR_JEDI_VISIBILITY("jedi.visibility"); + +// deprecated badge objvars (will be used to move old badges over to the collection system) +static const std::string OBJVAR_BADGES("badge.tracking"); +static const std::string OBJVAR_COUNT_BADGES("badge.count"); + +// residence house id objvar +const std::string OBJVAR_PLAYER_HOUSE_ID("residenceHouseId"); + +// If a pet accepts a group invitation but is deleted before +// being given the group information, we need to try to remove +// him from the group in the future +static const unsigned MAX_ATTEMPTS_TO_REMOVE_PET_FROM_GROUP = 30; +static const int TIME_BETWEEN_ATTEMPTS_TO_REMOVE_PET = 1; + +// creature regen constants +const static std::string CREATURES_TABLE("datatables/mob/creatures.iff"); + +//---------------------------------------------------------------------- + +namespace CreatureObjectNamespace +{ + const int POINTS_PER_TIER = 4; + // ---------------------------------------------------------------------- + + const char* s_inventoryTemplate = "object/tangible/inventory/character_inventory.iff"; + const char* s_datapadTemplate = "object/tangible/datapad/character_datapad.iff"; + const char* s_missionBagTemplate = "object/tangible/mission_bag/mission_bag.iff"; + const char* s_bankTemplate = "object/tangible/bank/character_bank.iff"; + const char* s_appearanceTemplate = "object/tangible/inventory/appearance_inventory.iff"; + + SlotId s_defaultWeaponSlotId = SlotId::invalid; + SlotId s_inventorySlotId = SlotId::invalid; + SlotId s_appearanceSlotId = SlotId::invalid; + bool s_allowNullDefaultWeapon = false; + + // ---------------------------------------------------------------------- + + std::map > s_instrumentTypeMap; + + // ---------------------------------------------------------------------- + + void loadInstrumentTable() + { + char const *fileName = ConfigServerGame::getInstrumentDataTableFilename(); + DataTable *t = DataTableManager::getTable(fileName, true); + if (!t) + { + FATAL(true, ("Could not find instrument datatable %s.", fileName)); + } + for (int row = 0; row < t->getNumRows(); ++row) + { + std::string name = t->getStringValue("serverTemplateName", row); + int visualId = t->getIntValue("instrumentVisualId", row); + int audioId = t->getIntValue("instrumentAudioId", row); + IGNORE_RETURN(s_instrumentTypeMap.insert(std::make_pair(name, std::make_pair(visualId, audioId)))); + } + DataTableManager::close(fileName); + } + + // ---------------------------------------------------------------------- + + int lookupInstrumentVisualId(char const * serverTemplateName) + { + std::map >::const_iterator i = s_instrumentTypeMap.find(std::string(serverTemplateName)); + if (i != s_instrumentTypeMap.end()) + return (*i).second.first; + return 0; + } + + // ---------------------------------------------------------------------- + + int lookupInstrumentAudioId(char const * serverTemplateName) + { + std::map >::const_iterator i = s_instrumentTypeMap.find(std::string(serverTemplateName)); + if (i != s_instrumentTypeMap.end()) + return (*i).second.second; + return 0; + } + + // ---------------------------------------------------------------------- + + std::map s_danceVisualMap; + + // ---------------------------------------------------------------------- + + void loadDanceVisualTable() + { + char const *fileName = ConfigServerGame::getPerformanceDataTableFilename(); + DataTable *t = DataTableManager::getTable(fileName, true); + for (int row = 0; row < t->getNumRows(); ++row) + { + int visualId = t->getIntValue("danceVisualId", row); + if (visualId) + { + IGNORE_RETURN(s_danceVisualMap.insert(std::make_pair(row+1, visualId))); + } + } + DataTableManager::close(fileName); + } + + struct CommandSeriesRecord + { + std::string commandName; + std::string baseCommandName; + int level; + }; + std::vector s_commandSeriesRecords; + + void loadCommandSeriesTable() + { + DataTable *t = DataTableManager::getTable("datatables/command/command_series.iff", true); + for (int row = 0; row < t->getNumRows(); ++row) + { + CommandSeriesRecord csr; + csr.commandName = t->getStringValue("commandName", row); + csr.baseCommandName = t->getStringValue("baseCommandName", row); + csr.level = t->getIntValue("level", row); + IGNORE_RETURN(s_commandSeriesRecords.push_back(csr)); + } + DataTableManager::close("datatables/command/command_series.iff"); + } + + // ---------------------------------------------------------------------- + + int lookupDanceVisual(int performanceType) + { + std::map::const_iterator i = s_danceVisualMap.find(performanceType); + if (i != s_danceVisualMap.end()) + return (*i).second; + return 0; + } + + // ---------------------------------------------------------------------- + + bool instrumentTooFar(Vector const &playerPos_w, Vector const &instrumentPos_w) + { + static float maxDistSquared = sqr(ConfigServerGame::getMaxInstrumentPlayDistance()); + if (playerPos_w.magnitudeBetweenSquared(instrumentPos_w) < maxDistSquared) + return false; + return true; + } + + // ---------------------------------------------------------------------- + + CreatureObject::AllCreaturesSet g_creatureList; + + std::vector > gs_missionRequestQueue; + std::vector > gs_missionRequestQueueDeferredRemoves; + + void removeCreatureFromMissionRequestQueue(const CreatureObject * creature) + { + std::vector >::iterator qiter; + for(qiter = gs_missionRequestQueue.begin(); qiter != gs_missionRequestQueue.end(); ++qiter) + { + if((*qiter).first == creature) + { + gs_missionRequestQueueDeferredRemoves.push_back((*qiter)); + } + } + } + + std::deque s_spawnQueue; + std::deque s_missionQueue; + + //---------------------------------------------------------------------- + //- @odo: these lists really need to be moved into C++ + + bool isBuildingAdminForTarget (const ServerObject & object, const ServerObject & target) + { + + const TangibleObject* hopperObject = target.asTangibleObject(); + const CreatureObject* player = object.asCreatureObject(); + if (!player || !hopperObject) + return false; + return hopperObject->isOnAdminList(*player); + } + + //---------------------------------------------------------------------- + + bool canHopperForTarget (const ServerObject & object, const ServerObject & target) + { + const TangibleObject* hopperObject = target.asTangibleObject(); + const CreatureObject* player = object.asCreatureObject(); + if (!player || !hopperObject) + return false; + return hopperObject->isOnHopperList(*player); + } + + //---------------------------------------------------------------------- + + bool isTargetBuildingBaseObject (const ServerObject & buildingObject, const ServerObject & target) + { + static const std::string objvarname_baseObjects = "player_structure.base_objects"; + + const NetworkId & targetId = target.getNetworkId (); + + typedef stdvector::fwd NetworkIdVector; + static NetworkIdVector ids; + ids.clear (); + + if (buildingObject.getObjVars ().getItem (objvarname_baseObjects, ids)) + { + for (NetworkIdVector::const_iterator it = ids.begin (); it != ids.end (); ++it) + { + const NetworkId & id = *it; + if (id == targetId) + return true; + } + } + + return false; + } + + bool isOnVendorList(const CreatureObject& object, const ServerObject& target) + { + static const std::string objvarname_vendorList = "player_structure.vendor.vendorList"; + + const Unicode::String & requestorFirstName = object.getAssignedObjectFirstName (); + typedef stdvector::fwd StringVector; + static StringVector sv; + sv.clear (); + + if (target.getObjVars ().getItem (objvarname_vendorList, sv)) + { + for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) + { + const Unicode::String & vendorFirstName = *it; + if (Unicode::caseInsensitiveCompare (vendorFirstName, requestorFirstName)) + { + return true; + } + } + } + return false; + } + + //---------------------------------------------------------------------- + + namespace SlotNames + { + static const ConstCharCrcLowerString datapad ("datapad"); + static const ConstCharCrcLowerString inventory ("inventory"); + static const ConstCharCrcLowerString bank ("bank"); + static const ConstCharCrcLowerString hair ("hair"); + static const ConstCharCrcLowerString ghost ("ghost"); + static const ConstCharCrcLowerString appearance ("appearance_inventory"); + static const ConstCharCrcLowerString hangar ("hangar"); + } + + uint64 s_containmentStatesMask = 0; + std::map s_containerSlotStates; + + namespace GroupHelpers + { + bool creatureIsContainedInPOBShip(CreatureObject const * creatureObject); + void findAllTargetsForGroup(CreatureObject * const targetObj, std::vector & targets); + bool roomInGroup(GroupObject const * groupObj, int additionalMembers); + GroupMemberParam const buildGroupMemberParam(CreatureObject const * creatureObject); + void buildGroupMemberParamsFromCreatures(std::vector const & targets, GroupObject::GroupMemberParamVector & targetMemberParams); + } + + // ---------------------------------------------------------------------- + + void skipField(std::string const &source, unsigned int &pos) + { + while (source[pos] && source[pos] != '~') + ++pos; + if (source[pos] == '~') + ++pos; + } + + // ---------------------------------------------------------------------- + + void nextString(std::string const &source, unsigned int &pos, std::string &ret) + { + unsigned int oldPos = pos; + while (source[pos] && source[pos] != '~') + ++pos; + ret = source.substr(oldPos, pos-oldPos); + if (source[pos] == '~') + ++pos; + } + + // ---------------------------------------------------------------------- + + void nextOid(std::string const &source, unsigned int &pos, NetworkId &ret) + { + unsigned int oldPos = pos; + skipField(source, pos); + ret = NetworkId(source.substr(oldPos, pos-oldPos)); + } + + // ---------------------------------------------------------------------- + + void nextFloat(std::string const &source, unsigned int &pos, float &ret) + { + ret = static_cast(atof(source.c_str()+pos)); + skipField(source, pos); + } + + // for enforcing height restriction when restoring decoration layout + std::map, std::pair > s_mapCellHeightRestriction; + + void restoreItemDecorationLayout(CreatureObject & decorator, PlayerObject & decoratorPlayerObject, CachedNetworkId const & item, TangibleObject const & pob, CachedNetworkId const & cell, Vector const & position, Quaternion const & orientation); +} + +//======================================================================= + +using namespace CreatureObjectNamespace; + +//======================================================================= + +void CreatureObject::PostureChangeCallback::modified(CreatureObject &target, Postures::Enumerator oldValue, Postures::Enumerator value, bool) const +{ + UNREF(oldValue); + // Make creatures not collidable when they're in dead or incapacitated posture + CollisionProperty * collision = target.getCollisionProperty(); + if (collision) + { + bool collidable = (value != Postures::Dead && value != Postures::Incapacitated); + collision->setCollidable(collidable); + } + + //-- Retrieve the collection of avialable locomotions for fast/slow/stationary movement speeds. + // This info is used on authoritative and proxy objects to make calcLocomotions(), called every alter, + // considerably more efficient. + target.getAvailableLocomotions(); + if (value == Postures::Dead) + Pvp::handleCreatureDied(target); +} + +//======================================================================= + +void CreatureObject::LocomotionChangeCallback::modified(CreatureObject &target, Locomotions::Enumerator oldValue, Locomotions::Enumerator value, bool) const +{ + ScriptParams params; + params.addParam(value); + params.addParam(oldValue); + + if (target.isAuthoritative()) + { + GameScriptObject * const script = target.getScriptObject(); + + if (script != 0) + { + script->trigAllScripts(Scripting::TRIG_LOCOMOTION_CHANGED, params); + } + } +} + +// ====================================================================== + +void CreatureObject::StateChangeCallback::modified(CreatureObject &target, uint64 oldValue, uint64 newValue, bool isLocal) const +{ + UNREF(newValue); + UNREF(isLocal); + UNREF(oldValue); + //-- Retrieve the collection of avialable locomotions for fast/slow/stationary movement speeds. + // This info is used on authoritative and proxy objects to make calcLocomotions(), called every alter, + // considerably more efficient. + target.getAvailableLocomotions(); +} + +// ====================================================================== + +CreatureAttitude::CreatureAttitude() : + m_behavior(Behaviors::Invalid), + m_angerState(kAngerCalm), + m_fearState(kFearCalm) +{ + for (int i = 0; i (getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_walk)), + m_baseRunSpeed (-1.0f), + m_runSpeed (safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_run)), + m_accelScale (1.0f), + m_accelPercent (1.0f), + m_turnScale (1.0f), + m_slopeModAngle (safe_cast(getSharedTemplate())->getSlopeModAngle() * PI / 180), + m_baseSlopeModPercent (safe_cast(getSharedTemplate())->getSlopeModPercent()), + m_slopeModPercent (1.0f), + m_waterModPercent (safe_cast(getSharedTemplate())->getWaterModPercent()), + m_lookAtTarget (), + m_intendedTarget (), + m_cover (0), + m_coverVisibility (true), + m_currentWeapon (), + m_modMap (), + m_skills (), + m_deferComputeTotalAttributes (0), + m_group (), + m_groupInviter (), + m_inviterForPendingGroup (), + m_performanceType (), + m_performanceStartTime (), + m_animatingSkillData (), + m_level (-1), + m_previousLevel (-1), + m_totalLevelXp (0), + m_levelHealthGranted (0), + m_invulnerabilityTimer (), + m_alternateAppearanceSharedObjectTemplateName (), + m_clientMfdStatusUpdateMessage(0), + m_timedMod (), + m_timedModDuration (), + m_timedModUpdateTime (), + m_addedToSpawnQueue (false), + m_numberOfMissionsWantedInMissionBag(0), + m_fastLocomotion (Locomotions::Invalid), + m_slowLocomotion (Locomotions::Invalid), + m_stationaryLocomotion (Locomotions::Invalid), + m_vehiclePhysicsData (0), + m_missionCriticalObjectSet(), + m_groupMissionCriticalObjectSet(), + m_triggerVolumeEntered(), + m_pseudoPlayedTime(0.0f), + m_buffs(), + m_persistedBuffs(), + m_clientUsesAnimationLocomotion(false), + m_difficulty(static_cast(D_normal)), + m_hologramType(-1), + m_visibleOnMapAndRadar(true), + m_lookAtYaw(0.0f), + m_useLookAtYaw(false), + m_fixedupPersistentBuffsAfterLoading(false), + m_fixedupLevelXpAfterLoading(false), + m_lavaResistance(0.0f), + m_lastWaterDamageTime(0), + m_isBeast(false), + m_forceShowHam(false), + m_regionFlagTimer(ConfigServerGame::getRegionFlagUpdateTimeSecs()), + m_wearableAppearanceData(), + m_decoyOrigin(NetworkId::cms_invalid) +{ + addProperty(*(new CommandQueue(*this))); + + // get the shared object template + const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); + NOT_NULL(sharedTemplate); + + // Handle scale. + // setScaleFactor(safe_cast(getSharedTemplate())->getScale()); + // Cannot set scale with setScaleFactor() since this object isn't authoratative yet. Expect many + // bugs from the lack of authority setting within a constructor. + const float scale = std::max (0.0f, sharedTemplate->getScale()); + m_scaleFactor = scale; + setScale (Vector::xyz111 * scale); + + // get the attribute values + { + for (int i = 0; i < Attributes::NumberOfAttributes; ++i) + { + m_attributes.set(i, static_cast( + newTemplate->getAttributes(static_cast< + ServerCreatureObjectTemplate::Attributes>(i)))); + m_maxAttributes.set(i, m_attributes.get(i)); + m_cachedCurrentAttributeModValues.set(i, 0); + m_cachedMaxAttributeModValues.set(i, 0); + m_regeneration[i] = 0; + } + // store the default regen values in the former faucet attrib slots + m_attributes.set(Attributes::Constitution, static_cast(ConfigServerGame::getDefaultHealthRegen())); + m_attributes.set(Attributes::Stamina, static_cast(ConfigServerGame::getDefaultActionRegen())); + m_attributes.set(Attributes::Willpower, static_cast(ConfigServerGame::getDefaultMindRegen())); + } + + // fix the size of the mental state vectors + m_maxMentalStates.resize(MentalStates::NumberOfMentalStates, 0); + m_mentalStateDecays.resize(MentalStates::NumberOfMentalStates, 0); + + CreatureAttitude initialState; + + // get the mental state values + { + for (int i = 0; i < MentalStates::NumberOfMentalStates; ++i) + { + const ServerCreatureObjectTemplate::MentalStates state = static_cast(i); + + m_maxMentalStates.set(i, static_cast(newTemplate->getMaxMentalStates(state))); + initialState.m_currentValues[i] = 0; + m_mentalStateDecays.set(i, float(newTemplate->getMentalStatesDecay(state))); + } + } + + m_currentAttitude.set(initialState); + m_lastBehavior.set(-1); + + m_fearCutoffs[CreatureAttitude::kFearCalm] = 0; + m_fearCutoffs[CreatureAttitude::kFearAlert] = 25; + m_fearCutoffs[CreatureAttitude::kFearThreaten] = 50; + m_fearCutoffs[CreatureAttitude::kFearFlee] = 75; + m_fearCutoffs[CreatureAttitude::kFearPanic] = 100; + + m_angerCutoffs[CreatureAttitude::kAngerCalm] = 0; + m_angerCutoffs[CreatureAttitude::kAngerAttack] = 60; + m_angerCutoffs[CreatureAttitude::kAngerFrenzy] = 100; + + CollisionProperty * pCollision = getCollisionProperty(); + + if(pCollision) + { + pCollision->setServerSide(true); + } + + addMembersToPackages(); + + m_guildId.setSourceObject(this); + m_guildWarEnabled.setSourceObject(this); + m_militiaOfCityId.setSourceObject(this); + m_locatedInCityId.setSourceObject(this); + m_group.setSourceObject(this); + m_posture.setSourceObject(this); + m_locomotion.setSourceObject(this); + m_invulnerabilityTimer.setSourceObject(this); + + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + CustomizationData *const cd = fetchCustomizationData(); + if (cd) + { + VehicleHoverDynamics::setInitialParams (*cd, + safe_cast (getSharedTemplate ())->getSpeedMin (SharedCreatureObjectTemplate::MT_walk), + safe_cast (getSharedTemplate ())->getSpeed (SharedCreatureObjectTemplate::MT_run), + safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_walk), + safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_run), + safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_walk), + safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_run)); + + cd->release (); + } + } + + m_lavaResistance = WaterTypeManager::getLavaResistance(getObjectTemplateName()); + + IGNORE_RETURN(g_creatureList.insert(this)); + + ObjectTracker::addCreature(); +} + +//----------------------------------------------------------------------- + +CreatureObject::~CreatureObject() +{ + //-- This must be the first line in the destructor to invalidate any watchers watching this object + nullWatchers(); + + if (m_vehiclePhysicsData) + { + delete m_vehiclePhysicsData; + m_vehiclePhysicsData = 0; + } + + if (isAuthoritative()) + { + GroupObject *group = getGroup(); + if (group) + { + group->removeGroupMember(getNetworkId()); + } + else + { + // If we are a pet... + if ( getMasterId() != NetworkId::cms_invalid ) + { + // We need to clean up outstanding group invitations since + // there are race conditions with ServerUniverse group + // objects and us getting added to them + + // Check for an outstanding group formation + const NetworkId groupInviterNetworkId = getInviterForPendingGroup(); + if ( groupInviterNetworkId != NetworkId::cms_invalid ) + { + // Send a message to the group inviter to tell them to remove + // us from the group... + + // We need to tell the network ID of the pet and we need to keep + // of how many times this message has been sent to the inviter + char msgBuffer[100]; + sprintf( msgBuffer, "%s 1", getNetworkId().getValueString().c_str() ); + + // Send the message with a delay + if ( MessageToQueue::isInstalled() ) + { + MessageToQueue::getInstance().sendMessageToC( groupInviterNetworkId, + "C++RemovePetFromGroup", + msgBuffer, + TIME_BETWEEN_ATTEMPTS_TO_REMOVE_PET, + false ); // reliable + } + } + } + } + + if (getGuildId()) + GuildInterface::onAboutToClearGuildId(*this); + } + + if (isPlayerControlled()) + removeFromSpawnQueue(); + + removeCreatureFromMissionRequestQueue(this); + if (isInWorld()) + removeFromWorld(); + + Controller *controller = getController(); + if (controller) + { + CreatureController *creatureController = safe_cast(controller); + ServerSecureTrade *trade = creatureController->getSecureTrade(); + if (trade) + trade->cancelTrade(*this); + } +// AICreatureController * aiController = AICreatureController::asAiCreatureController(controller); +// if (aiController != NULL) +// { +// aiController->stop(); +// } + + IGNORE_RETURN(g_creatureList.erase(this)); + + delete m_clientMfdStatusUpdateMessage; + + // We should have have been removed from all TriggerVolumes by + // now, but if we haven't, we need to tell any TriggerVolumes + // that we haven't been removed from to remove us from their + // contents list, or else those TriggerVolumes will have a + // pointer to a non-existent object + for (std::set::const_iterator i = m_triggerVolumeEntered.begin(); i != m_triggerVolumeEntered.end(); ++i) + { + WARNING(true, ("CreatureObject (%s) being destroyed but hasn't been removed from TriggerVolume (%s) owned by (%s)", + getDebugInformation().c_str(), + (*i)->getName().c_str(), + (*i)->getOwner().getDebugInformation().c_str())); + + (*i)->objectDestroyed(*this); + } + + ObjectTracker::removeCreature(); +} + + +//----------------------------------------------------------------------- + +CreatureObject * CreatureObject::asCreatureObject() +{ + return this; +} + +//----------------------------------------------------------------------- + +CreatureObject const * CreatureObject::asCreatureObject() const +{ + return this; +} + +//----------------------------------------------------------------------- + +void CreatureObject::install() +{ + loadDanceVisualTable(); + loadInstrumentTable(); + loadCommandSeriesTable(); + + installForMounts(); + + s_defaultWeaponSlotId = SlotIdManager::findSlotId(ConstCharCrcLowerString("default_weapon")); + FATAL(s_defaultWeaponSlotId == SlotId::invalid, ("failed to find SlotId for default_weapon: the slot definition file was improperly loaded or modified.")); + + s_inventorySlotId = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); + FATAL(s_inventorySlotId == SlotId::invalid, ("failed to find SlotId for inventory: the slot definition file was improperly loaded or modified.")); + + s_appearanceSlotId = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); + FATAL(s_appearanceSlotId == SlotId::invalid, ("Failed to find SlotId for appearance: the slot definition file was improperly loaded or modified.")); + + s_containerSlotStates[ShipSlotIdManager::getShipPilotSlotId()] = States::getStateMask(States::PilotingShip); + s_containerSlotStates[ShipSlotIdManager::getPobShipPilotSlotId()] = States::getStateMask(States::PilotingPobShip); + s_containerSlotStates[ShipSlotIdManager::getShipOperationsSlotId()] = States::getStateMask(States::ShipOperations); + s_containerSlotStates[ShipSlotIdManager::getPobShipOperationsSlotId()] = States::getStateMask(States::ShipOperations); + + { + // corresponds to slots in CreatureObject_Mounts.cpp + char slotName[256]; + s_containerSlotStates[SlotIdManager::findSlotId(ConstCharCrcLowerString("rider"))] = States::getStateMask(States::RidingMount); + for (int i = 1; i < 8; ++i) + { + snprintf(slotName, 255, "rider%d", i); + SlotId const slot = SlotIdManager::findSlotId(ConstCharCrcLowerString(slotName)); + s_containerSlotStates[slot] = States::getStateMask(States::RidingMount); + } + } + + for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex) + { + s_containerSlotStates[ShipSlotIdManager::getShipGunnerSlotId(weaponIndex)] = States::getStateMask(States::ShipGunner); + s_containerSlotStates[ShipSlotIdManager::getPobShipGunnerSlotId(weaponIndex)] = States::getStateMask(States::ShipGunner); + } + + s_containmentStatesMask = States::getStateMask(States::ShipInterior); + for (std::map::const_iterator i = s_containerSlotStates.begin(); i != s_containerSlotStates.end(); ++i) + s_containmentStatesMask |= (*i).second; + + // for enforcing height restriction when restoring decoration layout + { + char const * const cellHeightDataTableName = "datatables/structure/cell_height.iff"; + DataTable * table = DataTableManager::getTable(cellHeightDataTableName, true); + if (table) + { + int const columnStructure = table->findColumnNumber("template"); + int const columnCell = table->findColumnNumber("cell"); + int const columnMinHeight = table->findColumnNumber("min_height"); + int const columnMaxHeight = table->findColumnNumber("max_height"); + if ((columnStructure >= 0) && (columnCell >= 0) && (columnMinHeight >= 0) && (columnMaxHeight >= 0)) + { + std::string structure; + std::string cell; + + for (int i = 0, numRows = table->getNumRows(); i < numRows; ++i) + { + structure = table->getStringValue(columnStructure, i); + if (structure.empty()) + continue; + + cell = table->getStringValue(columnCell, i); + if (cell.empty()) + continue; + + s_mapCellHeightRestriction[std::make_pair(CrcLowerString::calculateCrc(structure.c_str()), CrcLowerString::calculateCrc(cell.c_str()))] = std::make_pair(table->getFloatValue(columnMinHeight, i), table->getFloatValue(columnMaxHeight, i)); + } + } + + DataTableManager::close(cellHeightDataTableName); + } + } + + ExitChain::add(CreatureObject::remove, "CreatureObject::remove"); +} + +//----------------------------------------------------------------------- + +void CreatureObject::remove() +{ +} + +//----------------------------------------------------------------------- + +/** + * Returns a shared template if none was given for this object. + * + * @return the shared template + */ +const SharedObjectTemplate * CreatureObject::getDefaultSharedTemplate() const +{ +static const ConstCharCrcLowerString templateName("object/creature/base/shared_creature_default.iff"); + + if (m_defaultSharedTemplate == NULL) + { + m_defaultSharedTemplate = safe_cast( + ObjectTemplateList::fetch(templateName)); +#ifdef DEBUG + WARNING(m_defaultSharedTemplate == NULL, ("Cannot create " + "default shared object template %s", templateName.getString())); +#endif + if (m_defaultSharedTemplate != NULL) + ExitChain::add (removeDefaultTemplate, "CreatureObject::removeDefaultTemplate"); + } + return m_defaultSharedTemplate; +} // CreatureObject::getDefaultSharedTemplate + +//----------------------------------------------------------------------- + +/** + * Cleans up the default shared template. + */ +void CreatureObject::removeDefaultTemplate() +{ + if (m_defaultSharedTemplate != NULL) + { + m_defaultSharedTemplate->releaseReference(); + m_defaultSharedTemplate = NULL; + } +} // CreatureObject::removeDefaultTemplate + +//----------------------------------------------------------------------- + +bool CreatureObject::isSpawningAllowed() const +{ + ServerObject const * container = safe_cast(ContainerInterface::getContainedByObject(*this)); + + return isAuthoritative() + && getScriptObject()->isScriptListInitialized() + && + ( + !container || container->asCreatureObject() + ) + && ( ConfigServerGame::getBoundarySpawningAllowed() + || getExposedProxyList().empty()) + && ( ConfigServerGame::getEnableSpawningNearLoadBeacons() + || !ServerWorld::isInLoadBeaconRange(getPosition_w())); +} + +//----------------------------------------------------------------------- + +void CreatureObject::addToSpawnQueue() +{ + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::addToSpawnQueue"); + + if (m_addedToSpawnQueue || !isSpawningAllowed()) + return; + + DEBUG_FATAL(std::find(s_spawnQueue.begin(), s_spawnQueue.end(), getNetworkId()) != s_spawnQueue.end(), ("spawn queue is inconsistant with m_addedToSpawnQueue flag")); + + s_spawnQueue.push_back(getNetworkId()); + + m_addedToSpawnQueue = true; +} + +//----------------------------------------------------------------------- + +void CreatureObject::removeFromSpawnQueue() +{ + if (m_addedToSpawnQueue) + { + std::deque::iterator f = std::find(s_spawnQueue.begin(), s_spawnQueue.end(), getNetworkId()); + if (f != s_spawnQueue.end()) + s_spawnQueue.erase(f); + m_addedToSpawnQueue = false; + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::runSpawnQueue() +{ + static int framesPerSpawn = ConfigServerGame::getFramesPerSpawn(); + static int64 lastSpawnFrame = 0; + static int64 currentSpawnFrame = 0; + + ++currentSpawnFrame; + + if (currentSpawnFrame - lastSpawnFrame >= framesPerSpawn) + { + int i = 1; + if (framesPerSpawn == 0) + i = ConfigServerGame::getSpawnQueueSize(); + + while (i > 0 && !s_spawnQueue.empty()) + { + NetworkId const id = s_spawnQueue.front(); + s_spawnQueue.pop_front(); + + // Only spawn if we can resolve the object, and it believes spawning + // should be allowed. If we can resolve the object but spawning is not + // allowed, do not re-add it to the queue and mark it as such. + + CreatureObject * const spawner = safe_cast(NetworkIdManager::getObjectById(id)); + + if (spawner) + { + if (spawner->isSpawningAllowed()) + { + ScriptParams params; + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(id, "spawn_Trigger", dictionary->getSerializedData(), 0, false); + } + s_spawnQueue.push_back(id); + } + else + spawner->m_addedToSpawnQueue = false; + } + --i; + } + lastSpawnFrame = currentSpawnFrame; + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::showSpawnQueue(Unicode::String & result) +{ + for (std::deque::iterator i = s_spawnQueue.begin(); i != s_spawnQueue.end(); ++i) + { + ServerObject const * const obj = safe_cast(NetworkIdManager::getObjectById((*i))); + if (obj) + { + result += Unicode::narrowToWide((*i).getValueString()); + result += Unicode::narrowToWide(" - "); + result += obj->getObjectName(); + result += Unicode::narrowToWide("\n"); + } + } +} + +//----------------------------------------------------------------------- +/** +*/ +bool CreatureObject::assignMission(MissionObject * missionObject) +{ + bool result = false; + if(missionObject) + { + ServerObject * datapad = getDatapad(); + if(datapad) + { + // if this mission is coming from our own mission bag, increment missions wanted + ServerObject * missionBag = getMissionBag(); + if(missionBag) + { + Container * container = ContainerInterface::getContainer(*missionBag); + ContainerIterator iter; + bool found = false; + int i = 0; + for(iter = container->begin(); iter != container->end(); ++iter) + { + MissionObject * mo = safe_cast((*iter).getObject()); + if(mo) + { + i++; + if(mo == missionObject) + { + found = true; + } + } + } + if(found) + { + setNumberOfMissionsWantedInMissionBag(i + 1); + } + } + + Container::ContainerErrorCode tmp = Container::CEC_Success; + result = ContainerInterface::transferItemToGeneralContainer(*datapad, *missionObject, NULL, tmp); + if(result) + { + missionObject->setMissionHolderId(getNetworkId()); + + } + } + } + return result; +} + +//----------------------------------------------------------------------- + +void CreatureObject::setMissionBoardUISequenceId(const uint8 sequenceId) +{ + m_missionListRequestSequenceId = sequenceId; +} + +//----------------------------------------------------------------------- + +std::vector CreatureObject::getMissions() +{ + std::vector result; + ServerObject * const datapad = getDatapad(); + if (datapad) + { + Container * const container = ContainerInterface::getContainer(*datapad); + if (container) + { + for (ContainerIterator iter = container->begin(); iter != container->end(); ++iter) + { + ServerObject * const serverMissionObject = safe_cast((*iter).getObject()); + if (serverMissionObject) + { + MissionObject * const missionObject = serverMissionObject->asMissionObject(); + if (missionObject) + result.push_back(*iter); + } + } + } + } + return result; +} + +//----------------------------------------------------------------------- + +bool CreatureObject::canManipulateObject(ServerObject const &target, bool movingObject, bool doPermissionCheckOnItem, bool doPermissionCheckOnParents, float maxRange, Container::ContainerErrorCode& code, bool skipNoTradeCheck, bool * allowedByGodMode) const +{ + if (allowedByGodMode) + *allowedByGodMode = false; + + if (getClient() && !ObserveTracker::isObserving(*getClient(), target) && (target.getCacheVersion() == 0)) + { + code = Container::CEC_Unknown; + return false; + } + + code = Container::CEC_Success; + ServerObjectTemplate const * const targetTemplate = safe_cast(target.getObjectTemplate()); + NOT_NULL(targetTemplate); + + bool canMoveInWorld = false; + bool godCanMove = false; + + ServerObject const * const serverTarget = safe_cast(&target); + if (!serverTarget || (movingObject && serverTarget->getCacheVersion() > 0)) + { + code = Container::CEC_Unmovable; + return false; + } + + if (serverTarget->isInBazaarOrVendor() && !(serverTarget->isVendor() || serverTarget->isBazaarTerminal())) + { + code = Container::CEC_Unknown; + return false; + } + + ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*serverTarget)); + + //-- don't transfer from/to factory crates + if (containedBy && containedBy->getGameObjectType () == SharedObjectTemplate::GOT_misc_factory_crate) + { + code = Container::CEC_Unknown; + return false; + } + + { + for (size_t i = 0; i < targetTemplate->getMoveFlagsCount(); ++i) + { + if (targetTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_player) + { + canMoveInWorld = true; + godCanMove = true; + } + else if (targetTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_gm) + godCanMove = true; + } + } + + //Gods don't have distance checks or anything, so we can exit early if they are a god at this point. + if ((canMoveInWorld || godCanMove) && getClient() && getClient()->isGod()) + { + if (allowedByGodMode) + *allowedByGodMode = true; + + return true; + } + + //---------------------------------------------------------------------- + + // see if the object is flagged as being owner-only manipulatable + if (!skipNoTradeCheck) + { + if (target.markedNoTrade()) + { + // the item must be owned by this creature + + NetworkId ownerId; + if (target.asIntangibleObject()) + ownerId = containedBy ? containedBy->getOwnerId() : NetworkId::cms_invalid; + else + ownerId = target.getOwnerId(); + + if (ownerId != getNetworkId()) + { + code = Container::CEC_NoPermission; + return false; + } + } + } + + //---------------------------------------------------------------------- + + // exclude these object types from being moved by players + const int got = serverTarget->getGameObjectType (); + + CreatureObject const * const creatureTarget = serverTarget->asCreatureObject(); + if (movingObject) + { + // If the object isn't contained they may be trying to move the object + // check the flags on the template to see if it can be picked up. + if (!canMoveInWorld && target.isInWorld ()) + { +// DEBUG_REPORT_LOG(true, ("canManipulate failed - This object is in the world and is flagged as immobile\n")); + code = Container::CEC_NoPermission; + return false; + } + + // can't move creatures we don't own + if (creatureTarget && creatureTarget->getOwnerId() != getNetworkId()) + { + code = Container::CEC_NoPermission; + return false; + } + + if (GameObjectTypes::isTypeOf (got, SharedObjectTemplate::GOT_building) || + GameObjectTypes::isTypeOf (got, SharedObjectTemplate::GOT_installation) || + got == SharedObjectTemplate::GOT_lair || + got == SharedObjectTemplate::GOT_camp || + got == SharedObjectTemplate::GOT_vehicle || + got == SharedObjectTemplate::GOT_corpse || + serverTarget->asCellObject() || + got == SharedObjectTemplate::GOT_data_mission_object) + { + code = Container::CEC_UnmovableType; + return false; + } + + //-- can't move items in the world cell unless we are explicitly owning them + if (serverTarget->isInWorldCell () && serverTarget->getOwnerId () != getNetworkId ()) + { + code = Container::CEC_NoPermission; + return false; + } + } + + //---------------------------------------------------------------------- + + ServerObject const * const firstParentInWorld = safe_cast(ContainerInterface::getFirstParentInWorld(target)); + if (firstParentInWorld && firstParentInWorld != ContainerInterface::getFirstParentInWorld(*this) && firstParentInWorld->asTangibleObject()) + { + + if (maxRange > 0.0f) + { + float distance = findPosition_w().magnitudeBetween(firstParentInWorld->findPosition_w()); + distance -= getRadius(); + distance -= firstParentInWorld->getRadius(); + // Check range on the server with a 1m fudge factor in it. + if (distance > maxRange + 1.0f) + { + code = Container::CEC_OutOfRange; + return false; + } + } + + // skip LOS check if the item is being restored as part of decoration layout restore + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (!playerObject || (playerObject->getRestoreDecorationObjectBeingRestored() != target.getNetworkId())) + { + if (!checkLOSTo(*firstParentInWorld)) + { + code = Container::CEC_CantSee; +// DEBUG_REPORT_LOG(true, ("LOS check failed in can manipulate\n")); + return false; + } + } + } + + //---------------------------------------------------------------------- + + bool manipulateOk = true; + + if (target.asTangibleObject() && target.asTangibleObject()->isLocked()) + { + TangibleObject const * tangibleTarget = target.asTangibleObject(); + + bool allow = false; + + if(tangibleTarget->isUserOnAccessList(getNetworkId()) || tangibleTarget->isGuildOnAccessList(getGuildId())) + { + // Still have to obey house rules. + ServerObject const * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*serverTarget)); + if (movingObject && topmost) + { + //Handle the case where we are in a designer placed building and a designer placed container (loot chest) + if ( topmost->getOwnerId() == NetworkId::cms_invalid + && ( firstParentInWorld->getOwnerId() == NetworkId::cms_invalid + || firstParentInWorld->getOwnerId() == getNetworkId()) + && serverTarget != firstParentInWorld) + { + allow = true; + } + //Handle the case where we are in a player building or pob ship + else if (topmost->getOwnerId() == getNetworkId() || isBuildingAdminForTarget (*this, *topmost)) + { + const bool isContainerPortallized = topmost->getPortalProperty() != 0; + + allow = (!isContainerPortallized || !movingObject || !isTargetBuildingBaseObject (*topmost, *serverTarget)); + } + else + allow = false; + } + else + allow = true; + } + else + { + // Our target is locked, but allow admins on a building to be able to manipulate the object. + + + ServerObject const * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*serverTarget)); + if (topmost) + { + //Handle the case where we are in a designer placed building and a designer placed container (loot chest) + if ( topmost->getOwnerId() == NetworkId::cms_invalid + && ( firstParentInWorld->getOwnerId() == NetworkId::cms_invalid + || firstParentInWorld->getOwnerId() == getNetworkId()) + && serverTarget != firstParentInWorld) + { + allow = true; + } + //Handle the case where we are in a player building or pob ship + else if (topmost->getOwnerId() == getNetworkId()) + { + const bool isContainerPortallized = topmost->getPortalProperty() != 0; + + allow = (!isContainerPortallized || !movingObject || !isTargetBuildingBaseObject (*topmost, *serverTarget)); + } + else + allow = false; + } + + } + + if(!allow) + code = Container::CEC_NoPermission; + + return allow; + } + + //---------------------------------------------------------------------- + //-- see if we need to check permissions of the object itself + + if (doPermissionCheckOnItem) + { + //Do not allow players to manipulate other players or things contained by other players + if (serverTarget->isPlayerControlled() && serverTarget != this) + { + code = Container::CEC_NoPermission; + return false; + } + + if (serverTarget->getOwnerId () == getNetworkId()) + { + manipulateOk = true; + } + + //-- an invalid owner means we can manipulate the item in general, + //-- e.g. opening a container, but not move it + else if (movingObject || serverTarget->getOwnerId ().isValid ()) + { + manipulateOk = false; + } + } + + //---------------------------------------------------------------------- + //-- see if the permission check on parents needs to be carried out. + +//ParentCheck on item +//if item is a vendor, get topmost and check vendor list +//else +// get first parent in world +// if is an installation check hopper list +// else if it is a creature, check the immediate parent for ownership only (covers corpses, inventory, etc) +// else check ownership of topmost, with 0 being allowed. +// if topmost happens to be a player building, check its admin list and make sure the object being moved isn't part of the house +// else if topmost happens to be an unowned building, then any sub containers can be looted + + if (doPermissionCheckOnParents) + { + + // Check our access list. + if(containedBy && containedBy->asTangibleObject() && containedBy->asTangibleObject()->isLocked()) + { + TangibleObject const * tangibleParent = containedBy->asTangibleObject(); + + if(tangibleParent->isUserOnAccessList(getNetworkId()) || tangibleParent->isGuildOnAccessList(getGuildId())) + { + manipulateOk = true; + } + else + { + manipulateOk = false; + code = Container::CEC_NoPermission; + } + + } + else if (!manipulateOk || movingObject) + { + //-- can't move items contained by a manufacturing schematic + { + if (containedBy && containedBy->getGameObjectType () == SharedObjectTemplate::GOT_data_manufacturing_schematic) + { + code = Container::CEC_NoPermission; + return false; + } + } + + if (firstParentInWorld) + { + const int containerGot = firstParentInWorld->getGameObjectType (); + if (GameObjectTypes::isTypeOf (containerGot, SharedObjectTemplate::GOT_installation)) + { + //-- test admin status on installation + manipulateOk = canHopperForTarget (*this, *firstParentInWorld); + } + else if (firstParentInWorld->asCreatureObject()) + { + // check for ownership + manipulateOk = (containedBy && (containedBy->getOwnerId() == getNetworkId() || containedBy->getOwnerId() == NetworkId::cms_invalid)); + } + else + { + ServerObject const * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*serverTarget)); + if (topmost) + { + //Handle the case where we are in a designer placed building and a designer placed container (loot chest) + if ( topmost->getOwnerId() == NetworkId::cms_invalid + && ( firstParentInWorld->getOwnerId() == NetworkId::cms_invalid + || firstParentInWorld->getOwnerId() == getNetworkId()) + && serverTarget != firstParentInWorld) + { + manipulateOk = true; + } + //Handle the case where we are in a player building or pob ship + else if (topmost->getOwnerId() == getNetworkId() || isBuildingAdminForTarget (*this, *topmost)) + { + const bool isContainerPortallized = topmost->getPortalProperty() != 0; + + manipulateOk = (!isContainerPortallized || !movingObject || !isTargetBuildingBaseObject (*topmost, *serverTarget)); + } + else + manipulateOk = false; + } + else + manipulateOk = false; + } + } + else + manipulateOk = false; + } + } + + + //---------------------------------------------------------------------- + + if (!manipulateOk && code == Container::CEC_Success) + code = Container::CEC_NoPermission; + + return manipulateOk; +} + +//----------------------------------------------------------------------- +/** + * Do any processing needed during endBaselines() to handle this object if + * it is contained by another object. + * + * @return true if object should have addToWorld() called on it; false otherwise. + */ + +bool CreatureObject::handleContentsSetup() +{ + bool ret = TangibleObject::handleContentsSetup(); + setStatesDueToContainment(); + return ret; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setStatesDueToContainment() +{ + uint64 oldStates = m_states.get(); + uint64 states = oldStates&(~s_containmentStatesMask); + + ServerObject const *containingObject = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (containingObject) + { + SlottedContainer const *slottedContainer = containingObject->getSlottedContainerProperty(); + if (slottedContainer) + { + SlottedContainmentProperty const *slottedContainmentProperty = ContainerInterface::getSlottedContainmentProperty(*this); + if (slottedContainmentProperty) + { + int currentArrangement = slottedContainmentProperty->getCurrentArrangement(); + if (currentArrangement != -1) + { + SlottedContainmentProperty::SlotArrangement const &slotArrangement = slottedContainmentProperty->getSlotArrangement(currentArrangement); + for (SlottedContainmentProperty::SlotArrangement::const_iterator i = slotArrangement.begin(); i != slotArrangement.end(); ++i) + states |= s_containerSlotStates[*i]; + } + } + } + else if (containingObject->asCellObject()) + { + // special case - state set when in the interior of a pob ship + ServerObject const * const portallizedObject = safe_cast(ContainerInterface::getContainedByObject(*containingObject)); + if (portallizedObject && portallizedObject->asShipObject()) + states |= States::getStateMask(States::ShipInterior); + } + } + + if (states != oldStates) + m_states = states; +} + +//----------------------------------------------------------------------- + +void CreatureObject::forwardServerObjectSpecificBaselines() const +{ + TangibleObject::forwardServerObjectSpecificBaselines(); + + Property const * const property = getProperty(SlowDownProperty::getClassPropertyId()); + if (property != NULL) + { + SlowDownProperty const * const slowdownProperty = safe_cast(property); + + SlowDownEffectMessage const message(getNetworkId(), slowdownProperty->getTarget(), slowdownProperty->getConeLength(), slowdownProperty->getConeAngle(), slowdownProperty->getSlopeAngle(), slowdownProperty->getExpireTime()); + ServerMessageForwarding::send(message); + } + + // if we are an ai creature, have our controller send our current ai state + AICreatureController const * const aiCreatureController = AICreatureController::asAiCreatureController(getController()); + + if (aiCreatureController != NULL) + { + aiCreatureController->forwardServerObjectSpecificBaselines(); +} +} + +//----------------------------------------------------------------------- + +void CreatureObject::sendObjectSpecificBaselinesToClient(Client const &client) const +{ + TangibleObject::sendObjectSpecificBaselinesToClient(client); + + Property const * const property = getProperty(SlowDownProperty::getClassPropertyId()); + if (property != NULL) + { + SlowDownProperty const * const slowdownProperty = safe_cast(property); + + SlowDownEffectMessage const message(getNetworkId(), slowdownProperty->getTarget(), slowdownProperty->getConeLength(), slowdownProperty->getConeAngle(), slowdownProperty->getSlopeAngle(), slowdownProperty->getExpireTime()); + client.send(message, true); + } + + UpdatePostureMessage const updatePostureMessage(getNetworkId(), getPosture()); + client.send(updatePostureMessage, true); +} + +//----------------------------------------------------------------------- + +/** + * Initializes a newly created object. + */ +void CreatureObject::initializeFirstTimeObject() +{ + TangibleObject::initializeFirstTimeObject(); + + //-- Get ourselves into a reasonable locomotion state. + updateMovementInfo(); + + // create the default weapon + initializeDefaultWeapon(); + + // set the current weapon + WeaponObject * weapon = getReadiedWeapon(); + if (weapon != NULL) + setCurrentWeapon(*weapon); + + //Quick error check since all creatures should have a default weapon + WARNING_STRICT_FATAL(!getDefaultWeapon(), ("Creature %s (%s) has no default " + "weapon", getNetworkId().getValueString().c_str(), getTemplateName())); + + const ServerCreatureObjectTemplate * myTemplate = safe_cast(getObjectTemplate()); + Unicode::String newName = NameManager::getInstance().generateRandomName(ConfigServerGame::getCharacterNameGeneratorDirectory(), myTemplate->getNameGeneratorType()); + if (!newName.empty()) + { + setObjectName(newName); + } + + setOwnerId(getNetworkId()); + recomputeSlopeModPercent(); + + setupSkillData(); + packWearables(); + + ServerObject *bankContainer = getBankContainer(); + if (bankContainer) + bankContainer->setLoadContents(false); + + // note: this MUST come after TangibleObject::initializeFirstTimeObject() is called + float defaultAlterTime = 0; + if (!isPlayerControlled()) + defaultAlterTime = AlterResult::cms_alterQuickly; +// DEBUG_REPORT_LOG(true, ("[aitest] setting creature %s default alter time to %f\n", getNetworkId().getValueString().c_str(), defaultAlterTime)); + setDefaultAlterTime(defaultAlterTime); +} // CreatureObject::initializeFirstTimeObject + +//----------------------------------------------------------------------- + +void CreatureObject::onLoadedFromDatabase() +{ + if (isAuthoritative()) + { + if (isPlayerControlled()) + { + onClientAboutToLoad(); + + // Initialize A-Tab info if we need to. + SlottedContainer * const container = ContainerInterface::getSlottedContainer(*this); + if(container) + { + SlotId slot; + Container::ContainerErrorCode tmp; + slot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); + if(slot != SlotId::invalid) + { + Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); + Object* appearanceInventory = itemId.getObject(); + if(appearanceInventory == NULL) + { + WARNING(true, ("Player %s has lost their appearance inventory", getNetworkId().getValueString().c_str())); + appearanceInventory = ServerWorld::createNewObject(s_appearanceTemplate, *this, slot, false); + if(!appearanceInventory) + { + DEBUG_FATAL(true, ("Could not create an appearance inventory for the player who lost theirs")); + } + } + } + } + + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + // move old badges over to the collection system + if (getObjVars().hasItem(OBJVAR_BADGES) && (getObjVars().getType(OBJVAR_BADGES) == DynamicVariable::INT_ARRAY)) + { + std::vector badges; + getObjVars().getItem(OBJVAR_BADGES, badges); + + if (!badges.empty()) + playerObject->migrateLegacyBadgesToCollection(badges); + + removeObjVarItem(OBJVAR_BADGES); + removeObjVarItem(OBJVAR_COUNT_BADGES); + } + + // check for Jedi initialization + if (getObjVars().hasItem(OBJVAR_NEW_JEDI_FORCE)) + { + int start_force; + getObjVars().getItem(OBJVAR_NEW_JEDI_FORCE, start_force); + removeObjVarItem(OBJVAR_NEW_JEDI_FORCE); + if (start_force > 0) + { + playerObject->setMaxForcePower(start_force); + playerObject->setForcePowerRegenRate(ConfigServerGame::getMinForcePowerRegenRate()); + } + else + { + WARNING(true, ("Player %s had the %s objvar, but it had a " + "value of %d", getNetworkId().getValueString().c_str(), + OBJVAR_NEW_JEDI_FORCE.c_str(), start_force)); + } + } + + // check the non-pool attributes: their value should be the + // same as their max value, since we don't regenerate/heal them + for (int i = 0; i < Attributes::NumberOfAttributes; ++i) + { + if (Attributes::isAttribPool(i)) + continue; + + Attributes::Value attrib = getUnmodifiedAttribute(i); + Attributes::Value max = getUnmodifiedMaxAttribute(i); + if (attrib != max) + setAttribute(i, max); + } + + // initialize the character born date, if necessary + playerObject->setBornDate(); + + // retroactively set CTS history and CTS title(s), if necessary, + // and fix up the character's born date, if necessary, if it was + // incorrectly changed from a prior CTS where the character's born + // date was not transferred; + // + // should be done *AFTER* the above statement to initialize the + // character born date, if necessary + GameServer::setRetroactiveCtsHistory(*this); + + // set the "born on " title if this galaxy supports + // it and it hasn't already been set on this character + if (!getObjVars().hasItem("bornOnGalaxyTitleSet")) + { + // lower case cluster name and replace - with _ for use with the collection slot name + std::string collectionSlotName = std::string("born_on_") + Unicode::toLower(GameServer::getInstance().getClusterName()); + + std::string::size_type pos = collectionSlotName.find('-'); + while (pos != std::string::npos) + { + collectionSlotName.replace(pos, 1, 1, '_'); + pos = collectionSlotName.find('-'); + } + + CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(collectionSlotName); + if (collectionSlot) + { + FATAL((collectionSlot->collection.name != std::string("born_on_collection")), ("collection slot %s must be in collection born_on_collection", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.name != std::string("born_on_page")), ("collection slot %s must be in collection page born_on_page", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.book.name != std::string("born_on_book")), ("collection slot %s must be in collection book born_on_book", collectionSlot->name.c_str())); + + // see if character transferred from another galaxy, and + // if yes, then the original galaxy is the home galaxy + std::string originalSourceGalaxy; + int earliestTransferTime = -1; + + DynamicVariableList::NestedList const ctsTransactions(getObjVars(), "ctsHistory"); + for (DynamicVariableList::NestedList::const_iterator i = ctsTransactions.begin(); i != ctsTransactions.end(); ++i) + { + Unicode::String ctsTransactionDetail; + if (i.getValue(ctsTransactionDetail)) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(ctsTransactionDetail, tokens, NULL, NULL) && (tokens.size() >= 4)) + { + int const transferTime = atoi(Unicode::wideToNarrow(tokens[0]).c_str()); + if ((earliestTransferTime == -1) || (transferTime < earliestTransferTime)) + { + earliestTransferTime = transferTime; + originalSourceGalaxy = Unicode::wideToNarrow(tokens[1]); + } + } + } + } + + // character transferred from another galaxy, so + // use the original galaxy as the home galaxy + if (!originalSourceGalaxy.empty()) + { + // lower case cluster name and replace - with _ for use with the collection slot name + collectionSlotName = std::string("born_on_") + Unicode::toLower(originalSourceGalaxy); + + std::string::size_type pos = collectionSlotName.find('-'); + while (pos != std::string::npos) + { + collectionSlotName.replace(pos, 1, 1, '_'); + pos = collectionSlotName.find('-'); + } + + collectionSlot = CollectionsDataTable::getSlotByName(collectionSlotName); + if (collectionSlot) + { + FATAL((collectionSlot->collection.name != std::string("born_on_collection")), ("collection slot %s must be in collection born_on_collection", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.name != std::string("born_on_page")), ("collection slot %s must be in collection page born_on_page", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.book.name != std::string("born_on_book")), ("collection slot %s must be in collection book born_on_book", collectionSlot->name.c_str())); + } + } + } + + // set "born on " collection slot and clear all the other "born on " collection slots; + // this still needs to be run even if collectionSlot is NULL in order to forcefully clear all of the + // other "born on " collection slots, since we are reusing deleted/no longer used collection + // slot bits, and those bits may be left in a set state at the time they were deleted/no longer used + std::vector const & slots = CollectionsDataTable::getSlotsInCollection("born_on_collection"); + + for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) + { + playerObject->modifyCollectionSlotValue((*iter)->name, ((*iter == collectionSlot) ? 1ll : -1ll)); + } + + IGNORE_RETURN(setObjVarItem("bornOnGalaxyTitleSet", 1)); + } + } + + // wait for all loading/initialization to complete, and then double + // check the character's title to make sure it is a valid title + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++CheckCharacterTitle", "", 30, false); + } + + // store the default regen values in the former faucet attrib slots + m_attributes.set(Attributes::Constitution, static_cast(ConfigServerGame::getDefaultHealthRegen())); + m_attributes.set(Attributes::Stamina, static_cast(ConfigServerGame::getDefaultActionRegen())); + m_attributes.set(Attributes::Willpower, static_cast(ConfigServerGame::getDefaultMindRegen())); + + if(!isPlayerControlled()) + fixupPersistentBuffsAfterLoading(); + else + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject && playerObject->isInitialized()) + { + fixupPersistentBuffsAfterLoading(); + fixupLevelXpAfterLoading(); + } + } + + // there are cetain states we don't want to be in on start-up + setState(States::Cover, false); + setState(States::Combat, false); + setState(States::Peace, false); + setState(States::Aiming, false); + setState(States::Meditate, false); + setState(States::Berserk, false); + setState(States::FeignDeath, false); + setState(States::Tumbling, false); + setState(States::Rallied, false); + setState(States::Stunned, false); + setState(States::Blinded, false); + setState(States::Dizzy, false); + setState(States::Intimidated, false); + setState(States::Immobilized, false); + setState(States::Crafting, false); + setState(States::MountedCreature, false); + setState(States::Disguised, false); + setStatesDueToContainment(); + + // override the speeds stored in the database + // @todo: make the speeds non-persisted + setBaseWalkSpeed((safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_walk))); + setBaseRunSpeed((safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_run))); + } + + // setupSkillData MUST be called before we add the bonuses for equipment! + setupSkillData(); + packWearables(); + + if (isAuthoritative() && isPlayerControlled()) + { + // make sure the player has no more expertise skills than they should have for their level + // if they do, log them as a suspected cheater + int const remainingExpertisePoints = getRemainingExpertisePoints(); + + if (remainingExpertisePoints < 0) + { + LOG("CustomerService", + ("SuspectedCheaterChannel: %s has more expertises than level %d allows. Amount over limit is %d.", + PlayerObject::getAccountDescription(this).c_str(), getLevel(), -remainingExpertisePoints) + ); + } + + // if we are a player, go through all the creature's equipment and update for + // bonus skill mods + std::vector > skillModBonuses; + std::vector > attribBonuses; + Container const * const equipment = ContainerInterface::getContainer(*this); + if (equipment != NULL) + { + for (ContainerConstIterator i(equipment->begin()); i != equipment->end(); ++i) + { + ServerObject const * const so = safe_cast((*i).getObject()); + if (so) + { + TangibleObject const * const equippedItem = so->asTangibleObject(); + if (equippedItem != NULL) + { + equippedItem->getSkillModBonuses(skillModBonuses); + int bonusCount = skillModBonuses.size(); + { + for (int j = 0; j < bonusCount; ++j) + { + std::pair const &bonus = skillModBonuses[j]; + addModBonus(bonus.first, bonus.second); + } + } + equippedItem->getAttribBonuses(attribBonuses); + bonusCount = attribBonuses.size(); + { + for (int j = 0; j < bonusCount; ++j) + { + std::pair const &bonus = attribBonuses[j]; + addAttribBonus(bonus.first, bonus.second); + } + } + } + } + } + } + } + + TangibleObject::onLoadedFromDatabase(); + + if (isAuthoritative()) + { + // note: this MUST come after TangibleObject::onLoadedFromDatabase() is called + float defaultAlterTime = 0; + if (!isPlayerControlled()) + defaultAlterTime = AlterResult::cms_alterQuickly; +// DEBUG_REPORT_LOG(true, ("[aitest] setting creature %s default alter time to %f\n", getNetworkId().getValueString().c_str(), defaultAlterTime)); + setDefaultAlterTime(defaultAlterTime); + + CreatureController * controller = getCreatureController(); + if (controller != NULL) + controller->updateHibernate(); + } +} + +//----------------------------------------------------------------------- + +/** + * Initializes a proxy object. + */ +void CreatureObject::endBaselines() +{ + // catch people in potentially deleted newbie halls + if (NewbieTutorial::getSceneId() == ServerWorld::getSceneId()) + getContainedByProperty()->setContainedBy(NetworkId::cms_invalid); + + TangibleObject::endBaselines(); + + if (isAuthoritative()) + { + // set our initial posture depending if we are incapacitated/dead or not + Postures::Enumerator posture = getPosture(); + if (isDead()) + posture = Postures::Dead; + if (getAttribute(Attributes::Health) <= 0) + { + // make sure we are incapacitated, unless we are dead + if (posture != Postures::Dead) + posture = Postures::Incapacitated; + } + + if (posture != getPosture()) + setPosture(posture); + + updateMovementInfo(); + + // Fix up guildId - set regardless of whether it is already correct, as this + // triggers entry into the guild chat room. + int guildId = GuildInterface::getGuildId(getNetworkId()); + + // fix up issue there a guild leader gets mistakenly removed + // from the guild (i.e. the guild leader's permission is reset + // to 0, meaning he is only a sponsored member, and the guild + // id won't be returned in GuildInterface::getGuildId()), causing + // the guild to be leaderless; we only need to get the guild id + // for the guild that this character is the leader of; setGuildId() + // will do the rest of the work + if (guildId == 0) + guildId = GuildInterface::getGuildIdForGuildLeader(getNetworkId()); + + setGuildId(guildId); + + // Fix up guildWarEnabled + setGuildWarEnabled(GuildInterface::getGuildMemberGuildWarEnabled(getGuildId(), getNetworkId())); + + // Fix up militiaOfCityId + setMilitiaOfCityId(CityInterface::getMilitiaOfCityId(getNetworkId())); + + // Mount: needs to grab its position from the rider since the rider dictates + // mount position. + if (getState(States::MountedCreature)) + { + CreatureObject const *const rider = getPrimaryMountingRider(); + if (rider) + { + // Use parent space since both the rider and mount should be + // attached to the same thing. Initially this is limited to + // the world. + setPosition_p(rider->getPosition_p()); + } + } + + // depersist persisted command cooldowns + CommandQueue * commandQueue = getCommandQueue(); + if (commandQueue) + { + commandQueue->depersistCooldown(); + } + + // make sure that factional player characters are at least rank 1 (rating 0) + // and non-factional player characters have no current GCW points or rating + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + if (player) + { + static int const min = std::numeric_limits::min(); + if (PvpData::isImperialFactionId(getPvpFaction()) || PvpData::isRebelFactionId(getPvpFaction())) + { + // decrementing the value by a really large + // number will cause it to reset to 0 + if (player->getCurrentGcwRating() < Pvp::getMinRatingForRank()) + player->modifyCurrentGcwRating(min, true); + } + else + { + // decrementing the value by a really large + // number will cause it to reset to 0 + if (player->getCurrentGcwPoints() > 0) + player->modifyCurrentGcwPoints(min, false); + + if (player->getCurrentGcwRating() != -1) + player->modifyCurrentGcwRating(min, false); + + if (player->getCurrentPvpKills() > 0) + player->modifyCurrentPvpKills(min, false); + } + + // make sure that m_nextGcwRatingCalcTime is set so that the + // rating will be recalculated at the next recalculation interval + player->setNextGcwRatingCalcTime(true); + + // migrate veteran rewards claim tracking information to new system + VeteranRewardManager::migrateVeteranRewardsClaimInformation(*this); + + // request the list of account feature transactions for the character + // from the LoginServer DB which will be compared to the list of account + // feature transactions stored on the character, and if there is any + // discrepancy, then it probably means there was a rollback, so we would + // need to grant the character any missing item(s) + FeatureIdTransactionRequest const fitr(GameServer::getInstance().getProcessId(), player->getStationId(), getNetworkId()); + GameServer::getInstance().sendToCentralServer(fitr); + + // set the guild rank + GuildMemberInfo const * const guildMemberInfo = GuildInterface::getGuildMemberInfo(getGuildId(), getNetworkId()); + if (guildMemberInfo) + player->setGuildRank(guildMemberInfo->m_rank); + + // set the citizen rank + // join the city chat room + std::vector const & cityIds = CityInterface::getCitizenOfCityId(getNetworkId()); + if (!cityIds.empty()) + { + int const cityId = cityIds.front(); + CitizenInfo const * const citizenInfo = CityInterface::getCitizenInfo(cityId, getNetworkId()); + if (citizenInfo) + player->setCitizenRank(citizenInfo->m_citizenRank); + + // join the city chat room + CityInterface::enterCityChatRoom(cityId, *this); + } + + // set the player's citizenship information + player->updateCitizenshipInfo(); + + // set the player's GCW Region info + player->updateGcwRegionInfo(); + + // set the player's GCW Region Defender info + player->updateGcwDefenderRegionInfo(); + + // fix the citizen name in the citizen roster, if necessary + CityInterface::verifyCitizenName(getNetworkId(), Unicode::wideToNarrow(getAssignedObjectName())); + + // check for over lot limit condition + player->setAccountNumLotsOverLimitSpam(); + + // fix the pgc chronicler's name in the pgc rating data, if necessary + CityInterface::verifyPgcChroniclerName(getNetworkId(), Unicode::wideToNarrow(getAssignedObjectName())); + + // depersist galactic reserve + { + // migrate any galactic reserve information that's stored in the PlayerObject into the CreatureObject + int temp; + if (player->getObjVars().getItem("galactic_reserve", temp)) + { + player->removeObjVarItem("galactic_reserve"); + setObjVarItem("galactic_reserve", temp); + } + + if (player->getObjVars().getItem("galactic_reserve_cooldown", temp)) + { + player->removeObjVarItem("galactic_reserve_cooldown"); + setObjVarItem("galactic_reserve_cooldown", temp); + } + + player->depersistGalacticReserveDeposit(); + } + + // depersist mercenary status + if (!ConfigServerGame::getEnableCovertImperialMercenary()) + { + player->modifyCollectionSlotValue("covert_imperial_mercenary", -1); + } + + if (!ConfigServerGame::getEnableOvertImperialMercenary()) + { + player->modifyCollectionSlotValue("overt_imperial_mercenary", -1); + } + + if (!ConfigServerGame::getEnableCovertRebelMercenary()) + { + player->modifyCollectionSlotValue("covert_rebel_mercenary", -1); + } + + if (!ConfigServerGame::getEnableOvertRebelMercenary()) + { + player->modifyCollectionSlotValue("overt_rebel_mercenary", -1); + } + + if (!PvpData::isNeutralFactionId(getPvpFaction())) + { + player->modifyCollectionSlotValue("covert_imperial_mercenary", -1); + player->modifyCollectionSlotValue("overt_imperial_mercenary", -1); + player->modifyCollectionSlotValue("covert_rebel_mercenary", -1); + player->modifyCollectionSlotValue("overt_rebel_mercenary", -1); + } + else + { + if (player->hasCompletedCollectionSlot("covert_imperial_mercenary")) + { + Pvp::setNeutralMercenaryFaction(*this, PvpData::getImperialFactionId(), PvpType_Covert); + } + else if (player->hasCompletedCollectionSlot("overt_imperial_mercenary")) + { + Pvp::setNeutralMercenaryFaction(*this, PvpData::getImperialFactionId(), PvpType_Declared); + } + else if (player->hasCompletedCollectionSlot("covert_rebel_mercenary")) + { + Pvp::setNeutralMercenaryFaction(*this, PvpData::getRebelFactionId(), PvpType_Covert); + } + else if (player->hasCompletedCollectionSlot("overt_rebel_mercenary")) + { + Pvp::setNeutralMercenaryFaction(*this, PvpData::getRebelFactionId(), PvpType_Declared); + } + } + } + } + else + { + getAvailableLocomotions(); + } + + checkAndRestoreRequiredSlots(); + + // get the current weapon, which will set it to our held or default weapon + IGNORE_RETURN(getCurrentWeapon()); + + // Rider: needs to not participate in CollisionWorld. + if (getState(States::RidingMount)) + { + CollisionProperty *const collisionProperty = getCollisionProperty(); + if (collisionProperty) + { + if (isInWorld()) + CollisionWorld::removeObject(this); + + collisionProperty->setDisableCollisionWorldAddRemove(true); + } + } + + // Fix up the footprint's swim height to take into consideration any scaling on this creature. + Footprint *const footprint = getFootprint(); + if (footprint) + footprint->setSwimHeight(getSwimHeight()); + + if (isAuthoritative()) + recomputeSlopeModPercent(); + + if (ConfigServerGame::getMoveSimEnabled ()) + MoveSimManager::checkApplySimulation (*this); + + if (isAuthoritative()) + GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); +} // CreatureObject::endBaselines + +//----------------------------------------------------------------------- + +void CreatureObject::checkAndRestoreRequiredSlots() +{ + SlottedContainer * const container = ContainerInterface::getSlottedContainer(*this); + if (container == NULL) + { + WARNING_STRICT_FATAL(true, ("This creature is not slotted!")); + return; + } + + // get the default weapon from it's slot and set the class variable + + bool foundDefaultWeapon = false; + Container::ContainerErrorCode tmp = Container::CEC_Success; + Container::ContainedItem const itemId = container->getObjectInSlot(s_defaultWeaponSlotId, tmp); + Object * const o = itemId.getObject(); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so && so->asWeaponObject()) + foundDefaultWeapon = true; + } + + if (!foundDefaultWeapon) + { + if (isAuthoritative()) + { + // try to make the default weapon from the template instead + initializeDefaultWeapon(); + } + else + { + WARNING_STRICT_FATAL(true, ("Unable to find default weapon slot id for %s(%s)", + getNetworkId().getValueString().c_str(), + getObjectTemplateName())); + } + } + + if (isPlayerControlled() && isAuthoritative()) + { + //restore inventory, mission bag, and datapad for players + + SlotId slot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); + if (slot != SlotId::invalid) + { + Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); + Object* inventory = itemId.getObject(); + if (inventory == NULL) + { + WARNING(true, ("Player %s has lost their inventory", getNetworkId().getValueString().c_str())); + inventory = ServerWorld::createNewObject(s_inventoryTemplate, *this, slot, false); + if (!inventory) + { + DEBUG_FATAL(true, ("Could not create an inventory for the player who lost theirs")); + } + } + } + + slot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::datapad); + if (slot != SlotId::invalid) + { + Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); + Object* datapad = itemId.getObject(); + if (datapad == NULL) + { + WARNING(true, ("Player %s has lost their datapad", getNetworkId().getValueString().c_str())); + datapad = ServerWorld::createNewObject(s_datapadTemplate, *this, slot, false); + if (!datapad) + { + DEBUG_FATAL(true, ("Could not create an datapad for the player who lost theirs")); + } + } + } + + slot = SlotIdManager::findSlotId(ConstCharCrcLowerString("mission_bag")); + if (slot != SlotId::invalid) + { + Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); + ServerObject* missionBag = safe_cast(itemId.getObject()); + if (missionBag == NULL) + { + WARNING(true, ("Player %s has lost their mission bag", getNetworkId().getValueString().c_str())); + missionBag = ServerWorld::createNewObject(s_missionBagTemplate, *this, slot, false); + if (!missionBag) + { + DEBUG_FATAL(true, ("Could not create a mission bag for the player who lost theirs")); + } + else + missionBag->persist(); + } + } + + slot = SlotIdManager::findSlotId(ConstCharCrcLowerString("bank")); + if (slot != SlotId::invalid) + { + Container::ContainedItem itemId = container->getObjectInSlot(slot, tmp); + ServerObject* bank = safe_cast(itemId.getObject()); + if (bank == NULL) + { + WARNING(true, ("Player %s has lost their bank", getNetworkId().getValueString().c_str())); + bank = ServerWorld::createNewObject(s_bankTemplate, *this, slot, false); + if (!bank) + { + DEBUG_FATAL(true, ("Could not create a bank for the player who lost theirs")); + } + else + { + bank->persist(); + bank->setLoadContents(false); + } + } + } + } +} + +//----------------------------------------------------------------------- + +/** + * Allows an object to do pre-deletion cleanup. + */ +void CreatureObject::onRemovingFromWorld() +{ + TangibleObject::onRemovingFromWorld(); + if (isAuthoritative()) + { + // if we are crafting, end the crafting session + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + if (player != NULL && player->isCrafting()) + player->stopCrafting(false); + + // exit all notify regions + Archive::AutoDeltaSet >::const_iterator i; + for(i = m_notifyRegions.begin(); i != m_notifyRegions.end(); ++i) + { + ScriptParams params; + params.addParam(i->first.c_str()); + params.addParam(i->second.c_str()); + if(getScriptObject()) + { + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_EXIT_REGION, params)); + } + } + m_notifyRegions.clear(); + } + + if (isMountable()) + IGNORE_RETURN(detachAllRiders()); + { + } +} + +void CreatureObject::addToWorld() +{ + if (getKill()) + return; + + if (isInWorld()) + { + DEBUG_WARNING(true, ("Calling add to world on object already in it %s", getNetworkId().getValueString().c_str())); + return; + } + updateWorldSphere(); + + Object::addToWorld(); + updateTriggerVolumes(); + + if (getScriptObject() != NULL) + getScriptObject()->setOwnerIsLoaded(); + + ContainedByProperty * const containedByProperty = getContainedByProperty(); + if (containedByProperty && containedByProperty->getContainedByNetworkId().isValid()) + { + Object const * const containedByObject = containedByProperty->getContainedBy(); + if (containedByObject && !containedByObject->isInWorld()) + { + if (!ServerWorld::isSpaceScene()) + { + // attempt to put the character at the ejection point of the building + DynamicVariableLocationData ejectionPoint; + if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) + { + DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building does not exist anymore or is not loaded in the world\n",getNetworkId().getValueString().c_str(), containedByProperty->getContainedByNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building does not exist anymore or is not loaded in the world",getNetworkId().getValueString().c_str(), containedByProperty->getContainedByNetworkId().getValueString().c_str())); + removeObjVarItem("building_ejection_point"); + teleportObject(ejectionPoint.pos, ejectionPoint.cell, "", ejectionPoint.pos,""); + + } + else + // warp the player to the Mos Eisley Starport + { + DEBUG_REPORT_LOG(true, ("Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); + GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this),"tatooine",Vector(3528,5,-4804),NetworkId::cms_invalid,Vector(3528,5,-4804)); + } + } + } + } + + onAddedToWorld(); +} + +//----------------------------------------------------------------------- + +void CreatureObject::initializeNewPlayer() +{ +} + +//----------------------------------------------------------------------- + +/** Set up the inventory object for the creature and initialize with contents from template. + */ +void CreatureObject::setupInventory() +{ + +} + +//----------------------------------------------------------------------- + +/** + * Sets up the creature's skills and related data. + */ +void CreatureObject::setupSkillData() +{ + if (isAuthoritative()) + { + // clear out our current skill related data + m_modMap.clear(); + if (isPlayerControlled()) + { + clearCommands(); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + { + playerObject->clearSchematics(); + } + } + + m_skills.erase(0); + + // set the skill related data from the skills + for (SkillList::const_iterator skillIter = m_skills.begin(); skillIter != m_skills.end(); ++skillIter) + { + SkillObject const * skill = *skillIter; + if (skill) + { + // init skillmods + std::vector > const &statMods = skill->getStatisticModifiers(); + std::vector >::const_iterator modIter; + for (modIter = statMods.begin(); modIter != statMods.end(); ++modIter) + { + addModValue((*modIter).first, (*modIter).second, true); + } + // init skill commands + { + const SkillObject::StringVector & sv = skill->getCommandsProvided (); + for (SkillObject::StringVector::const_iterator i = sv.begin(); + i != sv.end(); ++i) + { + grantCommand(*i, true); + } + } + // init schematics + { + const SkillObject::StringVector & sv = skill->getSchematicsGranted (); + for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) + grantSchematicGroup("+" + *i, true); + } + } + } + + // read the non-skill data from the objvars and add those to the creature + // note that we add them as "from skill" so that they don't get added to the + // objvar list again + { + DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_NOT_SKILL_MODS); + DynamicVariableList::NestedList::const_iterator i(mods.begin()); + int value; + for (; i != mods.end(); ++i) + { + i.getValue(value); + addModValue(i.getName(), value, true); + } + } + { + DynamicVariableList::NestedList commands(getObjVars(), OBJVAR_NOT_SKILL_COMMANDS); + DynamicVariableList::NestedList::const_iterator i(commands.begin()); + for (; i != commands.end(); ++i) + { + grantCommand(i.getName(), true); + } + if(getClient()) + { + revokeCommand(AdminAccountManager::getAdminCommandName(), false); + + if (getClient()->isGod()) + grantCommand(AdminAccountManager::getAdminCommandName(), false); + } + } + { + DynamicVariableList::NestedList schematics(getObjVars(), OBJVAR_NOT_SKILL_SCHEMATICS); + DynamicVariableList::NestedList::const_iterator i(schematics.begin()); + for (; i != schematics.end(); ++i) + { + grantSchematic(strtoul(i.getName().c_str(), NULL, 10), true); + } + } + + // calculate the level based on the skill list + recalculateLevel(); + } +} // CreatureObject::setupSkillData + +//----------------------------------------------------------------------- + +/** + * Creates a default controller for this object. + * + * @return the object's controller + */ +Controller* CreatureObject::createDefaultController () +{ + const ServerCreatureObjectTemplate * myTemplate = safe_cast< + const ServerCreatureObjectTemplate *>(getObjectTemplate()); + + Controller * controller = 0; + if (myTemplate->getCanCreateAvatar()) + { + controller = new PlayerCreatureController(this); + } + else + { + controller = new AICreatureController(this); + + AICreatureController * const aiCreatureController = AICreatureController::asAiCreatureController(controller); + + if (aiCreatureController != NULL) + { + aiCreatureController->addServerNpAutoDeltaVariables(m_serverPackage_np); + } + } + + setController(controller); + return controller; +} // CreatureObject::createDefaultController + +//----------------------------------------------------------------------- + +CreatureController* CreatureObject::getCreatureController() +{ + return safe_cast(getController()); +} + +//---------------------------------------------------------------------- + +const CreatureController* CreatureObject::getCreatureController() const +{ + return safe_cast(getController()); +} + +//---------------------------------------------------------------------- + +void CreatureObject::setAuthority() +{ + // don't recalculate our attribs until all our equipment has been made + // authoritative + ++m_deferComputeTotalAttributes; + TangibleObject::setAuthority(); + --m_deferComputeTotalAttributes; + computeTotalAttributes(); +} + +//---------------------------------------------------------------------- + + +void CreatureObject::setAuthServerProcessId(uint32 processId) +{ + uint32 const oldProcess = getAuthServerProcessId(); + TangibleObject::setAuthServerProcessId(processId); + + if (oldProcess != getAuthServerProcessId()) + { + // we can't trade if we are on different servers, so cancel it + if (getCreatureController()->getSecureTrade() != NULL) + { + getCreatureController()->getSecureTrade()->cancelTrade(*this); + } + } +} + +//---------------------------------------------------------------------- + +/** + * Updates the creature. Removes it from combat if it is incapacitated. + * + * @param time current game time + * + * @return base class result + */ +float CreatureObject::alter(float time) +{ + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter"); + float const result = TangibleObject::alter(time); + + m_regionFlagTimer.updateNoReset(time); // Update our notify timer. + + if (isPlayerControlled() && (isIncapacitated() || isDead())) + { + // If the player is trading, cancel the trade. + // We need to force the issue to catch edge cases. + ServerSecureTrade * const secureTradeObject = getCreatureController()->getSecureTrade(); + if (secureTradeObject != NULL) + { + secureTradeObject->cancelTrade(*this); + } + } + + if (!isAuthoritative()) + { + // Non-authoritative activity. + removeFromSpawnQueue(); + } + else + { + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter auth stuff"); + //-- Mounts/vehicles: driver moves the server's mount/vehicle position to that of the driver. + transferRiderPositionToMount(); + + updateVehiclePhysicsData (); + + // Authoritative activity. + + // update the invulnerability timer + if (m_invulnerabilityTimer.get() != 0.0f) + { + float const timeLeft = std::max(0.f, m_invulnerabilityTimer.get()-time); + m_invulnerabilityTimer.set(timeLeft); + } + else + { + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter commandqueue"); + // update the command queue + getCommandQueue()->update(time); + } + + //check timer and migrate stats if necessary + +//disable self stat migration +#if 0 + migrateStats(time); +#endif + + if (isPlayerControlled()) + { + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter auth player stuff"); + // keep the spawn queue pumping. + // todo: if the spawn queue is starving out players because + // there are too may other players on the queue, make some + // preliminary checks (e.g. in a city, too many creatures nearby) + // and reduce the spawn queue size + addToSpawnQueue(); + + { + PROFILER_AUTO_BLOCK_DEFINE("gradual customizations"); + ServerImageDesignerManager::updateGradualCustomizations(this); + } + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + PROFILER_AUTO_BLOCK_DEFINE("playerobject stuff"); + playerObject->alterPlayedTime(time); + playerObject->updateKillMeter(time); + playerObject->checkStomach(); + playerObject->checkTheater(getPosition_w(), getSceneId(), getRunSpeed(), 128.0f); + updateGroup(); + + if (playerObject->getIsUnsticking() && getPositionChanged()) + { + Chat::sendSystemMessageSimple(*this, SharedStringIds::unstick_request_cancelled, NULL); + playerObject->setIsUnsticking(false); + } + } + + if (!ServerWorld::isSpaceScene()) + { + // if we're in a conversation, end it if we move too far from the npc + if (m_npcConversation != NULL) + { + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::alter::npcConvCheck"); + bool endConversation = false; + // check the distance to the npc + ServerObject const * const npc = safe_cast(m_npcConversation->getNPC().getObject()); + if (npc != NULL) + { + float distance = findPosition_w().magnitudeBetween(npc->findPosition_w()); + distance -= getRadius(); + distance -= npc->getRadius(); + if (distance > ConfigServerGame::getNpcConversationDistance()) + endConversation = true; + } + else + { + endConversation = true; + } + if (endConversation) + endNpcConversation(); + } + } + } + alterPseudoPlayedTime(time); + updateBuffs(); + + //-- Handle mounts-specific functionality for an authoritative rider or mount. + alterAuthoritativeForMounts(); + } + + // see if we are performing a slow down effect + Property * property = getProperty(SlowDownProperty::getClassPropertyId()); + if (property != NULL) + { + // has it expired? + SlowDownProperty * slowdown = safe_cast(property); + if (slowdown->getExpireTime() <= ServerClock::getInstance().getGameTimeSeconds()) + { + // yes, remove the effect + removeProperty(SlowDownProperty::getClassPropertyId()); + } + else + { + // we need to find every authoritative non-player creature in the effect's + // area, and and tell them they are moving on our effect "hill" during their next alter + // (player creatures are handled on the player's client) + Object * target = slowdown->getTarget().getObject(); + if (target != NULL) + { + std::vector found; + ServerWorld::findAuthoritativeNonPlayerCreaturesInCone(*this, *target, slowdown->getConeLength(), slowdown->getConeAngle(), found); + if (!found.empty()) + { + // compute the effective normal vector of our "hill" + Vector normal(getPosition_w() - target->getPosition_w()); + normal.y = 0; + normal.normalize(); + normal *= cos(slowdown->getSlopeAngle() + PI_OVER_2); + normal.y = sin(slowdown->getSlopeAngle() + PI_OVER_2); + for (std::vector::iterator i = found.begin(); i != found.end(); ++i) + { + if ((*i)->getNetworkId() != getNetworkId()) + safe_cast(*i)->addTerrainSlopeEffect(normal); + } + } + } + } + } + + //-- Handle mounts-specific functionality for all mounts. We'll do sanity checking in here. + alterAnyForMounts(); + + //-- Handle updateMovementInfo. + if (getLocalFlag(LocalObjectFlags::CreatureObject_RequiresMovementInfoUpdate)) + { + updateMovementInfo(); + setLocalFlag(LocalObjectFlags::CreatureObject_RequiresMovementInfoUpdate, false); + } + + m_locomotion = calcLocomotion(); + + if (PlayerCreatureController::getPlayerObject(this) != 0) + { + if (m_level.get() != m_previousLevel) + { + if (isAuthoritative()) + { + GameScriptObject * const script = getScriptObject(); + + if (script != 0) + { + ScriptParams params; + params.addParam(m_previousLevel); + params.addParam(m_level.get()); + script->trigAllScripts(Scripting::TRIG_COMBAT_LEVEL_CHANGED, params); + } + } + m_previousLevel = m_level.get(); + levelChanged(); + } + } + + return result; +} + +//----------------------------------------------------------------------- + +bool CreatureObject::canDestroy() const +{ + // turn off our default weapon so it won't prevent us from getting + // destroyed + WeaponObject * defaultWeapon = getDefaultWeapon(); + if (defaultWeapon != NULL) + defaultWeapon->setAsDefaultWeapon(false); + + bool result = TangibleObject::canDestroy(); + if (!result) + { + // we're not being destroyed, turn our default weapon back on + if (defaultWeapon != NULL) + defaultWeapon->setAsDefaultWeapon(true); + } + + return result; +} + +//----------------------------------------------------------------------- + +float CreatureObject::getPvpRegionCheckTime() +{ + return ConfigServerGame::getCreaturePvpRegionCheckTime(); +} + +//----------------------------------------------------------------------- + +/** + * Sets the default weapon for a creature. This function bootstraps the default weapon. + * After this function is called, there should always be a weapon in the default + * weapon slot. + */ +void CreatureObject::initializeDefaultWeapon() +{ + FATAL(!isAuthoritative(), ("CreatureObject::initializeDefaultWeapon: obj %s, while nonauth", getDebugInformation().c_str())); + + ServerCreatureObjectTemplate const * const myTemplate = safe_cast(getObjectTemplate()); + if (myTemplate != NULL) + { + ServerWeaponObjectTemplate const *weaponTemplate = myTemplate->getDefaultWeapon(); + if (weaponTemplate == NULL) + { + WARNING(true, ("Creature template %s has no valid default weapon!", getTemplateName())); + + // try to use the fallback weapon + weaponTemplate = dynamic_cast(ObjectTemplateList::fetch(ConfigServerGame::getFallbackDefaultWeapon())); + + FATAL(weaponTemplate == NULL, ("CreatureObject::initializeFirstTimeObject fallback weapon template %s is bad!", ConfigServerGame::getFallbackDefaultWeapon())); + } + + WeaponObject * const weapon = safe_cast(ServerWorld::createNewObject(*weaponTemplate, *this, s_defaultWeaponSlotId, false)); + + if (weapon != NULL) + weapon->setAsDefaultWeapon(true); + else + { + WARNING_STRICT_FATAL(true, ("CreatureObject::initializeDefaultWeapon unable to create default weapon %s for creature %s", weaponTemplate->getName(), getNetworkId().getValueString().c_str())); + } + + weaponTemplate->releaseReference(); + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::swapDefaultWeapons(WeaponObject &newDefaultWeapon, ServerObject &weaponContainer) +{ + FATAL(!isAuthoritative(), ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, while obj nonauth", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); + FATAL(!newDefaultWeapon.isAuthoritative(), ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, while newDefaultWeapon nonauth", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); + FATAL(!weaponContainer.isAuthoritative(), ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, while weaponContainer nonauth", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); + + // There is a window here where the default weapon can be null, so we + // set a flag that it's ok until we've finished the transfer. + FATAL(s_allowNullDefaultWeapon, ("CreatureObject::swapDefaultWeapons has been recursively called!")); + + WeaponObject * const oldDefaultWeapon = getDefaultWeapon(); + FATAL(!oldDefaultWeapon, ("CreatureObject::swapDefaultWeapons: obj %s, weapon %s, weaponContainer %s, with no current default weapon", getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str())); + + s_allowNullDefaultWeapon = true; + + // Move the current default weapon into the weapon container + oldDefaultWeapon->setAsDefaultWeapon(false); + Container::ContainerErrorCode err = Container::CEC_Success; + bool const success1 = ContainerInterface::transferItemToVolumeContainer(weaponContainer, *oldDefaultWeapon, 0, err, true); + FATAL(!success1, ("CreatureObject::swapDefaultWeapons: obj %s, old default weapon %s, new default weapon %s, weaponContainer %s, old default weapon transfer to weaponContainer failed with error %d", getDebugInformation().c_str(), oldDefaultWeapon->getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str(), static_cast(err))); + + // Try to move the new default weapon into the default weapon slot + bool const success2 = ContainerInterface::transferItemToSlottedContainer(*this, newDefaultWeapon, s_defaultWeaponSlotId, 0, err); + if (success2) + newDefaultWeapon.setAsDefaultWeapon(true); + else + { + // We failed to swap in the new default weapon, so we need to move the old one back in. + bool const success3 = ContainerInterface::transferItemToSlottedContainer(*this, *oldDefaultWeapon, s_defaultWeaponSlotId, 0, err); + FATAL(!success3, ("CreatureObject::swapDefaultWeapons: obj %s, old default weapon %s, new default weapon %s, weaponContainer %s, old default weapon transfer back to default weapon slot after failure to switch to new default weapon failed with error %d", getDebugInformation().c_str(), oldDefaultWeapon->getDebugInformation().c_str(), newDefaultWeapon.getDebugInformation().c_str(), weaponContainer.getDebugInformation().c_str(), static_cast(err))); + oldDefaultWeapon->setAsDefaultWeapon(true); + } + + s_allowNullDefaultWeapon = false; + return success2; +} + +// ---------------------------------------------------------------------- + +WeaponObject *CreatureObject::getDefaultWeapon() const +{ + SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); + if (container == NULL) + { + return NULL; + } + + WeaponObject * defaultWeapon = NULL; + Container::ContainerErrorCode error; + Container::ContainedItem itemId = container->getObjectInSlot(s_defaultWeaponSlotId, error); + if (error == Container::CEC_Success) + { + Object * const o = itemId.getObject(); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so) + defaultWeapon = so->asWeaponObject(); + } + FATAL(!s_allowNullDefaultWeapon && defaultWeapon == NULL, ("CreatureObject::getDefaultWeapon, weapon is NULL! Object in default slot is %s", itemId.getValueString().c_str())); + } + return defaultWeapon; +} + +// ---------------------------------------------------------------------- + +/** + * Returns an attribute value, modified by attribute mods. + * + * @param attribute the attribute to get + */ +Attributes::Value CreatureObject::getAttribute(Attributes::Enumerator attribute) const +{ + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + { + DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); + return 0; + } + + return getAdjustedAttribute(attribute, m_attributes[attribute]); +} + +//----------------------------------------------------------------------- + +/** + * Returns an attribute value, adjusted by wounds, etc. + * + * @param attribute the attribute type + * @param value the value to adjust + * + * @returns value adjusted by various params + */ +Attributes::Value CreatureObject::getAdjustedAttribute(Attributes::Enumerator attribute, + Attributes::Value value) const +{ + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + { + DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); + return value; + } + + // modify the attribute for attrib mods + value = static_cast( + value + m_cachedCurrentAttributeModValues[attribute]); + + // modify for partial regeneration + value = static_cast(value + static_cast(floor(m_regeneration[attribute]))); + + //cap maximum value + Attributes::Value max = getMaxAttribute(attribute); + if (value > max) + value = max; + + return value; +} // CreatureObject::getAdjustedAttribute + +//----------------------------------------------------------------------- + +/** + * Returns a max attribute value, modified by attribute mods. + * + * @param attribute the attribute to get + */ +Attributes::Value CreatureObject::getMaxAttribute(Attributes::Enumerator attribute, bool capStat) const +{ + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + { + DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); + return 0; + } + + Attributes::Value value = getUnmodifiedMaxAttribute(attribute); + value = static_cast( + value + m_cachedMaxAttributeModValues[attribute] + m_attribBonus[attribute]); + + if (capStat) + { + // make sure the value doesn't go below the defined minimum value + if (Attributes::isAttribPool(attribute) && value < ConfigServerGame::getMinPoolValue()) + value = static_cast(ConfigServerGame::getMinPoolValue()); + + // double-check that the max isn't <= 0 + if (value < 1) + value = 1; + } + return value; +} + +//----------------------------------------------------------------------- + +const std::map > & CreatureObject::getModMap() const +{ + return m_modMap.getMap(); +} + +//----------------------------------------------------------------------- + +const int CreatureObject::getModValue(const std::string & modName) const +{ + int result = 0; + std::map >::const_iterator f = m_modMap.find(modName); + if(f != m_modMap.end()) + { + result = (*f).second.first; + } + return result; +} + +//----------------------------------------------------------------------- + +/** + * Returns the value for a skill mod, modified by any special equipment the + * creature may be wearing. + * + * @param statMod the name of the skill mod + * + * @return the mod value + */ +const int CreatureObject::getEnhancedModValue(const std::string & modName) const +{ + int base = 0; + int bonus = 0; + + std::map >::const_iterator f = m_modMap.find(modName); + if (f != m_modMap.end()) + { + base = (*f).second.first; + bonus = (*f).second.second; + } + if (bonus > ConfigSharedGame::getMaxCreatureSkillModBonus()) + bonus = ConfigSharedGame::getMaxCreatureSkillModBonus(); + return base + bonus; +} // CreatureObject::getEnhancedSkillStatMod + +//----------------------------------------------------------------------- + +/** + * Returns the value for a skill mod, modified by any special equipment the + * creature may be wearing. This version does not respect getMaxCreatureSkillModBonus + * + * @param statMod the name of the skill mod + * + * @return the mod value + */ +const int CreatureObject::getEnhancedModValueUncapped(const std::string & modName) const +{ + int base = 0; + int bonus = 0; + + std::map >::const_iterator f = m_modMap.find(modName); + if (f != m_modMap.end()) + { + base = (*f).second.first; + bonus = (*f).second.second; + } + return base + bonus; +} // CreatureObject::getEnhancedSkillStatMod + +//----------------------------------------------------------------------- + +void CreatureObject::setModValue(const std::string & modName, const int value) +{ + if(isAuthoritative()) + { + int oldBonus = 0; + Archive::AutoDeltaMap >::const_iterator found = + m_modMap.find(modName); + if (found != m_modMap.end()) + oldBonus = (*found).second.second; + if (value != 0 || oldBonus != 0) + { + m_modMap.set(modName, std::make_pair(value, oldBonus)); + } + else + { + m_modMap.erase(modName); + } + + updateSlopeMovement(modName); + } + else + { + sendControllerMessageToAuthServer(CM_setModValue, new MessageQueueGenericValueType >(std::make_pair(modName, value))); + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::addModValue(const std::string & modName, const int value, bool fromSkill) +{ + int currentVal = getModValue(modName); + setModValue(modName, currentVal + value); + if (!fromSkill) + { + // update the objvars for the value + std::string objvarName(OBJVAR_NOT_SKILL_MODS + "." + modName); + int currentValue = 0; + getObjVars().getItem(objvarName, currentValue); + currentValue += value; + if (currentValue != 0) + setObjVarItem(objvarName, currentValue); + else + removeObjVarItem(objvarName); + } +} + +// ---------------------------------------------------------------------- + +/** + * Adds a skill mod bonus to the creature. + * + * @param statMod the skill mod name + * @param bonus the bonus value + */ +void CreatureObject::addModBonus(const std::string & modName, int bonus) +{ + if(isAuthoritative()) + { + int oldBase = 0; + int oldBonus = 0; + Archive::AutoDeltaMap >::const_iterator found = + m_modMap.find(modName); + if (found != m_modMap.end()) + { + oldBase = (*found).second.first; + oldBonus = (*found).second.second; + } + bonus += oldBonus; + if (bonus != 0 || oldBase != 0) + { + m_modMap.set(modName, std::make_pair(oldBase, bonus)); + } + else + { + m_modMap.erase(modName); + } + + updateSlopeMovement(modName); + } + else + { +// sendControllerMessageToAuthServer(CM_setModValue, new MessageQueueGenericValueType >(std::make_pair(modName, value))); + } +} // CreatureObject::addModBonus + +// ---------------------------------------------------------------------- + +/** + * Adds an attrib bonus to the creature. + * + * @param attrib the attribute + * @param bonus the bonus value + */ +void CreatureObject::addAttribBonus(int attrib, int bonus) +{ + if (isAuthoritative()) + { + if (attrib < 0 || attrib >= Attributes::NumberOfAttributes) + return; + + int newBonus = m_attribBonus[attrib] + bonus; + if (newBonus > ConfigServerGame::getMaxTotalAttribBonus()) + newBonus = ConfigServerGame::getMaxTotalAttribBonus(); + else if (newBonus < -ConfigServerGame::getMaxTotalAttribBonus()) + newBonus = -ConfigServerGame::getMaxTotalAttribBonus(); + m_attribBonus.set(attrib, newBonus); + } +} // CreatureObject::addAttribBonus + +// ---------------------------------------------------------------------- + +void CreatureObject::updateSlopeMovement(const std::string & modName) +{ + // if I'm modifiying the slope mod, update my speed + if (modName == SLOPE_MOD) + recomputeSlopeModPercent(); + // if I'm modifiying the group slope mod and I'm a group leader, + // update my group's speed + else if (modName == GROUP_SLOPE_MOD && getGroup() != NULL && + getGroup()->getGroupLeaderId() == getNetworkId()) + { + const GroupObject::GroupMemberVector & members = getGroup()->getGroupMembers(); + GroupObject::GroupMemberVector::const_iterator iter; + for (iter = members.begin(); iter != members.end(); ++iter) + { + CreatureObject * member = safe_cast( + NetworkIdManager::getObjectById((*iter).first)); + if (member != NULL) + member->recomputeSlopeModPercent(); + } + } +} + +// ---------------------------------------------------------------------- + +/** + * Cause the client to dance using the specified dance style. + * + * This function will change the server and clients to the SkillAnimating + * posture. + * + * @param enabled if true, start doing the skill. If false, stop doing the skill. + * @param danceStyle the number of the dance style. + * + * @return true if this function succeeded, false if it failed for any reason. + */ + +bool CreatureObject::showDanceVisuals(bool enabled) +{ + //-- Ensure we are authoratative. This function should only be called + // indirectly via the command table, which guarantees it is called on the + // authoratative object. + if (!isAuthoritative()) + { + DEBUG_WARNING(true, ("showDanceVisuals() should be called only on the authoratative object.")); + return false; + } + + if (!enabled) + { + //-- Set the server object to the upright posture. + setPosture(Postures::Upright); + + //-- Tell all clients to switch to the specified posture. + Controller *const controller = getController(); + if (controller) + controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::Upright, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); + else + DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); + } + else + { + int visualId = lookupDanceVisual(getPerformanceType()); + if (visualId == 0) + return false; + + //-- Set the server object to animating skill posture. + setPosture(Postures::SkillAnimating); + + //-- Tell all clients to switch to the specified posture. + Controller *const controller = getController(); + if (controller) + controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::SkillAnimating, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); + else + DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); + + //-- Modify the animating skill data string. + char buffer[64]; + + sprintf(buffer, "dance_%d", visualId); + m_animatingSkillData = buffer; + } + + //-- Success. + return true; +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::showMusicianVisuals(bool enabled) +{ + //-- Ensure we are authoratative. This function should only be called + // indirectly via the command table, which guarantees it is called on the + // authoratative object. + if (!isAuthoritative()) + { + DEBUG_WARNING(true, ("showMusicianVisuals() should be called only on the authoratative object.")); + return false; + } + + if (!enabled) + { + //-- Set the server object to the upright posture. + setPosture(Postures::Upright); + + //-- Tell all clients to switch to the specified posture. + Controller *const controller = getController(); + if (controller) + controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::Upright, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); + else + DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); + } + else + { + //-- Determine the type of instrument used by this creature. + // @todo + const int instrumentId = getInstrumentVisualId(); + if (instrumentId == 0) + { + WARNING(true, ("tried to call showMusicianVisuals without a valid instrument")); + return false; + } + + //-- Set the server object to animating skill posture. + setPosture(Postures::SkillAnimating); + + //-- Tell all clients to switch to the specified posture. + Controller *const controller = getController(); + if (controller) + controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(Postures::SkillAnimating, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); + else + DEBUG_WARNING(true, ("showDanceVisuals(): no controller, could not tell clients to go to SkillAnimating posture.")); + + //-- Modify the animating skill data string. + char buffer[64]; + + sprintf(buffer, "music_%d", instrumentId); + m_animatingSkillData = buffer; + } + + //-- Success. + return true; +} + +//----------------------------------------------------------------------- + +void CreatureObject::sendMusicFlourish(int flourishIndex) +{ + Controller *controller = getController(); + if (controller) + { + MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(flourishIndex); + controller->appendMessage( + CM_musicFlourish, + 0.0f, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_ALL_CLIENT); + } +} + +//----------------------------------------------------------------------- + +/** + * Returns a mental state value, modified by mental state mods. + * + * @param attribute the attribute to get + */ +MentalStates::Value CreatureObject::getMentalState(MentalStates::Enumerator attribute) const +{ + if (attribute < 0 || attribute >= MentalStates::NumberOfMentalStates) + { + DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", attribute)); + return 0.0f; + } + + MentalStates::Value value = static_cast(m_currentAttitude.get().m_currentValues[attribute]); + return value; +} + +//----------------------------------------------------------------------- + +/** + * Returns a mental state value, modified by mental state mods. + * + * @param attribute the attribute to get + */ +MentalStates::Value CreatureObject::getMentalStateToward(const NetworkId &target, MentalStates::Enumerator attribute) const +{ + if (attribute < 0 || attribute >= MentalStates::NumberOfMentalStates) + { + DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", attribute)); + return 0.0f; + } + + MentalStates::Value value = static_cast(m_currentAttitude.get().m_currentValues[attribute]); + + CreatureAttitude const * const cs = getAttitudeToward(target); + if (cs) + { + value = static_cast(value + cs->m_currentValues[attribute]); + } + return value; +} + +//----------------------------------------------------------------------- + +int CreatureObject::getExperiencePoints(const std::string & experienceType) const +{ + if (isPlayerControlled()) + { + const PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + return playerObject->getExperiencePoints(experienceType); + } + return 0; +} + +//----------------------------------------------------------------------- + +const std::map & CreatureObject::getExperiencePoints() const +{ + static const std::map emptyResult; + if(isPlayerControlled()) + { + const PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if(playerObject != NULL) + { + return playerObject->getExperiencePoints(); + } + } + return emptyResult; +} + +//----------------------------------------------------------------------- + +const CreatureObject::SkillList & CreatureObject::getSkillList() const +{ + return m_skills.get(); +} + +//----------------------------------------------------------------------- + +const int CreatureObject::grantExperiencePoints(const std::string & experienceType, int amount) +{ + if (isPlayerControlled()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + { + int const amountGranted = playerObject->grantExperiencePoints(experienceType, amount); + + LevelManager::LevelData levelData(m_level.get(), m_totalLevelXp.get()); + LevelManager::addXpToLevelData(levelData, experienceType, amountGranted); + + setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); + + return amountGranted; + } + } + return INT_MIN; +} + +// ---------------------------------------------------------------------- + +const bool CreatureObject::grantSkill(const SkillObject & newSkill) +{ + if(isAuthoritative()) + { + //-- jww: simply return true if the skill is already in the vector + //-- this was the previous behavior, dunno if it should return false + if (hasSkill (newSkill)) + return true; + + // signal scripts that skill is about to be granted. If the script returns override, cancel skill grant. + { + ScriptParams params; + params.addParam(newSkill.getSkillName().c_str()); + if (getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_ABOUT_TO_BE_GRANTED, params) == SCRIPT_OVERRIDE) + { + return false; + } + } + + m_skills.insert(&newSkill); + if(getClient()) + { + LOG("CustomerService", ("Skill: Account %s CharacterId %s has acquired skill %s", getClient()->getAccountName().c_str(), getNetworkId().getValueString().c_str(), newSkill.getSkillName().c_str())); + } + + { + const SkillObject::StringVector & sv = newSkill.getCommandsProvided (); + for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) + grantCommand(*i, true); + } + + const std::vector > & statMods = newSkill.getStatisticModifiers(); + std::vector >::const_iterator modIter; + for(modIter = statMods.begin(); modIter != statMods.end(); ++ modIter) + { + addModValue((*modIter).first, (*modIter).second, true); + } + + { + const SkillObject::StringVector & sv = newSkill.getSchematicsGranted (); + for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) + grantSchematicGroup("+" + *i, true); + } + + // signal scripts that skill has been granted + ScriptParams params; + params.addParam(newSkill.getSkillName().c_str()); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_GRANTED, + params)); + + LevelManager::LevelData levelData(m_level.get(), m_totalLevelXp.get()); + LevelManager::addSkillToLevelData(levelData, newSkill.getSkillName()); + + setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); + } + else + { + sendControllerMessageToAuthServer(CM_grantSkill, new MessageQueueGenericValueType(newSkill.getSkillName())); + } + + return true; +} + +//----------------------------------------------------------------------- + +void CreatureObject::revokeSkill(const SkillObject & oldSkill, bool silent) +{ + if(isAuthoritative()) + { + // signal scripts that skill has been revoked + ScriptParams params; + params.addParam(oldSkill.getSkillName().c_str()); + if(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_ABOUT_TO_BE_REVOKED, params) == SCRIPT_CONTINUE) + { + + for (SkillList::const_iterator it = m_skills.begin(); it != m_skills.end(); ++it) + { + const SkillObject * const skill = *it; + + if (skill) + { + const SkillObject::SkillVector &prerequisiteSkills = skill->getPrerequisiteSkills(); + + for (SkillObject::SkillVector::const_iterator pit = prerequisiteSkills.begin(); pit != prerequisiteSkills.end(); ++pit) + { + const SkillObject * const prereq = *pit; + NOT_NULL (prereq); + + if (oldSkill.getSkillName() == prereq->getSkillName()) + { + if (!silent) + Chat::sendSystemMessage(*this, SharedStringIds::revoke_dependant_skill, Unicode::emptyString); + return; + } + } + } + } + + if (m_skills.contains(&oldSkill)) + { + // remove granted commands + { + const SkillObject::StringVector & sv = oldSkill.getCommandsProvided (); + for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) + revokeCommand(*i, true); + } + + // remove granted skill mods + const std::vector > & statMods = oldSkill.getStatisticModifiers(); + std::vector >::const_iterator modIter; + for(modIter = statMods.begin(); modIter != statMods.end(); ++ modIter) + { + addModValue((*modIter).first, -(*modIter).second, true); + } + + // remove schematics that were granted by any schematic groups + { + const SkillObject::StringVector & sv = oldSkill.getSchematicsGranted (); + for (SkillObject::StringVector::const_iterator i = sv.begin(); i != sv.end(); ++i) + { + const std::string & grantedGroup = *i; + grantSchematicGroup("-" + grantedGroup, true); + } + } + + m_skills.erase(&oldSkill); + if(getClient()) + { + LOG("CustomerService", ("Skill: Account %s CharacterId %s has lost skill %s", getClient()->getAccountName().c_str(), getNetworkId().getValueString().c_str(), oldSkill.getSkillName().c_str())); + } + + // Remove the current skill title if this is a player and their current title + // is this skill + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + + if ((playerObject != NULL) && + (oldSkill.getSkillName() == playerObject->getTitle())) + { + StringId message("shared", "skill_title_removed"); + Unicode::String outOfBand; + if (!silent) + Chat::sendSystemMessage(*this, message, outOfBand); + + playerObject->setTitle(""); + } + + // signal scripts that skill has been revoked + ScriptParams params; + params.addParam(oldSkill.getSkillName().c_str()); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILL_REVOKED,params)); + + // update the level data + LevelManager::LevelData levelData(m_level.get(), m_totalLevelXp.get()); + LevelManager::removeSkillFromLevelData(levelData, oldSkill.getSkillName()); + + setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); + } + } + } + else + { + LOG("CustomerService", ("Skill: Could not revoke skill %s from character %s because it is a proxy so we're forwarding this to the auth server.", + oldSkill.getSkillName().c_str(), getNetworkId().getValueString().c_str())); + sendControllerMessageToAuthServer(CM_revokeSkill, new MessageQueueGenericValueType(oldSkill.getSkillName())); + } +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::grantSchematicGroup(const std::string & groupNameWithModifier, bool fromSkill) +{ + if (isPlayerControlled()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + return playerObject->grantSchematicGroup(groupNameWithModifier, fromSkill); + } + return false; +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::grantSchematic(const std::string & schematicName, bool fromSkill) +{ + return grantSchematic(Crc::calculate(schematicName.c_str()), fromSkill); +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::grantSchematic(uint32 schematicCrc, bool fromSkill) +{ + if (isPlayerControlled()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + return playerObject->grantSchematic(schematicCrc, fromSkill); + } + return false; +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::revokeSchematic(const std::string & schematicName, bool fromSkill) +{ + return revokeSchematic(Crc::calculate(schematicName.c_str()), fromSkill); +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::revokeSchematic(uint32 schematicCrc, bool fromSkill) +{ + if (isPlayerControlled()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + return playerObject->revokeSchematic(schematicCrc, fromSkill); + } + return false; +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::hasSchematic(const std::string & schematicName) +{ + return hasSchematic(Crc::calculate(schematicName.c_str())); +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::hasSchematic(uint32 schematicCrc) +{ + if (isPlayerControlled()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + return playerObject->hasSchematic(schematicCrc); + } + return false; +} + +//----------------------------------------------------------------------- + +const bool CreatureObject::hasSkill(const SkillObject & skill) const +{ + return std::find (m_skills.begin(), m_skills.end (), &skill) != m_skills.end(); +} + +//----------------------------------------------------------------------- + +/** + * Sets up the object for being in or out of combat. + * @todo: this should really be in tangible only, we need to have a command queue + * for tangibles + * + * @param inCombat flag to put the object in combat-ready state or not + * + * @return true if state was set, false if something went wrong + */ +void CreatureObject::setInCombat(bool inCombat) +{ + TangibleObject::setInCombat(inCombat); + + if (isAuthoritative()) + { + if (!inCombat) + { + setState(States::Aiming, false); + } + else + { + // if we are crafting, end the crafting session + + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + + if (player != NULL && player->isCrafting()) + { + player->stopCrafting(false); + } + } + } +} + +//----------------------------------------------------------------------- + +/** + * If this object is in combat, adds an aim to it. + */ +void CreatureObject::addAim () +{ + TangibleObject::addAim(); + if (isInCombat()) + { + setState(States::Aiming, true); + } +} // CreatureObject::addAim + +//----------------------------------------------------------------------- + +/** + * If this object is in combat, clear's it's aims. + */ +void CreatureObject::clearAims () +{ + TangibleObject::clearAims(); + if (isInCombat()) + { + setState(States::Aiming, false); + } +} // CreatureObject::clearAims + +//----------------------------------------------------------------------- + +/** + * Modifies a creature's attribute. No other function should modify the pool indexes + * of m_attributes. Will incapacitate the creature if an attribute drops to 0. + * + * @param attrib the attribute to modify + * @param delta amount to modify the attribute by + * @param checkIncapacitation flag to check for incap/recap + * @param source who is doing the damage (NetworkId::cms_invalid + * for no one) + * @param force force the change, even if we would normally not + * make it + * + * @return the amount of damage actually applied + */ +int CreatureObject::alterAttribute(Attributes::Enumerator attrib, int delta, + bool checkIncapacitation, const NetworkId & source, bool force) +{ + if (isAuthoritative()) + { + if (attrib < 0 || attrib >= Attributes::NumberOfAttributes) + { + DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attrib)); + return 0; + } + + if (!Attributes::isAttribPool(attrib)) + { + // we only alter pool values now, regeneration is set directly + DEBUG_REPORT_LOG(true, ("CreatureObject::alterAttribute called on %s for non-pool attrib (%d)\n", + getNetworkId().getValueString().c_str(), attrib)); + return 0; + } + + if (delta == 0) + return 0; + + // Use TangibleObject::isInvulnerable so we don't consider invulnerability timers + if ((isDead() || TangibleObject::isInvulnerable()) && !force) + return 0; + + if (getMaxAttribute(attrib) <= 0 && !force) + return 0; + + // if we are taking damage, try and damage any attrib mods instead + int attribModChange = 0; + int regenChange = 0; + if (delta < 0) + { + attribModChange = changeAttribModCurrentValue(attrib, delta, false); + if (attribModChange == delta) + { + computeTotalAttributes(); + if (checkIncapacitation) + testIncapacitation(source); + return attribModChange; + } + else + { + delta -= attribModChange; + } + + // if we are still taking damage, try and reduce any accumulated + // regeneration points + if (delta < 0 && m_regeneration[attrib] > 0) + { + if (m_regeneration[attrib] >= -delta) + { + // regen can absorb it all + m_regeneration[attrib] += delta; + computeTotalAttributes(); + if (checkIncapacitation) + testIncapacitation(source); + return attribModChange + delta; + } + else + { + regenChange = -static_cast(floor(m_regeneration[attrib])); + m_regeneration[attrib] += regenChange; + delta -= regenChange; + } + } + } + + // Don't set the actual attribute until the end of this function, + // to avoid changing it multiple times and generating network spam + int newValue = m_attributes[attrib] + delta; + + // if the attribute is more than the max attribute, reduce it + int maxAttribLimit = getUnmodifiedMaxAttribute(attrib) + getAttributeBonus(attrib); + if (newValue > maxAttribLimit) + { + int overflow = newValue - maxAttribLimit; + delta -= overflow; + newValue = maxAttribLimit; + + // try and heal any attrib mods + attribModChange = changeAttribModCurrentValue(attrib, overflow, false); + } + + // cap for min attrib value, depending on attrib type + int minValue = 0; + if (isPlayerControlled()) + { + if (Attributes::isAttribPool(attrib)) + minValue = ConfigServerGame::getMinPoolValue(); + } + int adjustedNewValue = getAdjustedAttribute(attrib, static_cast< + Attributes::Value>(newValue)); + if (adjustedNewValue < minValue) + { + newValue = minValue - (adjustedNewValue - newValue); + adjustedNewValue = minValue; +#ifdef _DEBUG + adjustedNewValue = getAdjustedAttribute(attrib, static_cast< + Attributes::Value>(newValue)); + if (adjustedNewValue != minValue) + { + DEBUG_WARNING(true, ("CreatureObject::alterAttribute, " + "adjustedNewValue != minValue")); + } +#endif + } + + if (newValue != m_attributes[attrib]) + { + // clip delta so whoever did the damage won't get overkill xp + if (adjustedNewValue < 0) + adjustedNewValue = 0; + delta = adjustedNewValue - getAttribute(attrib); + + // change the attribute + m_attributes.set(attrib, static_cast(newValue)); + + // update the client and check for incapacitation + computeTotalAttributes(); + if (checkIncapacitation) + testIncapacitation(source); + } + else + delta = 0; + + return delta + attribModChange + regenChange; + } + else + { + sendControllerMessageToAuthServer(CM_alterAttribute, + new MessageQueueAlterAttribute(attrib, delta, checkIncapacitation, + source)); + return 0; + } +} // CreatureObject::alterAttribute + +//----------------------------------------------------------------------- + +/** + * Tests to see if we need to be incapacitated/recapacitated. + * + * @param attackerId the object that may have caused our incapacitation. + */ +void CreatureObject::testIncapacitation(const NetworkId & attackerId) +{ + WARNING_STRICT_FATAL(!isAuthoritative(), ("CreatureObject::testIncapacitation invoked on non-authoritative object %s:%s", getObjectTemplateName(), getNetworkId().getValueString().c_str())); + + if (m_deferComputeTotalAttributes <= 0) + { + int const health = getAttribute(Attributes::Health); + + if (!isIncapacitated()) + { + // see if we are incapacitated + + if (health <= 0) + { + setIncapacitated(true, attackerId); + } + } + else + { + // recapacitate if any attribute is above 0 + + if (health > 0) + { + setIncapacitated(false, attackerId); + } + } + } +} + +//----------------------------------------------------------------------- + +/** + * Applies an attribute modifier to this creature. + * + * @param name the attrib mod name + * @param attrib the attribute to modify + * @param value the value to apply + * @param duration how long the modifier lasts + * @param attackRate time to get to the peak modifier value + * @param decayRate time for the modifier to be reduced to 0 + * @param flags flags that define how the mod works + */ +void CreatureObject::addAttributeModifier(const std::string & name, + Attributes::Enumerator attrib, int value, float duration, float attackRate, + float decayRate, int flags) +{ + AttribMod::AttribMod mod; + + if (!name.empty()) + { + AttribModNameManager::getInstance().addAttribModName(name.c_str()); + mod.tag = Crc::calculate(name.c_str()); + } + else + mod.tag = 0; + mod.attrib = attrib; + mod.value = value; + mod.attack = attackRate; + mod.sustain = duration; + mod.decay = decayRate; + mod.flags = flags; + if (!Attributes::isAttribPool(mod.attrib)) + { + // non-pool mods must change both max and current + mod.flags |= + AttribMod::AMF_changeMax | + AttribMod::AMF_attackCurrent | + AttribMod::AMF_decayCurrent; + } + LOG("CustomerService", ("Attribs: Added attrib mod to %s. Mod data: " + "%s(%u) %d %d %.2f %.2f %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + name.c_str(), mod.tag, mod.attrib, mod.value, mod.attack, mod.sustain, + mod.decay, mod.flags)); + addAttributeModifier(mod); +} // CreatureObject::addAttributeModifier + +//----------------------------------------------------------------------- + +/** + * Applies a skillmod modifier to this creature. + * + * @param name the attrib mod name + * @param skill the skillmod to modify + * @param value the value to apply + * @param duration how long the modifier lasts (-1 = infinite, or until the player logs off) + * @param flags flags that define how the mod works + */ +void CreatureObject::addSkillmodModifier(const std::string & name, + const std::string & skill, int value, float duration, int flags) +{ + AttribMod::AttribMod mod; + + if (skill.empty()) + { + WARNING_STRICT_FATAL(true, ("CreatureObject::addSkillmodModifier called " + "with empty string for skill")); + return; + } + + if (!name.empty()) + { + AttribModNameManager::getInstance().addAttribModName(name.c_str()); + mod.tag = Crc::calculate(name.c_str()); + } + else + mod.tag = 0; + + AttribModNameManager::getInstance().addAttribModName(skill.c_str()); + mod.skill = Crc::calculate(skill.c_str()); + mod.value = value; + mod.attack = 0; + mod.sustain = duration; + mod.decay = 0; + mod.flags = flags | AttribMod::AMF_skillMod; + + LOG("CustomerService", ("Attribs: Added skill mod to %s. Mod data: " + "%s(%u) %s(%u) %d %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + name.c_str(), mod.tag, skill.c_str(), mod.skill, + mod.value, mod.sustain, mod.flags)); + addAttributeModifier(mod); +} // CreatureObject::addSkillmodModifier + +//----------------------------------------------------------------------- + +/** + * Applies an attribute modifier to this creature. + * + * @param mod the mod to add + * @param attacker who is causing the mod to be applied + * + * @return the amount the attrib was modified by, if the mod did direct damage + */ +int CreatureObject::addAttributeModifier(const AttribMod::AttribMod & mod, + ServerObject * attacker) +{ +static char internalTagBuf[] = {'_','_','i','n','t','e','r','n','a','l','T','a','g','N','a','m','e','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','\0'}; +static const int internalTagBufLen = strlen(internalTagBuf); + + int damage = 0; + + if (isAuthoritative()) + { + ++m_deferComputeTotalAttributes; + + if (AttribMod::isDirectDamage(mod)) + { + // check if we're making a potentially dangerous mod + if (!Attributes::isAttribPool(mod.attrib)) + { + WARNING(true, ("Creature %s is having non-pool attribute %d instantly " + "modified! This change will be permanent!", + getNetworkId().getValueString().c_str(), mod.attrib)); + } + + // apply instantanious damage directly +#ifdef _DEBUG + if (ConfigCombatEngine::getDebugDamage()) + { + char debugBuffer[1024]; + snprintf(debugBuffer, 1024, "creature %s attribute %d(%d) modified by %d to %d\n", + getNetworkId().getValueString().c_str(), + mod.attrib, + m_attributes[mod.attrib], + mod.value, + m_attributes[mod.attrib] + mod.value); + DEBUG_REPORT_LOG (true, ("%s", debugBuffer)); + if (attacker != NULL) + { + Client *client = attacker->getClient(); + if (client != NULL) + ConsoleMgr::broadcastString(debugBuffer, client); + } + } +#endif + + damage = alterAttribute(mod.attrib, mod.value, false, + attacker ? attacker->getNetworkId() : NetworkId::cms_invalid); + } + else if (AttribMod::isAttribMod(mod) && mod.decay == AttribMod::AMDS_antidote) + { + removeAttributeModifiers(mod.attrib); + } + else + { + if (mod.attack >= 0 && (mod.sustain >= 0 || mod.sustain == -1.0f)) + { + // apply other damage to the attribMod list + CreatureMod newMod; + newMod.startTime = ServerClock::getInstance().getGameTimeSeconds(); + newMod.maxVal = 0; + newMod.currentVal = 0; + newMod.mod = mod; + if (newMod.mod.tag == 0) + { + // we need to have some sort of tag, so we use an internal + // name hash + std::pair::const_iterator, bool> insertResult; + do + { + newMod.mod.tag = Crc::calculate(&internalTagBuf[0]); + char * c = &internalTagBuf[internalTagBufLen-1]; + while (++(*c) == '9' + 1) + { + *c-- = '0'; + } + insertResult = m_attributeModList.insert(newMod.mod.tag, newMod); + } while (!insertResult.second); + + // clear any flags that assume we have a valid tag. + if (newMod.mod.flags & AttribMod::AMF_triggerOnDone) + { + newMod.mod.flags &= ~AttribMod::AMF_triggerOnDone; + + DEBUG_WARNING(true, ("Creature %s has a mod flagged as " + "trigger when done, but has no mod name.", + getNetworkId().getValueString().c_str())); + } + if (newMod.mod.flags & AttribMod::AMF_visible) + { + newMod.mod.flags &= ~AttribMod::AMF_visible; + + DEBUG_WARNING(true, ("Creature %s received a mod flagged as " + "visible, but has no mod name.", + getNetworkId().getValueString().c_str())); + } + } + else + { + m_attributeModList.insert(mod.tag, newMod); + } + + if ((mod.flags & AttribMod::AMF_visible) && isPlayerControlled()) + { + // send the mod name and the mod time length to the player + // NOTE: we just send the tag value to the client, we expect + // the client to get the mod name from a datatable + float time = mod.attack; + if (mod.decay > 0) + time += mod.decay; + if (mod.sustain > 0) + time += mod.sustain; + else if (mod.sustain == -1.0f) + time = -1.0f; + sendTimedModData(mod.tag, time); + } + } + else + { + const char * modName = AttribModNameManager::getInstance().getAttribModName(mod.tag); + if (modName == NULL) + modName = ""; + WARNING(true, ("Creature %s received a mod %s with invalid " + "attack(%.2f) or duration(%.2f)", + getNetworkId().getValueString().c_str(), modName, mod.attack, + mod.sustain)); + } + } + + --m_deferComputeTotalAttributes; + } + else + { + sendControllerMessageToAuthServer(CM_addAttributeModifier, + new MessageQueueGenericValueType(mod)); + } + return damage; +} // CreatureObject::addAttributeModifier + +//----------------------------------------------------------------------- + +/** + * Checks if the creature has a given attrib/skill mod on them. + * + * @param modName the name of the mod to look for + * + * @return tue if the creature has the mod, false if not + */ +bool CreatureObject::hasAttribModifier(const std::string & modName) const +{ + // since the mod name may be a group name, we need to get any names + // that may be derived from the modName + std::vector nameCrcs; + AttribModNameManager::getInstance().getAttribModCrcsFromBase(modName, nameCrcs); + + // if we have any name that matches a value in nameCrcs, we can return true + for (std::vector::const_iterator i = nameCrcs.begin(); + i != nameCrcs.end(); ++i) + { + if (m_attributeModList.find(*i) != m_attributeModList.end()) + return true; + } + return false; +} // CreatureObject::hasAttribModifier + +//----------------------------------------------------------------------- + +/** + * Removes an attribute/skill modifier from this creature. + * + * @param modName the name of the mod to look for + */ +void CreatureObject::removeAttributeModifier (const std::string & modName) +{ + // since the mod name may be a group name, we need to get any names + // that may be derived from the modName + std::vector nameCrcs; + AttribModNameManager::getInstance().getAttribModCrcsFromBase(modName, nameCrcs); + + // if we have any name that matches a value in nameCrcs, we can return true + std::map::const_iterator f; + for (std::vector::const_iterator i = nameCrcs.begin(); + i != nameCrcs.end(); ++i) + { + f = m_attributeModList.find(*i); + if (f != m_attributeModList.end()) + { + const CreatureMod & m = (*f).second; + + // if the mod is visible, we need to tell the player it's being + // removed + if (m.mod.flags & AttribMod::AMF_visible) + { + sendCancelTimedMod(m.mod.tag); + } + const char * type = "attrib"; + if (AttribMod::isSkillMod(m.mod)) + { + const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); + if (skillModName != NULL) + addModValue(skillModName, -m.maxVal, true); + else + { + WARNING(true, ("Unable to remove skillmod mod on player %s due to " + "unknown skill mod crc. Mod data: %u %u %d %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); + } + type = "skill"; + } + m_attributeModList.erase(f); +// LOG("CustomerService", ("Attribs: Removed named %s mod %s from %s", +// type, modName.c_str(), PlayerObject::getAccountDescription(this).c_str())); + } + } +} // CreatureObject::removeAttributeModifier + +//----------------------------------------------------------------------- + +/** + * Removes all attribute modifiers for a given attribute from this creature. + * + * @param attribute the attribute to clear + */ +void CreatureObject::removeAttributeModifiers(Attributes::Enumerator attribute) +{ + if(isAuthoritative()) + { + DEBUG_FATAL(attribute < 0 || attribute >= Attributes::NumberOfAttributes, + ("attribute out of range\n")); + + LOG("CustomerService", ("Attribs: Removed all attrib mods affecting " + "attrib %d from %s", attribute, + PlayerObject::getAccountDescription(this).c_str())); + + m_cachedCurrentAttributeModValues.set(attribute, 0); + m_cachedMaxAttributeModValues.set(attribute, 0); + + typedef Archive::AutoDeltaMap::const_iterator ModIter; + for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) + { + if (!AttribMod::isSkillMod((*i).second.mod) && + (*i).second.mod.attrib == attribute) + { + // if the mod is visible, we need to tell the player it's being + // removed + if ((*i).second.mod.flags & AttribMod::AMF_visible) + { + sendCancelTimedMod((*i).second.mod.tag); + } + + i = m_attributeModList.erase(i); + } + else + ++i; + } + + computeTotalAttributes(); + } + else + { + sendControllerMessageToAuthServer(CM_removeAttributeModifiers, new MessageQueueGenericValueType(attribute)); + } +} // CreatureObject::removeAttributeModifiers + +//----------------------------------------------------------------------- + +/** + * Removes all the attribute modifiers from this creature. + */ +void CreatureObject::removeAllAttributeModifiers () +{ +int i; + + if (isAuthoritative()) + { + for (i = 0; i < Attributes::NumberOfAttributes; ++i) + { + m_cachedCurrentAttributeModValues.set(i, 0); + m_cachedMaxAttributeModValues.set(i, 0); + } + + typedef Archive::AutoDeltaMap::const_iterator ModIter; + for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) + { + if (!AttribMod::isSkillMod((*i).second.mod)) + { + // if the mod is visible, we need to tell the player it's being + // removed + if ((*i).second.mod.flags & AttribMod::AMF_visible) + { + sendCancelTimedMod((*i).second.mod.tag); + } + + i = m_attributeModList.erase(i); + } + else + ++i; + } + + computeTotalAttributes(); + + LOG("CustomerService", ("Attribs: removed all attrib mods from %s.", + PlayerObject::getAccountDescription(this).c_str())); + } + else + { + sendControllerMessageToAuthServer(CM_removeAllAttributeModifiers, 0); + } +} // CreatureObject::removeAllAttributeModifiers + +//----------------------------------------------------------------------- + +/** +* Removes all the attribute and skill mod modifiers from this creature. +* Does NOT remove buffs, only the effects so be sure to manually remove +* any buffs for which you need the icons to go away. +*/ +void CreatureObject::removeAllAttributeAndSkillmodMods () +{ + if (isAuthoritative()) + { + // remove all attrib and skill mod mods + typedef Archive::AutoDeltaMap::const_iterator ModIter; + for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) + { + const CreatureMod & m = (*i).second; + if (AttribMod::isSkillMod(m.mod)) + { + const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); + if (skillModName != NULL) + addModValue(skillModName, -m.maxVal, true); + } + // if the mod is visible, we need to tell the player it's being + // removed + if (m.mod.flags & AttribMod::AMF_visible) + { + sendCancelTimedMod(m.mod.tag); + } + // if the mod is flagged as having a callback, call the script + if (m.mod.flags & AttribMod::AMF_triggerOnDone) + { + const char * modName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); + if (modName != NULL) + { + ScriptParams params; + params.addParam(modName); + params.addParam(true); + if (AttribMod::isAttribMod(m.mod)) + { + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_ATTRIB_MOD_DONE, params)); + } + else if (AttribMod::isSkillMod(m.mod)) + { + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_SKILL_MOD_DONE, params)); + } + + } + } + + i = m_attributeModList.erase(i); + } + for (int j = 0; j < Attributes::NumberOfAttributes; ++j) + { + m_cachedCurrentAttributeModValues.set(j, 0); + m_cachedMaxAttributeModValues.set(j, 0); + } + computeTotalAttributes(); + } + else + { + sendControllerMessageToAuthServer(CM_removeAllAttributeAndSkillmodModifiers, 0); + } + +} + +//----------------------------------------------------------------------- + +/** + * Returns a attrib/skillmod mod with a given name attached to the creature. + * + * @param modName the mod to look for + * + * @return the mod, or NULL if there is no mod with that name attached to us + */ +const AttribMod::AttribMod * CreatureObject::getAttributeModifier( + const std::string & modName) const +{ + // since the mod name may be a group name, we need to get any names + // that may be derived from the modName + std::vector nameCrcs; + AttribModNameManager::getInstance().getAttribModCrcsFromBase(modName, nameCrcs); + + // if we have any name that matches a value in nameCrcs, we can return it + for (std::vector::const_iterator i = nameCrcs.begin(); + i != nameCrcs.end(); ++i) + { + std::map::const_iterator found = m_attributeModList.find(*i); + if (found != m_attributeModList.end()) + return &((*found).second.mod); + } + return NULL; +} // CreatureObject::getAttributeModifier + +//----------------------------------------------------------------------- + +/** + * Returns the attribute modifiers on this creature. + */ +const std::map & CreatureObject::getAttributeModifiers() const +{ + return m_attributeModList.getMap(); +} // CreatureObject::getAttributeModifiers + +//----------------------------------------------------------------------- + +/** + * Sends info about a mod that's affecting a player to the client. + * + * @param id the mod id + * @param time how long the mod lasts (in sec) + * @param updateCache whether or not to update the cached list of timed mods that have been sent to the client + */ +void CreatureObject::sendTimedModData(uint32 id, float time, bool updateCache/* = true*/) +{ + if (isPlayerControlled() && getController() != NULL && id != 0) + { + MessageQueueGenericValueType > * const msg = + new MessageQueueGenericValueType >( + std::make_pair(id, time)); + getController()->appendMessage( + static_cast(CM_modData), + 0, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + + if (isPlayerControlled() && isAuthoritative() && updateCache && id != 0) + { + const int index = m_timedMod.find(id); + + if (index >= 0) + { + m_timedModDuration.set(index, time); + m_timedModUpdateTime.set(index, ServerClock::getInstance().getGameTimeSeconds()); + } + else + { + m_timedMod.push_back(id); + m_timedModDuration.push_back(time); + m_timedModUpdateTime.push_back(ServerClock::getInstance().getGameTimeSeconds()); + } + } +} // CreatureObject::sendTimedModData + +//----------------------------------------------------------------------- + +/** + * Tells a client to cancel a timed mod. + * + * @param id the mod id + */ +void CreatureObject::sendCancelTimedMod(uint32 id) +{ + if (isPlayerControlled() && getController() != NULL && id != 0) + { + MessageQueueGenericValueType * const msg = + new MessageQueueGenericValueType(id); + getController()->appendMessage( + static_cast(CM_cancelMod), + 0, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + + if (isPlayerControlled() && isAuthoritative() && id != 0) + { + const int index = m_timedMod.find(id); + + if (index >= 0) + { + m_timedMod.erase(index); + m_timedModDuration.erase(index); + m_timedModUpdateTime.erase(index); + } + } +} // CreatureObject::sendCancelTimedMod + +//----------------------------------------------------------------------- + +/** + * Applies damage done during combat to the creature. + * + * @param damageData the damage + */ +void CreatureObject::applyDamage(const CombatEngineData::DamageData &damageData) +{ + WARNING_STRICT_FATAL(!isAuthoritative(), ("CreatureObject::applyDamageTo " + "invoked on non-authoritative object %s:%s", getObjectTemplateName(), + getNetworkId().getValueString().c_str())); + + if (!isAuthoritative()) + return; + + //-- vehicles get damaged like tangibles + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + TangibleObject::applyDamage (damageData); + return; + } + + int healthDamage = 0; // damage info we will send to the client + int actionDamage = 0; // damage info we will send to the client + int mindDamage = 0; // damage info we will send to the client + + ServerObject *attacker = safe_cast(damageData.attackerId.getObject()); + + // if the attacker is a player and we are not, and we are incapped/dead, + // don't allow additional damage + if (attacker != NULL && attacker->isPlayerControlled() && !isPlayerControlled() && + (isIncapacitated() || isDead())) + { + return; + } + + ++m_deferComputeTotalAttributes; + + std::vector::const_iterator iter; + for (iter = damageData.damage.begin(); iter != damageData.damage.end(); ++iter) + { + const AttribMod::AttribMod &mod = *iter; + if (mod.value == 0) + continue; + + int damage = -addAttributeModifier(mod, attacker); + if (damage != 0) + { + if (mod.attrib == Attributes::Health) + healthDamage += damage; + else if (mod.attrib == Attributes::Action) + actionDamage += damage; + else if (mod.attrib == Attributes::Mind) + mindDamage += damage; + } + } + + --m_deferComputeTotalAttributes; + + computeTotalAttributes(); + + // tell scripts we have taken combat damage + if (damageData.attackerId != NetworkId::cms_invalid && + (healthDamage > 0 || actionDamage > 0 || mindDamage > 0)) + { + NOT_NULL(getScriptObject()); + int damageArray[] = {healthDamage, 0, actionDamage, 0, mindDamage, 0}; + std::vector damageParam(&damageArray[0], &damageArray[Attributes::NumberOfAttributes]); + + ScriptParams params; + params.addParam(damageData.attackerId); + params.addParam(damageData.weaponId); + params.addParam(damageParam); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_CREATURE_DAMAGED, + params)); + } + testIncapacitation(damageData.attackerId); +} // CreatureObject::applyDamage + +//----------------------------------------------------------------------- + +/** + * Changes attrib mod(s) on the creature due to combat damage or healing. Note + * that only positive attrib mods can be changed + * + * @param attrib the index of the attribute getting damaged + * @param delta the amount to change the mod by + * @param checkPoolOverflow flag to check if a pool value is over its max value + * + * @return the amount the attrib mod(s) changed + */ +int CreatureObject::changeAttribModCurrentValue(Attributes::Enumerator attrib, int delta, bool checkPoolOverflow) +{ + if (!isAuthoritative()) + { + DEBUG_WARNING(true, ("CreatureObject::damageAttribMods called for " + "non-authoritative creature %s, attrib %d", + getNetworkId().getValueString().c_str(), attrib)); + return 0; + } + + if (attrib < 0 || attrib >= Attributes::NumberOfAttributes) + { + DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attrib)); + return 0; + } + + int startDelta = delta; + typedef Archive::AutoDeltaMap::const_iterator ModIter; + for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end() && + delta != 0; ++i) + { + CreatureMod m = (*i).second; + if (AttribMod::isAttribMod(m.mod) && m.mod.attrib == attrib && m.mod.value > 0) + { + if (delta > 0) + { + // healing mods + if (m.maxVal > m.currentVal) + { + if (m.maxVal - m.currentVal >= delta) + { + // this mod can take the entire change + m.currentVal += delta; + delta = 0; + } + else + { + // this mod can only take part of the change + delta -= (m.maxVal - m.currentVal); + m.currentVal = m.maxVal; + } + m_attributeModList.set((*i).first, m); + } + } + else + { + // damaging mods + if (m.currentVal > 0) + { + if (m.currentVal + delta > 0) + { + // this mod can take the entire change + m.currentVal += delta; + delta = 0; + } + else + { + // this mod can only take part of the change + delta += m.currentVal; + m.currentVal = 0; + } + m_attributeModList.set((*i).first, m); + } + } + } + } + + if (startDelta != delta) + recomputeAttribModTotals(checkPoolOverflow); + + return startDelta - delta; +} // CreatureObject::changeAttribModCurrentValue + +//----------------------------------------------------------------------- + +/** + * Recomputes the values due to attrib mods to be added to the creature's current + * and max attribs. + * + * @param checkPoolOverflow flag to check if a pool value is over its max value + */ +void CreatureObject::recomputeAttribModTotals(bool checkPoolOverflow) +{ +int i; + + if (!isAuthoritative()) + return; + + int newCachedMaxAttributeModValues[Attributes::NumberOfAttributes]; + int newCachedCurrentAttributeModValues[Attributes::NumberOfAttributes]; + for (i = 0; i < Attributes::NumberOfAttributes; ++i) + { + newCachedMaxAttributeModValues[i] = 0; + newCachedCurrentAttributeModValues[i] = 0; + } + + typedef Archive::AutoDeltaMap::const_iterator ModIter; + for (ModIter j = m_attributeModList.begin(); j != m_attributeModList.end(); ++j) + { + const CreatureMod & m = (*j).second; + if (AttribMod::isAttribMod(m.mod)) + { + if ((m.mod.flags & AttribMod::AMF_changeMax)) + newCachedMaxAttributeModValues[m.mod.attrib] += m.maxVal; + newCachedCurrentAttributeModValues[m.mod.attrib] += m.currentVal; + } + } + + for (i = 0; i < Attributes::NumberOfAttributes; ++i) + { + m_cachedMaxAttributeModValues.set(i, static_cast(newCachedMaxAttributeModValues[i])); + m_cachedCurrentAttributeModValues.set(i, static_cast(newCachedCurrentAttributeModValues[i])); + + if (newCachedCurrentAttributeModValues[i] < 0) + { + // don't let the mod prevent us from healing out of incapacitation + int healedAttrib = getAdjustedAttribute(i, getUnmodifiedMaxAttribute(i)); + if (healedAttrib < 0) + { + m_cachedMaxAttributeModValues.set(i, static_cast( + m_cachedMaxAttributeModValues[i] - healedAttrib + 1)); + m_cachedCurrentAttributeModValues.set(i, static_cast( + m_cachedCurrentAttributeModValues[i] - healedAttrib + 1)); + } + } + + if (Attributes::isAttribPool(i) && checkPoolOverflow) + { + // since we can modify the max value and not the current value, damage + // the attribute if it is over the max + int max = getMaxAttribute(i); + int current = getUnmodifiedAttribute(i) + m_cachedCurrentAttributeModValues[i]; + if (current > max) + { + IGNORE_RETURN(alterAttribute(i, max - current, true)); + } + } + } +} // CreatureObject::recomputeAttribModTotals + +//----------------------------------------------------------------------- + +/** + * Advances the timing of attribute buffs and debuffs. Should be called by the controller from the + * authoritative object. + * + * @param time The amount of time to advance the buff. + */ +void CreatureObject::decayAttributes(float time) +{ + if (!isAuthoritative()) + return; + + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::decayAttributes"); + + // prevent client-seen attributes from being updated until all the attributes + // have been modified + ++m_deferComputeTotalAttributes; + + const uint32 currentTime = ServerClock::getInstance().getGameTimeSeconds(); + typedef Archive::AutoDeltaMap::const_iterator ModIter; + { // contain i because VC isn't compilant + for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) + { + CreatureMod m = (*i).second; + if (AttribMod::isDirectDamage(m.mod)) + { + DEBUG_WARNING(true, ("CreatureObject::decayAttributes has direct " + "damage mod in its list")); + continue; + } + + const float deltaTime = static_cast(currentTime - m.startTime); + float decayBegin = m.mod.attack; + if (m.mod.sustain > 0) + decayBegin += m.mod.sustain; + float totalTime = decayBegin; + if (m.mod.decay > 0) + totalTime += m.mod.decay; + if (m.mod.sustain == -1.0f) + { + // mod never expires + decayBegin = -1.0f; + totalTime = -1.0f; + } + int modValue = 0; + + if (deltaTime >= totalTime && totalTime != -1.0f) + { + // end of the mod time, erase the mod + if (AttribMod::isSkillMod(m.mod)) + { + const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); + if (skillModName != NULL) + { + addModValue(skillModName, -m.maxVal, true); + + LOG("CustomerService", ("Attribs: Expired skill mod on %s. Mod data: " + "%u %u %d %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); + } + else + { + WARNING(true, ("Unable to expire skillmod mod on player %s due to " + "unknown skill mod crc. Mod data: %u %u %d %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); + } + } + else + { + LOG("CustomerService", ("Attribs: Expired attrib mod on %s. Mod data: " + "%u %d %d %.2f %.2f %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + m.mod.tag, m.mod.attrib, m.mod.value, m.mod.attack, m.mod.sustain, + m.mod.decay, m.mod.flags)); + } + + // remove the mod from ourself + i = m_attributeModList.erase(i); + + if (m.mod.flags & AttribMod::AMF_triggerOnDone) + { + // tell scripts the mod has ended + const char * modName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); + if (modName != NULL) + { + ScriptParams params; + params.addParam(modName); + params.addParam(false); + if (AttribMod::isAttribMod(m.mod)) + { + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_ATTRIB_MOD_DONE, params)); + } + else if (AttribMod::isSkillMod(m.mod)) + { + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_SKILL_MOD_DONE, params)); + } + } + else + { + WARNING(true, ("Unable to trigger mod done on player %s due to " + "unknown mod name crc. Mod data: %u %u %d %.2f %.2f %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + m.mod.tag, m.mod.attrib, m.mod.value, m.mod.attack, + m.mod.sustain, m.mod.decay, m.mod.flags)); + } + } + if (m.mod.flags & AttribMod::AMF_visible) + { + // tell the client to erase the mod icon + sendCancelTimedMod(m.mod.tag); + } + } + else + { + if (deltaTime < m.mod.attack) // in attack phase + { + float t = deltaTime / m.mod.attack; + modValue = static_cast(m.mod.value * t + 0.5f); + } + else if (deltaTime < decayBegin || decayBegin == -1.0f) // in sustain phase + { + modValue = m.mod.value; + } + else if (deltaTime < totalTime) // in decay phase + { + float t = (deltaTime - decayBegin) / m.mod.decay; + modValue = static_cast(m.mod.value * (1.0f-t) + 0.5f); + } + + if (m.maxVal != modValue) + { + int delta = modValue - m.maxVal; + // Even if the mod is flagged as not updating max, we still need + // to change it here so we can calculate the next frame's delta. + // We'll check for updating max in recomputeAttribModTotals instead. + m.maxVal = modValue; + + if (AttribMod::isSkillMod(m.mod)) + { + // add the skillmod mod as if it were from a skill, + // which makes it temporary + const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); + if (skillModName != NULL) + addModValue(skillModName, delta, true); + else + { + WARNING(true, ("Unable to add skillmod mod on player %s due to " + "unknown skill mod crc. Mod data: %u %u %d %.2f %d", + PlayerObject::getAccountDescription(this).c_str(), + m.mod.tag, m.mod.skill, m.mod.value, m.mod.sustain, m.mod.flags)); + } + } + else + { + // see if we need to update the mod current value in addition + // to the max value + // non-pool attribs must update the current value + bool updateCurrent = !Attributes::isAttribPool(m.mod.attrib); + if (!updateCurrent) + { + // check the mod flags + if (deltaTime < decayBegin) + { + if ((m.mod.flags & AttribMod::AMF_attackCurrent)) + updateCurrent = true; + } + else + { + if ((m.mod.flags & AttribMod::AMF_decayCurrent)) + updateCurrent = true; + } + } + if (updateCurrent) + { + if ((m.mod.flags & AttribMod::AMF_changeMax) || + !Attributes::isAttribPool(m.mod.attrib)) + { + m.currentVal += delta; + } + else + { + // we are doing damage/healing over time, modify the + // attribute directly + IGNORE_RETURN(alterAttribute(m.mod.attrib, delta, true, + NetworkId::cms_invalid, false)); + } + } + } + + // make sure the mod's current val doesn't get out of range + if (m.mod.value >= 0) + { + if (m.currentVal > m.maxVal) + m.currentVal = m.maxVal; + else if (m.currentVal < 0) + m.currentVal = 0; + } + else + { + if (m.currentVal < m.maxVal) + m.currentVal = m.maxVal; + else if (m.currentVal > 0) + m.currentVal = 0; + } + m_attributeModList.set((*i).first, m); + } + ++i; + } + } + } + + recomputeAttribModTotals(true); + + // regenerate attributes + int i; + bool attribRegen = false; + float regenerationRate[3] = {0,0,0}; + m_regenerationTime += time; + for (i = 0; i < 3; ++i) + { + int poolAttrib = Attributes::POOLS[i]; + int maxAttrib = getMaxAttribute(poolAttrib); + int currentAttrib = getAttribute(poolAttrib); + if (currentAttrib < maxAttrib) + { + attribRegen = true; + regenerationRate[i] = getRegenRate(poolAttrib); + m_regeneration[poolAttrib] += regenerationRate[i] * time; + } + } + + //-- + //-- update player incapacitation timer + //-- + + if (isPlayerControlled()) + { + // regenerate force powers + if (!isIncapacitated()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + playerObject->regenerateForcePower(time); + } + } + } + + // update the client + --m_deferComputeTotalAttributes; + computeTotalAttributes(); + if (isAuthoritative()) + testIncapacitation(NetworkId::cms_invalid); +} + +//----------------------------------------------------------------------- + +/** + * Advances the timing of mental state buffs and debuffs and decays mental states toward + * their default values. Should be called by the controller from the + * authoritative object. + * + * @param time The amount of time to advance the buff. + */ + +void CreatureObject::decayMentalStates(float time) +{ + if (isDead()) + return; + + // @todo AJS - make this take into account time since objects were unloaded when they are reloaded + int oldBehavior = m_currentAttitude.get().m_behavior; + CreatureAttitude newState = m_currentAttitude.get(); + updateBehavior(0, newState); + + CreatureAttitude newTargetState; + + int i; + // Initialize the decay values for each mental state + float decays[MentalStates::NumberOfMentalStates]; + for (i=0; i::const_iterator targetIterator, targetEnd = m_mentalStatesToward.end(); + for (targetIterator=m_mentalStatesToward.begin(); targetIterator != targetEnd; ++targetIterator) + { + newTargetState = targetIterator->second; + for (i=0; isecond.m_currentValues[i]; + if (newValue > 0) + { + newValue = std::max(newValue - decays[i], 0.0f); + } + else + { + newValue = std::min(newValue + decays[i], 0.0f); + } + newTargetState.m_currentValues[i] = newValue; + } + m_mentalStatesToward.set(targetIterator->first, newTargetState); + } + + // Now change the behaviors for all of the targetted objects + bool behaviorChanged[Behaviors::NumberOfBehaviors]; + + int behavior; + + // Clear the accumulated values for each behavior + for (behavior = 0; behavior < Behaviors::NumberOfBehaviors; ++behavior) + { + behaviorChanged[behavior] = false; + } + + clipMentalStatesToward(); + deleteUnusedMentalStatesToward(behaviorChanged); + + int newBehavior = newState.m_behavior; + if (!m_mentalStatesToward.empty()) + { + // Update the behavior toward each target, and also update the accumulated state values for each behavior + Archive::AutoDeltaMap::const_iterator i = m_mentalStatesToward.begin(), e=m_mentalStatesToward.end(); + for (; i != e; ++i) + { + oldBehavior = i->second.m_behavior; + newTargetState = i->second; + updateBehavior(&i->first, newTargetState); + if (newTargetState.m_behavior != oldBehavior) + { + if (oldBehavior >= 0) + { + m_targetsByBehavior[oldBehavior].erase(i->first); + behaviorChanged[oldBehavior] = true; + } + m_targetsByBehavior[newTargetState.m_behavior].insert(i->first); + behaviorChanged[newTargetState.m_behavior] = true; + } + m_mentalStatesToward.set(i->first, newTargetState); + if (newTargetState.m_behavior > newBehavior) + newBehavior = newTargetState.m_behavior; + } + } + + m_currentAttitude.set(newState); + + if (m_lastBehavior.get() != newBehavior) + { + const int lastBehavior = m_lastBehavior.get(); + m_lastBehavior = newBehavior; + behaviorChanged[newBehavior] = false; + + notifyTargetChange(lastBehavior, newBehavior, behaviorChanged); + } + else + { + notifyTargetChange(m_lastBehavior.get(), m_lastBehavior.get(), behaviorChanged); + } +} + +// -------------------------------------------------------------------------- + +/** + * Returns the weapon currently being carried by the creature, which may or may + * not be the weapon it is using. If the creature is not carrying a weapon, + * returns the default weapon. + * + * @return the weapon + */ +WeaponObject *CreatureObject::getReadiedWeapon() const +{ + static SlotId const rightHandSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("hold_r")); + + // first check the right hand. + SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*this); + if (slottedContainer) + { + if (slottedContainer->hasSlot(rightHandSlot)) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + Object * const o = slottedContainer->getObjectInSlot(rightHandSlot, tmp).getObject(); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so) + { + WeaponObject * const wo = so->asWeaponObject(); + if (wo) + return wo; + } + } + } + } + // nothing in the hand, return the default weapon + return getDefaultWeapon(); +} + +//---------------------------------------------------------------------- + +/** + * Returned the weapon the creature will use for combat. + * + * @return the weapon + */ +WeaponObject *CreatureObject::getCurrentWeapon() +{ + Object * const o = m_currentWeapon.get().getObject(); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so) + { + WeaponObject * const currentWeapon = so->asWeaponObject(); + if (currentWeapon) + return currentWeapon; + } + } + + WeaponObject * const readiedWeapon = getReadiedWeapon(); + if (readiedWeapon) + setCurrentWeapon(*readiedWeapon); + return readiedWeapon; +} + +//---------------------------------------------------------------------- + +/** + * Sets the weapon the creature will use for combat. + * + * @param weapon the weapon + */ +void CreatureObject::setCurrentWeapon(WeaponObject & weapon) +{ + if(isAuthoritative()) + { + m_currentWeapon = CachedNetworkId(weapon); + } + else + { + sendControllerMessageToAuthServer(CM_setCurrentWeapon, new MessageQueueGenericValueType(weapon.getNetworkId())); + }; +} + +// -------------------------------------------------------------------------- + +int CreatureObject::getInstrumentVisualId() const +{ + static SlotId rightHandSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("hold_r")); + bool hasWeapon = false; + + // first check the right hand. + SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*this); + if (slottedContainer) + { + if (slottedContainer->hasSlot(rightHandSlot)) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + Object const * const object = slottedContainer->getObjectInSlot(rightHandSlot, tmp).getObject(); + if (object) + { + int type = lookupInstrumentVisualId(object->getObjectTemplateName()); + if (type) + return type; + ServerObject const * const so = object->asServerObject(); + if (so && so->asWeaponObject()) + hasWeapon = true; + } + } + } + + // then check the intended target if no weapon is equipped + if(!hasWeapon) + { + int visualId = internalGetInstrumentVisualId(getIntendedTarget()); + if(visualId) + return visualId; + } + + // last, check the look at target if no weapon is equipped + if (!hasWeapon) + { + int visualId = internalGetInstrumentVisualId(getLookAtTarget()); + if(visualId) + return visualId; + } + + return 0; +} + +// -------------------------------------------------------------------------- + +int CreatureObject::getInstrumentAudioId() const +{ + static SlotId rightHandSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("hold_r")); + bool hasWeapon = false; + + // first check the right hand. + SlottedContainer const * const slottedContainer = ContainerInterface::getSlottedContainer(*this); + if (slottedContainer) + { + if (slottedContainer->hasSlot(rightHandSlot)) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + Object const * const object = slottedContainer->getObjectInSlot(rightHandSlot, tmp).getObject(); + if (object) + { + int type = lookupInstrumentAudioId(object->getObjectTemplateName()); + if (type) + return type; + ServerObject const * const so = object->asServerObject(); + if (so && so->asWeaponObject()) + hasWeapon = true; + } + } + } + + // then check the intended target if no weapon is equipped + if (!hasWeapon) + { + int audioId = internalGetInstrumentAudioId(getIntendedTarget()); + if(audioId) + return audioId; + } + + // last, check the look at target if no weapon is equipped + if (!hasWeapon) + { + int audioId = internalGetInstrumentAudioId(getLookAtTarget()); + if(audioId) + return audioId; + } + return 0; +} + +// -------------------------------------------------------------------------- + +int CreatureObject::internalGetInstrumentAudioId(NetworkId const &id) const +{ + if (id != NetworkId::cms_invalid) + { + Object const * const object = NetworkIdManager::getObjectById(id); + if ( object + && !instrumentTooFar(getPosition_w(), object->getPosition_w()) + && ContainerInterface::getContainedByObject(*this) == ContainerInterface::getContainedByObject(*object)) + { + ServerObject const * const serverObj = object->asServerObject(); + if (!serverObj->getSharedTemplate()->getArrangementDescriptor()) + { + int type = lookupInstrumentAudioId(object->getObjectTemplateName()); + if (type) + return type; + } + } + } + return 0; +} + +// -------------------------------------------------------------------------- + +int CreatureObject::internalGetInstrumentVisualId(NetworkId const &id) const +{ + if (id != NetworkId::cms_invalid) + { + Object const * const object = NetworkIdManager::getObjectById(id); + if ( object + && !instrumentTooFar(getPosition_w(), object->getPosition_w()) + && ContainerInterface::getContainedByObject(*this) == ContainerInterface::getContainedByObject(*object)) + { + ServerObject const * const serverObj = object->asServerObject(); + if (!serverObj->getSharedTemplate()->getArrangementDescriptor()) + { + int type = lookupInstrumentVisualId(object->getObjectTemplateName()); + if (type) + return type; + } + } + } + return 0; +} + +// -------------------------------------------------------------------------- + +GroupObject *CreatureObject::getGroup() const +{ + if (m_group.get() != NetworkId::cms_invalid) + { + Object *obj = m_group.get().getObject(); + if (obj) + { + ServerObject *serverObj = obj->asServerObject(); + return serverObj->asGroupObject(); + } + } + return 0; +} + +// -------------------------------------------------------------------------- + +void CreatureObject::setGroup(GroupObject *group, bool disbandingCurrentGroup) +{ + if (isAuthoritative()) + { + NetworkId const oldGroupId = m_group.get(); + + m_group = group ? CachedNetworkId(*group) : CachedNetworkId::cms_cachedInvalid; + recomputeSlopeModPercent(); + + // Our group has finally been established, so don't worry about + // keeping track of who invited us to the group + setInviterForPendingGroup( NetworkId::cms_invalid ); + setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject && (playerObject->getSessionStartPlayTime() != 0)) + { + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); + if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.groupId != m_group.get())) + ServerUniverse::setConnectedCharacterGroupData(getNetworkId(), m_group.get()); + } + + // if joining a group, and the group currently + // has an active group pickup point, handle it + if (group && (oldGroupId != group->getNetworkId())) + { + unsigned int const secondsLeftOnGroupPickup = group->getSecondsLeftOnGroupPickup(); + if (secondsLeftOnGroupPickup) + { + std::pair const & groupPickupLocation = group->getGroupPickupLocation(); + if (!groupPickupLocation.first.empty()) + { + // tell group member that there's an active group pickup point + if (getClient()) + { + StringId::LocUnicodeString response; + if (StringId("group", "create_group_pickup_success_new_group_member").localize(response)) + { + ConsoleMgr::broadcastString(FormattedString<2048>().sprintf(Unicode::wideToNarrow(response).c_str(), CalendarTime::convertSecondsToMS(secondsLeftOnGroupPickup).c_str()), + getClient()); + } + } + + // create/update the group member's group pickup point waypoint + if (playerObject) + { + Location const location(groupPickupLocation.second, NetworkId::cms_invalid, Location::getCrcBySceneName(groupPickupLocation.first)); + playerObject->createOrUpdateReusableWaypoint(location, "groupPickupWp", Unicode::narrowToWide("Group Pickup Point"), Waypoint::White); + } + } + } + } + } + else + { + NetworkId groupId; + if(group) + groupId = group->getNetworkId(); + + sendControllerMessageToAuthServer(CM_setGroup, new MessageQueueGenericValueType >(std::make_pair(disbandingCurrentGroup, groupId))); + } +} + +// -------------------------------------------------------------------------- + +NetworkId const & CreatureObject::getGroupInviterId() const +{ + return m_groupInviter.get().first.first; +} + +// -------------------------------------------------------------------------- + +std::string const & CreatureObject::getGroupInviterName() const +{ + return m_groupInviter.get().first.second; +} + +// -------------------------------------------------------------------------- + +CreatureObject *CreatureObject::getGroupInviter() const +{ + NetworkId const & inviterId = m_groupInviter.get().first.first; + if (inviterId != NetworkId::cms_invalid) + { + Object * const o = NetworkIdManager::getObjectById(inviterId); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so) + return so->asCreatureObject(); + } + } + return 0; +} + +// -------------------------------------------------------------------------- + +void CreatureObject::setGroupInviter(NetworkId const &inviterId, std::string const& inviterName, NetworkId const &inviterShipId) +{ + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + MessageQueueGenericValueType > > *msg = new MessageQueueGenericValueType > >(std::make_pair(inviterName, std::make_pair(inviterId, inviterShipId))); + controller->appendMessage( + CM_setGroupInviter, + 0.0f, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + } + else + { + m_groupInviter = PlayerAndShipPair(std::make_pair(inviterId, inviterName), inviterShipId); + } +} + +// -------------------------------------------------------------------------- + +NetworkId const &CreatureObject::getInviterForPendingGroup() const +{ + // We agreed to join a group and this is the guy that invited us + return m_inviterForPendingGroup.get(); +} + +// -------------------------------------------------------------------------- + +void CreatureObject::setInviterForPendingGroup(NetworkId const &inviterId) +{ + // Once we agree to join a group, we keep track of who extended + // the invitation until we get an actual group object + m_inviterForPendingGroup = inviterId; +} + +// -------------------------------------------------------------------------- + +void CreatureObject::notifyTargetChange(int lastBehavior, int newBehavior, bool * i_targetsChanged) +{ + bool sendMessage = false; + Scripting::TrigId notification = Scripting::TRIG_TARGET_CHANGE; + ScriptParams params; + params.addParam(newBehavior); + if (lastBehavior != newBehavior) + { + notification = Scripting::TRIG_BEHAVIOR_CHANGE; + params.addParam(lastBehavior); + sendMessage = true; + } + std::vector targetListChanged; + targetListChanged.reserve(Behaviors::NumberOfBehaviors); + targetListChanged.resize(Behaviors::NumberOfBehaviors); + int i; + for (i=0; itrigAllScripts(notification, params)); + } +} + +// ---------------------------------------------------------------------- + +CreatureAttitude const *CreatureObject::getAttitudeToward(NetworkId const &target) const +{ + Archive::AutoDeltaMap::const_iterator i = m_mentalStatesToward.find(target); + if (i == m_mentalStatesToward.end()) + return 0; + return &i->second; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::clipMentalStatesToward() +{ + float maxDeltas[MentalStates::NumberOfMentalStates]; + float minValues[MentalStates::NumberOfMentalStates]; + MentalStates::Enumerator state; + for (state=0; state::const_iterator i = m_mentalStatesToward.begin(); + Archive::AutoDeltaMap::const_iterator e = m_mentalStatesToward.end(); + for (; i != e; ++i) + { + CreatureAttitude newState = i->second; + for (state=0; statesecond.m_currentValues[state]; + if (delta > maxDeltas[state]) + { + newState.m_currentValues[state] = maxDeltas[state]; + } + else if (delta < minValues[state]) + { + newState.m_currentValues[state] = 0; + } + } + m_mentalStatesToward.set(i->first, newState); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::deleteUnusedMentalStatesToward(bool * i_behaviorChanged) +{ + Archive::AutoDeltaMap::const_iterator i = m_mentalStatesToward.begin(); + Archive::AutoDeltaMap::const_iterator e = m_mentalStatesToward.end(); + std::vector to_erase; + for (; i != e; ++i) + { + ServerObject * object = ServerWorld::findObjectByNetworkId(i->first); + bool erase = true; + int state; + if (object) + { + for (state=0; statesecond.m_currentValues[state] > 0) + erase = false; + } + } + if (erase) + { + int currentObjectBehavior = i->second.m_behavior; + if (currentObjectBehavior != -1) // if -1, we are deleting an object that was added and removed in the same alter + { + if (currentObjectBehavior < Behaviors::Calm || currentObjectBehavior >= Behaviors::NumberOfBehaviors) + { + DEBUG_REPORT_LOG(true, ("deleteUnusedMentalStatesToward: currentBehavior %d is invalid", currentObjectBehavior)); + } + else + { + std::set::iterator currentTargetByBehaviorIter = m_targetsByBehavior[currentObjectBehavior].find(i->first); + if (currentTargetByBehaviorIter != m_targetsByBehavior[currentObjectBehavior].end()) + { + i_behaviorChanged[currentObjectBehavior] = true; + m_targetsByBehavior[currentObjectBehavior].erase(currentTargetByBehaviorIter); + } + } + } + to_erase.push_back(i->first); + } + } + std::vector::iterator tei; + for (tei = to_erase.begin(); tei!=to_erase.end(); ++tei) + { + m_mentalStatesToward.erase(*tei); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setMentalStateToward(const NetworkId &target, MentalStates::Enumerator state, MentalStates::Value value) +{ + if(! isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setMentalStateToward, new MessageQueueGenericValueType > >(std::make_pair(target, std::make_pair(state, value)))); + } + else + { + if (state < 0 || state >= MentalStates::NumberOfMentalStates) + { + DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); + return; + } + + ServerObject * object = ServerWorld::findObjectByNetworkId(target); + if (!object) + return; + + CreatureAttitude const * const cs = getAttitudeToward(target); + CreatureAttitude newState; + + if (!cs && value <= 0) + return; + + if (cs) + { + newState = *cs; + } + newState.m_currentValues[state] = value; + m_mentalStatesToward.set(target, newState); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setMentalStateTowardClampBehavior(const NetworkId &target, MentalStates::Enumerator state, MentalStates::Value value, Behaviors::Enumerator behavior) +{ + if(! isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setMentalStateTowardClampBehavior, new MessageQueueGenericValueType > > >(std::make_pair(target, std::make_pair(state, std::make_pair(value, behavior))))); + } + else + { + if (state < 0 || state >= MentalStates::NumberOfMentalStates) + { + DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); + return; + } + + if (behavior < Behaviors::Calm || behavior >= Behaviors::NumberOfBehaviors) + { + DEBUG_REPORT_LOG(true, ("setMentalStateTowardClampBehavior: behavior %d is invalid", behavior)); + return; + } + + ServerObject * object = ServerWorld::findObjectByNetworkId(target); + if (!object) + return; + + CreatureAttitude const * const cs = getAttitudeToward(target); + if (!cs && value <= 0) + return; + + CreatureAttitude newState; + if (cs) + { + newState = *cs; + } + float oldValue = newState.m_currentValues[state]; + + float maxValue = 0; + if (behavior >= Behaviors::Alert && behavior <= Behaviors::Retreat) // [1..3] 4 = flee + { + if (state != MentalStates::Fear) + { + DEBUG_REPORT_LOG(true, ("Bad mental state %d for behavior %d in setMentalStateTowardClampBehavior", state, behavior)); + return; + } + maxValue = m_fearCutoffs[behavior - Behaviors::Alert + 2]; // [2..4] out of [0..4] + } + else if (behavior == Behaviors::Attack) // [5] 6 = frenzy + { + if (state != MentalStates::Anger) + { + DEBUG_REPORT_LOG(true, ("Bad mental state %d for behavior %d in setMentalStateTowardClampBehavior", state, behavior)); + return; + } + maxValue = m_angerCutoffs[behavior - Behaviors::Attack + 2]; // [2..2] out of [0..2] + } + else if (behavior == Behaviors::Calm) + { + if (state == MentalStates::Fear) + { + maxValue = m_fearCutoffs[behavior+1]; + } + else + { + maxValue = 0.0f; + } + } + else + { + maxValue = 1e30f; // allow any value + } + maxValue = std::max(0.0f, maxValue - 1.0f); + if (oldValue < maxValue) + { + if (value > maxValue) + value = maxValue; + + newState.m_currentValues[state] = value; + m_mentalStatesToward.set(target, newState); + } + } +} + +//----------------------------------------------------------------------- + +/** +* Gets the creatures current state. 0 = calm, 1-4 = afraid, 5-7 = angry. +*/ + +bool CreatureObject::updateBehavior(const NetworkId * id, CreatureAttitude &state) const +{ + int attitude = state.m_behavior; + float anger = id ? getMentalStateToward(*id, MentalStates::Anger) : getMentalState(MentalStates::Anger); + float fear = id ? getMentalStateToward(*id, MentalStates::Fear) : getMentalState(MentalStates::Fear); + + while ((state.m_fearState > 0) && fear <= m_fearCutoffs[state.m_fearState-1]) // much less fearful than current state + { + state.m_fearState = static_cast(state.m_fearState - 1); + } + while ((state.m_fearState < CreatureAttitude::kFearStateCount-1) && fear >= m_fearCutoffs[state.m_fearState+1]) + { + state.m_fearState = static_cast(state.m_fearState + 1); + } + if (anger == 0) + state.m_angerState = CreatureAttitude::kAngerCalm; + else + { + while ((state.m_angerState > CreatureAttitude::kAngerAttack) && anger <= m_angerCutoffs[state.m_angerState-1]) // much less angry than current state + { + state.m_angerState = static_cast(state.m_angerState - 1); + } + while ((state.m_angerState < CreatureAttitude::kAngerStateCount-1) && anger >= m_angerCutoffs[state.m_angerState+1]) + { + state.m_angerState = static_cast(state.m_angerState + 1); + } + } + + if (anger > 0) + { + if (state.m_angerState == CreatureAttitude::kAngerCalm) // got here somehow, I don't know + state.m_behavior = CreatureAttitude::kAngerAttack + CreatureAttitude::kFearStateCount-1; + else + state.m_behavior = state.m_angerState + CreatureAttitude::kFearStateCount-1; + } + else + { + if (state.m_fearState == CreatureAttitude::kFearCalm) + state.m_behavior = 0; + else + state.m_behavior = state.m_fearState; + } + + return state.m_behavior != attitude; +} + +//----------------------------------------------------------------------- + +/** + * Returns the list of draft schematics this creature can use. + * + * @return the schematic list + */ +const std::map,int> & CreatureObject::getDraftSchematics() const +{ +static const std::map,int> npcSchematics; + + if (isPlayerControlled()) + { + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + return playerObject->getDraftSchematics(); + } + return npcSchematics; +} // CreatureObject::getDraftSchematics + +//----------------------------------------------------------------------- + +/** + * Tests if a given ingredient for use in crafting is in this creature's inventory. + * + * @param ingredient the ingredient to test + * + * @return true if the ingredient in in our inventory, false if not + */ +bool CreatureObject::isIngredientInInventory(const Object & ingredient) const +{ + const ServerObject * inventory = getInventory(); + if (inventory == NULL) + return false; + + const Object * container = ContainerInterface::getContainedByObject(ingredient); + while (container != NULL) + { + if (inventory->getNetworkId() == container->getNetworkId() || + getNetworkId() == container->getNetworkId()) + { + return true; + } + // go up a container level + container = ContainerInterface::getContainedByObject(*container); + } + return false; +} // CreatureObject::isIngredientInInventory + +//----------------------------------------------------------------------- + +/** + * Disables schematic filtering when this creature crafts. Note this only works + * if the creature is controlled by a god-mode player. + */ +void CreatureObject::disableSchematicFiltering() +{ + if (getClient() == NULL || !getClient()->isGod()) + return; + + setObjVarItem(OBJVAR_DISABLE_SCHEMATIC_FILTER, 1); +} // CreatureObject::disableSchematicFiltering + +//----------------------------------------------------------------------- + +/** + * Enables schematic filtering when this creature crafts. Note this only works + * if the creature is controlled by a god-mode player. + */ +void CreatureObject::enableSchematicFiltering() +{ + if (getClient() == NULL || !getClient()->isGod()) + return; + + removeObjVarItem(OBJVAR_DISABLE_SCHEMATIC_FILTER); +} // CreatureObject::enableSchematicFiltering + +//----------------------------------------------------------------------- + +/** + * Returns if schematic filtering is enabled or not. Note this only works + * if the creature is controlled by a god-mode player. + * + * @return true if filtering is on, false if it is off + */ +bool CreatureObject::isSchematicFilteringEnabled() +{ + if (getClient() == NULL || !getClient()->isGod()) + return true; + + return (!getObjVars().hasItem(OBJVAR_DISABLE_SCHEMATIC_FILTER)); +} // CreatureObject::isSchematicFilteringEnabled + +//----------------------------------------------------------------------- + +/** + * Returns a list of manufacture schematics in this creature's datapad. + * + * @param schematics list to be filled with the schematics + */ +void CreatureObject::getManufactureSchematics(std::vector & schematics) +{ + const ServerObject * datapad = getDatapad(); + if (datapad == NULL) + return; + const VolumeContainer * container = ContainerInterface::getVolumeContainer(*datapad); + if (container == NULL) + return; + + for (ContainerConstIterator iter = container->begin(); iter != container->end(); ++iter) + { + const ManufactureSchematicObject * schematic = dynamic_cast((*iter).getObject()); + if (schematic != NULL) + schematics.push_back(schematic); + } +} // CreatureObject::getManufactureSchematics(unfiltered) + +//----------------------------------------------------------------------- + +/** + * Returns a list of manufacture schematics in this creature's datapad, filtered + * by a bitmask of crafting types. + * + * @param schematics list to be filled with the schematics + * @param craftingTypes bitmask of valid crafting types + */ +void CreatureObject::getManufactureSchematics(std::vector & schematics, uint32 craftingTypes) +{ + const ServerObject * datapad = getDatapad(); + if (datapad == NULL) + return; + const VolumeContainer * container = ContainerInterface::getVolumeContainer(*datapad); + if (container == NULL) + return; + + for (ContainerConstIterator iter = container->begin(); iter != container->end(); ++iter) + { + const ManufactureSchematicObject * schematic = dynamic_cast((*iter).getObject()); + if (schematic != NULL && ((schematic->getCategory() & craftingTypes) != 0)) + schematics.push_back(schematic); + } +} // CreatureObject::getManufactureSchematics(filtered) + +//----------------------------------------------------------------------- + + +bool CreatureObject::isItemEquipped(const Object & item) const +{ + Object const * const itemContainedBy = ContainerInterface::getContainedByObject (item); + + if (itemContainedBy) + { + return (getNetworkId () == itemContainedBy->getNetworkId ()); + } + + return false; +} + +//----------------------------------------------------------------------- + +void CreatureObject::getBehaviorTargets(int behavior, std::vector &targets) +{ + if (behavior < 0 || behavior >= Behaviors::NumberOfBehaviors) + { + return; + } + + targets.clear(); + targets.reserve(m_targetsByBehavior[behavior].size()); + targets.resize(m_targetsByBehavior[behavior].size()); + std::set::const_iterator i; + std::vector::iterator src = targets.begin(); + for (i=m_targetsByBehavior[behavior].begin(); i!= m_targetsByBehavior[behavior].end(); ++i) + { + *src++=*i; + } +} + +//----------------------------------------------------------------------- + +int CreatureObject::getBehavior() const +{ + return m_lastBehavior.get(); +} + + +//----------------------------------------------------------------------- + +int CreatureObject::getBehaviorToward(const NetworkId &target) const +{ + CreatureAttitude const * const cs = getAttitudeToward(target); + if (!cs) + return 0; + return cs->m_behavior; +} + +//---------------------------------------------------------------------- + +int CreatureObject::getNiche() const +{ + const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); + return static_cast(sharedTemplate->getNiche()); +} + +//---------------------------------------------------------------------- + +SharedCreatureObjectTemplate::Species CreatureObject::getSpecies() const +{ + const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); + return static_cast(sharedTemplate->getSpecies()); +} + +//---------------------------------------------------------------------- + +SharedCreatureObjectTemplate::Race CreatureObject::getRace() const +{ + const SharedCreatureObjectTemplate * sharedTemplate = safe_cast(getSharedTemplate()); + return static_cast(sharedTemplate->getRace()); +} + +//---------------------------------------------------------------------- +/* +void CreatureObject::setAnimationState(CreatureObject::AnimationState state) +{ + m_animState = static_cast(state); +} +*/ +//---------------------------------------------------------------------- + +void CreatureObject::setMood(uint32 mood) +{ + if(isAuthoritative()) + { + DEBUG_WARNING (mood > 255, ("Mood %d out of range", mood)); + m_mood = static_cast(mood); + } + else + { + sendControllerMessageToAuthServer(CM_setMood, new MessageQueueGenericValueType(mood)); + } +} + +//---------------------------------------------------------------------- + +/** + * Sets the incapacitated state on the creature. + * + * @param flag true to incapacitate, false to recapacitate + * @param attacker who incapacitated us + */ +void CreatureObject::setIncapacitated(bool flag, const NetworkId & attackerId) +{ + if (isAuthoritative()) + { + if (flag) + { + clearHateList(); + } + + int oldPosture = getPosture(); + if (flag && oldPosture != Postures::Incapacitated) + { + ScriptParams params; + params.addParam(attackerId); + if (getScriptObject()->trigAllScripts( + Scripting::TRIG_ABOUT_TO_BE_INCAPACITATED, params) == SCRIPT_OVERRIDE) + { + LOG("CustomerService", ("Combat: %s not incapacitated due to script", + PlayerObject::getAccountDescription(this).c_str())); + return; + } + LOG("CustomerService", ("Combat: %s incapacitated", + PlayerObject::getAccountDescription(this).c_str())); + + // if we are crafting, end the crafting session + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + if (player != NULL && player->isCrafting()) + player->stopCrafting(false); + + if (isInNpcConversation()) + endNpcConversation(); + + setPosture(Postures::Incapacitated); + setState(States::FeignDeath, false); + + // invoke incapacitation script on us + if (oldPosture != Postures::Dead) + { + params.clear(); + params.addParam(attackerId); + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_INCAPACITATED, params)); + if (attackerId != NetworkId::cms_invalid) + { + // invoke incapacitation script on who incapacitated us + ServerObject * attacker = safe_cast( + NetworkIdManager::getObjectById(attackerId)); + if (attacker != NULL) + { + params.clear(); + params.addParam(getNetworkId()); + IGNORE_RETURN(attacker->getScriptObject()->trigAllScripts( + Scripting::TRIG_INCAPACITATE_TARGET, params)); + + TangibleObject * const tangibleAttacker = attacker->asTangibleObject(); + + if (tangibleAttacker != NULL) + { + tangibleAttacker->verifyHateList(); + } + } + } + } + } + else if (!flag && oldPosture == Postures::Incapacitated) + { + // allow scripts to prevent recapacitation + ScriptParams params; + if (getScriptObject()->trigAllScripts(Scripting::TRIG_RECAPACITATED, + params) == SCRIPT_OVERRIDE) + { + LOG("CustomerService", ("Combat: %s not recapacitated due to script", + PlayerObject::getAccountDescription(this).c_str())); + return; + } + + LOG("CustomerService", ("Combat: %s recapacitated", + PlayerObject::getAccountDescription(this).c_str())); + // recapacitate us + // Force the stand command to execute + setPosture(Postures::Upright); + } + // if we are a player, send us our new posture + if ((getController() != NULL) && !isInCombat()) + { + getController()->appendMessage( + CM_setPosture, + 0.0f, + new MessageQueuePosture(getPosture(), true), + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_ALL_CLIENT + ); + } + } + else + { + sendControllerMessageToAuthServer(CM_setIncapacitated, new MessageQueueGenericValueType >(std::make_pair(flag, attackerId))); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::updateMovementInfo() +{ + // TODO RAD - figure out a real fix for this + if (!canMove() && !isPlayerControlled()) + m_stopWalkRun = 0; + + //-- Retrieve walk and run multipliers from movement table. These are based on the creature's posture and states. + float walkSpeedModifier = 0.0f; + float runSpeedModifier = 0.0f; + + float accelScale = 0.0f; + float turnScale = 0.0f; + + getMovementTable()->getAllMovementRateScales(m_posture.get(), m_states.get(), walkSpeedModifier, runSpeedModifier, accelScale, turnScale); + m_accelScale = accelScale; + m_turnScale = turnScale; + + DEBUG_WARNING((walkSpeedModifier > 0.0f) && (runSpeedModifier > 0.0f) && (walkSpeedModifier != runSpeedModifier), ("updateMovementInfo(): both walk and run speed are nonzero but not equal,walk=[%g],run=[%g].", walkSpeedModifier, runSpeedModifier)); + m_movementScale = std::max(walkSpeedModifier, runSpeedModifier); + + //-- Calculate walk and run speed. + m_walkSpeed = (walkSpeedModifier > 0.0f) ? getBaseWalkSpeed() : 0.0f; + m_runSpeed = (runSpeedModifier > 0.0f) ? getBaseRunSpeed() : 0.0f; + + // If this creature is mounted, we want this creature's walkSpeed, runSpeed, movementScale and movementPercent set to the mount's + if (getState(States::RidingMount)) + { + CreatureObject *const mountedCreature = getMountedCreature(); + if (mountedCreature) + { + if (GameObjectTypes::isTypeOf (mountedCreature->getGameObjectType (), SharedObjectTemplate::GOT_vehicle) && + mountedCreature->m_vehiclePhysicsData) + { + m_runSpeed = mountedCreature->m_vehiclePhysicsData->m_runSpeed; + m_walkSpeed = mountedCreature->m_vehiclePhysicsData->m_walkSpeed; + } + else + { + m_walkSpeed = mountedCreature->getBaseWalkSpeed(); + m_runSpeed = mountedCreature->getBaseRunSpeed(); + } + } + } + + //-- Update fast/slow/stationary locomotion mappings. + getAvailableLocomotions(); + + //-- Choose locomotion. + m_locomotion = calcLocomotion(); + + // if the posture isn't sneak, make sure we don't have cover + if (getPosture() != Postures::Sneaking && getCover() != 0) + setCover(0); + + // if we are prone and have a movement mod > 50, increase our movement rate + if (getPosture() == Postures::Prone) + { + int movementMod = getEnhancedModValue(SLOPE_MOD); + GroupObject const *group = getGroup(); + if (group) + { + // get my group leader skill mod + NetworkId const &leaderId = group->getGroupLeaderId(); + if (leaderId != NetworkId::cms_invalid) + { + Object const *o = NetworkIdManager::getObjectById(leaderId); + if (o) + { + ServerObject const *so = o->asServerObject(); + if (so) + { + CreatureObject const *co = so->asCreatureObject(); + if (co) + movementMod += co->getEnhancedModValue(GROUP_SLOPE_MOD); + } + } + } + } + if (movementMod > 50) + { + float moveScale, accelScale, turnScale; + getMovementTable()->getRates(Postures::Upright, moveScale, accelScale, turnScale); + + movementMod -= 50; + if (movementMod > 50) + movementMod = 50; + float modScale = (movementMod / 50.0f) * ((moveScale / m_movementScale.get()) - 1.0f) + 1.0f; + m_movementScale = m_movementScale.get() * modScale; + } + } + + //-- Mounts: update to a mount's movement info needs to propagate to + // its rider. + if (getState(States::MountedCreature)) + { + typedef std::vector Riders; + Riders riders; + + getMountingRiders(riders); + + Riders::const_iterator ii = riders.begin(); + Riders::const_iterator iiEnd = riders.end(); + + for (; ii != iiEnd; ++ii) + { + CreatureObject *const rider = * ii; + + if (rider) + rider->requestMovementInfoUpdate(); + else + { + LOG("mounts-bug", ("CreatureObject::updateMovementInfo(): server id=[%d],mount id=[%s],has MountedCreature state but getMountingRider() returns null.", static_cast(GameServer::getInstance().getProcessId()), getNetworkId().getValueString().c_str())); + detachAllRiders(); + } + } + } + + //-- Prevent player from moving while stunned + if (getState(States::Stunned)) + { + m_turnScale = 0.0f; + m_movementScale = 0.0f; + } +} + +//---------------------------------------------------------------------- + +/** + * Sets a creature's posture, if it's allowed for its current state. This function + * should be called directly if source is CS_player, otherwise it should be called + * from setCombatState(). + * + * Note: callers should set isClientImmediate to false (the default) if changing + * posture during combat. Combat generally controls when the client visuals for + * posture will actually change. Setting isClientImmediate to true causes the client + * to drop any combat actions currently playing involving this creature and will + * make the client's visual posture change immediately. + * + * @param posture the new posture. + * @param isClientImmediate if set, the client changes visual posture immediately; + * otherwise, combat is assumed to migrate to this posture + * at the appropriate time (as instructed by the combat action + * message) or the client will revert to this new server posture + * in 5 seconds (as of this writing). + */ +void CreatureObject::setPosture(Postures::Enumerator newPosture, bool isClientImmediate) +{ + //-- vehicles can't be anything but upright + if (newPosture != Postures::Upright && GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + WARNING (true, ("CreatureObject attempt to set a vehicle to posture [%d].", newPosture)); + return; + } + + //-- Only do server message processing if the posture changed, but always send the + // posture to the clients if isClientImmediate is true --- the client visual posture + // is unknown on the server and may be different than the server posture. + Postures::Enumerator oldPosture = m_posture.get(); + bool const doServerProcessing = (oldPosture != newPosture); + + if (doServerProcessing) + { + //-- Process the posture change on the server only if the posture changed. + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setPosture, new MessageQueuePosture(newPosture, isClientImmediate)); + return; + } + + if (getMovementTable()->getLocomotion(newPosture, m_states.get(), MovementTable::kStationary) != Locomotions::Invalid) + { + Postures::Enumerator oldPosture = m_posture.get(); + + m_posture = newPosture; + + // If we were previously sitting on a chair, clear the flag. + if(oldPosture == Postures::Sitting) + setState(States::SittingOnChair, false); + + // @todo revisit this. updateMoevementInfo() indirectly changes auto delta variables. Since this isn't + // guaranteed to be the authoritative object, this is an invalid thing to do. + requestMovementInfoUpdate(); + + if (getScriptObject() != NULL) + { + ScriptParams params; + params.addParam(oldPosture); + params.addParam(newPosture); + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_CHANGED_POSTURE, params)); + } + + recomputeSlopeModPercent(); + } + } + + //-- Handle posture changes that should take effect immediately on the client. + if (isClientImmediate) + { + //-- Send if we're the authoritative server OR if we're not passing the message on to the authoritative server. + // This guarantees that we only send this message to the clients once. + bool const sendToClient = isAuthoritative() || !doServerProcessing; + if (sendToClient) + { + Controller *const controller = getController(); + if (controller) + controller->appendMessage(CM_setPosture, 0.0f, new MessageQueuePosture(newPosture, true), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); + else + DEBUG_WARNING(true, ("setPosture(): called with isClientImmediate but object id=[%s],template=[%s] has no controller.", getNetworkId().getValueString().c_str(), getObjectTemplateName())); + } + } +} + +// ---------------------------------------------------------------------- +/** + * Call this function to request that movement info be updated at the + * end of the next frame's alter. + * + * This function was needed to delay the updateMovementInfo() until + * after all transitive mount-related state was complete. It has the + * side effect of preventing the call from being made multiple times + * in the same frame. + */ + +void CreatureObject::requestMovementInfoUpdate() +{ + setLocalFlag(LocalObjectFlags::CreatureObject_RequiresMovementInfoUpdate, true); +} + +//----------------------------------------------------------------------- + +void CreatureObject::setCover(int cover) +{ + if(!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setCover, new MessageQueueGenericValueType(cover)); + } + else + { + m_cover = cover; + } +} + +// ---------------------------------------------------------------------- + +/** + * Sets the value of a state on a creature, if it's allowed for its current + * state. + * + * @param whichState which state to change + * @param value new value of the state + */ +void CreatureObject::setState(States::Enumerator whichState, bool value) +{ + if (isAuthoritative()) + { + if(whichState == States::Combat) + { + setInCombat(value); + return; + } + + //-- vehicles can't have most states + if (value && GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + switch (whichState) + { + case States::MountedCreature: + case States::Swimming: + case States::Combat: + // these states are okay for a vehicle to have, continue on with state change processing. + break; + + default: + // all other states are not okay for a vehicle to have, warn about them. + WARNING (true, ("CreatureObject id=[%s] attempt to set state id=[%d], name=[%s] on a vehicle, unsupported.", getNetworkId().getValueString().c_str(), whichState, States::getStateName(whichState))); + return; + } + } + + uint64 stateFlags = m_states.get(); + + // enforce a no state change if the creature is a glowing Jedi + if (value) + stateFlags |= States::getStateMask(whichState); + else + stateFlags &= ~States::getStateMask(whichState); + if (m_states.get() != stateFlags) + { + m_states = stateFlags; + requestMovementInfoUpdate(); + } + } + else + { + sendControllerMessageToAuthServer(CM_setState, new MessageQueueSetState(static_cast(whichState), value)); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setSayMode(uint32 sayMode) +{ + if(isAuthoritative()) + { + DEBUG_WARNING (sayMode > 255, ("Saymode %d out of range", sayMode)); + m_sayMode = static_cast(sayMode); + } + else + { + sendControllerMessageToAuthServer(CM_setSayMode, new MessageQueueGenericValueType(sayMode)); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setAnimationMood(const std::string & mood) +{ + if(isAuthoritative()) + { + m_animationMood = mood; + } + else + { + sendControllerMessageToAuthServer(CM_setAnimationMood, new MessageQueueGenericValueType(mood)); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setAttribute(Attributes::Enumerator attribute, Attributes::Value value) +{ + if(!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setAttribute, new MessageQueueGenericValueType >(std::make_pair(attribute, value))); + } + else + { + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + { + DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); + return; + } + if (!Attributes::isAttribPool(attribute)) + { + WARNING(true, ("CreatureObject::setAttribute called with non-pool attribute %d on creature %s. If this is a regeneration value, call setRegenRate() instead.", + attribute, getNetworkId().getValueString().c_str())); + return; + } + const Attributes::Value currentValue = m_attributes[attribute]; + IGNORE_RETURN(alterAttribute(attribute, value - currentValue, true)); + } +} + +//---------------------------------------------------------------------- + +/** Set the maximum value for an attribute. Optionally revalidate the stats for players. + */ +void CreatureObject::setMaxAttribute(Attributes::Enumerator attribute, Attributes::Value value, bool verifyPlayerMaxStats) +{ + if(! isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setMaxAttribute, new MessageQueueGenericValueType >(std::make_pair(attribute, value))); + } + else + { + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + { + DEBUG_REPORT_LOG(true, ("attribute out of range (%d)\n", attribute)); + return; + } + if (!Attributes::isAttribPool(attribute)) + { + WARNING(true, ("CreatureObject::setMaxAttribute called with non-pool attribute %d on creature %s. If this is a regeneration value, call setRegenRate() instead.", + attribute, getNetworkId().getValueString().c_str())); + return; + } + m_maxAttributes.set(attribute, value); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setMentalState(MentalStates::Enumerator state, MentalStates::Value value) +{ + if(! isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setMentalState, new MessageQueueGenericValueType >(std::make_pair(state, value))); + } + else + { + if (state < 0 || state >= MentalStates::NumberOfMentalStates) + { + DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); + return; + } + + if (value > m_maxMentalStates[state]) + value = m_maxMentalStates[state]; + else if (value < 0) + value = 0; + CreatureAttitude newState = m_currentAttitude.get(); + newState.m_currentValues[state] = value; + m_currentAttitude.set(newState); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setMaxMentalState(MentalStates::Enumerator state, MentalStates::Value value) +{ + if(isAuthoritative()) + { + if (state < 0 || state >= MentalStates::NumberOfMentalStates) + { + DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); + return; + } + + m_maxMentalStates.set(state, value); + } + else + { + sendControllerMessageToAuthServer(CM_setMaxMentalState, new MessageQueueGenericValueType >(std::make_pair(state, value))); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setMentalStateDecay(MentalStates::Enumerator state, float value) +{ + if(! isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setMentalStateDecay, new MessageQueueGenericValueType >(std::make_pair(state, value))); + } + else + { + if (state < 0 || state >= MentalStates::NumberOfMentalStates) + { + DEBUG_REPORT_LOG(true, ("mental state out of range (%d)\n", state)); + return; + } + + m_mentalStateDecays.set(state, value); + } +} + +//---------------------------------------------------------------------- + +ServerObject *CreatureObject::getObjectInSlot(ConstCharCrcLowerString const &slotName) +{ + SlottedContainer * const s = ContainerInterface::getSlottedContainer(*this); + if (s) + { + SlotId const dp = SlotIdManager::findSlotId(slotName); + Container::ContainerErrorCode tmp = Container::CEC_Success; + return safe_cast(s->getObjectInSlot(dp, tmp).getObject()); + } + + return 0; +} + +//---------------------------------------------------------------------- + +const ServerObject * CreatureObject::getObjectInSlot (const ConstCharCrcLowerString & slotName) const +{ + return const_cast(this)->getObjectInSlot (slotName); +} + +//----------------------------------------------------------------------- + +ServerObject * CreatureObject::getDatapad() +{ + return getObjectInSlot (SlotNames::datapad); +} + +//---------------------------------------------------------------------- + +const ServerObject * CreatureObject::getDatapad() const +{ + return const_cast(this)->getDatapad (); +} + +//---------------------------------------------------------------------- + +ServerObject * CreatureObject::getBank () +{ + return getObjectInSlot (SlotNames::bank); +} + +//---------------------------------------------------------------------- + +const ServerObject * CreatureObject::getBank () const +{ + return const_cast(this)->getBank (); +} + +//----------------------------------------------------------------------- + +ServerObject * CreatureObject::getInventory() +{ + return getObjectInSlot (SlotNames::inventory); +} + +//---------------------------------------------------------------------- + +const ServerObject * CreatureObject::getInventory() const +{ + return const_cast(this)->getInventory (); +} + +//---------------------------------------------------------------------- + +ServerObject * CreatureObject::getHair() +{ + return getObjectInSlot (SlotNames::hair); +} + +//------------------------------------------------------------------------ + +const ServerObject * CreatureObject::getHair() const +{ + return const_cast(this)->getHair (); +} + +//---------------------------------------------------------------------- + + +ServerObject * CreatureObject::getAppearanceInventory() +{ + return getObjectInSlot (SlotNames::appearance); +} + +//---------------------------------------------------------------------- + +const ServerObject * CreatureObject::getAppearanceInventory() const +{ + return const_cast(this)->getAppearanceInventory (); +} + +//---------------------------------------------------------------------- + + +ServerObject * CreatureObject::getHangar() +{ + return getObjectInSlot (SlotNames::hangar); +} + +//---------------------------------------------------------------------- + +const ServerObject * CreatureObject::getHangar() const +{ + return const_cast(this)->getHangar(); +} + + +//----------------------------------------------------------------------- + +bool CreatureObject::onContainerAboutToTransfer(ServerObject * destination, ServerObject* transferer) +{ + bool const baseResult = TangibleObject::onContainerAboutToTransfer(destination, transferer); + if (!baseResult) + return false; + + const PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + // let's prevent CS from putting any more players in their inventories + if(player && destination) + { + const CreatureObject * creatureDestination = destination->asCreatureObject(); + if(creatureDestination) + { + const PlayerObject * const playerDestination = PlayerCreatureController::getPlayerObject(creatureDestination); + if(playerDestination) + { + return false; + } + } + } + return onContainerAboutToTransferForMounts(destination, transferer); +} + + +/** + * Callback for when the creature is about to equip an item. Checks to make sure + * we don't equip two shields, and prevents equiping armor that would incapacitate + * us. + * + * @param item the item being equipped + * @param transferer who is causing the item to be equipped + * + * @return true to allow the transfer, false to prevent it + */ +int CreatureObject::onContainerAboutToGainItem(ServerObject& item, ServerObject* transferer) +{ + TangibleObject const * const object = item.asTangibleObject(); + if (object != NULL) + { + // See if this item is equippable + const char *sharedTemplateName = item.getSharedTemplateName(); + if (!isAppearanceEquippable(sharedTemplateName)) + { + if (getClient() != NULL) + { + StringId message("shared", "item_not_equippable"); + Unicode::String outOfBand; + Chat::sendSystemMessage(*this, message, outOfBand); + return Container::CEC_SilentError; + } + else + return Container::CEC_BlockedByDestinationContainer; + } + } + + + return TangibleObject::onContainerAboutToGainItem(item, transferer); +} // CreatureObject::onContainerAboutToGainItem + +//---------------------------------------------------------------------- + +/** + * Callback for when the creature unequips an item. + * + * @param destination where the item was transferred to + * @param item the item that was unequipped + * @param transferer who caused the transfer + */ +void CreatureObject::onContainerLostItem(ServerObject *destination, ServerObject &item, ServerObject *transferer) +{ + TangibleObject const * const tangibleObject = item.asTangibleObject(); + if (tangibleObject == NULL) + return; + + // check if the object applies skill mod bonuses when equipped + { + std::vector > skillModBonuses; + tangibleObject->getSkillModBonuses(skillModBonuses); + int const bonusCount = skillModBonuses.size(); + if (bonusCount > 0) + { + std::vector modNames(bonusCount); + std::vector modValues(bonusCount); + for (int i = 0; i < bonusCount; ++i) + { + std::pair const &bonus = skillModBonuses[i]; + addModBonus(bonus.first, -bonus.second); + modNames[i] = bonus.first.c_str(); + modValues[i] = -bonus.second; + } + ScriptParams params; + params.addParam(modNames); + params.addParam(modValues); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILLMODS_CHANGED, params)); + } + } + + // check if the object applies attribute bonuses when equipped + { + std::vector > attribBonuses; + tangibleObject->getAttribBonuses(attribBonuses); + int const bonusCount = attribBonuses.size(); + for (int i = 0; i < bonusCount; ++i) + { + std::pair const &bonus = attribBonuses[i]; + addAttribBonus(bonus.first, -bonus.second); + } + } + + + + // if the item is a weapon, make our current weapon our default weapon + WeaponObject const * const weaponObject = tangibleObject->asWeaponObject(); + if (weaponObject != NULL && getDefaultWeapon() != NULL) + setCurrentWeapon(*getDefaultWeapon()); + + // check if the object is our shield + if (tangibleObject == m_shield) + m_shield = NULL; + + //Update wearbles data + SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); + if (scp) + { + WearableEntry e("", scp->getCurrentArrangement(), item.getNetworkId(), 0); + int index = m_wearableData.find(e); + if (index >= 0) + { + m_wearableData.erase(index); + } + } + + TangibleObject::onContainerLostItem(destination, item, transferer); +} // CreatureObject::onContainerLostItem + +//---------------------------------------------------------------------- + +/** + * Callback for when the creature equips an item. + * shields, and weapons. + * + * @param item the item that was equipped + * @param transferer who caused the transfer + */ +void CreatureObject::onContainerGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) +{ + TangibleObject * const tangibleObject = item.asTangibleObject(); + if (tangibleObject == NULL) + return; + + // check if the object applies skill mod bonuses when equipped + { + std::vector > skillModBonuses; + tangibleObject->getSkillModBonuses(skillModBonuses); + int const bonusCount = skillModBonuses.size(); + if (bonusCount > 0) + { + std::vector modNames(bonusCount); + std::vector modValues(bonusCount); + for (int i = 0; i < bonusCount; ++i) + { + std::pair const &bonus = skillModBonuses[i]; + addModBonus(bonus.first, bonus.second); + modNames[i] = bonus.first.c_str(); + modValues[i] = bonus.second; + } + ScriptParams params; + params.addParam(modNames); + params.addParam(modValues); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SKILLMODS_CHANGED, params)); + } + } + + // check if the object applies attribute bonuses when equipped + { + std::vector > attribBonuses; + tangibleObject->getAttribBonuses(attribBonuses); + int const bonusCount = attribBonuses.size(); + for (int i = 0; i < bonusCount; ++i) + { + std::pair const &bonus = attribBonuses[i]; + addAttribBonus(bonus.first, bonus.second); + } + } + + // if the item is a weapon, make it our current weapon + WeaponObject * const weaponObject = tangibleObject->asWeaponObject(); + if (weaponObject != NULL) + setCurrentWeapon(*weaponObject); + + //Update wearables data + SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); + if (scp) + { + Object const * inventory = 0; + Object const * datapad = 0; + Object const * appearance = 0; + + SlottedContainer const * const myContainer = ContainerInterface::getSlottedContainer(*this); + + if (myContainer) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + static SlotId const inventorySlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); + if (inventorySlot != SlotId::invalid) + { + Container::ContainedItem itemId = myContainer->getObjectInSlot(inventorySlot, tmp); + inventory = itemId.getObject(); + } + SlotId datapadSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::datapad); + if (datapadSlot != SlotId::invalid) + { + Container::ContainedItem itemId = myContainer->getObjectInSlot(datapadSlot, tmp); + datapad = itemId.getObject(); + } + SlotId appearanceInvSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); + if (appearanceInvSlot != SlotId::invalid) + { + Container::ContainedItem itemId = myContainer->getObjectInSlot(appearanceInvSlot, tmp); + appearance = itemId.getObject(); + } + } + + if ( scp->isInAppearanceSlot() || tangibleObject == inventory || tangibleObject == datapad) + { + ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tangibleObject->getClientSharedTemplateName()); + if (clientSharedTemplateNameCrcString.isEmpty()) + WARNING(true, ("Could not find crc for %s. Wearable will not be streamed to client", tangibleObject->getClientSharedTemplateName())); + else if (tangibleObject->asWeaponObject() != NULL) + { + addPackedWearable(tangibleObject->getAppearanceData(), scp->getCurrentArrangement(), tangibleObject->getNetworkId(), clientSharedTemplateNameCrcString.getCrc(), + tangibleObject->createSharedBaselinesMessage(), tangibleObject->createSharedNpBaselinesMessage()); + } + else + addPackedWearable(tangibleObject->getAppearanceData(), scp->getCurrentArrangement(), tangibleObject->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); + } + } + + TangibleObject::onContainerGainItem(item, source, transferer); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::onContainerTransferComplete(ServerObject *oldContainer, ServerObject *newContainer) +{ + TangibleObject::onContainerTransferComplete(oldContainer, newContainer); + + setStatesDueToContainment(); + + if (!isInWorld()) + setMovementStationary(); + + ShipObject const * const oldContainingShipObject = ShipObject::getContainingShipObject(oldContainer); + ShipObject const * const newContainingShipObject = ShipObject::getContainingShipObject(newContainer); + + if (oldContainingShipObject != newContainingShipObject) + { + GroupObject * const groupObject = getGroup(); + + if (groupObject != 0) + { + if (oldContainingShipObject != 0) + { + if (oldContainingShipObject->getPortalProperty() != 0) + { + if (getNetworkId() == oldContainingShipObject->getOwnerId()) + { + NetworkId const & shipId = oldContainingShipObject->getNetworkId(); + groupObject->removePOBShip(shipId); + } + } + } + + if (newContainingShipObject != 0) + { + if (newContainingShipObject->getPortalProperty() != 0) + { + groupObject->addPOBShipAndOwner(newContainingShipObject->getNetworkId(), newContainingShipObject->getOwnerId()); + } + } + + NetworkId const & shipId = (newContainingShipObject != 0) ? newContainingShipObject->getNetworkId() : NetworkId::cms_invalid; + groupObject->setShipForMember(getNetworkId(), shipId); + } + } + + Client * const client = getClient(); + if (client && ServerWorld::isSpaceScene()) + { + ServerObject const * const oldTopmost = oldContainer ? safe_cast(ContainerInterface::getTopmostContainer(*oldContainer)) : this; + ServerObject * const newTopmost = newContainer ? safe_cast(ContainerInterface::getTopmostContainer(*newContainer)) : this; + if (oldTopmost != newTopmost) + { + SpaceVisibilityManager::removeClient(*client); + SpaceVisibilityManager::addClient(*client, *newTopmost); + } + } +} + +// ---------------------------------------------------------------------- +// this object got added to a trigger volume +void CreatureObject::onAddedToTriggerVolume(TriggerVolume & triggerVolume) +{ + WARNING(!isInWorld(), ("CreatureObject (%s) not in world but being added to TriggerVolume (%s) owned by (%s)", + getDebugInformation().c_str(), + triggerVolume.getName().c_str(), + triggerVolume.getOwner().getDebugInformation().c_str())); + + IGNORE_RETURN(m_triggerVolumeEntered.insert(&triggerVolume)); +} + +// ---------------------------------------------------------------------- +// this object got removed from a trigger volume +void CreatureObject::onRemovedFromTriggerVolume(TriggerVolume & triggerVolume) +{ + // NOTE: be careful about referencing the TriggerVolume because this + // function can be called from the TriggerVolume's dtor + IGNORE_RETURN(m_triggerVolumeEntered.erase(&triggerVolume)); +} + +// ---------------------------------------------------------------------- + +// ---------------------------------------------------------------------- + +/** + * Computes the total attributes and max attributes for sending to clients, + */ +void CreatureObject::computeTotalAttributes () +{ +int i; + + WARNING_STRICT_FATAL(!isAuthoritative(), ("computeTotalAttributes called on nonauthoritative object %s:%s", getObjectTemplateName(), getNetworkId().getValueString().c_str())); + + if (!isAuthoritative()) + return; + + if (m_deferComputeTotalAttributes <= 0) + { + if (m_regenerationTime >= ConfigServerGame::getRegenThreshold()) + { + // send updates to the client + m_regenerationTime -= ConfigServerGame::getRegenThreshold(); + for (i = 0; i < 3; ++i) + { + int poolAttrib = Attributes::POOLS[i]; + const float delta = static_cast(floor(m_regeneration[ + poolAttrib])); + if (delta >= 1.0f) + { + m_regeneration[poolAttrib] -= delta; + IGNORE_RETURN(alterAttribute(poolAttrib, static_cast( + delta), true)); + } + } + } + + if (ConfigServerGame::getCheckAttribLimits()) + { + // check and make sure our current attribs are <= our max attribs, + // for both unmodified and modified versions + for (i = 0; i < Attributes::NumberOfAttributes; ++i) + { + if (Attributes::isAttribPool(i)) + { + if (getUnmodifiedAttribute(i) > getUnmodifiedMaxAttribute(i)) + { + WARNING_STRICT_FATAL(true, ("Creature %s has attribute %d with " + "an unmodified current value > its max value! We will change " + "the current value! Current = %d, max = %d, " + "cur mods = %d, max mods = %d", + getNetworkId().getValueString().c_str(), + i, + static_cast(getUnmodifiedAttribute(i)), + static_cast(getUnmodifiedMaxAttribute(i)), + static_cast(m_cachedCurrentAttributeModValues[i]), + static_cast(m_cachedMaxAttributeModValues[i]))); + m_attributes.set(i, getUnmodifiedMaxAttribute(i)); + } + if (getAttribute(i) > getMaxAttribute(i)) + { + WARNING_STRICT_FATAL(true, ("Creature %s has attribute %d with " + "a current value > its max value! Current = %d(%d), max = " + "%d(%d), cur mods = %d, max mods = %d", + getNetworkId().getValueString().c_str(), + i, + static_cast(getAttribute(i)), + static_cast(getUnmodifiedAttribute(i)), + static_cast(getMaxAttribute(i)), + static_cast(getUnmodifiedMaxAttribute(i)), + static_cast(m_cachedCurrentAttributeModValues[i]), + static_cast(m_cachedMaxAttributeModValues[i]))); + } + } + } + } + + for (i = 0; i < Attributes::NumberOfAttributes; ++i) + { + if (Attributes::isAttribPool(i)) + { + m_totalAttributes.set(i, getAttribute(i) - static_cast(floor(m_regeneration[i]))); + m_totalMaxAttributes.set(i, getMaxAttribute(i)); + } + } + } +} // CreatureObject::computeTotalAttributes + +//---------------------------------------------------------------------- + +void CreatureObject::resetAttribute (Attributes::Enumerator attrib, Attributes::Value value) +{ + setMaxAttribute (attrib, value); + setAttribute (attrib, value); + m_shockWounds = 0; +} + +//---------------------------------------------------------------------- + +void CreatureObject::initializeAttribute(Attributes::Enumerator attrib, Attributes::Value value) +{ + m_maxAttributes.set(attrib, value); + m_attributes.set (attrib, value); +} + +//---------------------------------------------------------------------- + +/** + * Drains a creature's special abilities, based on it's drain attributes. + * + * @param action amount to drain the creature's action SA + * @param mind amount to drain the creature's mind SA + * + * @return true if the SA were drained, false if draining them would cause one + * to be < 0 + */ +bool CreatureObject::drainAttributes(Attributes::Value action, Attributes::Value mind) +{ + int i; + int mods[3] = {0, action, mind}; + int deltas[3]; + + // determine the amount to drain and make sure it won't incapaciate the creature + for (i = 0; i < 3; ++i) + { + if (mods[i] > 0) + { + deltas[i] = getAttribute(Attributes::POOLS[i]) - mods[i]; + if (deltas[i] < 0) + return false; + } + else + deltas[i] = -1; + } + + // drain the attributes + for (i = 0; i < 3; ++i) + { + if (deltas[i] >= 0) + alterAttribute(Attributes::POOLS[i], -mods[i], false); + } + return true; +} // CreatureObject::drainAttributes + +//---------------------------------------------------------------------- + +/** + * Tests draining an attribute, but does not actually modify the attrib. + * + * @param attribute the attribute to test + * @param value the amount to drain the attribute by + * + * @return the amount the attribute would be drained by, or -1 on error + */ +int CreatureObject::testDrainAttribute(Attributes::Enumerator attribute, + Attributes::Value value) const +{ + // we can only drain action and mind + if (attribute != Attributes::Action && attribute != Attributes::Mind) + return -1; + + if (getAttribute(attribute) - value <= 0) + return -1; + + return static_cast(value); +} // CreatureObject::testDrainAttribute + +//---------------------------------------------------------------------- + +void CreatureObject::onClientReady(Client *c) +{ + TangibleObject::onClientReady(c); + + // check cell permissions + Object * const attachedTo = getAttachedTo(); + if (attachedTo) + { + ServerObject * const serverAttachedTo = attachedTo->asServerObject(); + if (serverAttachedTo) + { + CellObject * const cellObject = serverAttachedTo->asCellObject(); + if (cellObject && !cellObject->isAllowed(*this)) + { + BuildingObject * const ownerBuilding = cellObject->getOwnerBuilding(); + if (ownerBuilding) + ownerBuilding->expelObject(*this); + } + } + } + + GroupObject *group = getGroup(); + if (group) + group->onGroupMemberConnect(getNetworkId()); + + // update the client with the list of mods currently on the character + + // but first, remove any mods from the list that has expired + uint32 const gameTimeSeconds = ServerClock::getInstance().getGameTimeSeconds(); + std::vector expiredMods; + std::vector::const_iterator iterTimedMod = m_timedMod.begin(); + std::vector::const_iterator iterTimedModDuration = m_timedModDuration.begin(); + std::vector::const_iterator iterTimedModUpdateTime = m_timedModUpdateTime.begin(); + + for (; iterTimedMod != m_timedMod.end(); ++iterTimedMod, ++iterTimedModDuration, ++iterTimedModUpdateTime) + { + if (*iterTimedModDuration >= 0) + { + if ((*iterTimedModUpdateTime + static_cast(*iterTimedModDuration)) < gameTimeSeconds) + expiredMods.push_back(*iterTimedMod); + } + } + + int index; + for (iterTimedMod = expiredMods.begin(); iterTimedMod != expiredMods.end(); ++iterTimedMod) + { + index = m_timedMod.find(*iterTimedMod); + + if (index >= 0) + { + m_timedMod.erase(index); + m_timedModDuration.erase(index); + m_timedModUpdateTime.erase(index); + } + } + + // send the mods to the client + iterTimedMod = m_timedMod.begin(); + iterTimedModDuration = m_timedModDuration.begin(); + iterTimedModUpdateTime = m_timedModUpdateTime.begin(); + + for (; iterTimedMod != m_timedMod.end(); ++iterTimedMod, ++iterTimedModDuration, ++iterTimedModUpdateTime) + { + if (*iterTimedModDuration >= 0) + sendTimedModData(*iterTimedMod, *iterTimedModDuration - static_cast(gameTimeSeconds - *iterTimedModUpdateTime), false); + else + sendTimedModData(*iterTimedMod, -1.0f, false); + } + + // update the client with the list of cooldowns currently on the character + + // visual only cooldown timers are stored in objvars + DynamicVariableList const & objvars = getObjVars(); + std::map > visualCooldownTimers; + for (DynamicVariableList::MapType::const_iterator iterObjVar = objvars.begin(); iterObjVar != objvars.end(); ++iterObjVar) + { + if (iterObjVar->first.find("visualCooldown.beginTime.") == 0) + { + int cooldownGroupCrc = 0; + if (1 == sscanf(iterObjVar->first.c_str(), "visualCooldown.beginTime.%d", &cooldownGroupCrc)) + { + int beginTime = 0; + if (iterObjVar->second.get(beginTime)) + { + std::map >::iterator iterFind = visualCooldownTimers.find(cooldownGroupCrc); + if (iterFind == visualCooldownTimers.end()) + { + visualCooldownTimers[cooldownGroupCrc] = std::make_pair(beginTime, 0); + } + else + { + iterFind->second.first = beginTime; + } + } + } + } + else if (iterObjVar->first.find("visualCooldown.endTime.") == 0) + { + int cooldownGroupCrc = 0; + if (1 == sscanf(iterObjVar->first.c_str(), "visualCooldown.endTime.%d", &cooldownGroupCrc)) + { + int endTime = 0; + if (iterObjVar->second.get(endTime)) + { + std::map >::iterator iterFind = visualCooldownTimers.find(cooldownGroupCrc); + if (iterFind == visualCooldownTimers.end()) + { + visualCooldownTimers[cooldownGroupCrc] = std::make_pair(0, endTime); + } + else + { + iterFind->second.second = endTime; + } + } + } + } + } + + char buffer[256]; + int const currentGameTime = static_cast(ServerClock::getInstance().getGameTimeSeconds()); + for (std::map >::const_iterator iterCooldown = visualCooldownTimers.begin(); iterCooldown != visualCooldownTimers.end(); ++iterCooldown) + { + // send any unexpired cooldowns to the client + if ((iterCooldown->second.first > 0) && (iterCooldown->second.second > 0) && (iterCooldown->second.first <= currentGameTime) && (currentGameTime < iterCooldown->second.second)) + { + CreatureController *controller = getCreatureController(); + if (controller) + { + MessageQueueCommandTimer *msg = new MessageQueueCommandTimer( + 0, + iterCooldown->first, + -1, + 0); + msg->setCurrentTime(MessageQueueCommandTimer::F_cooldown, static_cast(currentGameTime - iterCooldown->second.first)); + msg->setMaxTime (MessageQueueCommandTimer::F_cooldown, static_cast(iterCooldown->second.second - iterCooldown->second.first)); + + controller->appendMessage( + static_cast< int >( CM_commandTimer ), + 0.0f, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } + else + { + // cleanup the objvars for any expired/invalid cooldowns + snprintf(buffer, sizeof(buffer)-1, "visualCooldown.beginTime.%d", iterCooldown->first); + buffer[sizeof(buffer)-1] = '\0'; + removeObjVarItem(buffer); + + snprintf(buffer, sizeof(buffer)-1, "visualCooldown.endTime.%d", iterCooldown->first); + buffer[sizeof(buffer)-1] = '\0'; + removeObjVarItem(buffer); + } + } + + // command cooldown timers are stored in the command queue + CommandQueue const * commandQueue = getCommandQueue(); + if (commandQueue && getClient()) + { + double const currentTime = Clock::getCurrentTime(); + uint32 currentCooldownTimeSecond = 0; + uint32 maxCooldownTimeSecond = 0; + std::map > const & cooldowns = commandQueue->getCooldowns().getMap(); + for (std::map >::const_iterator cooldownsIter = cooldowns.begin(); cooldownsIter != cooldowns.end(); ++cooldownsIter) + { + if ((cooldownsIter->second.first <= currentTime) && (currentTime < cooldownsIter->second.second)) + { + // don't bother sending cooldown with less than 1 second left because + // by the time it gets to the client, it will probably have already expired + currentCooldownTimeSecond = static_cast(currentTime - cooldownsIter->second.first); + maxCooldownTimeSecond = static_cast(cooldownsIter->second.second - cooldownsIter->second.first); + + if (currentCooldownTimeSecond < maxCooldownTimeSecond) + { + GenericValueTypeMessage > > commandCooldown("SetCommandCooldown", std::make_pair(cooldownsIter->first, std::make_pair(currentCooldownTimeSecond, maxCooldownTimeSecond))); + getClient()->send(commandCooldown, true); + } + } + } + } + + // sync chat character count with chat server + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + if (player && (player->getChatSpamTimeEndInterval() > 0)) + { + time_t timeUnsquelch = static_cast(player->getSecondsUntilUnsquelched()); + if (timeUnsquelch > 0) + timeUnsquelch += ::time(NULL); + + GenericValueTypeMessage, int>, std::pair > > chatStatistics("ChatStatisticsGS", std::make_pair(std::make_pair(std::make_pair(getNetworkId(), static_cast(timeUnsquelch)), player->getChatSpamTimeEndInterval()), std::make_pair(player->getChatSpamSpatialNumCharacters(), player->getChatSpamNonSpatialNumCharacters()))); + Chat::sendToChatServer(chatStatistics); + } + + // if necessary, announce TCG monthly bonus booster pack and Swg Tcg Beta + if (getClient() && !getClient()->isUsingAdminLogin()) + { + VeteranRewardManager::announceMonthlyBonusBoosterPack(*this); + + if (ConfigServerGame::getAccountFeatureIdForTcgBetaAnnouncement() > 0) + VeteranRewardManager::announceSwgTcgBeta(*this); + } + // Make sure our player has the server's speed maximum + PlayerCreatureController const * playerController = safe_cast(getCreatureController()); + if(playerController) + { + GenericValueTypeMessage const msg("fca11a62d23041008a4f0df36aa7dca6", playerController->getServerSpeedForPlayer()); + Client const * const client = getClient(); + if (client) + return client->send(msg, true); + } + +} + +// ---------------------------------------------------------------------- + +void CreatureObject::onClientAboutToLoad() +{ + if (isAuthoritative()) + setInvulnerabilityTimer(ConfigServerGame::getCreatureLoadInvulnerableTimeWithoutClient()); + + TangibleObject::onClientAboutToLoad(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::onLoadingScreenComplete() +{ + TangibleObject::onLoadingScreenComplete(); + + if (isAuthoritative() && isInvulnerable()) + setInvulnerabilityTimer(ConfigServerGame::getCreatureLoadInvulnerableTimeWithClient()); +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::monitorCreatureMovement(const CachedNetworkId &ofTarget, float i_skittishness, float i_curve) +{ + Object * object = ofTarget.getObject(); + if (!object || object == this) + return false; + + Archive::AutoDeltaMap::const_iterator i = m_monitoredCreatureMovements.find(ofTarget); + MonitoredCreatureMovement newMovement; + if (i == m_monitoredCreatureMovements.end()) + { + newMovement.m_lastDistance = object->getPosition_w().magnitudeBetween(getPosition_w()); + newMovement.m_skittishness = i_skittishness; + newMovement.m_curve = i_curve; + } + else + { + newMovement = i->second; + newMovement.m_skittishness = i_skittishness; + newMovement.m_curve = i_curve; + + } + if (newMovement != i->second) + { + m_monitoredCreatureMovements.set(ofTarget, newMovement); + } + return true; +} + +//---------------------------------------------------------------------- + +bool CreatureObject::ignoreCreatureMovement(const CachedNetworkId &ofTarget) +{ + Archive::AutoDeltaMap::const_iterator i = m_monitoredCreatureMovements.find(ofTarget); + if (i == m_monitoredCreatureMovements.end()) + return false; + m_monitoredCreatureMovements.erase(ofTarget); + return true; +} + +//---------------------------------------------------------------------- + +void CreatureObject::reportMonitoredCreatures(float time) +{ + Vector ownerPosition = getPosition_w(); + std::vector toRemove; + Archive::AutoDeltaMap::const_iterator i; + for (i=m_monitoredCreatureMovements.begin(); i!=m_monitoredCreatureMovements.end(); ++i) + { + CachedNetworkId cnid(i->first); + Object * o = cnid.getObject(); + if (o) + { + MonitoredCreatureMovement newMovement = i->second; + + float lastDistance = newMovement.m_lastDistance; + float currentDistance = o->getPosition_w().magnitudeBetween(ownerPosition); + float approach = lastDistance - currentDistance; + //float tangentVelocity = sqrt(((mobDelta - targetDelta)/i_time).magnitudeSquared() - approachVelocity * approachVelocity); + + // calculate the fear delta + if (approach > 0) + { + float approachVelocity = approach / time; + float totalDistance = getApproachTriggerRange(); + float percent = 1 - ((lastDistance + currentDistance) * 0.5f) / totalDistance; + if (percent > 1) + percent = 1; + else if (percent < 0) + percent = 0; + if (i->second.m_curve < 0) + { + percent = -percent; + } + float absCurve = std::abs(i->second.m_curve); + float scale = pow(percent, absCurve) * (1+absCurve); + float speedScale = float(sqrt(approachVelocity / getRunSpeed())); + float fearDelta = approach * i->second.m_skittishness * speedScale * scale; + setMentalStateToward(i->first, MentalStates::Fear, getMentalStateToward(i->first, MentalStates::Fear)+fearDelta); + } + newMovement.m_lastDistance = currentDistance; + m_monitoredCreatureMovements.set(i->first, newMovement); + } + else + { + toRemove.push_back(i->first); + } + } + std::vector::iterator removeIt; + for (removeIt = toRemove.begin(); removeIt != toRemove.end(); ++removeIt) + { + m_monitoredCreatureMovements.erase(*removeIt); + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::doWarmupChecks(Command const &command, NetworkId const &targetId, Unicode::String const ¶ms, Command::ErrorCode &status, int &statusDetail) +{ + if (doesLocomotionInvalidateCommand(command)) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to locomotion %d", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str(), + getLocomotion())); + } + status = Command::CEC_Locomotion; + statusDetail = static_cast(getLocomotion()); + } + else if (isPlayerControlled() && command.m_characterAbility.size() && !hasCommand(command.m_characterAbility)) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to ability %s", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str(), + command.m_characterAbility.c_str())); + } + status = Command::CEC_Ability; + } + // target verification - don't execute the command if a target is + // required and none is present, or if there is never a target and + // one is specified + else if ( (command.m_targetType == Command::CTT_None && targetId != NetworkId::cms_invalid) + || (command.m_targetType == Command::CTT_Required && targetId == NetworkId::cms_invalid)) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to target type", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str())); + } + status = Command::CEC_TargetType; + } + else + { + // target range checking + if (command.m_targetType != Command::CTT_None && targetId != NetworkId::cms_invalid && command.m_maxRangeToTargetSquared != 0.0f) + { + Object *targetObj = NetworkIdManager::getObjectById(targetId); + if (!targetObj) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to range to target", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str())); + } + status = Command::CEC_TargetRange; + } + else + { + TangibleObject const * const tangible = dynamic_cast(targetObj); + if(tangible) + { + float distance = this->getDistanceBetweenCollisionSpheres_w(*tangible); + distance = sqr(distance); + + if(distance > command.m_maxRangeToTargetSquared) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to range to target", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str())); + } + status = Command::CEC_TargetRange; + } + } + else + { + if(findPosition_w().magnitudeBetweenSquared(targetObj->findPosition_w()) > command.m_maxRangeToTargetSquared) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to range to target", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str())); + } + + status = Command::CEC_TargetRange; + } + + } + + } + + } + if (status == Command::CEC_Success) + { + // make sure that the command is allowed in all states set on the creature currently + for (States::Enumerator i = 0; i < States::NumberOfStates; ++i) + { + // @todo: don't gate npc command usage on swimming + if (!isPlayerControlled() && i == States::Swimming) + continue; + + if (getState(i) && !command.m_statePermissions[i]) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to state %d", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str(), + i)); + } + status = Command::CEC_StateMustNotHave; + statusDetail = i; + break; + } + + if (!getState(i) && command.m_stateRequired[i]) + { + if (ConfigServerGame::getLogAllCommands()) + { + LOG( + "Command", + ("%s>%s %s ignored due to missing required state %d", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str(), + i)); + } + status = Command::CEC_StateMustHave; + statusDetail = i; + break; + } + } + } + } + +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::isDisabled() const +{ + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + return TangibleObject::isDisabled (); + + return (isIncapacitated() || isDead()); +} + +// ------------------------------------------------------------------- + +bool CreatureObject::makeDead(const NetworkId & killer, const NetworkId & corpse) +{ + if (isAuthoritative()) + { + if (isDead()) + { + clearHateList(); + return true; + } + + ScriptParams params; + params.addParam(killer); + params.addParam(corpse); + if (getScriptObject()->trigAllScripts(Scripting::TRIG_DEATH, params) != SCRIPT_CONTINUE) + return false; + + clearHateList(); + + // if we are crafting, end the crafting session + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + if (player != NULL && player->isCrafting()) + player->stopCrafting(false); + + // if we are in a conversation, end it + if (isInNpcConversation()) + endNpcConversation(); + + // remove all attrib and skill mod mods + typedef Archive::AutoDeltaMap::const_iterator ModIter; + for (ModIter i = m_attributeModList.begin(); i != m_attributeModList.end();) + { + const CreatureMod & m = (*i).second; + + bool remove = true; + //check to see if this attribute mod comes from a buff that should not be removed on death + const char * rawModName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); + if(rawModName) + { + std::string tmpModName(rawModName); + + //strip the attribute number from the mod name to get the raw buff name + //this is a little fragile because we are looking up the name of the + //buff, trusting that the mod name will be based on it + //in BuffManager.cpp, attributes that are assigned by a buff have the + //mod name as ("%s_%d", buffname, effectNum) so we will check to see if + //the name matches that format and if the resulting buff name is flagged + //to not be removed on death. + int namelength = tmpModName.size(); + if(namelength > 2 && tmpModName[namelength-2] == '_' && tmpModName[namelength-1] >= '0' && tmpModName[namelength-1] <= '9') + { + std::string buffname = tmpModName.substr(0,namelength-2); + uint32 buffNameCrc = Crc::normalizeAndCalculate(buffname.c_str()); + remove = BuffManager::getIsBuffRemovedOnDeath(buffNameCrc); + + // Check to see if this is a Pvp related death and we should ignore the removal. + if(remove && BuffManager::getDoesBuffDecayOnPvPDeath(buffNameCrc)) // We only care about buffs that would normally be removed on death and have the decay flag. + { + Object * killerObj = NetworkIdManager::getObjectById(killer); + if(killerObj && killerObj->asServerObject() && killerObj->asServerObject()->asCreatureObject()) + { + CreatureObject * killerCreature = killerObj->asServerObject()->asCreatureObject(); + PlayerObject * const playerKiller = PlayerCreatureController::getPlayerObject(killerCreature); + if(playerKiller) + remove = false; // Buffs that decay on PvP death don't get removed on PvP death. + else if(killerCreature->getMasterId() != NetworkId::cms_invalid) // Check to see if this is some type of pet. + { + Object * masterObj = NetworkIdManager::getObjectById(killerCreature->getMasterId()); + if(masterObj && masterObj->asServerObject() && masterObj->asServerObject()->asCreatureObject()) + { + CreatureObject * masterCreature = masterObj->asServerObject()->asCreatureObject(); + PlayerObject * const masterPlayer = PlayerCreatureController::getPlayerObject(masterCreature); // Pet has a valid player as a master. Pvp related. + if(masterPlayer) + remove = false; + } + } + } + }// End PvP check + } + } + + if(remove) + { + if (AttribMod::isSkillMod(m.mod)) + { + const char * skillModName = AttribModNameManager::getInstance().getAttribModName(m.mod.skill); + if (skillModName != NULL) + addModValue(skillModName, -m.maxVal, true); + } + // if the mod is visible, we need to tell the player it's being + // removed + if (m.mod.flags & AttribMod::AMF_visible) + { + sendCancelTimedMod(m.mod.tag); + } + // if the mod is flagged as having a callback, call the script + if (m.mod.flags & AttribMod::AMF_triggerOnDone) + { + const char * modName = AttribModNameManager::getInstance().getAttribModName(m.mod.tag); + if (modName != NULL) + { + ScriptParams params; + params.addParam(modName); + params.addParam(true); + if (AttribMod::isAttribMod(m.mod)) + { + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_ATTRIB_MOD_DONE, params)); + } + else if (AttribMod::isSkillMod(m.mod)) + { + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_SKILL_MOD_DONE, params)); + } + + } + } + + i = m_attributeModList.erase(i); + } + else + { + ++i; + } + } + for (int j = 0; j < Attributes::NumberOfAttributes; ++j) + { + m_cachedCurrentAttributeModValues.set(j, 0); + m_cachedMaxAttributeModValues.set(j, 0); + } + computeTotalAttributes(); + + LOG("CustomerService", ("Attribs: removed all attrib and skillmod mods " + "from %s due to death.", + PlayerObject::getAccountDescription(this).c_str())); + + if (!isPlayerControlled()) + setDefaultAlterTime(AlterResult::cms_keepNoAlter); + + //-- If we're in combat, the client will take care of arranging for + // a suitable transition to the dead posture; otherwise, make it + // happen immediately. + setPosture(Postures::Dead, !isInCombat()); + } + else + { + sendControllerMessageToAuthServer(CM_makeDead, new MessageQueueGenericValueType< + std::pair >(std::make_pair(killer, corpse))); + } + return true; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::makeNotDead() +{ + if (!isDead()) + return true; + + if (!isPlayerControlled()) + setDefaultAlterTime(AlterResult::cms_alterQuickly); + + setPosture(Postures::Prone, true); + testIncapacitation(NetworkId::cms_invalid); + return true; +} + +//-------------------------------------------------------------------- + +Locomotions::Enumerator CreatureObject::calcLocomotion() const +{ + Locomotions::Enumerator ret = Locomotions::Invalid; + if (m_stopWalkRun.get() > 1) + ret = m_fastLocomotion; + if (ret == Locomotions::Invalid && m_stopWalkRun.get() > 0) + ret = m_slowLocomotion; + if (ret == Locomotions::Invalid) + ret = m_stationaryLocomotion; + return ret; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::canMove() const +{ + return getMovementTable()->hasMovingLocomotion(m_posture.get(), m_states.get()) && !getObjVars().hasItem("forceNoMovement"); +} + +//---------------------------------------------------------------------- + +void CreatureObject::setScaleFactor(float scale) +{ + if(isAuthoritative()) + { + scale = std::max (0.0f, scale); + m_scaleFactor = scale; + setScale (Vector::xyz111 * scale); + } + else + { + sendControllerMessageToAuthServer(CM_setScaleFactor, new MessageQueueGenericValueType(scale)); + } +} + +//---------------------------------------------------------------------- + +/** + * Gets the approximate height of the creature, modified by it's posture. + * + * @return the creature's height + */ +float CreatureObject::getHeight() const +{ + float height = TangibleObject::getHeight(); + height *= getMovementTable()->getCanSeeHeightMod(m_posture.get(), m_states.get()); + + return height; +} // CreatureObject::getHeight + +//---------------------------------------------------------------------- + +/** + * Gets the approximate radius of the object. + * + * @return the object's radius + */ +float CreatureObject::getRadius() const +{ + const SharedCreatureObjectTemplate * myTemplate = safe_cast(getSharedTemplate()); + return myTemplate->getCollisionRadius() * std::max(getScale().x, getScale().z); +} // CreatureObject::getHeight + +//---------------------------------------------------------------------- + +Object const * CreatureObject::getStandingOn() const +{ + CollisionProperty const * collision = getCollisionProperty(); + + if(collision) + { + return collision->getStandingOn(); + } + else + { + return NULL; + } +} + +//---------------------------------------------------------------------- + +float CreatureObject::getFarNetworkUpdateRadius() const +{ + if (ServerWorld::getSceneId() == NewbieTutorial::getSceneId()) + return 0.f; + + float height = TangibleObject::getHeight(); + float radius; + + if (height < ConfigServerGame::getMaxSmallCreatureHeight()) + radius = ConfigServerGame::getSmallCreatureUpdateRadius(); + else if (height < ConfigServerGame::getMaxMediumCreatureHeight()) + radius = ConfigServerGame::getMediumCreatureUpdateRadius(); + else + radius = ConfigServerGame::getLargeCreatureUpdateRadius(); + + return radius; +} + +//---------------------------------------------------------------------- + +void CreatureObject::setShockWounds(int wound) +{ +static const StringId SHOCK_WOUND_ID("cbt_spam", "shock_wound"); + + if(isAuthoritative()) + { + // Use TangibleObject::isInvulnerable so we don't account for the invulnerability timer + if (TangibleObject::isInvulnerable()) + return; + + if (wound < 0) + wound = 0; + else if (wound > 1000) + wound = 1000; + if (wound != m_shockWounds.get()) + { + if (isInCombat()) + { + ProsePackage pp; + pp.stringId = SHOCK_WOUND_ID; + pp.digitInteger = wound - m_shockWounds.get(); + Unicode::String oob; + OutOfBandPackager::pack(pp, 0, oob); + MessageQueueCombatSpam spam(oob, false, false, false, 1); + performCombatSpam (spam, true, false, false); + } + m_shockWounds = wound; + } + } + else + { + sendControllerMessageToAuthServer(CM_setShockWounds, new MessageQueueGenericValueType(wound)); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setLookAtTarget(const NetworkId& id) +{ + if(isAuthoritative()) + { + m_lookAtTarget.set(id); + } + else + { + sendControllerMessageToAuthServer(CM_setLookAtTarget, new MessageQueueGenericValueType(id)); + } + + ShipObject * const ship = getPilotedShip(); + if(ship) + { + ship->setLookAtTargetFromPilot(id); + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::setIntendedTarget(const NetworkId& id) +{ + if(isAuthoritative()) + { + DEBUG_WARNING(true, ("CreatureObject::setIntendedTarget: '%s'", id.getValueString().c_str())); + m_intendedTarget.set(id); + } + else + { + sendControllerMessageToAuthServer(CM_setIntendedTarget, new MessageQueueGenericValueType(id)); + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::setMovementStationary() +{ + if (isAuthoritative()) + m_stopWalkRun = 0; +} + +//----------------------------------------------------------------------- + +void CreatureObject::setMovementWalk() +{ + if (isAuthoritative()) + m_stopWalkRun = 1; +} + +//----------------------------------------------------------------------- + +void CreatureObject::setMovementRun() +{ + if (isAuthoritative()) + m_stopWalkRun = 2; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::setSlopeModAngle(float angle) +{ + if(isAuthoritative()) + { + m_slopeModAngle = angle; + } + else + { + sendControllerMessageToAuthServer(CM_setSlopeModAngle, new MessageQueueGenericValueType(angle)); + } + return true; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::setSlopeModPercent(float percent) +{ + if(isAuthoritative()) + { + if (percent < 0.0f) + percent = 0.0f; + else if (percent > 1.0f) + percent = 1.0f; + m_baseSlopeModPercent = percent; + + // + // modify the percent reduced due to skill mods + // + + // get my skill mod + int movementMod = getEnhancedModValue(SLOPE_MOD); + if (getGroup() != NULL) + { + // get my group leader skill mod + const NetworkId & leaderId = getGroup()->getGroupLeaderId(); + if (leaderId != NetworkId::cms_invalid) + { + const CreatureObject * leader = safe_cast( + NetworkIdManager::getObjectById(leaderId)); + if (leader != NULL) + { + movementMod += leader->getEnhancedModValue(GROUP_SLOPE_MOD); + } + } + } + if (movementMod > 100) + movementMod = 100; + + switch (getPosture()) + { + case Postures::Upright: + if (movementMod > 50) + movementMod = 50; + if (movementMod > 0 && percent < 1.0f) + { + percent += (1.0f - percent) * ((float)movementMod / 50.0f); + } + break; + case Postures::Prone: + case Postures::Sneaking: +// movementMod -= 50; +// if (movementMod > 0 && percent < 1.0f) +// { +// percent += (1.0f - percent) * ((float)movementMod / 50.0f); +// } +// break; + case Postures::Crouched: + case Postures::Blocking: + case Postures::Climbing: + case Postures::Flying: + case Postures::LyingDown: + case Postures::Sitting: + case Postures::SkillAnimating: + case Postures::DrivingVehicle: + case Postures::RidingCreature: + case Postures::KnockedDown: + case Postures::Incapacitated: + case Postures::Dead: + default: + break; + } + + m_slopeModPercent = percent; + } + else + { + sendControllerMessageToAuthServer(CM_setSlopeModPercent, new MessageQueueGenericValueType(percent)); + } + return true; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::setWaterModPercent(float percent) +{ + if(isAuthoritative()) + { + m_waterModPercent = percent; + } + else + { + sendControllerMessageToAuthServer(CM_setWaterModPercent, new MessageQueueGenericValueType(percent)); + } + return true; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::setMovementScale(float scale) +{ + if(isAuthoritative()) + { + m_movementScale = scale; + } + else + { + sendControllerMessageToAuthServer(CM_setMovementScale, new MessageQueueGenericValueType(scale)); + } + return true; +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::setMovementPercent(float percent) +{ + if(isAuthoritative()) + { + m_movementPercent = percent; + } + else + { + sendControllerMessageToAuthServer(CM_setMovementPercent, new MessageQueueGenericValueType(percent)); + } + return true; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::setTurnPercent(float percent) +{ + if(isAuthoritative()) + { + m_turnScale = percent; + } + else + { + sendControllerMessageToAuthServer(CM_setTurnPercent, new MessageQueueGenericValueType(percent)); + } + return true; +} + +//-------------------------------------------------------------------- + +bool CreatureObject::setAccelScale(float scale) +{ + if(isAuthoritative()) + { + m_accelScale = scale; + } + else + { + sendControllerMessageToAuthServer(CM_setAccelScale, new MessageQueueGenericValueType(scale)); + } + return true; +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::setAccelPercent(float percent) +{ + if(isAuthoritative()) + { + m_accelPercent = percent; + } + else + { + sendControllerMessageToAuthServer(CM_setAccelPercent, new MessageQueueGenericValueType(percent)); + } + return true; +} + +//-------------------------------------------------------------------- +/** + * Instruct the clients to display the visuals for having this creature + * sit on the specified chair-like target object in the specified position. + * + * For chairs, where there is only a single spot to sit in, the positionIndex + * should be zero. For couches where, theoretically, we could have multiple + * creatures sit, the value should represent the space in which the player + * is sitting. + * + * @param targetObjectId the network id for the object on which the creature + * will sit. + * @param positionIndex the 0-based index of the position of the chair-like object + * in which the creature will sit. Typically this will be zero. + */ +void CreatureObject::sitOnObject(NetworkId const &chairCellId, Vector const &chairPosition_p) +{ + if (isAuthoritative()) + { + // you can't sit on something in a different cell than you + if (ContainerInterface::getContainedByProperty(*this)->getContainedByNetworkId() != chairCellId) + return; + + //-- If the chair is more than the allowed distance away from the authoritative position for the creature, log the attempt and ignore. + Vector const creaturePosition_p = getPosition_p(); + float const separationSquared = creaturePosition_p.magnitudeBetweenSquared(chairPosition_p); + + if (separationSquared > MessageQueueSitOnObject::cs_maximumChairRangeSquared) + { + LOG("move_validation", ("CreatureObject::sitOnObject: object id=[%s] out of range for specified chair position, separation=[%.2f] meters.", getNetworkId().getValueString().c_str(), separationSquared)); + return; + } + + //-- Get the controller. + Controller * const controller = getController(); + NetworkController * const networkController = safe_cast(controller); + ServerController * const serverController = safe_cast(networkController); + NOT_NULL(serverController); + + // teleport the player to the chairs location + // orientation doesn't matter in this case + Transform transform; + transform.setPosition_p(chairPosition_p); + serverController->teleport(transform, ContainerInterface::getContainingCellObject(*this)); + + //-- Send the SitOnObject controller message to all clients. + serverController->appendMessage(CM_sitOnObject, 0.0f, new MessageQueueSitOnObject(chairCellId, chairPosition_p), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); + + //-- Set the server posture to sitting & set SittingInChair state. + setPosture(Postures::Sitting); + setState(States::SittingOnChair, true); + } + else + { + sendControllerMessageToAuthServer(CM_sitOnObject, new MessageQueueSitOnObject(chairCellId, chairPosition_p)); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::onBiographyRetrieved(const NetworkId &owner, const Unicode::String &bio) +{ + //TODO: Biography handling code + //DEBUG_REPORT_LOG(true,("Biography for object %s received: %s\n",owner.getValueString().c_str(), Unicode::wideToNarrow(bio).c_str())); + + CreatureController *creatureController = getCreatureController(); + + if (creatureController != NULL) + { + typedef std::pair Payload; + + MessageQueueGenericValueType * const msg = new MessageQueueGenericValueType(Payload(owner, bio)); + + creatureController->appendMessage(static_cast(CM_biographyRetrieved), 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::onCharacterMatchRetrieved(MatchMakingCharacterResult const &results) +{ + CreatureController *creatureController = getCreatureController(); + + if (creatureController != NULL) + { + MessageQueueGenericValueType * const msg = new MessageQueueGenericValueType(results); + + creatureController->appendMessage(static_cast(CM_characterMatchRetrieved), 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::setLocomotion(Locomotions::Enumerator posture) +{ + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_setLocomotion, new MessageQueueGenericValueType(posture)); + } + else + { + Postures::Enumerator newPosture; + MovementTable::eLocomotionSpeed speed = getMovementTable()->getLocomotionData(posture, newPosture); + if (speed != MovementTable::kInvalid) + { + setPosture(newPosture); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::speakText(MessageQueueSpatialChat const &spatialChat) +{ + // a speech type may only be used if it either has no skills listed as providing it, or the creature has + // at least one of the skills listed. + + std::vector const &skillsProviding = SpatialChatManager::getSkillsProviding(spatialChat.getChatType()); + if (!skillsProviding.empty()) + { + bool found = false; + for (std::vector::const_iterator i = skillsProviding.begin(); i != skillsProviding.end(); ++i) + { + if (hasCommand(*i)) + { + found = true; + break; + } + } + if (!found) + return; + } + + TangibleObject::speakText(spatialChat); +} + +// ---------------------------------------------------------------------- + +int CreatureObject::getPerformanceType() const +{ + return m_performanceType.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setPerformanceType(int performanceType) +{ + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(performanceType); + controller->appendMessage( + CM_setPerformanceType, + 0.0f, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + } + else + { + m_performanceType = performanceType; + } +} + +// ---------------------------------------------------------------------- + +int CreatureObject::getPerformanceStartTime() const +{ + return m_performanceStartTime.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setPerformanceStartTime(int performanceStartTime) +{ + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(performanceStartTime); + controller->appendMessage( + CM_setPerformanceStartTime, + 0.0f, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + } + else + { + m_performanceStartTime = performanceStartTime; + } +} + +// ---------------------------------------------------------------------- + +NetworkId const &CreatureObject::getPerformanceListenTarget() const +{ + return m_performanceListenTarget.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setPerformanceListenTarget(NetworkId const &who) +{ + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(who); + controller->appendMessage( + CM_setPerformanceListenTarget, + 0.0f, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + } + else + { + m_performanceListenTarget = who; + } +} + +// ---------------------------------------------------------------------- + +NetworkId const &CreatureObject::getPerformanceWatchTarget() const +{ + return m_performanceWatchTarget.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setPerformanceWatchTarget(NetworkId const &who) +{ + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + MessageQueueGenericValueType *msg = new MessageQueueGenericValueType(who); + controller->appendMessage( + CM_setPerformanceWatchTarget, + 0.0f, + msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + } + else + { + m_performanceWatchTarget = who; + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::setGuildId(int guildId) +{ + FATAL(!isAuthoritative(), ("setGuildId called on nonauthoritative object")); + int oldGuildId = getGuildId(); + if (oldGuildId != guildId) + { + if (oldGuildId) + GuildInterface::onAboutToClearGuildId(*this); + m_guildId = guildId; + } + if (guildId) + GuildInterface::onGuildIdSet(*this); +} + +//----------------------------------------------------------------------- + +void CreatureObject::setTimeToUpdateGuildWarPvpStatus(unsigned long timeToUpdateGuildWarPvpStatus) +{ + FATAL(!isAuthoritative(), ("setTimeToUpdateGuildWarPvpStatus called on nonauthoritative object")); + m_timeToUpdateGuildWarPvpStatus = timeToUpdateGuildWarPvpStatus; +} + +//----------------------------------------------------------------------- + +void CreatureObject::setGuildWarEnabled(bool guildWarEnabled) +{ + FATAL(!isAuthoritative(), ("setGuildWarEnabled called on nonauthoritative object")); + m_guildWarEnabled = guildWarEnabled; + m_timeToUpdateGuildWarPvpStatus = 0; +} + +// ---------------------------------------------------------------------- + +int CreatureObject::getMilitiaOfCityId() const +{ + return m_militiaOfCityId.get(); +} + +//----------------------------------------------------------------------- + +void CreatureObject::setMilitiaOfCityId(int cityId) +{ + FATAL(!isAuthoritative(), ("setMilitiaOfCityId called on nonauthoritative object")); + m_militiaOfCityId = cityId; +} + +// ---------------------------------------------------------------------- + +int CreatureObject::getLocatedInCityId() const +{ + return m_locatedInCityId.get(); +} + +//----------------------------------------------------------------------- + +void CreatureObject::setLocatedInCityId(int newCityId) +{ + FATAL(!isAuthoritative(), ("setLocatedInCityId called on nonauthoritative object")); + int oldCityId = m_locatedInCityId.get(); + if (oldCityId != newCityId) + { + m_locatedInCityId.set(newCityId); + if (getScriptObject()) + { + ScriptParams params; + params.addParam(oldCityId); + params.addParam(newCityId); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_CITY_CHANGED, params)); + } + } +} + +// ---------------------------------------------------------------------- + +NetworkId const &CreatureObject::getMasterId() const +{ + return m_masterId.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setMasterId(NetworkId const &masterId) +{ + if (isAuthoritative()) + m_masterId = masterId; + else + sendControllerMessageToAuthServer(CM_setMasterId, new MessageQueueGenericValueType(masterId)); +} + +// ---------------------------------------------------------------------- + +float CreatureObject::getSwimHeight() const +{ + return safe_cast(getSharedTemplate())->getSwimHeight() * getScaleFactor(); +} + +//----------------------------------------------------------------------- + +const CreatureObject::AllCreaturesSet & CreatureObject::getAllCreatures() +{ + return g_creatureList; +} + +//----------------------------------------------------------------------- + +void CreatureObject::addToMissionRequestQueue(const NetworkId & terminalId) +{ + if (!ConfigServerGame::getDisableMissions()) + { + std::vector >::const_iterator f = std::find(gs_missionRequestQueue.begin(), gs_missionRequestQueue.end(), std::make_pair(this, terminalId)); + if(f == gs_missionRequestQueue.end()) + { + gs_missionRequestQueue.push_back(std::make_pair(this, terminalId)); + } + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::removeFromMissionRequestQueue(const NetworkId & creatureId) +{ + CreatureObject * creature = safe_cast(NetworkIdManager::getObjectById(creatureId)); + if (creature) + { + removeCreatureFromMissionRequestQueue(creature); + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::updateMissionRequestQueue() +{ + if(! gs_missionRequestQueue.empty()) + { + // remove pending creatures from previous run + std::vector >::const_iterator remIter; + std::vector >::iterator i; + for(remIter = gs_missionRequestQueueDeferredRemoves.begin(); remIter != gs_missionRequestQueueDeferredRemoves.end(); ++remIter) + { + for(i = gs_missionRequestQueue.begin(); i != gs_missionRequestQueue.end(); ++i) + { + if((*i).first == (*remIter).first) + { + gs_missionRequestQueue.erase(i); + break; + } + } + } + + gs_missionRequestQueueDeferredRemoves.clear(); + int count = 0; + + for(i = gs_missionRequestQueue.begin(); i != gs_missionRequestQueue.end(); ++i) + { + CreatureObject * creature = (*i).first; + + // if a delete happened while processing the queue, find the + // creature in the defferred deleted queue. If it's there, skip this + // creature and move on to the next + if(! gs_missionRequestQueueDeferredRemoves.empty()) + { + // is this creature in the queue? + remIter = std::find(gs_missionRequestQueueDeferredRemoves.begin(), gs_missionRequestQueueDeferredRemoves.end(), std::make_pair(creature, (*i).second)); + if(remIter != gs_missionRequestQueueDeferredRemoves.end()) + continue; + } + + // build vector of network ids for all mission objects in the mission bag + ServerObject * missionBag = creature->getMissionBag(); + if(missionBag) + { + static std::vector missionObjects; + + Container * container = ContainerInterface::getContainer(*missionBag); + ContainerIterator iter; + for(iter = container->begin(); iter != container->end(); ++iter) + { + MissionObject * missionObject = safe_cast((*iter).getObject()); + if(missionObject) + { + missionObjects.push_back(missionObject->getNetworkId()); + } + } + + ScriptParams p; + p.addParam(creature->getNetworkId()); + p.addParam((*i).second); + p.addParam(missionObjects); + GameScriptObject * script = creature->getScriptObject(); + if(script) + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_PLAYER_REQUEST_MISSION_BOARD, p)); + removeCreatureFromMissionRequestQueue(creature); + missionObjects.clear(); + } + ++count; + if (count >= ConfigServerGame::getMissionRequestsPerFrame()) + { + break; + } + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::getAttributes(stdvector >::fwd &data) const +{ + TangibleObject::getAttributes(data); +} + +//----------------------------------------------------------------------- + +bool CreatureObject::isAppearanceEquippable(const char *appearanceTemplateName) +{ + // Returns whether an object template is wearable based on the data in the + // appearance_table.tab + + bool result = true; + + // Make sure this object has a valid appearance + + if (appearanceTemplateName == NULL) + { + result = false; + } + else + { + // Check to see if we even care about the creature object depending + // on its gender/species combination + + SharedCreatureObjectTemplate::Species species = getSpecies(); + SharedCreatureObjectTemplate::Gender gender = getGender(); + + int column = -1; + + // Get the species index + + switch (species) + { + case SharedCreatureObjectTemplate::SP_human: { column = 1; } break; + case SharedCreatureObjectTemplate::SP_rodian: { column = 3; } break; + case SharedCreatureObjectTemplate::SP_monCalamari: { column = 5; } break; + case SharedCreatureObjectTemplate::SP_wookiee: { column = 7; } break; + case SharedCreatureObjectTemplate::SP_twilek: { column = 9; } break; + case SharedCreatureObjectTemplate::SP_trandoshan: { column = 11; } break; + case SharedCreatureObjectTemplate::SP_zabrak: { column = 13; } break; + case SharedCreatureObjectTemplate::SP_bothan: { column = 15; } break; + case SharedCreatureObjectTemplate::SP_ithorian: { column = 17; } break; + case SharedCreatureObjectTemplate::SP_sullustan: { column = 19; } break; + default: { } break; + } + + // Add in the gender index + + switch (gender) + { + case SharedCreatureObjectTemplate::GE_male: { } break; + case SharedCreatureObjectTemplate::GE_female: { column += 1; } break; + default: { } break; + } + + if (column > 0) + { + // If the object template is in the list, then check if it is equippable, otherwise + // there is no restriction so the item must be equippable + + std::string objectTemplateName(appearanceTemplateName); + + if (!objectTemplateName.empty()) + { + // Strip out just the object template name + + size_t const slashIndex = objectTemplateName.rfind('/'); + size_t const dotIndex = objectTemplateName.rfind('.'); + + std::string fileName; + + if (slashIndex == std::string::npos) + { + fileName = objectTemplateName.substr(0, dotIndex); + } + else if (dotIndex == std::string::npos) + { + fileName = objectTemplateName.substr(slashIndex + 1); + } + else + { + fileName = objectTemplateName.substr(slashIndex + 1, dotIndex - slashIndex - 1); + } + + if (AppearanceManager::isAppearanceManaged(fileName)) + { + // A ':block' token in the data table denotes the item is not equippable + + std::string destAppearancePath; + + AppearanceManager::getAppearanceName(destAppearancePath, fileName, column); + + static const std::string tagBlock = ":block"; + + if (destAppearancePath == tagBlock) + { + result = false; + } + } + } + } + } + + return result; +} + +// ---------------------------------------------------------------------- + +/** + * Sends a message to the Planet Server to update the position of the object. + */ +void CreatureObject::updatePlanetServerInternal(const bool forceUpdate) const +{ + if (forceUpdate || getPositionChanged()) + { + // If this is a mount with a rider on it, use the larger of the rider and mount's + // interest radius for the mount. This allows the planet server to update nodes + // marked for proxy subscription properly. Otherwise we'll get a destroy proxy + // for the mount the first time it moves into a node that hasn't yet been subscribed, + // immediately followed by a create proxy message for the mount when the rider's + // position gets updated. + + int effectiveInterestRadius = getInterestRadius(); + if (getState(States::MountedCreature)) + { + CreatureObject const *const rider = getPrimaryMountingRider(); + if (rider) + effectiveInterestRadius = std::max(rider->getInterestRadius(), getInterestRadius()); + } + + if (!ContainerInterface::getContainedByObject(*this) || (effectiveInterestRadius > 0)) + { + bool hibernating = false; + if(getCreatureController()) + hibernating = getCreatureController()->getHibernate(); + + AICreatureController const * const aiCreatureController = dynamic_cast(getCreatureController()); + + Object const * const topmostContainer = ContainerInterface::getTopmostContainer(*this); + FATAL(!topmostContainer, ("Object %s was contained by something, but getTopmostContainer() returned NULL", getNetworkId().getValueString().c_str())); + Vector const &position = topmostContainer->getPosition_p(); + UpdateObjectOnPlanetMessage const msg( + getNetworkId(), + topmostContainer == this ? NetworkId::cms_invalid : topmostContainer->getNetworkId(), + static_cast(position.x), + static_cast(position.y), + static_cast(position.z), + effectiveInterestRadius, + static_cast(getLocationReservationRadius()), + false, + true, + static_cast(getObjectType()), + static_cast(getLevel()), + hibernating, + getTemplateCrc(), + aiCreatureController ? aiCreatureController->getMovementType() : -1, + getIsStatic() == true ? 1 : 0); + GameServer::getInstance().sendToPlanetServer(msg); + } + } +} + +// ---------------------------------------------------------------------- + +int CreatureObject::getCurrentTargetsTotal(const std::map & targets) +{ + int sum = 0; + for(std::map::const_iterator i = targets.begin(); i != targets.end(); ++i) + { + sum += i->second; + } + return sum; +} + +// ====================================================================== + +ServerObject *CreatureObject::getMissionBag() const +{ + SlottedContainer const * const s = ContainerInterface::getSlottedContainer(*this); + if (s) + { + static SlotId const bankId = SlotIdManager::findSlotId(MISSION_BAG_SLOT_NAME); + Container::ContainerErrorCode tmp = Container::CEC_Success; + Object * const o = s->getObjectInSlot(bankId, tmp).getObject(); + if (o) + return o->asServerObject(); + } + return 0; +} + +// ====================================================================== + +ServerObject *CreatureObject::getBankContainer() const +{ + return const_cast(this)->getBank (); +} + +// ====================================================================== + +namespace PlayerBanks +{ + const static Unicode::String invalidBankName = + Unicode::narrowToWide("INVALID_BANK_NAME"); +} + +//---------------------------------------------------------------------- + +Unicode::String CreatureObject::getBankName() const +{ + Unicode::String bankName = PlayerBanks::invalidBankName; + getObjVars().getItem(OBJVAR_BANK_ID,bankName); + return bankName; +} + +// ====================================================================== + +bool CreatureObject::isBankMember(Unicode::String bankName) const +{ + return (bankName.compare(getBankName()) == 0); +} + +// ====================================================================== + +bool CreatureObject::joinBank(Unicode::String bankName) +{ + if (getBankName() == bankName) + { + StringId message("system_msg", "already_member_of_bank"); + Unicode::String outOfBand; + Chat::sendSystemMessage(*this, message, outOfBand); + return false; + } + if (getBankName() != PlayerBanks::invalidBankName) + { + StringId message("system_msg", "member_of_different_bank"); + Unicode::String outOfBand; + Chat::sendSystemMessage(*this, message, outOfBand); + return false; + } + StringId message("system_msg", "succesfully_joined_bank"); + Unicode::String outOfBand; + Chat::sendSystemMessage(*this, message, outOfBand); +// printf("Setting item (%s) on objvars (%x)\n", OBJVAR_BANK_ID.c_str(), (int)objVars); + setObjVarItem(OBJVAR_BANK_ID, bankName); + /*DynamicVariable *objvar = objVars->getItemByName(OBJVAR_BANK_ID); + if (objvar) + { + DynamicVariableString *stringVar = dynamic_cast(objvar); + stringVar->setValue(bankName); + }*/ + return true; +} + +// ====================================================================== + +void CreatureObject::quitBank() +{ + ServerObject *bankContainer = getBankContainer(); + if (bankContainer) + { + Container *container = ContainerInterface::getContainer(*bankContainer); + if (container->getNumberOfItems() != 0) + { + //Can't quit bank, you still have items in it + StringId message("system_msg", "bank_not_empty"); + Unicode::String outOfBand; + Chat::sendSystemMessage(*this, message, outOfBand); + return; + } + } + StringId message("system_msg", "succesfully_quit_bank"); + Unicode::String outOfBand; + Chat::sendSystemMessage(*this, message, outOfBand); + setObjVarItem(OBJVAR_BANK_ID, PlayerBanks::invalidBankName); + /*DynamicVariable *objvar = objVars->getItemByName(OBJVAR_BANK_ID); + if (objvar) + { + DynamicVariableString *stringVar = dynamic_cast(objvar); + stringVar->setValue(PlayerBanks::invalidBankName); + }*/ + setObjVarItem(OBJVAR_OPEN_BANK_TERMINAL_ID, NetworkId::cms_invalid); + if (bankContainer) + { + ScriptParams params; + params.addParam(getNetworkId()); + IGNORE_RETURN (bankContainer->getScriptObject()->trigAllScripts(Scripting::TRIG_CLOSED_CONTAINER, params)) + ; + Client *client = getClient(); + if (client) + { + GenericValueTypeMessage m("ClosedContainerMessage", bankContainer->getNetworkId()); + client->send(m, true); + ObserveTracker::onClientClosedContainer(*client, *bankContainer); + } + } +} + +// ---------------------------------------------------------------------- + +float CreatureObject::getInvulnerabilityTimer() const +{ + return m_invulnerabilityTimer.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setInvulnerabilityTimer(float duration) +{ + if (isAuthoritative()) + { + DEBUG_REPORT_LOG(true, ("Setting creature invulnerability timer for %s to %g\n", getDebugInformation().c_str(), duration)); + m_invulnerabilityTimer = duration; + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::isInvulnerable() const +{ + if (m_invulnerabilityTimer.get() > 0.f) + return true; + return TangibleObject::isInvulnerable(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::handleCMessageTo(MessageToPayload const &message) +{ + if (message.getMethod() == "C++RenameFailed") + { + std::string reason(message.getDataAsString()); + if (reason.empty()) + reason = "Rename request failed."; + + Chat::sendSystemMessage(*this,Unicode::narrowToWide(reason),Unicode::String()); + } + else if ((message.getMethod() == "C++PlayerRenameRequestSubmitted") || (message.getMethod() == "C++PlayerLastNameRenameRequestSubmitted")) + { + // set objvar to indicate there's a pending rename request for this character, + // and the time of the rename request, to enforce the 90 days wait between rename + if (!getClient() || !getClient()->isGod()) + setObjVarItem("renameCharacterRequest.requestTime", static_cast(::time(NULL))); + + std::string const newName(message.getDataAsString()); + if (getObjVars().hasItem("renameCharacterRequest.requestTime") && !newName.empty()) + { + setObjVarItem("renameCharacterRequest.requestNewName", newName); + } + + // for player requested rename, send message to CentralServer to drop the character, + // and prevent the character from further login until the rename request has been completed + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + GenericValueTypeMessage > > > const msg("PlayerRenameRequestSubmitted", std::make_pair(static_cast(playerObject->getStationId()), std::make_pair(getNetworkId(), std::make_pair(newName, (message.getMethod() == "C++PlayerLastNameRenameRequestSubmitted"))))); + GameServer::getInstance().sendToCentralServer(msg); + } + } + else if (message.getMethod() == "C++GmRenameRequestSubmitted") + { + std::string reason(message.getDataAsString()); + if (reason.empty()) + reason = "Rename request submitted."; + + Chat::sendSystemMessage(*this,Unicode::narrowToWide(reason),Unicode::String()); + } + else if (message.getMethod() == "C++experience") + { + std::vector const & packedData = message.getPackedDataVector(); + std::vector::const_iterator spacePos = std::find(packedData.begin(), packedData.end(), ' '); + if (spacePos != packedData.end()) + { + int amount = atoi(std::string(spacePos + 1, packedData.end()).c_str()); + grantExperiencePoints(std::string(packedData.begin(), spacePos), amount); + } + } + else if (message.getMethod() == "C++AddJediSlot") + { + // if we haven't received an addJediToAccountAck(), resend the Jedi request + if (!getObjVars().hasItem(OBJVAR_ADD_JEDI_ACK)) + { + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + if (player != NULL) + { + player->addJediToAccount(); + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++AddJediSlot", "", 5 * 60, true); + } + } + else + { + removeObjVarItem(OBJVAR_ADD_JEDI_ACK); + } + } + else if (message.getMethod() == "ClientMfdStatusUpdateMessage") + { + if (getClient() && isAuthoritative()) + { + if (!message.getPackedDataVector().empty()) + { + static Archive::ByteStream bs; + bs.clear(); + bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); + Archive::put(bs, message.getPackedDataVector()); + Archive::ReadIterator ri = bs.begin(); + ClientMfdStatusUpdateMessage mfdUpdate(ri); + getClient()->send(mfdUpdate, false); + } + } + } + else if (message.getMethod() == "FindFriend") + { + if (getClient() && isAuthoritative()) + { + if (!message.getPackedDataVector().empty()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + static Archive::ByteStream bs; + bs.clear(); + bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); + Archive::put(bs, message.getPackedDataVector()); + Archive::ReadIterator ri = bs.begin(); + NetworkId source; + std::string sourceName; + Archive::get(ri, source); + Archive::get(ri, sourceName); + playerObject->replyLocationToFriend(sourceName, source); + } + } + } + } + else if (message.getMethod() == "LocationToFriend") + { + if (getClient() && isAuthoritative()) + { + if (!message.getPackedDataVector().empty()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + static Archive::ByteStream bs; + bs.clear(); + bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); + Archive::put(bs, message.getPackedDataVector()); + Archive::ReadIterator ri = bs.begin(); + Location friendLocation; + NetworkId friendId; + Archive::get(ri, friendLocation); + Archive::get(ri, friendId); + playerObject->receiveLocationToFriend(friendId, friendLocation); + } + } + } + } + else if (message.getMethod() == "FailLocationToFriend") + { + if (getClient() && isAuthoritative()) + { + if (!message.getPackedDataVector().empty()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + static Archive::ByteStream bs; + bs.clear(); + bs.put((&(message.getPackedDataVector()[0])), message.getPackedDataVector().size()); + Archive::put(bs, message.getPackedDataVector()); + Archive::ReadIterator ri = bs.begin(); + NetworkId friendId; + Archive::get(ri, friendId); + playerObject->receiveFailLocationToFriend(friendId); + } + } + } + } + else if (message.getMethod() == "C++TheaterDestroyed") + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + playerObject->handleCMessageTo(message); + } + } + else if (message.getMethod() == "C++RemovePetFromGroup") + { + if (!message.getPackedDataVector().empty()) + { + std::string packedData(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + + // Parse the info from the message + char petNetworkIdBuffer[100]; + unsigned msgSendCount; + sscanf(packedData.c_str(), "%s %u", petNetworkIdBuffer, &msgSendCount); + + // Turn the string into a network Id + NetworkId petNetworkId( petNetworkIdBuffer ); + + // Try to remove the pet from the group + GroupObject *group = getGroup(); + if (group && group->isGroupMember(petNetworkId)) + { + group->removeGroupMember(petNetworkId); + } + else + { + // We will only try to remove the pet so many times... + if (msgSendCount < MAX_ATTEMPTS_TO_REMOVE_PET_FROM_GROUP) + { + // We will try again in the future... + ++msgSendCount; + + // We need to tell the network ID of the pet and we need to keep + // of how many times this message has been sent to the inviter + char msgBuffer[100]; + sprintf( msgBuffer, "%s %u", petNetworkId.getValueString().c_str(), msgSendCount ); + + // Send the message with a delay + MessageToQueue::getInstance().sendMessageToC( getNetworkId(), + "C++RemovePetFromGroup", + msgBuffer, + TIME_BETWEEN_ATTEMPTS_TO_REMOVE_PET, + false ); // reliable + } + } + } + } + else if (message.getMethod() == "C++WaitForPatrolPreload") + { + if (ServerWorld::isPreloadComplete()) + { + DEBUG_REPORT_LOG(ConfigServerGame::isAiLoggingEnabled(),("C++WaitForPatrolPreload being handled for %s\n", getNetworkId().getValueString().c_str())); + + MessageToQueue::cancelRecurringMessageTo(getNetworkId(), "C++WaitForPatrolPreload"); + + AICreatureController * const aiCreatureController = safe_cast(getController()); + if (aiCreatureController != NULL) + { + const std::string data = message.getDataAsString(); + std::string::size_type locationStart = 0; + std::string::size_type locationEnd = data.find('|', locationStart); + std::vector locations; + while (locationEnd != std::string::npos) + { + locations.push_back(Unicode::narrowToWide(data.substr(locationStart, locationEnd - locationStart))); + locationStart = locationEnd + 1; + locationEnd = data.find('|', locationStart); + } + + bool random = false; + bool flip = false; + bool repeat = false; + + if (data.size() > (locationStart+2)) + { + random = data.at(locationStart++) != '0'; + flip = data.at(locationStart++) != '0'; + repeat = data.at(locationStart++) != '0'; + } + int startPoint = 0; + if (data.size() > locationStart && data.at(locationStart) == '*') + { + ++locationStart; + startPoint = atoi(data.substr(locationStart).c_str()); + } + + aiCreatureController->patrol(locations, random, flip, repeat, startPoint); + } + } + } + else if (message.getMethod() == "C++WarnAboutVendorPurge") + { + LOG("CustomerService",("Purge: Sending warning emails to the owner (%s) of vendor (%s) effected by a purge",getNetworkId().getValueString().c_str(),message.getDataAsString().c_str())); + + const StringId subject("player_structure", "vendor_purge_warning_subject"); + const StringId body("player_structure", "vendor_purge_warning_body"); + const Unicode::String mail_subject = Unicode::narrowToWide("@" + subject.getCanonicalRepresentation()); + const Unicode::String mail_body = Unicode::narrowToWide("@" + body.getCanonicalRepresentation()); + + ProsePackage pp; + pp.stringId = body; + pp.other.str = Unicode::narrowToWide(message.getDataAsString()); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("Galactic Housing Authority", Unicode::wideToNarrow(getObjectName()), + mail_subject, Unicode::emptyString, oob); + } + else if (message.getMethod() == "C++CheckCharacterTitle") + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject && !playerObject->getTitle().empty()) + { + static uint32 const commandHash = Crc::normalizeAndCalculate("setCurrentSkillTitle"); + const Command &command = CommandTable::getCommand(static_cast(commandHash)); + if (!command.isNull()) + { + commandQueueEnqueue(command, NetworkId::cms_invalid, Unicode::narrowToWide(playerObject->getTitle()), 0, false); + } + } + } + else if (message.getMethod() == "C++CharacterSheetInfoResidenceLocationRsp") + { + if (!message.getPackedDataVector().empty()) + { + // location of residence + std::string const residenceLoc(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + + // get the city(ies) this character is a citizen of + std::string citizensOf; + std::vector const & cityId = CityInterface::getCitizenOfCityId(getNetworkId()); + if (!cityId.empty()) + { + std::string cityName; + for (std::vector::const_iterator iterCity = cityId.begin(); iterCity != cityId.end(); ++iterCity) + { + CityInfo const & cityInfo = CityInterface::getCityInfo(*iterCity); + cityName = cityInfo.getCityName(); + if (cityName.empty()) + continue; + + if (!citizensOf.empty()) + citizensOf += ","; + + if (getNetworkId() == cityInfo.getLeaderId()) + citizensOf += "*"; + + citizensOf += cityName; + } + } + + // send to client + GenericValueTypeMessage > message("CharacterSheetResponseResLoc", std::make_pair(residenceLoc, citizensOf)); + Client * const client = getClient(); + if (client) + client->send(message, true); + } + } + else if (message.getMethod() == "C++SpammerReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + std::string::size_type const pos = params.find(' '); + if ((pos != std::string::npos) && (params.size() > (pos + 1))) + { + NetworkId const actor(params.substr(0, pos)); + std::string const actorName(params.substr(pos + 1)); + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + bool canSpammer = true; + + // on a session-authenticated cluster, cannot /spammer a secured login character + if (getClient() && getClient()->isGodValidated()) + { + if (!ConfigServerGame::getAdminGodToAll() && !ConfigServerGame::getEnableWardenCanSquelchSecuredLogin()) + { + canSpammer = false; + } + } + + // cannot /spammer self + if (canSpammer && (actor == getNetworkId())) + { + canSpammer = false; + } + + // cannot /spammer a target that is already squelched + if (canSpammer && (playerObject->getSecondsUntilUnsquelched() != 0)) + { + canSpammer = false; + } + + if (!canSpammer) + { + MessageToQueue::getInstance().sendMessageToC(actor, + "C++SpammerRspCannotSpammerTarget", + Unicode::wideToNarrow(getAssignedObjectName()), + 0, + false); + } + else + { + // do it + playerObject->squelch(actor, actorName, ConfigServerGame::getWardenSquelchDurationSeconds()); + + std::string result = getNetworkId().getValueString(); + result += "|"; + result += Unicode::wideToNarrow(getAssignedObjectName()); + result += "|"; + result += playerObject->getAccountDescription(); + + MessageToQueue::getInstance().sendMessageToC(actor, + "C++SpammerRspSuccess", + result, + 0, + false); + } + } + else + { + MessageToQueue::getInstance().sendMessageToC(actor, + "C++SpammerRspInvalidTarget", + std::string(), + 0, + false); + } + } + } + } + else if (message.getMethod() == "C++SpammerRspTargetNotFound") + { + Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); + } + else if (message.getMethod() == "C++SpammerRspInvalidTarget") + { + Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); + } + else if (message.getMethod() == "C++SpammerRspCannotSpammerTarget") + { + if (!message.getPackedDataVector().empty()) + { + std::string const targetName(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "cannot_spammer_target"); + prosePackage.target.str = Unicode::narrowToWide(targetName); + Chat::sendSystemMessage(*this, prosePackage); + } + } + else if (message.getMethod() == "C++SpammerRspSuccess") + { + if (!message.getPackedDataVector().empty()) + { + std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + std::string::size_type const pos1 = result.find('|'); + if ((pos1 != std::string::npos) && (result.size() > (pos1 + 1))) + { + std::string::size_type const pos2 = result.find('|', (pos1 + 1)); + if ((pos2 != std::string::npos) && (result.size() > (pos2 + 1))) + { + NetworkId const target(result.substr(0, pos1)); + std::string const targetName(result.substr(pos1 + 1, pos2 - pos1 - 1)); + std::string const targetAccountDescription(result.substr(pos2 + 1)); + + // request /report + ReportManager::addReport(getAssignedObjectFirstName(), getNetworkId(), Unicode::narrowToWide(NameManager::normalizeName(targetName)), target, std::string("Warden")); + + // log it + LOG("CustomerService", ("Warden:%s has spammer %s", PlayerObject::getAccountDescription(this).c_str(), targetAccountDescription.c_str())); + + // display confirmation message + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "confirm_spammer"); + prosePackage.target.str = Unicode::narrowToWide(targetName); + Chat::sendSystemMessage(*this, prosePackage); + } + } + } + } + else if (message.getMethod() == "C++UnspammerReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + NetworkId const actor(params); + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + bool canUnspammer = true; + + // cannot /unspammer a target that is not currently /spammer(ed) + if (playerObject->getSecondsUntilUnsquelched() <= 0) + { + canUnspammer = false; + } + + // can only /unspammer target that was /spammer(ed) by the actor + if (canUnspammer && (playerObject->getSquelchedById() != actor)) + { + canUnspammer = false; + } + + if (!canUnspammer) + { + MessageToQueue::getInstance().sendMessageToC(actor, + "C++UnspammerRspCannotUnspammerTarget", + Unicode::wideToNarrow(getAssignedObjectName()), + 0, + false); + } + else + { + // do it + playerObject->unsquelch(); + + std::string result = Unicode::wideToNarrow(getAssignedObjectName()); + result += "|"; + result += playerObject->getAccountDescription(); + + MessageToQueue::getInstance().sendMessageToC(actor, + "C++UnspammerRspSuccess", + result, + 0, + false); + } + } + else + { + MessageToQueue::getInstance().sendMessageToC(actor, + "C++UnspammerRspInvalidTarget", + std::string(), + 0, + false); + } + } + } + else if (message.getMethod() == "C++UnspammerRspTargetNotFound") + { + Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); + } + else if (message.getMethod() == "C++UnspammerRspInvalidTarget") + { + Chat::sendSystemMessage(*this, StringId("warden", "invalid_target"), Unicode::emptyString); + } + else if (message.getMethod() == "C++UnspammerRspCannotUnspammerTarget") + { + if (!message.getPackedDataVector().empty()) + { + std::string const targetName(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "cannot_unspammer_target"); + prosePackage.target.str = Unicode::narrowToWide(targetName); + Chat::sendSystemMessage(*this, prosePackage); + } + } + else if (message.getMethod() == "C++UnspammerRspSuccess") + { + if (!message.getPackedDataVector().empty()) + { + std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + std::string::size_type const pos = result.find('|'); + if ((pos != std::string::npos) && (result.size() > (pos + 1))) + { + std::string const targetName(result.substr(0, pos)); + std::string const targetAccountDescription(result.substr(pos + 1)); + + // log it + LOG("CustomerService", ("Warden:%s has unspammer %s", PlayerObject::getAccountDescription(this).c_str(), targetAccountDescription.c_str())); + + // display confirmation message + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "confirm_unspammer"); + prosePackage.target.str = Unicode::narrowToWide(targetName); + Chat::sendSystemMessage(*this, prosePackage); + } + } + } + else if (message.getMethod() == "C++DeputizeWardenReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + NetworkId existingWarden; + StationId existingWardenStationId; + bool success = false; + + Unicode::String const delimiters(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector tokens; + if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 2)) + { + existingWarden = NetworkId(Unicode::wideToNarrow(tokens[0])); + + // quick way to convert a string to a uint32 + existingWardenStationId = static_cast(NetworkId(Unicode::wideToNarrow(tokens[1])).getValue()); + + if (existingWarden != getNetworkId()) + { + PlayerObject * po = PlayerCreatureController::getPlayerObject(this); + if (po && !po->isWarden() && (po->getStationId() == existingWardenStationId)) + { + // make warden + success = true; + po->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::Warden)); + + // send success message back to existing warden who deputized this warden + std::string result = Unicode::wideToNarrow(getAssignedObjectName()); + result += "|"; + result += po->getAccountDescription(); + + MessageToQueue::getInstance().sendMessageToC(existingWarden, + "C++DeputizeWardenRspSuccess", + result, + 0, + false); + } + } + } + + if (!success) + { + MessageToQueue::getInstance().sendMessageToC(existingWarden, + "C++DeputizeWardenRspCannotDeputize", + std::string(), + 0, + false); + } + } + } + else if (message.getMethod() == "C++DeputizeWardenRspSuccess") + { + if (!message.getPackedDataVector().empty()) + { + std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + std::string::size_type const pos = result.find('|'); + if ((pos != std::string::npos) && (result.size() > (pos + 1))) + { + std::string const newWardenName(result.substr(0, pos)); + std::string const newWardenAccountInfo(result.substr(pos + 1)); + + // log it + LOG("CustomerService", ("WardenPlayerDeputize:%s has deputized %s", PlayerObject::getAccountDescription(this).c_str(), newWardenAccountInfo.c_str())); + + // display confirmation message + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "confirm_deputize"); + prosePackage.target.str = Unicode::narrowToWide(newWardenName); + Chat::sendSystemMessage(*this, prosePackage); + } + } + } + else if (message.getMethod() == "C++DeputizeWardenRspCannotDeputize") + { + Chat::sendSystemMessage(*this, StringId("warden", "cannot_deputize"), Unicode::emptyString); + } + else if (message.getMethod() == "C++UndeputizeWardenReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + NetworkId existingWarden; + StationId existingWardenStationId; + bool success = false; + + Unicode::String const delimiters(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector tokens; + if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 2)) + { + existingWarden = NetworkId(Unicode::wideToNarrow(tokens[0])); + + // quick way to convert a string to a uint32 + existingWardenStationId = static_cast(NetworkId(Unicode::wideToNarrow(tokens[1])).getValue()); + + if (existingWarden != getNetworkId()) + { + PlayerObject * po = PlayerCreatureController::getPlayerObject(this); + if (po && po->isWarden() && (po->getStationId() == existingWardenStationId)) + { + // revoke warden + success = true; + po->setPriviledgedTitle(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)); + + // send success message back to existing warden who undeputized this warden + std::string result = Unicode::wideToNarrow(getAssignedObjectName()); + result += "|"; + result += po->getAccountDescription(); + + MessageToQueue::getInstance().sendMessageToC(existingWarden, + "C++UndeputizeWardenRspSuccess", + result, + 0, + false); + } + } + } + + if (!success) + { + MessageToQueue::getInstance().sendMessageToC(existingWarden, + "C++UndeputizeWardenRspCannotUndeputize", + std::string(), + 0, + false); + } + } + } + else if (message.getMethod() == "C++UndeputizeWardenRspSuccess") + { + if (!message.getPackedDataVector().empty()) + { + std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + std::string::size_type const pos = result.find('|'); + if ((pos != std::string::npos) && (result.size() > (pos + 1))) + { + std::string const priorWardenName(result.substr(0, pos)); + std::string const pirorWardenAccountInfo(result.substr(pos + 1)); + + // log it + LOG("CustomerService", ("WardenPlayerUndeputize:%s has undeputized %s", PlayerObject::getAccountDescription(this).c_str(), pirorWardenAccountInfo.c_str())); + + // display confirmation message + ProsePackage prosePackage; + prosePackage.stringId = StringId("warden", "confirm_undeputize"); + prosePackage.target.str = Unicode::narrowToWide(priorWardenName); + Chat::sendSystemMessage(*this, prosePackage); + } + } + } + else if (message.getMethod() == "C++UndeputizeWardenRspCannotUndeputize") + { + Chat::sendSystemMessage(*this, StringId("warden", "cannot_undeputize"), Unicode::emptyString); + } + else if (message.getMethod() == "C++OnCollectionServerFirst") + { + if (!message.getPackedDataVector().empty()) + { + std::string const collectionName(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + CollectionsDataTable::CollectionInfoCollection const * const collectionInfo = CollectionsDataTable::getCollectionByName(collectionName); + if (collectionInfo && collectionInfo->trackServerFirst) + { + GameScriptObject * gameScriptObject = const_cast(getScriptObject()); + if (gameScriptObject) + { + ScriptParams params; + params.addParam(collectionInfo->page.book.name.c_str()); // book + params.addParam(collectionInfo->page.name.c_str()); // page + params.addParam(collectionInfo->name.c_str()); // collection + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SERVER_FIRST, params)); + } + } + } + } + else if (message.getMethod() == "C++InviteToGroupReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + + bool success = false; + NetworkId actor, actorShip, group; + std::string actorName; + GroupObject const * groupObject = NULL; + StringId responseSid; + + Unicode::String const delimiters(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector tokens; + if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 4)) + { + success = true; + actor = NetworkId(Unicode::wideToNarrow(tokens[0])); + actorShip = NetworkId(Unicode::wideToNarrow(tokens[1])); + group = NetworkId(Unicode::wideToNarrow(tokens[2])); + actorName = Unicode::wideToNarrow(tokens[3]); + + ServerObject const * so = (group.isValid() ? safe_cast(NetworkIdManager::getObjectById(group)) : NULL); + groupObject = (so ? so->asGroupObject() : NULL); + } + + if (success) + { + std::vector targets; + GroupHelpers::findAllTargetsForGroup(this, targets); + + if (!GroupHelpers::roomInGroup(groupObject, targets.size())) + { + responseSid = GroupStringId::SID_GROUP_FULL; + success = false; + } + } + + if (success) + { + if ((this->getGroup()) && (!GroupHelpers::creatureIsContainedInPOBShip(this))) + { + responseSid = GroupStringId::SID_GROUP_ALREADY_GROUPED; + success = false; + } + } + + if (success) + { + GameScriptObject* const gso = getScriptObject(); + if (gso != NULL && gso->hasScript("ai.beast")) + { + responseSid = GroupStringId::SID_GROUP_BEASTS_CANT_JOIN; + success = false; + } + } + + if (success) + { + NetworkId const & oldInviter = getGroupInviterId(); + if (oldInviter.isValid()) + { + if (oldInviter == actor) + responseSid = GroupStringId::SID_GROUP_CONSIDERING_YOUR_GROUP; + else + responseSid = GroupStringId::SID_GROUP_CONSIDERING_OTHER_GROUP; + + success = false; + } + } + + if (success) + { + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject && playerObject->isIgnoring(Unicode::toLower(actorName))) + { + responseSid = GroupStringId::SID_GROUP_INVITE_NO_TARGET_SELF; + success = false; + } + } + + if (success) + { + // cannot be invited if in combat + if (getState(States::Combat) && ConfigServerGame::getGroupInviteInviteeCombatRestriction()) + { + responseSid = GroupStringId::SID_GROUP_INVITE_TARGET_IN_COMBAT; + success = false; + } + } + + if (success) + { + ProsePackage pp; + pp.stringId = GroupStringId::SID_GROUP_INVITE_TARGET; + pp.target.str = Unicode::narrowToWide(actorName); + pp.actor.id = getNetworkId(); + + Chat::sendSystemMessage(*this, pp); + + setGroupInviter(actor, actorName, actorShip); + + responseSid = GroupStringId::SID_GROUP_INVITE_LEADER; + } + + std::string const objectName(Unicode::wideToNarrow(getAssignedObjectName())); + + std::string response = responseSid.getCanonicalRepresentation(); + response += "|"; + + if (!objectName.empty()) + { + response += "nameString|"; + response += objectName; + } + else + { + StringId nameSid = getObjectNameStringId(); + response += "nameStringId|"; + response += nameSid.getCanonicalRepresentation(); + } + + MessageToQueue::getInstance().sendMessageToC(actor, + "C++GroupOperationGenericRsp", + response, + 0, + false); + } + } + else if (message.getMethod() == "C++InviteToGroupRspTargetNotFound") + { + Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_INVITE_NO_TARGET_SELF, NULL); + } + else if (message.getMethod() == "C++GroupOperationGenericRsp") + { + if (!message.getPackedDataVector().empty()) + { + std::string const result(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + Unicode::String const delimiters(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector tokens; + if ((Unicode::tokenize(Unicode::narrowToWide(result), tokens, &delimiters, NULL)) && (tokens.size() == 3)) + { + std::string const response(Unicode::wideToNarrow(tokens[0])); + std::string const responseParmType(Unicode::wideToNarrow(tokens[1])); + std::string const responseParm(Unicode::wideToNarrow(tokens[2])); + + ProsePackage pp; + pp.stringId = StringId(response); + + if (responseParmType == std::string("nameString")) + { + pp.target.str = Unicode::narrowToWide(responseParm); + } + else + { + pp.target.stringId = StringId(responseParm); + } + + pp.actor.id = getNetworkId(); + + Chat::sendSystemMessage(*this, pp); + } + } + } + else if (message.getMethod() == "C++UninviteFromGroupReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + + bool success = false; + NetworkId actor; + std::string actorName; + StringId responseSid; + + Unicode::String const delimiters(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector tokens; + if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 2)) + { + success = true; + actor = NetworkId(Unicode::wideToNarrow(tokens[0])); + actorName = Unicode::wideToNarrow(tokens[1]); + } + + if (success) + { + if (actor != getGroupInviterId()) + { + responseSid = GroupStringId::SID_GROUP_UNINVITE_NOT_INVITED; + success = false; + } + } + + if (success) + { + ProsePackage pp; + pp.stringId = GroupStringId::SID_GROUP_UNINVITE_TARGET; + pp.target.str = Unicode::narrowToWide(actorName); + pp.actor.id = getNetworkId(); + + Chat::sendSystemMessage(*this, pp); + + setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); + + responseSid = GroupStringId::SID_GROUP_UNINVITE_SELF; + } + + std::string const objectName(Unicode::wideToNarrow(getAssignedObjectName())); + + std::string response = responseSid.getCanonicalRepresentation(); + response += "|"; + + if (!objectName.empty()) + { + response += "nameString|"; + response += objectName; + } + else + { + StringId nameSid = getObjectNameStringId(); + response += "nameStringId|"; + response += nameSid.getCanonicalRepresentation(); + } + + MessageToQueue::getInstance().sendMessageToC(actor, + "C++GroupOperationGenericRsp", + response, + 0, + false); + } + } + else if (message.getMethod() == "C++UninviteFromGroupRspTargetNotFound") + { + Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_UNINVITE_NO_TARGET_SELF, NULL); + } + else if (message.getMethod() == "C++GroupJoinInviterInfoReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + NetworkId const invitee(params); + GroupObject const * const existingGroup = getGroup(); + GroupMemberParam gmp = GroupHelpers::buildGroupMemberParam(this); + + char buffer[1024]; + snprintf(buffer, sizeof(buffer)-1, "%s|%s|%s|%d|%d|%d|%s|%d|%d|%d", + (existingGroup ? existingGroup->getNetworkId().getValueString().c_str() : "0"), + gmp.m_memberId.getValueString().c_str(), + gmp.m_memberName.c_str(), + gmp.m_memberDifficulty, + static_cast(gmp.m_memberProfession), + (gmp.m_memberIsPC ? 1 : 0), + gmp.m_memberShipId.getValueString().c_str(), + (gmp.m_memberShipIsPOB ? 1 : 0), + (gmp.m_memberOwnsPOB ? 1 : 0), + (getState(States::Combat) ? 1 : 0)); + + buffer[sizeof(buffer)-1] = '\0'; + + MessageToQueue::getInstance().sendMessageToC(invitee, + "C++GroupJoinInviterInfoRsp", + buffer, + 0, + false); + + // if the inviter had been invited in the meantime, have them decline + if (getGroupInviterId().isValid()) + setGroupInviter(NetworkId::cms_invalid, std::string(), NetworkId::cms_invalid); + } + } + else if (message.getMethod() == "C++GroupJoinInviterInfoRsp") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + bool success = false; + NetworkId existingGroupId; + NetworkId inviterId; + std::string inviterName; + int inviterDifficulty = 1; + LfgCharacterData::Profession inviterProfession = LfgCharacterData::Prof_Unknown; + bool inviterIsPC = true; + NetworkId inviterShipId; + bool inviterShipIsPOB = false; + bool inviterOwnsPOB = false; + bool inviterInCombat = false; + + Unicode::String const delimiters(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector tokens; + if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 10)) + { + success = true; + existingGroupId = NetworkId(Unicode::wideToNarrow(tokens[0])); + inviterId = NetworkId(Unicode::wideToNarrow(tokens[1])); + inviterName = Unicode::wideToNarrow(tokens[2]); + inviterDifficulty = atoi(Unicode::wideToNarrow(tokens[3]).c_str()); + inviterProfession = static_cast(atoi(Unicode::wideToNarrow(tokens[4]).c_str())); + inviterIsPC = (atoi(Unicode::wideToNarrow(tokens[5]).c_str()) != 0); + inviterShipId = NetworkId(Unicode::wideToNarrow(tokens[6])); + inviterShipIsPOB = (atoi(Unicode::wideToNarrow(tokens[7]).c_str()) != 0); + inviterOwnsPOB = (atoi(Unicode::wideToNarrow(tokens[8]).c_str()) != 0); + inviterInCombat = (atoi(Unicode::wideToNarrow(tokens[9]).c_str()) != 0); + } + + GroupObject * existingGroup = NULL; + if (success) + { + if (existingGroupId.isValid()) + { + ServerObject * so = safe_cast(NetworkIdManager::getObjectById(existingGroupId)); + existingGroup = (so ? so->asGroupObject() : NULL); + if (!existingGroup) + { + success = false; + Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_EXISTING_GROUP_NOT_FOUND, NULL); + } + } + } + + if (success) + { + // make sure inviter hasn't joined another group since the invite + if (existingGroup && (inviterId != existingGroup->getGroupLeaderId())) + { + success = false; + ProsePackage pp; + pp.stringId = GroupStringId::SID_GROUP_JOIN_INVITER_NOT_LEADER; + pp.target.str = Unicode::narrowToWide(inviterName); + pp.actor.id = getNetworkId(); + + Chat::sendSystemMessage(*this, pp); + } + } + + if (success) + { + // cannot join if the inviter is in combat + if (inviterInCombat && ConfigServerGame::getGroupJoinInviterCombatRestriction()) + { + success = false; + ProsePackage pp; + pp.stringId = GroupStringId::SID_GROUP_JOIN_LEADER_IN_COMBAT; + pp.target.str = Unicode::narrowToWide(inviterName); + pp.actor.id = getNetworkId(); + + Chat::sendSystemMessage(*this, pp); + } + } + + std::vector targets; + if (success) + { + GroupHelpers::findAllTargetsForGroup(this, targets); + + if (existingGroup && !GroupHelpers::roomInGroup(existingGroup, targets.size())) + { + success = false; + Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_JOIN_FULL, NULL); + } + } + + if (success) + { + // if we are in a POB group then we need to disband it + GroupObject * const groupFromPOB = getGroup(); + if (groupFromPOB != 0) + { + groupFromPOB->disbandGroup(); + + std::vector::const_iterator ii = targets.begin(); + std::vector::const_iterator iiEnd = targets.end(); + + for (; ii != iiEnd; ++ii) + { + if ((*ii)->getGroup() == groupFromPOB) + (*ii)->getGroup()->onGroupMemberRemoved((*ii)->getNetworkId(), true); + } + + if (getGroup() == groupFromPOB) + getGroup()->onGroupMemberRemoved(getNetworkId(), true); + } + + if (existingGroup) + { + GroupObject::GroupMemberParamVector targetMemberParams; + GroupHelpers::buildGroupMemberParamsFromCreatures(targets, targetMemberParams); + + int const numberOfTargets = static_cast(targetMemberParams.size()); + + for (int i = 0; i < numberOfTargets; ++i) + { + existingGroup->addGroupMember(targetMemberParams[i]); + } + } + else + { + // if the inviter happens to be in the same ship as you then we need to remove + // him from the targets list so that he isn't added to the new group twice + for (std::vector::iterator ii = targets.begin(); ii != targets.end(); ++ii) + { + if ((*ii)->getNetworkId() == inviterId) + { + targets.erase(ii); + break; + } + } + + GroupObject::GroupMemberParamVector targetMemberParams; + GroupHelpers::buildGroupMemberParamsFromCreatures(targets, targetMemberParams); + + // group did not already exist, so form it with the inviter as the leader + if (!targetMemberParams.empty()) + ServerUniverse::getInstance().createGroup(GroupMemberParam(inviterId, inviterName, inviterDifficulty, inviterProfession, inviterIsPC, inviterShipId, inviterShipIsPOB, inviterOwnsPOB), targetMemberParams); + } + + // Until the targets are actually told they are in a group + // (the authoritative group object may be on another server) + // we will keep track of who extended the invitation + std::vector::const_iterator ii = targets.begin(); + std::vector::const_iterator iiEnd = targets.end(); + for (; ii != iiEnd; ++ii) + { + (*ii)->setInviterForPendingGroup(inviterId); + } + } + } + } + else if (message.getMethod() == "C++GroupJoinInviterInfoReqInviterNotFound") + { + Chat::sendSystemMessageSimple(*this, GroupStringId::SID_GROUP_MUST_BE_INVITED, NULL); + } + else if (message.getMethod() == "C++LeaveGroupReq") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + GroupObject const * const groupObj = getGroup(); + if (groupObj && (groupObj->getNetworkId() == NetworkId(params)) && (groupObj->getGroupLeaderId() != getNetworkId())) + { + static uint32 const commandHash = Crc::normalizeAndCalculate("leaveGroup"); + const Command &command = CommandTable::getCommand(static_cast(commandHash)); + if (!command.isNull()) + { + commandQueueEnqueue(command, NetworkId::cms_invalid, Unicode::String(), 0, false, static_cast(Command::CP_Front), true); + } + } + } + } + else if (message.getMethod() == "C++GroupPickupPointCreated") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + + Unicode::String const delimiters(Unicode::narrowToWide("|")); + Unicode::UnicodeStringVector tokens; + if ((Unicode::tokenize(Unicode::narrowToWide(params), tokens, &delimiters, NULL)) && (tokens.size() == 5)) + { + // tell group member that the group pickup point has been created + if (getClient()) + { + StringId::LocUnicodeString response; + if (StringId("group", "create_group_pickup_success_others").localize(response)) + { + ConsoleMgr::broadcastString(FormattedString<2048>().sprintf(Unicode::wideToNarrow(response).c_str(), Unicode::wideToNarrow(tokens[4]).c_str(), CalendarTime::convertSecondsToMS(static_cast(ConfigServerGame::getGroupPickupPointTimeLimitSeconds())).c_str()), + getClient()); + } + } + + // create/update the group member's group pickup point waypoint + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + std::string const planetName = Unicode::wideToNarrow(tokens[0]); + int const x = atoi(Unicode::wideToNarrow(tokens[1]).c_str()); + int const y = atoi(Unicode::wideToNarrow(tokens[2]).c_str()); + int const z = atoi(Unicode::wideToNarrow(tokens[3]).c_str()); + + Location const location(Vector(static_cast(x), static_cast(y), static_cast(z)), NetworkId::cms_invalid, Location::getCrcBySceneName(planetName)); + playerObject->createOrUpdateReusableWaypoint(location, "groupPickupWp", Unicode::narrowToWide("Group Pickup Point"), Waypoint::White); + } + } + } + } + else if (message.getMethod() == "C++OccupyUnlockedSlotRsp") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + LoginUpgradeAccountMessage::OccupyUnlockedSlotResponse const response = static_cast(::atoi(params.c_str())); + + if (response == LoginUpgradeAccountMessage::OUSR_success) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request SUCCESS", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_success"), Unicode::emptyString); + + // let the client know so it can change the character to be properly displayed on the character select screen + Client * const client = getClient(); + if (client) + { + GenericValueTypeMessage > const characterChangedUnlocked("CharacterChangedUnlocked", std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId())); + client->send(characterChangedUnlocked, true); + } + } + else if (response == LoginUpgradeAccountMessage::OUSR_db_error) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - internal db error", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_error"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unlocked_slot) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - account doesn't have an unlocked slot", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_no_unlocked_slot"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::OUSR_account_has_no_unoccupied_unlocked_slot) + { + LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - account has no unoccupied unlocked slot", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_no_unoccupied_unlocked_slot"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::OUSR_cluster_already_has_unlocked_slot_character) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - cluster already has an unlocked slot character", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "occupy_unlocked_slot_db_has_unlocked_slot"), Unicode::emptyString); + } + else + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s OccupyUnlockedSlot request FAILED - unknown result code (%d)", PlayerObject::getAccountDescription(this).c_str(), static_cast(response))); + } + } + } + else if (message.getMethod() == "C++VacateUnlockedSlotRsp") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + LoginUpgradeAccountMessage::VacateUnlockedSlotResponse const response = static_cast(::atoi(params.c_str())); + + if (response == LoginUpgradeAccountMessage::VUSR_success) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request SUCCESS", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_success"), Unicode::emptyString); + + // let the client know so it can change the character to be properly displayed on the character select screen + Client * const client = getClient(); + if (client) + { + GenericValueTypeMessage > const characterChangedNormal("CharacterChangedNormal", std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId())); + client->send(characterChangedNormal, true); + } + } + else if (response == LoginUpgradeAccountMessage::VUSR_db_error) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - internal db error", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_error"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::VUSR_account_has_no_unlocked_slot) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - account doesn't have an unlocked slot", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_no_unlocked_slot"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::VUSR_not_unlocked_slot_character) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - character is not an unlocked slot character", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_not_unlocked_slot_character"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::VUSR_no_available_normal_character_slot) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - no available normal character slot for the account on this galaxy", PlayerObject::getAccountDescription(this).c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "vacate_unlocked_slot_db_no_available_normal_character_slot"), Unicode::emptyString); + } + else + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s VacateUnlockedSlot request FAILED - unknown result code (%d)", PlayerObject::getAccountDescription(this).c_str(), static_cast(response))); + } + } + } + else if (message.getMethod() == "C++SwapUnlockedSlotRsp") + { + if (!message.getPackedDataVector().empty()) + { + Archive::ByteStream bs; + bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); + + Archive::ReadIterator ri = bs.begin(); + GenericValueTypeMessage, std::pair > > > const swapUnlockedSlotRsp(ri); + + LoginUpgradeAccountMessage::SwapUnlockedSlotResponse const response = static_cast(swapUnlockedSlotRsp.getValue().first.first); + if (response == LoginUpgradeAccountMessage::SUSR_success) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s (%s) request SUCCESS", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().second.second.second.c_str())); + + ProsePackage prosePackage; + prosePackage.stringId = StringId("unlocked_slot", "swap_unlocked_slot_success"); + prosePackage.target.str = Unicode::narrowToWide(swapUnlockedSlotRsp.getValue().second.second.second); + Chat::sendSystemMessage(*this, prosePackage); + + // let the client know so it can change the character to be properly displayed on the character select screen + Client * const client = getClient(); + if (client) + { + GenericValueTypeMessage > const characterChangedNormal("CharacterChangedNormal", std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId())); + client->send(characterChangedNormal, true); + + GenericValueTypeMessage > const characterChangedUnlocked("CharacterChangedUnlocked", std::make_pair(GameServer::getInstance().getClusterName(), swapUnlockedSlotRsp.getValue().second.second.first)); + client->send(characterChangedUnlocked, true); + } + } + else if (response == LoginUpgradeAccountMessage::SUSR_db_error) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - internal db error", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_error"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::SUSR_account_has_no_unlocked_slot) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - account doesn't have an unlocked slot", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_no_unlocked_slot"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::SUSR_not_unlocked_slot_character) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - source character is not an unlocked slot character", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_not_unlocked_slot_character"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::SUSR_invalid_target_character) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - target character is either not valid, not on the same account, or not on this galaxy", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_invalid_target_character"), Unicode::emptyString); + } + else if (response == LoginUpgradeAccountMessage::SUSR_target_character_already_unlocked_slot_character) + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - target character is already an unlocked slot character", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str())); + + Chat::sendSystemMessage(*this, StringId("unlocked_slot", "swap_unlocked_slot_db_target_is_already_unlocked_character"), Unicode::emptyString); + } + else + { + // CS log the response + LOG("CustomerService",("JediUnlockedSlot:%s SwapUnlockedSlot with %s request FAILED - unknown result code (%d)", PlayerObject::getAccountDescription(this).c_str(), swapUnlockedSlotRsp.getValue().second.second.first.getValueString().c_str(), swapUnlockedSlotRsp.getValue().first.first)); + } + } + } + else if (message.getMethod() == "C++AccountFeatureIdResponse") + { + if (!message.getPackedDataVector().empty()) + { + Archive::ByteStream bs; + bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); + + Archive::ReadIterator ri = bs.begin(); + AccountFeatureIdResponse const msg(ri); + + if ((msg.getTarget() == getNetworkId()) && (msg.getResultCode() == RESULT_SUCCESS)) + { + Client * client = getClient(); + if (client) + { + if (msg.getGameCode() == PlatformGameCode::SWG) + client->setAccountFeatureIds(msg.getFeatureIds()); + } + } + + if ((msg.getRequestReason() == AccountFeatureIdRequest::RR_ConsoleCommandReloadRequest) && msg.getRequester().isValid() && (msg.getRequester() == getNetworkId())) + { + if (msg.getResultCode() == RESULT_SUCCESS) + { + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request for feature Id for account (%lu) was successful", msg.getTargetStationId()), + getClient()); + + if (msg.getGameCode() == PlatformGameCode::SWG) + { + ConsoleMgr::broadcastString("you can use the /getAccountInfo command on a targeted character to view the character's account SWG feature Id", + getClient()); + } + + if (msg.getResultCameFromSession()) + { + std::map const & sessionFeatureIdsData = msg.getSessionFeatureIdsData(); + + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("session/Platform reported successful result code (%u, %s:%s), (%d) feature Ids for account (%lu)", msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str(), sessionFeatureIdsData.size(), msg.getTargetStationId()), + getClient()); + + for (std::map::const_iterator iter = sessionFeatureIdsData.begin(); iter != sessionFeatureIdsData.end(); ++iter) + { + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%lu (%s)", iter->first, iter->second.c_str()), + getClient()); + } + } + else if (msg.getGameCode() != PlatformGameCode::SWG) + { + std::map const & featureIds = msg.getFeatureIds(); + + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("(%d) feature Ids for account (%lu)", featureIds.size(), msg.getTargetStationId()), + getClient()); + + for (std::map::const_iterator iter = featureIds.begin(); iter != featureIds.end(); ++iter) + { + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("%lu (%d)", iter->first, iter->second), + getClient()); + } + } + } + else + { + if (msg.getResultCameFromSession()) + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request for feature Id for account (%lu) failed with error code (%u, %s:%s)", msg.getTargetStationId(), msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str()), getClient()); + else + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request for feature Id for account (%lu) failed with error code (%u)", msg.getTargetStationId(), msg.getResultCode()), getClient()); + } + } + + if ((msg.getRequestReason() == AccountFeatureIdRequest::RR_ReloadRewardCheck) && msg.getRequester().isValid() && (msg.getRequester() == getNetworkId()) && (msg.getGameCode() == PlatformGameCode::SWG)) + { + // let script know the that account feature id has been + // retrieved so it can resume the rewards claim process + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "veteranAccountFeatureIdResponse", std::vector(), 0, false); + } + } + } + else if (message.getMethod() == "C++FeatureIdTransactionResponse") + { + if (!message.getPackedDataVector().empty()) + { + Archive::ByteStream bs; + bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); + + Archive::ReadIterator ri = bs.begin(); + FeatureIdTransactionResponse const msg(ri); + VeteranRewardManager::verifyFeatureIdTransactions(*this, msg.getTransactions()); + } + } + else if (message.getMethod() == "C++TransferReplyMoveValidation") + { + if (!message.getPackedDataVector().empty()) + { + Archive::ByteStream bs; + bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); + + Archive::ReadIterator ri = bs.begin(); + TransferReplyMoveValidation const msg(ri); + + // we should only be here if the validation failed + TransferRequestMoveValidation::TransferRequestSource const transferRequestSource = msg.getTransferRequestSource(); + if (transferRequestSource == TransferRequestMoveValidation::TRS_console_god_command) + { + TransferReplyMoveValidation::TransferReplyMoveValidationResult const result = msg.getResult(); + + if (result == TransferReplyMoveValidation::TRMVR_cannot_create_regular_character) + { + ConsoleMgr::broadcastString(FormattedString<256>().sprintf("the destination station id (%u) is not allowed to create any more character on the destination galaxy (%s)", msg.getDestinationStationId(), msg.getDestinationGalaxy().c_str()), getClient()); + } + else if (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid) + { + ConsoleMgr::broadcastString(FormattedString<256>().sprintf("either the destination galaxy (%s) is invalid, or the destination galaxy (%s) is not using the same login server as this galaxy", msg.getDestinationGalaxy().c_str(), msg.getDestinationGalaxy().c_str()), getClient()); + } + else if (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected) + { + ConsoleMgr::broadcastString(FormattedString<256>().sprintf("the destination galaxy (%s) is not currently started", msg.getDestinationGalaxy().c_str()), getClient()); + } + else if (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading) + { + ConsoleMgr::broadcastString(FormattedString<256>().sprintf("the destination galaxy (%s) is currently loading", msg.getDestinationGalaxy().c_str()), getClient()); + } + else + { + ConsoleMgr::broadcastString(FormattedString<256>().sprintf("transfer validation failed with error code (%d)", static_cast(result)), getClient()); + } + } + else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_transfer)) + { + TransferReplyMoveValidation::TransferReplyMoveValidationResult const result = msg.getResult(); + if (result == TransferReplyMoveValidation::TRMVR_cannot_create_regular_character) + { + ScriptParams params; + params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateFailCannotCreateCharacter", dictionary->getSerializedData(), 0, false); + } + } + else if ((result == TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid) || + (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected) || + (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading)) + { + ScriptParams params; + params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateFailDestGalaxyUnavailable", dictionary->getSerializedData(), 0, false); + } + } + else + { + LOG("CustomerService", ("CharacterTransfer: transfer validation failed for [%u, %s, %s (%s)] to [%u, %s, %s] with unexpected error code (%d)", msg.getSourceStationId(), msg.getSourceGalaxy().c_str(), msg.getSourceCharacter().c_str(), msg.getSourceCharacterId().getValueString().c_str(), msg.getDestinationStationId(), msg.getDestinationGalaxy().c_str(), msg.getDestinationCharacter().c_str(), static_cast(result))); + } + } + else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_transfer)) + { + TransferReplyMoveValidation::TransferReplyMoveValidationResult const result = msg.getResult(); + if (result == TransferReplyMoveValidation::TRMVR_cannot_create_regular_character) + { + ScriptParams params; + params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateFailCannotCreateCharacter", dictionary->getSerializedData(), 0, false); + } + } + else if ((result == TransferReplyMoveValidation::TRMVR_destination_galaxy_invalid) || + (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_not_connected) || + (result == TransferReplyMoveValidation::TRMVR_destination_galaxy_in_loading)) + { + ScriptParams params; + params.addParam(msg.getDestinationGalaxy().c_str(), "destinationGalaxy"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateFailDestGalaxyUnavailable", dictionary->getSerializedData(), 0, false); + } + } + else + { + LOG("CustomerService", ("CharacterTransfer: transfer validation failed for [%u, %s, %s (%s)] to [%u, %s, %s] with unexpected error code (%d)", msg.getSourceStationId(), msg.getSourceGalaxy().c_str(), msg.getSourceCharacter().c_str(), msg.getSourceCharacterId().getValueString().c_str(), msg.getDestinationStationId(), msg.getDestinationGalaxy().c_str(), msg.getDestinationCharacter().c_str(), static_cast(result))); + } + } + } + } + else if (message.getMethod() == "C++TransferReplyNameValidation") + { + if (!message.getPackedDataVector().empty()) + { + Archive::ByteStream bs; + bs.put(reinterpret_cast(&message.getPackedDataVector()[0]), static_cast(message.getPackedDataVector().size())); + + Archive::ReadIterator ri = bs.begin(); + GenericValueTypeMessage > const msg(ri); + + TransferRequestMoveValidation::TransferRequestSource const transferRequestSource = msg.getValue().second.getTransferRequestSource(); + + if (!msg.getValue().second.getIsValidName()) + { + if (transferRequestSource == TransferRequestMoveValidation::TRS_console_god_command) + { + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("the character name (%s) is not available on galaxy (%s) because of reason (%s)", msg.getValue().second.getDestinationCharacterName().c_str(), msg.getValue().second.getDestinationGalaxy().c_str(), msg.getValue().first.c_str()), getClient()); + } + else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_transfer)) + { + ScriptParams params; + params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); + params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); + params.addParam(msg.getValue().first.c_str(), "reason"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateFailNameValidation", dictionary->getSerializedData(), 0, false); + } + } + else if ((transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_validate) || (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_transfer)) + { + ScriptParams params; + params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); + params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); + params.addParam(msg.getValue().first.c_str(), "reason"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateFailNameValidation", dictionary->getSerializedData(), 0, false); + } + } + } + else if (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_freects_command_validate) + { + ScriptParams params; + params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); + params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleFreeCtsValidateSuccess", dictionary->getSerializedData(), 0, false); + } + } + else if (transferRequestSource == TransferRequestMoveValidation::TRS_ingame_cts_command_validate) + { + ScriptParams params; + params.addParam(msg.getValue().second.getDestinationGalaxy().c_str(), "destinationGalaxy"); + params.addParam(msg.getValue().second.getDestinationCharacterName().c_str(), "destinationCharacterName"); + ScriptDictionaryPtr dictionary; + GameScriptObject::makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), "handleCtsValidateSuccess", dictionary->getSerializedData(), 0, false); + } + } + } + } + else if (message.getMethod() == "C++PickupAllRoomItemsIntoInventory") + { + // use while(true) loop to use break to discontinue processing and go to the end of loop to run cleanup code + PlayerObject * playerObject = NULL; + while (true) + { + playerObject = PlayerCreatureController::getPlayerObject(this); + if (!playerObject) + break; + + // player has disconnected + if (!getClient()) + break; + + // don't allow this in god mode because it could be used accidentally and pick up a bunch of stuff, + // and god mode allows stuff to be picked up, which wouldn't normally be allowed to be picked up + if (getClient()->isGod()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you switched into GOD mode."), Unicode::emptyString); + break; + } + + // player is not "active", meaning he's probably doing it with a macro + if (playerObject->getSessionLastActiveTime() == 0) + break; + + int operationId = 0; + if (!getObjVars().getItem("pickupDropAllItemsOperation.operationId", operationId) || (operationId == 0)) + break; + + if (operationId != playerObject->getPickupDropAllItemsOperationId()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an unexpected condition. Please try the operation again."), Unicode::emptyString); + break; + } + + NetworkId const & cellId = playerObject->getPickupDropAllItemsCellId(); + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (!containingCell || !containingCell->asCellObject() || (containingCell->getNetworkId() != cellId)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you have left the room."), Unicode::emptyString); + break; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you have left the room."), Unicode::emptyString); + break; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you have left the room."), Unicode::emptyString); + break; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); + break; + } + + if (!containingPOB->isOnAdminList(*this)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because you are no longer the the owner or an admin of the structure or POB ship."), Unicode::emptyString); + break; + } + + ServerObject * const targetInventoryObj = getInventory(); + if (!targetInventoryObj) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); + break; + } + + VolumeContainer * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); + if (!targetInventoryContainer) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); + break; + } + + int const inventoryBaseLimit = targetInventoryContainer->getTotalVolume(); + int const inventoryLimit = (playerObject->getPickupAllItemsAllowInventoryOverload() ? std::max(inventoryBaseLimit, (inventoryBaseLimit + ConfigServerGame::getMoveValidationMaxInventoryOverload() - 11)) : inventoryBaseLimit); + + if (targetInventoryContainer->getCurrentVolume() >= inventoryLimit) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because your inventory is full."), Unicode::emptyString); + + // if they didn't run the command with the -overload + // option, remind them about the -overload option + if (!playerObject->getPickupAllItemsAllowInventoryOverload()) + Chat::sendSystemMessage(*this, Unicode::narrowToWide("If you wish to pick up more items than available inventory space, you can specify the \"overload\" option with the command by typing \"/pickupAllRoomItemsIntoInventory -overload\" which will pick up additional items and overload your inventory, but not so overloaded as to prevent you from moving."), Unicode::emptyString); + + break; + } + + Container const * const cellContainer = ContainerInterface::getContainer(*containingCell); + if (!cellContainer) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because of an internal error."), Unicode::emptyString); + break; + } + + std::set & processedItemsSoFar = playerObject->getPickupDropAllItemsProcessedItemsSoFar(); + std::list cellContents; + { + for (ContainerConstIterator iter = cellContainer->begin(); iter != cellContainer->end(); ++iter) + { + if ((*iter != getNetworkId()) && (processedItemsSoFar.count(*iter) <= 0)) + cellContents.push_back(*iter); + } + } + + if (cellContents.empty()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because no more items in the room can be picked up or the room is empty."), Unicode::emptyString); + break; + } + + // if necessary, temporary increase the inventory limit to allow overload + if (inventoryLimit > inventoryBaseLimit) + targetInventoryContainer->debugDoNotUseSetCapacity(inventoryLimit); + + int numberOfItemsPickedUpSoFar = playerObject->getPickupDropAllItemsNumItemsSoFar(); + + char buffer[512]; + Vector const pos = Transform::identity.getPosition_p(); + snprintf(buffer, sizeof(buffer)-1, " %s -1 %f %f %f", targetInventoryObj->getNetworkId().getValueString().c_str(), pos.x, pos.y, pos.z); + buffer[sizeof(buffer)-1] = '\0'; + Unicode::String const commandTransferItemMiscParams = Unicode::narrowToWide(buffer); + + static uint32 const hashTransferItemMisc = Crc::normalizeAndCalculate("transferItemMisc"); + Command const & commandTransferItemMisc = CommandTable::getCommand(hashTransferItemMisc); + ServerObject const * cellContent; + bool blockedByNoTrade; + bool showPickUpMenu; + Container::ContainerErrorCode cec; + int previousVolume, newVolume; + int numberOfItemsToProcessThisRound = ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound(); + for (std::list::const_iterator iter = cellContents.begin(); iter != cellContents.end(); ++iter) + { + --numberOfItemsToProcessThisRound; + processedItemsSoFar.insert(*iter); + + cellContent = safe_cast(iter->getObject()); + if (!cellContent) + continue; + + if (ContainerInterface::getContainedByObject(*cellContent) != containingCell) + continue; + + // see if the item would normally have the "Pick Up" menu item on it + if (!PlayerCreatureController::objectMenuRequestCanManipulateObject(*this, *cellContent, blockedByNoTrade, showPickUpMenu)) + continue; + + if (!showPickUpMenu) + continue; + + // see if item would fit in inventory + if (!targetInventoryContainer->mayAdd(*cellContent, cec)) + continue; + + // "Pick Up" the item, just as if the player had used the "Pick Up" radial or /pickup command + previousVolume = targetInventoryContainer->getCurrentVolume(); + CommandCppFuncs::commandFuncTransferMisc(commandTransferItemMisc, getNetworkId(), cellContent->getNetworkId(), commandTransferItemMiscParams); + + // stop trying when inventory is full + newVolume = targetInventoryContainer->getCurrentVolume(); + if (newVolume >= inventoryLimit) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because your inventory is full."), Unicode::emptyString); + + // if they didn't run the command with the -overload + // option, remind them about the -overload option + if (!playerObject->getPickupAllItemsAllowInventoryOverload()) + Chat::sendSystemMessage(*this, Unicode::narrowToWide("If you wish to pick up more items than available inventory space, you can specify the \"overload\" option with the command by typing \"/pickupAllRoomItemsIntoInventory -overload\" which will pick up additional items and overload your inventory, but not so overloaded as to prevent you from moving."), Unicode::emptyString); + + break; + } + + // update count of how many items have been picked up for the operation + numberOfItemsPickedUpSoFar += std::max(0, (newVolume - previousVolume)); + + // stop trying when enough items have been picked up for the operation + if (numberOfItemsPickedUpSoFar > inventoryLimit) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because \"enough\" items have been picked up."), Unicode::emptyString); + break; + } + + // only do so many items each round, to spread out the load + if (numberOfItemsToProcessThisRound <= 0) + break; + } + + // if necessary, restore the inventory limit + if (inventoryLimit > inventoryBaseLimit) + targetInventoryContainer->debugDoNotUseSetCapacity(inventoryBaseLimit); + + // stop if inventory is full + if (targetInventoryContainer->getCurrentVolume() >= inventoryLimit) + break; + + // stop if enough items have been picked up for the operation + if (numberOfItemsPickedUpSoFar > inventoryLimit) + break; + else + playerObject->setPickupDropAllItemsNumItemsSoFar(numberOfItemsPickedUpSoFar); + + // stop if no more items can be picked up + if (numberOfItemsToProcessThisRound > 0) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /pickupAllRoomItemsIntoInventory operation has been terminated because no more items in the room can be picked up or the room is empty."), Unicode::emptyString); + break; + } + + // queue up the next round of pickup + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++PickupAllRoomItemsIntoInventory", + "", + 1, + false); + + return; + } + + // if we reach this point, it means we are stopping the operation, so cleanup + removeObjVarItem("pickupDropAllItemsOperation"); + + if (playerObject) + { + playerObject->setPickupDropAllItemsOperationId(0); + playerObject->setPickupDropAllItemsCellId(NetworkId::cms_invalid); + playerObject->setPickupAllItemsAllowInventoryOverload(false); + playerObject->setPickupDropAllItemsNumItemsSoFar(0); + playerObject->getPickupDropAllItemsProcessedItemsSoFar().clear(); + } + } + else if (message.getMethod() == "C++DropAllInventoryItemsIntoRoom") + { + // use while(true) loop to use break to discontinue processing and go to the end of loop to run cleanup code + PlayerObject * playerObject = NULL; + while (true) + { + playerObject = PlayerCreatureController::getPlayerObject(this); + if (!playerObject) + break; + + // player has disconnected + if (!getClient()) + break; + + // don't allow this in god mode because it could be used accidentally and drop a bunch of stuff, + // and god mode allows stuff to be dropped, which wouldn't normally be allowed to be dropped + if (getClient()->isGod()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you switched into GOD mode."), Unicode::emptyString); + break; + } + + // player is not "active", meaning he's probably doing it with a macro + if (playerObject->getSessionLastActiveTime() == 0) + break; + + int operationId = 0; + if (!getObjVars().getItem("pickupDropAllItemsOperation.operationId", operationId) || (operationId == 0)) + break; + + if (operationId != playerObject->getPickupDropAllItemsOperationId()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an unexpected condition. Please try the operation again."), Unicode::emptyString); + break; + } + + NetworkId const & cellId = playerObject->getPickupDropAllItemsCellId(); + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (!containingCell || !containingCell->asCellObject() || (containingCell->getNetworkId() != cellId)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you have left the room."), Unicode::emptyString); + break; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you have left the room."), Unicode::emptyString); + break; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you have left the room."), Unicode::emptyString); + break; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an internal error."), Unicode::emptyString); + break; + } + + if (!containingPOB->isOnAdminList(*this)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because you are no longer the the owner or an admin of the structure or POB ship."), Unicode::emptyString); + break; + } + + int pobBaseItemLimit = 0; + int pobAdditionalItems = 0; + const int pobItemLimit = containingPOB->getPobTotalItemLimit(pobBaseItemLimit, pobAdditionalItems); + + if (containingPOB->getPobItemCount() >= pobItemLimit) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because the structure or POB ship is full."), Unicode::emptyString); + break; + } + + ServerObject const * const targetInventoryObj = getInventory(); + if (!targetInventoryObj) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an internal error."), Unicode::emptyString); + break; + } + + VolumeContainer const * const targetInventoryContainer = ContainerInterface::getVolumeContainer(*targetInventoryObj); + if (!targetInventoryContainer) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because of an internal error."), Unicode::emptyString); + break; + } + + int const inventoryOverloadLimit = targetInventoryContainer->getTotalVolume() + ConfigServerGame::getMoveValidationMaxInventoryOverload(); + + std::set & processedItemsSoFar = playerObject->getPickupDropAllItemsProcessedItemsSoFar(); + std::list inventoryContents; + { + for (ContainerConstIterator iter = targetInventoryContainer->begin(); iter != targetInventoryContainer->end(); ++iter) + { + if (processedItemsSoFar.count(*iter) <= 0) + inventoryContents.push_back(*iter); + } + } + + if (inventoryContents.empty()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because no more items in your inventory can be dropped or your inventory is empty."), Unicode::emptyString); + break; + } + + int numberOfItemsDroppedSoFar = playerObject->getPickupDropAllItemsNumItemsSoFar(); + + char buffer[512]; + Vector const pos = getTransform_o2c().getPosition_p(); + snprintf(buffer, sizeof(buffer)-1, " %s -1 %f %f %f", containingCell->getNetworkId().getValueString().c_str(), pos.x, pos.y, pos.z); + buffer[sizeof(buffer)-1] = '\0'; + Unicode::String const commandTransferItemMiscParams = Unicode::narrowToWide(buffer); + + static uint32 const hashTransferItemMisc = Crc::normalizeAndCalculate("transferItemMisc"); + Command const & commandTransferItemMisc = CommandTable::getCommand(hashTransferItemMisc); + ServerObject const * inventoryContent; + int previousVolume, newVolume; + int numberOfItemsToProcessThisRound = ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound(); + for (std::list::const_iterator iter = inventoryContents.begin(); iter != inventoryContents.end(); ++iter) + { + --numberOfItemsToProcessThisRound; + processedItemsSoFar.insert(*iter); + + inventoryContent = safe_cast(iter->getObject()); + if (!inventoryContent) + continue; + + if (ContainerInterface::getContainedByObject(*inventoryContent) != targetInventoryObj) + continue; + + previousVolume = containingPOB->getPobItemCount(); + if ((previousVolume + inventoryContent->getVolume()) > pobItemLimit) + continue; + + // "Drop" the item, just as if the player had used the "Drop" radial + CommandCppFuncs::commandFuncTransferMisc(commandTransferItemMisc, getNetworkId(), inventoryContent->getNetworkId(), commandTransferItemMiscParams); + + // stop trying when POB is full + newVolume = containingPOB->getPobItemCount(); + if (newVolume >= pobItemLimit) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because the structure or POB ship is full."), Unicode::emptyString); + break; + } + + // update count of how many items have been dropped for the operation + numberOfItemsDroppedSoFar += std::max(0, (newVolume - previousVolume)); + + // stop trying when enough items have been dropped for the operation + if ((numberOfItemsDroppedSoFar > inventoryOverloadLimit) && (numberOfItemsDroppedSoFar > ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound())) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because \"enough\" items have been dropped."), Unicode::emptyString); + break; + } + + // only do so many items each round, to spread out the load + if (numberOfItemsToProcessThisRound <= 0) + break; + } + + // stop if POB is full + if (containingPOB->getPobItemCount() >= pobItemLimit) + break; + + // stop if enough items have been dropped for the operation + if ((numberOfItemsDroppedSoFar > inventoryOverloadLimit) && (numberOfItemsDroppedSoFar > ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound())) + break; + else + playerObject->setPickupDropAllItemsNumItemsSoFar(numberOfItemsDroppedSoFar); + + // stop if no more items can be dropped + if (numberOfItemsToProcessThisRound > 0) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The /dropAllInventoryItemsIntoRoom operation has been terminated because no more items in your inventory can be dropped or your inventory is empty."), Unicode::emptyString); + break; + } + + // queue up the next round of drop + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++DropAllInventoryItemsIntoRoom", + "", + 1, + false); + + return; + } + + // if we reach this point, it means we are stopping the operation, so cleanup + removeObjVarItem("pickupDropAllItemsOperation"); + + if (playerObject) + { + playerObject->setPickupDropAllItemsOperationId(0); + playerObject->setPickupDropAllItemsCellId(NetworkId::cms_invalid); + playerObject->setPickupAllItemsAllowInventoryOverload(false); + playerObject->setPickupDropAllItemsNumItemsSoFar(0); + playerObject->getPickupDropAllItemsProcessedItemsSoFar().clear(); + } + } + else if (message.getMethod() == "C++RestoreDecorationLayout") + { + // use while(true) loop to use break to discontinue processing and go to the end of loop to run cleanup code + PlayerObject * playerObject = NULL; + while (true) + { + playerObject = PlayerCreatureController::getPlayerObject(this); + if (!playerObject) + break; + + // player has disconnected + if (!getClient()) + break; + + // player is not "active", meaning he's probably doing it with a macro + if (playerObject->getSessionLastActiveTime() == 0) + break; + + int operationId = 0; + if (!getObjVars().getItem("restoreDecorationOperation.operationId", operationId) || (operationId == 0)) + break; + + if (operationId != playerObject->getRestoreDecorationOperationId()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because of an unexpected condition. Please try the operation again."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + ServerObject * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + ServerObject * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + if (containingPOBso->getNetworkId() != playerObject->getRestoreDecorationPobId()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you have left the structure or POB ship."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + TangibleObject * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because of an internal error."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + if (!containingPOB->isOnAdminList(*this)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been terminated because you are no longer the the owner or an admin of the structure or POB ship."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + int numberOfItemsToProcessThisRound = ConfigServerGame::getPickDropAllRoomItemsNumberOfItemsPerRound(); + std::list, std::pair > > & restoreDecorationLayoutList = playerObject->getRestoreDecorationLayoutList(); + while (!restoreDecorationLayoutList.empty() && (numberOfItemsToProcessThisRound > 0)) + { + std::pair, std::pair > const & front = restoreDecorationLayoutList.front(); + restoreItemDecorationLayout(*this, *playerObject, front.first.first, *containingPOB, front.first.second, front.second.first, front.second.second); + playerObject->setRestoreDecorationAttemptedCount(playerObject->getRestoreDecorationAttemptedCount() + 1); + --numberOfItemsToProcessThisRound; + restoreDecorationLayoutList.pop_front(); + } + + if (restoreDecorationLayoutList.empty()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("The restore decoration layout operation has been completed."), Unicode::emptyString); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("%d items to be moved/restored, %d items attempted, %d items moved/restored.", playerObject->getRestoreDecorationTotalCount(), playerObject->getRestoreDecorationAttemptedCount(), playerObject->getRestoreDecorationSuccessCount())), Unicode::emptyString); + break; + } + + // queue up the next round of restore + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++RestoreDecorationLayout", + "", + 1, + false); + + return; + } + + // if we reach this point, it means we are stopping the operation, so cleanup + removeObjVarItem("restoreDecorationOperation"); + + if (playerObject) + { + playerObject->setRestoreDecorationOperationId(0); + playerObject->setRestoreDecorationPobId(NetworkId::cms_invalid); + playerObject->setRestoreDecorationTotalCount(0); + playerObject->setRestoreDecorationAttemptedCount(0); + playerObject->setRestoreDecorationSuccessCount(0); + playerObject->getRestoreDecorationLayoutList().clear(); + } + } + else if (message.getMethod() == "C++CityAddCitizen") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + const int cityId = atoi(params.c_str()); + if (cityId > 0) + CityInterface::enterCityChatRoom(cityId, *this); + } + } + else if (message.getMethod() == "C++CityRemoveCitizen") + { + if (!message.getPackedDataVector().empty()) + { + std::string const params(message.getPackedDataVector().begin(), message.getPackedDataVector().end()); + const int cityId = atoi(params.c_str()); + if (cityId > 0) + CityInterface::leaveCityChatRoom(cityId, *this); + } + } + else + { + TangibleObject::handleCMessageTo(message); + } +} + +//----------------------------------------------------------------------- + +bool CreatureObject::alwaysSendReliableTransform() const +{ + return false; +} + +//----------------------------------------------------------------------- + +bool CreatureObject::immediateLogoutAllowed() +{ + // Notes: + // 1. This should only be called on authoritative objects. + // 2. This call is triggered by a client disconnect that we will only see if a client is + // already associated with this object. + // 3. A client is only associated with an object when the object has finished baselines and + // is authoritative; therefore, we should never hit a case where a player that is logging + // in gets disconnected and causes this function to get called. + // 4. Even though this function is phrased as a query, it has some serious side effects. + // Calling it should be treated as if the caller is saying "Prepare for a disconnect" even + // though script can override and prevent an immediate logout. + DEBUG_FATAL(!isAuthoritative(), ("CreatureObject::immediateLogoutAllowed() should only be called on authoritative objects.")); + + // if we are in an npc conversation, end it + if (isInNpcConversation()) + endNpcConversation(); + + // if we are mounted, dismount. + if (getState(States::RidingMount)) + { + CreatureObject *const mountedCreature = getMountedCreature(); + if (mountedCreature) + mountedCreature->detachRider(getNetworkId()); + } + + virtualOnLogout(); + + LOG("CustomerService", ("Money:%s logging out with %d money", PlayerObject::getAccountDescription(getNetworkId()).c_str(), getTotalMoney())); + + ScriptParams params; + return (getScriptObject()->trigAllScripts(Scripting::TRIG_IMMEDIATE_LOGOUT, params) == SCRIPT_CONTINUE); +} + +//----------------------------------------------------------------------- + +float CreatureObject::getStepHeight() const +{ + return static_cast(getSharedTemplate())->getStepHeight(); +} + +//---------------------------------------------------------------------- + +float CreatureObject::getApproachTriggerRange() const +{ + return static_cast(getObjectTemplate())->getApproachTriggerRange(); +} + +//---------------------------------------------------------------------- + +void CreatureObject::setIsBeast(bool newValue) +{ + if(m_isBeast.get() != newValue) + { + m_isBeast.set(newValue); + } +} + +//---------------------------------------------------------------------- + +bool CreatureObject::setForceShowHam(bool show) +{ + if(!isAuthoritative()) + { + return false; + } + + m_forceShowHam.set(show); + return true; +} + +//---------------------------------------------------------------------- + +void CreatureObject::setIsStatic(bool newValue) +{ + if(m_isStatic.get() != newValue) + { + m_isStatic = newValue; + if (newValue) + { + TerrainObject* const terrain = TerrainObject::getInstance(); + if (terrain && terrain->isReferenceObject(this)) + terrain->removeReferenceObject(this); + // don't alter static creatures + if (!isPlayerControlled()) + setDefaultAlterTime(AlterResult::cms_keepNoAlter); + } + else + { + potentiallyAddToTerrain(); + if (!isPlayerControlled()) + setDefaultAlterTime(AlterResult::cms_alterQuickly); + } + } +} + +//---------------------------------------------------------------------- + +bool CreatureObject::potentiallyAddToTerrain() +{ + //@todo don't make reference object if any of the following are true: + // check is "asleep" (must add when woken up) + + TerrainObject* const terrain = TerrainObject::getInstance (); + if ( isAuthoritative() && !getIsStatic() && !getCreatureController()->getHibernate() && terrain && !terrain->isReferenceObject(this) && isInWorldCell() ) + { + terrain->addReferenceObject(this); + return true; + } + return false; +} + +//---------------------------------------------------------------------- + +void CreatureObject::virtualOnAddedToWorldCell() +{ + TangibleObject::virtualOnAddedToWorldCell(); + potentiallyAddToTerrain(); + m_lastRegionNotifyPosition = getPosition_w(); + m_lastRegionNotifyPosition.x += 1.0f; // force a check + checkNotifyRegions(); +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::virtualOnRemovedFromWorldCell() +{ + TangibleObject::virtualOnRemovedFromWorldCell(); + + TerrainObject* const terrain = TerrainObject::getInstance(); + if (terrain && terrain->isReferenceObject(this)) + terrain->removeReferenceObject(this); +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::virtualOnSetAuthority() +{ + TangibleObject::virtualOnSetAuthority(); + + potentiallyAddToTerrain(); + + for (int i = 0; i < Attributes::NumberOfAttributes; ++i) + m_regeneration[i] = 0; + + if (isPlayerControlled()) + { + setNumberOfMissionsWantedInMissionBag(ConfigServerGame::getNumberOfMissionsWantedInMissionBag()); + + if (isInitialized()) + { + Client *client = GameServer::getInstance().getClient(getNetworkId()); + if (client) + client->onLoadPlayer(*this); + } + } + + AICreatureController * const controller = AICreatureController::asAiCreatureController(getController()); + + if (controller) + controller->setAuthority(true); + + //-- Update the creature's group mission critical object set + GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::virtualOnReleaseAuthority() +{ + TangibleObject::virtualOnReleaseAuthority(); + TerrainObject* const terrain = TerrainObject::getInstance(); + if (terrain && terrain->isReferenceObject(this)) + terrain->removeReferenceObject(this); + + AICreatureController * const controller = AICreatureController::asAiCreatureController(getController()); + + if(controller) + { + if (getProperty(SlopeEffectProperty::getClassPropertyId()) != NULL) + removeProperty(SlopeEffectProperty::getClassPropertyId()); + controller->setAuthority(false); + } +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::virtualOnLogout() +{ + TangibleObject::virtualOnLogout(); + PlayerObject * const player = PlayerCreatureController::getPlayerObject(this); + if (player != NULL) + player->virtualOnLogout(); +} + +//------------------------------------------------------------------------------------------ + +bool CreatureObject::wantSawAttackTriggers() const +{ + if (isDisabled()) + return false; + return TangibleObject::wantSawAttackTriggers(); +} + +//---------------------------------------------------------------------- + +void CreatureObject::addPackedWearable(std::string const &appearanceData, int arrangementIndex, NetworkId const &networkId, uint32 sharedTemplateCrcValue, const BaselinesMessage * weaponSharedBaselines, const BaselinesMessage * weaponSharedNpBaselines) +{ + //-- Check if this network id already exists in the wearable list. + size_t const length = m_wearableData.size(); + for (size_t i = 0; i < length; ++i) + { + WearableEntry const &entry = m_wearableData[i]; + if (entry.m_networkId == networkId) + { + // Check if this entry exists but in a different configuration. + WARNING((entry.m_arrangement != arrangementIndex), ("attempted to add object id=[%s] in packed wearable list multiple times in different arrangements, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_arrangement, arrangementIndex)); + WARNING((static_cast(entry.m_objectTemplate) != sharedTemplateCrcValue), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by shared object template crc value, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_objectTemplate, static_cast(sharedTemplateCrcValue))); + DEBUG_WARNING((entry.m_appearanceString != appearanceData), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by appearance customization data.", appearanceData.c_str())); + + // Done, this entry is already in the wearable data list. + + // we own the weaponSharedBaselines and weaponSharedBaselines pointers, so if + // we are not going to add them to the wearables list, we must delete them + if (weaponSharedBaselines) + delete weaponSharedBaselines; + if (weaponSharedNpBaselines) + delete weaponSharedNpBaselines; + + return; + } + } + + //-- Add the new entry. + m_wearableData.push_back(WearableEntry(appearanceData, arrangementIndex, networkId, sharedTemplateCrcValue, weaponSharedBaselines, weaponSharedNpBaselines)); +} + +//---------------------------------------------------------------------- + +void CreatureObject::packWearables() +{ + // Pack wearables data + + SlottedContainer const * const myContainer = ContainerInterface::getSlottedContainer(*this); + + if (myContainer) + { + Object const * inventory = 0; + Object const * datapad = 0; + Object const * appearance = 0; + Container::ContainerErrorCode tmp = Container::CEC_Success; + static SlotId const inventorySlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::inventory); + if (inventorySlot != SlotId::invalid) + { + Container::ContainedItem itemId = myContainer->getObjectInSlot(inventorySlot, tmp); + inventory = itemId.getObject(); + } + SlotId datapadSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::datapad); + if (datapadSlot != SlotId::invalid) + { + Container::ContainedItem itemId = myContainer->getObjectInSlot(datapadSlot, tmp); + datapad = itemId.getObject(); + } + SlotId appearanceInvSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); + if (appearanceInvSlot != SlotId::invalid) + { + Container::ContainedItem itemId = myContainer->getObjectInSlot(appearanceInvSlot, tmp); + appearance = itemId.getObject(); + } + + for (ContainerConstIterator iter = myContainer->begin(); iter != myContainer->end(); ++iter) + { + Object const * const o = (*iter).getObject(); + if (o) + { + ServerObject const * const so = o->asServerObject(); + if (so) + { + TangibleObject const * const tang = so->asTangibleObject(); + if (tang) + { + SlottedContainmentProperty const * const scp = ContainerInterface::getSlottedContainmentProperty(*tang); + if (scp) + { + if (scp->isInAppearanceSlot() || tang == inventory || tang == datapad ) + { + ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tang->getClientSharedTemplateName()); + if (clientSharedTemplateNameCrcString.isEmpty()) + WARNING(true, ("Could not find crc for [%s]. Wearable will not be streamed to client", tang->getClientSharedTemplateName())); + else if (so->asWeaponObject() != NULL) + { + addPackedWearable(tang->getAppearanceData(), scp->getCurrentArrangement(), tang->getNetworkId(), clientSharedTemplateNameCrcString.getCrc(), + tang->createSharedBaselinesMessage(), tang->createSharedNpBaselinesMessage()); + } + else + addPackedWearable(tang->getAppearanceData(), scp->getCurrentArrangement(), tang->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); + } + } + } + } + } + } + + if(appearance) + { + SlottedContainer const * const myAppearanceContainer = ContainerInterface::getSlottedContainer(*appearance); + for(ContainerConstIterator iter = myAppearanceContainer->begin(); iter!= myAppearanceContainer->end(); ++iter) + { + Object const * const o = (*iter).getObject(); + if (o) + { + ServerObject const * const so = o->asServerObject(); + if (so) + { + TangibleObject const * const tang = so->asTangibleObject(); + if (tang) + { + SlottedContainmentProperty const * const scp = ContainerInterface::getSlottedContainmentProperty(*tang); + if (scp) + { + if (scp->isInAppearanceSlot()) + { + ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tang->getClientSharedTemplateName()); + if (clientSharedTemplateNameCrcString.isEmpty()) + WARNING(true, ("Could not find crc for [%s]. Wearable will not be streamed to client", tang->getClientSharedTemplateName())); + else + addPackedAppearanceWearable(tang->getAppearanceData(), scp->getCurrentArrangement(), tang->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); + } + } + } + } + } + } + } + } +} + +// ---------------------------------------------------------------------- + +/** + * Called when we get an ack back that a Jedi slot has been added to our account. + * This function should only be called by PlayerObject::addJediToAccountAck()! + */ +void CreatureObject::addJediToAccountAck() +{ + // flag success via an objvar so we can end the timed callback C++AddJediSlot + setObjVarItem(OBJVAR_ADD_JEDI_ACK, 1); +} // CreatureObject::addJediToAccountAck + + +//---------------------------------------------------------------------- + +void CreatureObject::setNumberOfMissionsWantedInMissionBag(int n) +{ + int i = 0; + ServerObject * const missionBag = getMissionBag(); + if(missionBag) + { + Container * const container = ContainerInterface::getContainer(*missionBag); + ContainerIterator iter; + for(iter = container->begin(); iter != container->end(); ++iter) + { + Object * const o = (*iter).getObject(); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so && so->asMissionObject()) + ++i; + } + } + + if (n - i > 0) + { + if (m_numberOfMissionsWantedInMissionBag <= 0) + { + // place object on mission object create queue + s_missionQueue.push_back(getNetworkId()); + } + m_numberOfMissionsWantedInMissionBag = n - i; + } + else if (i - n > 0) + { + // remove mission objects from the bag + int j = 0; + for (iter = container->begin(), j = 0; (iter != container->end() && j < i - n); ++iter, ++j) + { + Object * const o = (*iter).getObject(); + if (o) + { + ServerObject * const so = o->asServerObject(); + if (so && so->asMissionObject()) + so->kill(); + } + } + } + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::runMissionCreationQueue() +{ + int i = ConfigServerGame::getMissionCreationQueueSize(); + while(i > 0 && !s_missionQueue.empty()) + { + const NetworkId id = s_missionQueue.front(); + s_missionQueue.pop_front(); + CreatureObject * creature = safe_cast(NetworkIdManager::getObjectById(id)); + if(creature) + { + if(creature->isAuthoritative()) + { + if(MissionObject::createMissionObjectInCreatureMissionBag(creature)) + creature->m_numberOfMissionsWantedInMissionBag--; + if(creature->m_numberOfMissionsWantedInMissionBag > 0) + s_missionQueue.push_back(id); + } + } + i--; + } +} + +//---------------------------------------------------------------------- + +int CreatureObject::getMaxNumberOfLots() const +{ + return HOUSING_MAX_LOTS; +} + +//---------------------------------------------------------------------- + +NetworkId CreatureObject::getHouse() const +{ + NetworkId houseId; + + // the objvar houseId is per player and is used if it exists + if (getObjVars().getItem(OBJVAR_PLAYER_HOUSE_ID, houseId)) + return houseId; + + return NetworkId::cms_invalid; +} + +//---------------------------------------------------------------------- + +void CreatureObject::setHouse(const CachedNetworkId & houseId) +{ + if (isAuthoritative()) + { + // store as an objvar to keep this id per player vs. per account + setObjVarItem(OBJVAR_PLAYER_HOUSE_ID, houseId); + } + else + { + sendControllerMessageToAuthServer(CM_setHouse, new MessageQueueGenericValueType(houseId)); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::getAvailableLocomotions() +{ + getMovementTable()->getAllLocomotions(m_posture.get(), m_states.get(), m_fastLocomotion, m_slowLocomotion, m_stationaryLocomotion); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::calcPvpableState() +{ + setPvpable(true); +} + +// ---------------------------------------------------------------------- + +float CreatureObject::getBaseWalkSpeed() const +{ + float speed = m_baseWalkSpeed.get(); + if (speed < 0.0f) + return safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_walk); + return speed; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setBaseWalkSpeed(float speed) +{ + if (isAuthoritative()) + { + if (m_baseWalkSpeed.get() != speed) + { + m_baseWalkSpeed = speed; + requestMovementInfoUpdate(); + } + } + else + { + Controller *controller = getController(); + if (controller) + controller->appendMessage( + CM_creatureSetBaseWalkSpeed, + speed, + 0, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +// ---------------------------------------------------------------------- + +float CreatureObject::getBaseRunSpeed() const +{ + float speed = m_baseRunSpeed.get(); + if (speed < 0.0f) + return safe_cast(getSharedTemplate())->getSpeed(SharedCreatureObjectTemplate::MT_run); + return speed; +} + +// ---------------------------------------------------------------------- + +int CreatureObject::loadPackedHouses() +{ + int numHouses = 0; + ServerObject *datapad = getDatapad(); + if (datapad) + { + VolumeContainer const * datapadContainer = ContainerInterface::getVolumeContainer(*datapad); + if (datapadContainer) + { + // iterate over contents. + for(ContainerConstIterator iter(datapadContainer->begin()); + iter != datapadContainer->end(); + ++iter) + { + const CachedNetworkId & objId = (*iter); + const ServerObject * obj = safe_cast(objId.getObject()); + if (obj && (obj->getGameObjectType() == SharedObjectTemplate::GOT_data_house_control_device)) + { + // if object is a house control device, then go ahead and get the first contained item - + // should be the house itself. + SlottedContainer const *hcdContainer = ContainerInterface::getSlottedContainer(*obj); + if (hcdContainer && hcdContainer->getNumberOfItems() > 0) + { + //load the contents for the house. + for(ContainerConstIterator hcdIter(hcdContainer->begin()); + hcdIter != hcdContainer->end(); + ++hcdIter) + { + Object * const houseId = (*hcdIter).getObject(); + BuildingObject * const house = (houseId ? houseId->asServerObject()->asBuildingObject() : NULL); + if (house && !house->getContentsLoaded()) + { + LOG("CustomerService", ("CharacterTransfer: starting packed house load (%s) for CTS character %s", house->getNetworkId().getValueString().c_str(), PlayerObject::getAccountDescription(this).c_str())); + + numHouses++; + house->loadContents(); + setLoadCTSPackedHouses(true); + } + } + } + } + } + } + } + + return numHouses; +} + +// ---------------------------------------------------------------------- + +std::vector CreatureObject::uploadCharacterData(const bool withItems, const bool allowOverride) +{ + std::vector result; + + if(getClient()) + { + GameScriptObject * scriptObject = getScriptObject(); + if(scriptObject) + { + int resultSize = 0; + std::vector tmp; + tmp.resize(ConfigServerGame::getCtsDefaultScriptDictionarySizeBytes()); + + ScriptParams p; + p.addParam(tmp); + p.addParam(resultSize); + p.addParam(withItems); + p.addParam(allowOverride); + REPORT_LOG(true, ("Calling OnStartCharacterUpload from CreatureObject.cpp\n")); + IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_START_CHARACTER_UPLOAD, p)); + + resultSize = p.getIntParam(1); + tmp = p.getByteArrayParam(0); + int i; + for(i=0; i < resultSize; ++i) + { + result.push_back(tmp[static_cast(i)]); + } + LOG("CustomerService", ("CharacterTransfer: CreatureObject::uploadCharacterData() yields a buffer %d bytes long", result.size())); + } + } + return result; +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::receiveCharacterTransferMessage(const std::vector & packedCharacterData) +{ + bool result = false; + GameScriptObject * scriptObject = getScriptObject(); + if(scriptObject) + { + ScriptParams p; + p.addParam(packedCharacterData); + if(scriptObject->trigAllScripts(Scripting::TRIG_DOWNLOAD_CHARACTER, p)) + { + result = true; + } + } + + if (result) + { + // tell CentralServer to not allow login for this character + // until the character has been persisted and unloaded + GenericValueTypeMessage > > const msg( + "SetSceneForPlayer", + std::make_pair( + getNetworkId(), + std::make_pair(ServerWorld::getSceneId(), true))); + + GameServer::getInstance().sendToCentralServer(msg); + + // set the idle time so that the character will be disconnected + // in ConfigServerGame::getIdleLogoutTimeAfterCharacterTransferSec() + // so that the character will get unloaded after the next save cycle, + // so that the player can log in the character; this should be much + // faster than the default idle disconnect behavior where the character + // would get disconnected in ConfigServerGame::getIdleLogoutTimeSec() + if (getClient()) + getClient()->resetIdleTimeAfterCharacterTransfer(); + } + + return result; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::receiveCharacterTransferStatusMessage(const std::string & statusMessage) +{ + GameScriptObject * scriptObject = getScriptObject(); + if(scriptObject) + { + ScriptParams p; + p.addParam(statusMessage.c_str()); + scriptObject->trigAllScripts(Scripting::TRIG_RECEIVE_CHARACTER_TRANSFER_STATUS_MESSAGE, p); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setBaseRunSpeed(float speed) +{ + if (isAuthoritative()) + { + if (m_baseRunSpeed.get() != speed) + { + m_baseRunSpeed = speed; + requestMovementInfoUpdate(); + } + } + else + { + Controller *controller = getController(); + if (controller) + controller->appendMessage( + CM_creatureSetBaseRunSpeed, + speed, + 0, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +// ---------------------------------------------------------------------- + +/** + * Tests if this creature has a bounty on another creature. + * (Virtual function, overriden in SwgCreatureObject) + * + * @param target the creature to test if we have a bounty on + * + * @return true if we have a bounty on the target, false if not + */ +bool CreatureObject::hasBounty(const CreatureObject & target) const +{ + //@todo: this should really be a function of the pvp classes, but we + // need this to be virtual + return false; +} // CreatureObject::hasBounty + +// ---------------------------------------------------------------------- + +/** + * Tests if this creature has a bounty on anything. + * (Virtual function, overriden in SwgCreatureObject, can't be pure virtual + * because ServerCreatureObjectTemplate has a function that instantiates a CreatureObject) + */ +bool CreatureObject::hasBounty() const +{ + return false; +} + +// ---------------------------------------------------------------------- + +/** + * Return a list of all the bounty hunters targeting this creature. + * + * Overriden in SwgCreatureObject. + */ +std::vector const & CreatureObject::getJediBountiesOnMe() const +{ + static const std::vector nothing; + return nothing; +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::hasBountyMissionForTarget(const NetworkId & targetId) const +{ + const ServerObject * const datapad = getDatapad(); + if (!datapad) + return false; + + const Container * const container = ContainerInterface::getContainer(*datapad); + if (!container) + return false; + + for (ContainerConstIterator iter = container->begin(); iter != container->end(); ++iter) + { + const ServerObject * const serverMissionObject = safe_cast((*iter).getObject()); + if (serverMissionObject) + { + const MissionObject * const missionObject = serverMissionObject->asMissionObject(); + if (missionObject) + { + static const unsigned int bounty = CrcLowerString::calculateCrc("bounty"); + NetworkId bountyTargetId; + + if ((missionObject->getMissionType() == bounty) && (missionObject->getObjVars().getItem("objTarget", bountyTargetId)) && (bountyTargetId == targetId)) + return true; + } + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setAlternateAppearance(std::string const &sharedObjectTemplateName) +{ + //-- Ensure we're authoritative. + if (!isAuthoritative()) + { + WARNING(true, + ("CreatureObject::setAppearanceFromObjectTemplate(): called on non-authoritative object id=[%s], server id=[%d]", + getNetworkId().getValueString().c_str(), + static_cast(GameServer::getInstance().getProcessId()) + )); + return; + } + + // See if we're trying to turn off our alt appearance + std::string const none("none"); + if(sharedObjectTemplateName.find(none) != std::string::npos && sharedObjectTemplateName.size() == none.size()) + { + GameScriptObject * const scriptObject = this->getScriptObject(); + if(scriptObject) + { + ScriptParams params; + params.addParam(getNetworkId()); + if(scriptObject->trigAllScripts(Scripting::TRIG_ON_ABOUT_TO_REVERT_APPEARANCE, params) == SCRIPT_OVERRIDE) + return; + m_alternateAppearanceSharedObjectTemplateName.set(sharedObjectTemplateName); + + setState(States::Disguised, false); + + params.clear(); + params.addParam(getNetworkId()); + + IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_REVERTED_APPEARANCE, params)); + + } + + return; + } + + //-- Ensure the serverObjectTemplateName exists. + if (sharedObjectTemplateName.empty() || !TreeFile::exists(sharedObjectTemplateName.c_str())) + { + WARNING(true, + ("CreatureObject::setAppearanceFromObjectTemplate(): called on id=[%s], server id=[%d]: invalid serverObjectTemplateName [%s]", + getNetworkId().getValueString().c_str(), + static_cast(GameServer::getInstance().getProcessId()), + sharedObjectTemplateName.c_str() + )); + return; + } + + + ObjectTemplate const *sharedObjectTemplate = ObjectTemplateList::fetch(sharedObjectTemplateName); + SharedCreatureObjectTemplate const *const sharedObjectTemplateAsCreature = dynamic_cast(sharedObjectTemplate); + + if (sharedObjectTemplate && sharedObjectTemplateAsCreature) + { + //-- Ensure there is an appearance filename. + if (!sharedObjectTemplateAsCreature->getAppearanceFilename().empty()) + { + GameScriptObject * const scriptObject = this->getScriptObject(); + if(scriptObject) + { + ScriptParams params; + params.addParam(getNetworkId()); + params.addParam(sharedObjectTemplateName.c_str()); + + if(scriptObject->trigAllScripts(Scripting::TRIG_ON_ABOUT_TO_CHANGE_APPEARANCE, params) == SCRIPT_OVERRIDE) + return; + + //-- Set the alternate shared object template name since it is different from the natural shared object template name. + m_alternateAppearanceSharedObjectTemplateName.set(sharedObjectTemplateAsCreature->getAppearanceFilename()); + + setState(States::Disguised, true); + + params.clear(); + params.addParam(getNetworkId()); + + IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_CHANGED_APPEARANCE, params)); + } + + } + + // Release resources. + sharedObjectTemplate->releaseReference(); + sharedObjectTemplate = 0; + } + +} + +// ====================================================================== + +bool operator!=(CreatureMod const &a, CreatureMod const &b) +{ + return a.mod != b.mod + || a.startTime != b.startTime + || a.maxVal != b.maxVal + || a.currentVal != b.currentVal; +} + +// ====================================================================== + +namespace Archive +{ + void put(Archive::ByteStream &target, CreatureAttitude const &state) + { + target.put(&state.m_behavior, 4); + target.put(&state.m_angerState, 4); + target.put(&state.m_fearState, 4); + for (int i = 0; i < MentalStates::NumberOfMentalStates; ++i) + target.put(&state.m_currentValues[i], 4); + } + + void get(Archive::ReadIterator &source, CreatureAttitude &state) + { + source.get(&state.m_behavior, 4); + source.get(&state.m_angerState, 4); + source.get(&state.m_fearState, 4); + for (int i = 0; i < MentalStates::NumberOfMentalStates; ++i) + source.get(&state.m_currentValues[i], 4); + } + + //---------------------------------------------------------------------- + + void put(Archive::ByteStream &target, MonitoredCreatureMovement const &state) + { + target.put(&state.m_lastDistance, sizeof(state.m_lastDistance)); + target.put(&state.m_skittishness, sizeof(state.m_skittishness)); + target.put(&state.m_curve, sizeof(state.m_curve)); + } + + void get(Archive::ReadIterator &source, MonitoredCreatureMovement &state) + { + source.get(&state.m_lastDistance, sizeof(state.m_lastDistance)); + source.get(&state.m_skittishness, sizeof(state.m_skittishness)); + source.get(&state.m_curve, sizeof(state.m_curve)); + } + + //---------------------------------------------------------------------- + + void put(Archive::ByteStream &target, CreatureMod const &mod) + { + target.put(&mod.startTime, sizeof(mod.startTime)); + target.put(&mod.maxVal, sizeof(mod.maxVal)); + target.put(&mod.currentVal, sizeof(mod.currentVal)); + put(target, mod.mod); + } + + void get(Archive::ReadIterator &source, CreatureMod &mod) + { + source.get(&mod.startTime, sizeof(mod.startTime)); + source.get(&mod.maxVal, sizeof(mod.maxVal)); + source.get(&mod.currentVal, sizeof(mod.currentVal)); + get(source, mod.mod); + } +}; + +//---------------------------------------------------------------------- + +float CreatureObject::getWalkSpeed () const +{ + float walkSpeed = m_walkSpeed.get(); + + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + if (m_vehiclePhysicsData) + { + walkSpeed = m_vehiclePhysicsData->m_walkSpeed; + } + } + + return walkSpeed * getMovementScale() * getMovementPercent(); +} + +//---------------------------------------------------------------------- + +float CreatureObject::getRunSpeed () const +{ + float runSpeed = m_runSpeed.get(); + + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + if (m_vehiclePhysicsData) + { + runSpeed = m_vehiclePhysicsData->m_runSpeed; + } + } + + return runSpeed * getMovementScale() * getMovementPercent(); +} + +//---------------------------------------------------------------------- + +float CreatureObject::getAccelerationForSpeed (float currentSpeed) const +{ + float accel = 0.0f; + + if (currentSpeed <= getWalkSpeed ()) + accel = safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_walk); + else + accel = safe_cast (getSharedTemplate ())->getAccelerationMax (SharedCreatureObjectTemplate::MT_run); + + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + if (m_vehiclePhysicsData) + { + if (m_vehiclePhysicsData->m_runSpeed) + { + const float speedPercent = std::min (1.0f, currentSpeed / m_vehiclePhysicsData->m_runSpeed); + accel = m_vehiclePhysicsData->m_accelerationMin + (m_vehiclePhysicsData->m_accelerationMax - m_vehiclePhysicsData->m_accelerationMin) * speedPercent; + } + } + } + + return accel * getAccelScale() * getAccelPercent(); +} + +//---------------------------------------------------------------------- + +float CreatureObject::getTurnRateForSpeed (float currentSpeed) const +{ + float turnRate = 0.0f; + + if (currentSpeed <= getWalkSpeed ()) + turnRate = safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_walk); + else + turnRate = safe_cast (getSharedTemplate ())->getTurnRate (SharedCreatureObjectTemplate::MT_run); + + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + if (m_vehiclePhysicsData) + { + if (m_vehiclePhysicsData->m_runSpeed) + { + const float speedPercent = std::min (1.0f, currentSpeed / m_vehiclePhysicsData->m_runSpeed); + turnRate = convertRadiansToDegrees (m_vehiclePhysicsData->m_turnRateMin + (m_vehiclePhysicsData->m_turnRateMax - m_vehiclePhysicsData->m_turnRateMin) * speedPercent); + } + } + } + + return turnRate; +} + +//---------------------------------------------------------------------- + +float CreatureObject::getSlopeMod () const +{ + return 1.0f; +} + +//----------------------------------------------------------------------- + +float CreatureObject::getAcceleration(SharedCreatureObjectTemplate::MovementTypes movementType) const +{ + float walk = getAccelerationForSpeed (getWalkSpeed ()); + float run = getAccelerationForSpeed (getRunSpeed ()); + + if (walk < 0.1f) + walk = 0.1f; + if (walk < run) + { + run = walk; + } + if (movementType == SharedCreatureObjectTemplate::MT_walk) + return walk; + else + return run; +} + +//----------------------------------------------------------------------- + +float CreatureObject::getTurnRate(SharedCreatureObjectTemplate::MovementTypes movementType) const +{ + float walk = getTurnRateForSpeed (getWalkSpeed ()); + float run = getTurnRateForSpeed (getRunSpeed ()); + + if (walk < 30.0f) + walk = 30.0f; + if (walk < run) + { + run = walk * 0.5f; + } + if (movementType == SharedCreatureObjectTemplate::MT_walk) + return walk; + else + return run; +} + +//---------------------------------------------------------------------- + +void CreatureObject::updateVehiclePhysicsData () +{ + if (GameObjectTypes::isTypeOf (getGameObjectType (), SharedObjectTemplate::GOT_vehicle)) + { + if (!m_vehiclePhysicsData) + m_vehiclePhysicsData = new VehiclePhysicsData; + + const CustomizationData *const cd = fetchCustomizationData(); + if (cd) + { + VehicleHoverDynamics::readParamsFromCustomizationData (*cd, + m_vehiclePhysicsData->m_minMoveSpeed, + m_vehiclePhysicsData->m_runSpeed, + m_vehiclePhysicsData->m_turnRateMin, + m_vehiclePhysicsData->m_turnRateMax, + m_vehiclePhysicsData->m_accelerationMin, + m_vehiclePhysicsData->m_accelerationMax); + + cd->release (); + m_vehiclePhysicsData->m_walkSpeed = 0.5f * m_vehiclePhysicsData->m_runSpeed; + return; + } + } + + if (m_vehiclePhysicsData) + { + delete m_vehiclePhysicsData; + m_vehiclePhysicsData = 0; + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::unequipAllItems() +{ + //-- Ensure we're authoritative. + if (!isAuthoritative()) + { + WARNING(true, + ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d] but this object is not authoritative.", + getNetworkId().getValueString().c_str(), + getObjectTemplateName(), + static_cast(GameServer::getInstance().getProcessId()) + )); + return; + } + + //-- Get the equipment container for the creature. + SlottedContainer * const equipmentContainer = ContainerInterface::getSlottedContainer(*this); + if (!equipmentContainer) + { + WARNING(true, + ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d]: failed to get equipment slotted container, error code=[%d].", + getNetworkId().getValueString().c_str(), + getObjectTemplateName(), + static_cast(GameServer::getInstance().getProcessId()) + )); + return; + } + + //-- Get the inventory container for the creature. + Container::ContainerErrorCode errorCode = Container::CEC_Success; + Container::ContainedItem inventoryContainedItem = equipmentContainer->getObjectInSlot(s_inventorySlotId, errorCode); + Object *const inventoryObjectBase = inventoryContainedItem.getObject(); + ServerObject *const inventoryObject = inventoryObjectBase ? inventoryObjectBase->asServerObject() : NULL; + if (!inventoryObject || (errorCode != Container::CEC_Success)) + { + WARNING(true, + ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d]: failed to get inventory object from equipment, error code=[%d].", + getNetworkId().getValueString().c_str(), + getObjectTemplateName(), + static_cast(GameServer::getInstance().getProcessId()), + static_cast(errorCode) + )); + return; + } + + VolumeContainer *const inventoryContainer = ContainerInterface::getVolumeContainer(*inventoryObject); + if (!inventoryContainer) + { + WARNING(true, + ("unequipAllItems() called on object id=[%s], template=[%s] on server id=[%d]: inventory object is NULL.", + getNetworkId().getValueString().c_str(), + getObjectTemplateName(), + static_cast(GameServer::getInstance().getProcessId()) + )); + return; + } + + //-- Collect items to move into inventory. This includes items in all slots that players can manipulate. + typedef std::vector ServerObjectVector; + ServerObjectVector itemsToTransfer; + + { + ContainerIterator const endIt = equipmentContainer->end(); + for (ContainerIterator it = equipmentContainer->begin(); it != endIt; ++it) + { + // Get the equipment item. + Container::ContainedItem containedItem = *it; + Object *const objectBase = containedItem.getObject(); + ServerObject *const object = objectBase ? objectBase->asServerObject() : NULL; + if (!object) + { + WARNING(true, + ("null object in equipment container for object id=[%s]: equipment item id=[%s].", + getNetworkId().getValueString().c_str(), + containedItem.getValueString().c_str() + )); + continue; + } + + // Get the slotted containment property so we can check the slot characteristics. + SlottedContainmentProperty const *const property = ContainerInterface::getSlottedContainmentProperty(*object); + if (!property) + { + WARNING(true, + ("object in equipment container for object id=[%s], equipment item id=[%s] has no SlottedContainmentProperty.", + getNetworkId().getValueString().c_str(), + containedItem.getValueString().c_str() + )); + continue; + } + + // Check if any of the current arrangement's slots are not player manipulatable. + if (property->canManipulateArrangement(property->getCurrentArrangement())) + itemsToTransfer.push_back(object); + } + } + + //-- Transfer selected equipped items to inventory. + { + ServerObjectVector::iterator const endIt = itemsToTransfer.end(); + for (ServerObjectVector::iterator it = itemsToTransfer.begin(); it != endIt; ++it) + { + ServerObject *const object = *it; + if (!object) + continue; + + ContainerInterface::transferItemToVolumeContainer(*inventoryObject, *object, NULL, errorCode); + WARNING(errorCode != Container::CEC_Success, + ("unequipAllItems(): CreatureObject id=[%s] failed to transfer item id=[%s], template=[%s] from equipment to inventory container, container error code [%d].", + getNetworkId().getValueString().c_str(), + object->getNetworkId().getValueString().c_str(), + object->getObjectTemplateName(), + static_cast(errorCode) + )); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::virtualOnSetClient() +{ + TangibleObject::virtualOnSetClient(); + + handleTutorialTransition(); + + setNumberOfMissionsWantedInMissionBag(ConfigServerGame::getNumberOfMissionsWantedInMissionBag()); +} + +//---------------------------------------------------------------------- + +std::vector CreatureObject::getWearableData() +{ + return m_wearableData.get(); +} + +//---------------------------------------------------------------------- + +void CreatureObject::setWearableData(std::vector const & packedWearables) +{ + m_wearableData.set(packedWearables); +} + +//---------------------------------------------------------------------- + +void CreatureObject::onContainedItemAppearanceDataModified(TangibleObject const & target, std::string const & oldValue, std::string const & value) +{ + TangibleObject::onContainedItemAppearanceDataModified(target, oldValue, value); + + if(oldValue != value) + { + std::vector wearableData = getWearableData(); + for(std::vector::iterator i = wearableData.begin(); i != wearableData.end(); ++i) + { + if(target.getNetworkId() == i->m_networkId) + { + i->m_appearanceString = value; + setWearableData(wearableData); + //there will only be one object with the target's networkid, so we can return + return; + } + } + } +} + +//---------------------------------------------------------------------- + +void CreatureObject::updateGroup() +{ + GroupObject * group = getGroup(); + if(group) + { + const std::vector > & groupMembers = group->getGroupMembers(); + + // if there are members that might need an update + if(! groupMembers.empty()) + { + // setup the update status message that is sent to the client + if(! m_clientMfdStatusUpdateMessage) + { + // this is the first time an update might need to have been sent + m_clientMfdStatusUpdateMessage = new ClientMfdStatusUpdateMessage(getNetworkId(), ServerWorld::getSceneId(), findPosition_w(), ConfigFile::getKeyFloat("ServerGame", "groupLocationUpdateTimer", 1.0f), ConfigFile::getKeyFloat("ServerGame", "groupLocationUpdateMinimumMoveDistance", 64.0f)); + } + else + { + // it's already been constructed, update members + m_clientMfdStatusUpdateMessage->setSceneName(ServerWorld::getSceneId()); + m_clientMfdStatusUpdateMessage->setWorldCoordinates(findPosition_w()); + } + + // if there are still members to update since the last calculation, select + // the first one in the list and send the message + if(! m_clientMfdStatusUpdateMessage->getMembersToUpdate().empty()) + { + if(m_clientMfdStatusUpdateMessage->updateMemberUpdateTimer(Clock::frameTime())) + { + // default, assume that the object is observed and no messageTo + // is needed + bool sendMessageTo = false; + + while(! sendMessageTo && (!m_clientMfdStatusUpdateMessage->getMembersToUpdate().empty())) + { + static Archive::ByteStream bs; + bs.clear(); + NetworkId memberId = m_clientMfdStatusUpdateMessage->getMembersToUpdate().back(); + m_clientMfdStatusUpdateMessage->getMembersToUpdate().pop_back(); + + if(memberId != getNetworkId()) + { + // cull bad network id's + if(memberId != NetworkId::cms_invalid) + { + Object * obj = NetworkIdManager::getObjectById(memberId); + if(obj) + { + ServerObject * target = obj->asServerObject(); + if(target && target->getClient()) + { + // check to see whether the target observing this creature + // if it is, then the client will be updated automatically + if(! ObserveTracker::isObserving(*target->getClient(), *this)) + { + // this creature is not being observed by the target player + // if it is authoritative on this server, however, send + // the message directly. + if(target->isAuthoritative()) + { + target->getClient()->send(*m_clientMfdStatusUpdateMessage, false); + } + else + { + // the object is valid, but + // not authoritative on this + // server, send a messageTO + sendMessageTo = true; + } + } // else normal game operation will take care of updating the client MFD status window + } + else if(target && !target->getClient() && !target->isAuthoritative()) + { + // target is valid, but probably a proxy of a player + // controlled object. Send a message to the remote + // server + sendMessageTo = true; + } + else if(! target) + { + WARNING_STRICT_FATAL(true, ("While updating group locations, group member ID %s refers to an object that is not a server object!", memberId.getValueString().c_str())); + } + } + else + { + // not on this server, send a message + sendMessageTo = true; + } + } // else memberId is an invalid NetworkId + } // else memberId is self + if(sendMessageTo) + { + // the group member is not locally authoritative + // on this server and is not being observed, the only + // way to get data to the group member is by sending + // a message to. + + bs.clear(); + m_clientMfdStatusUpdateMessage->pack(bs); + // send the messageTo to the target object + MessageToQueue::getInstance().sendMessageToC(memberId, "ClientMfdStatusUpdateMessage", std::string(reinterpret_cast(bs.getBuffer()), bs.getSize()), 0, false); + } + } + } + } + // If the message hasn't changed since the last attempt, don't + // bother sending the update + else if(m_clientMfdStatusUpdateMessage->getHasChanged()) + { + // add group members to the mfs status update member id list + m_clientMfdStatusUpdateMessage->getMembersToUpdate().clear(); + std::vector >::const_iterator i; + for(i = groupMembers.begin(); i != groupMembers.end(); ++i) + { + if(i->first != NetworkId::cms_invalid && i->first != getNetworkId()) + m_clientMfdStatusUpdateMessage->addMemberToUpdate(i->first); + } + } + } + else + { + // the group is empty, clean up any memory that might have been used before + delete m_clientMfdStatusUpdateMessage; + m_clientMfdStatusUpdateMessage = 0; + } + } + else + { + // the group is empty, clean up any memory that might have been used before + delete m_clientMfdStatusUpdateMessage; + m_clientMfdStatusUpdateMessage = 0; + } + + if(m_clientMfdStatusUpdateMessage) + { + m_clientMfdStatusUpdateMessage->setHasChanged(false); + } +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::handleTutorialTransition() +{ + // this is where all the code lives for the special transitions for the tutorial... + // much of the implementation is implemented in NewbieTutorial and is called through here + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + + if (playerObject) + { + // check if this player is coming from the character creation / selection screen + bool isFromLogin = playerObject->getIsFromLogin(); + playerObject->setIsFromLogin(false); + bool startTutorial = !ConfigServerGame::getSkipTutorial(); + if (startTutorial) + { + // let the npe phase determine whether or not to do the tutorial + startTutorial = (NewbieTutorial::shouldStartTutorial(this)); + } + + const std::string currentScene = ServerWorld::getSceneId(); + if (NewbieTutorial::isInTutorialArea(this)) + { + LOG("npe", ("handleTutorialTransition called for object %s in scene %s at location %f %f %f\n", getNetworkId().getValueString().c_str(), currentScene.c_str(), getPosition_w().x, getPosition_w().y, getPosition_w().z)); + + // check and see if they are loading into a tutorial area. If so, make sure they only have objects in the FileManifest + if (ConfigServerGame::getStripNonFreeAssetsFromPlayersInTutorial()) + { + LOG("npe", ("handleTutorialTransition removing any non-free assets from object %s\n", getNetworkId().getValueString().c_str())); + NewbieTutorial::stripNonFreeAssetsFromPlayerInTutorial(this); + } + } + + if (startTutorial && currentScene == NewbieTutorial::getSceneId()) + { + // if we are in the tutorial scene, force a teleportFixup here so we can determine if we are in a container + handleTeleportFixup(false); + + ServerObject const * container = safe_cast(ContainerInterface::getContainedByObject(*this)); + + // if they are on the tutorial planet, but not in a valid container, create a tutorial instance for them + if (!container || !container->isAuthoritative() || isFromLogin) + { + // the player should be in the tutorial and is in the right place, go ahead and place them + NewbieTutorial::setupCharacterForTutorial(this); + Vector newLocation = getPosition_w(); + if (newLocation == Vector(0,0,0)) + { + LOG("npe", ("handleTutorialTransition setup tutorial at the origin for object %s\n", getNetworkId().getValueString().c_str())); + } + ServerObject *tutorial = NewbieTutorial::createTutorial(newLocation); + + FATAL(!tutorial, ("failed to create tutorial for player which already exists.")); + std::string startCellName = NewbieTutorial::getStartCellName(); + + Vector startCoords = NewbieTutorial::getStartCoords(); + LOG("npe", ("handleTutorialTransition created newbie tutorial %s (%s authoritative) for %s (%s authoritative)\n", tutorial->getNetworkId().getValueString().c_str(), (tutorial->isAuthoritative()) ? "is" : "not", getNetworkId().getValueString().c_str(), (isAuthoritative()) ? "is" : "not")); + + teleportObject(newLocation, tutorial->getNetworkId(), startCellName, startCoords, "", true); + } + } + else if ( + (startTutorial && isFromLogin) + ) + { + // if the creature object is coming from login, and they should start the tutorial + // or if the player is on a free trial account, but is on a non-free trial planet or location (NOT GOOD!) + // warp them to the tutorial planet + LOG("npe", ("Warping player (%s) back to tutorial because they are coming from login (%i) or because they are on a free trial account (%i) and trying to get to a non-free trial planet (%s: %f %f %f)\n", getNetworkId().getValueString().c_str(), isFromLogin, (getClient() && getClient()->isFreeTrialAccount()), ServerWorld::getSceneId().c_str(), getPosition_w().x, getPosition_w().y, getPosition_w().z)); + NewbieTutorial::setupCharacterForTutorial(this); + GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this), NewbieTutorial::getSceneId(), NewbieTutorial::getTutorialLocation(), NetworkId::cms_invalid, Vector(0,0,0)); + } + } +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::onContainerChildLostItem(ServerObject * destination, ServerObject& item, ServerObject* source, ServerObject* transferer) +{ + ServerObject::onContainerChildLostItem(destination, item, source, transferer); + + GameScriptObject * gameScriptObject = getScriptObject(); + if(gameScriptObject) + { + NetworkId itemId = item.getNetworkId(); + NetworkId sourceId; + if(source) + sourceId = source->getNetworkId(); + NetworkId transfererId; + if(transferer) + transfererId = transferer->getNetworkId(); + NetworkId destinationId; + if(destination) + destinationId = destination->getNetworkId(); + + ScriptParams params; + params.addParam (itemId); + params.addParam (sourceId); + params.addParam (transfererId); + params.addParam (destinationId); + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_CONTAINER_CHILD_LOST_ITEM, params)); + } + + if(isPlayerControlled()) // Source == Appearance Inventory + { + //Update wearble appearance data + SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); + if (scp) + { + WearableEntry e("", scp->getCurrentArrangement(), item.getNetworkId(), 0); + int index = m_wearableAppearanceData.find(e); + if (index >= 0) + { + m_wearableAppearanceData.erase(index); + } + } + } + +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::onContainerChildGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) +{ + ServerObject::onContainerChildGainItem(item, source, transferer); + + GameScriptObject * gameScriptObject = getScriptObject(); + if(gameScriptObject) + { + NetworkId itemId = item.getNetworkId(); + NetworkId sourceId; + if(source) + sourceId = source->getNetworkId(); + NetworkId transfererId; + if(transferer) + transfererId = transferer->getNetworkId(); + + ScriptParams params; + params.addParam (itemId); + params.addParam (sourceId); + params.addParam (transfererId); + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_CONTAINER_CHILD_GAIN_ITEM, params)); + } + + if(isPlayerControlled()) + { + TangibleObject* tangibleObject = item.asTangibleObject(); + + if(!tangibleObject) + return; + + //Update wearables data + SlottedContainmentProperty* scp = ContainerInterface::getSlottedContainmentProperty(item); + if (scp) + { + Object const * appearance = 0; + + SlottedContainer const * const myContainer = ContainerInterface::getSlottedContainer(*this); + + if (myContainer) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + SlotId appearanceInvSlot = SlotIdManager::findSlotId(CreatureObjectNamespace::SlotNames::appearance); + if (appearanceInvSlot != SlotId::invalid) + { + Container::ContainedItem itemId = myContainer->getObjectInSlot(appearanceInvSlot, tmp); + appearance = itemId.getObject(); + } + } + + Object const * container = ContainerInterface::getContainedByObject(*tangibleObject); + bool const inAppearanceInv = (container == appearance); + if (scp->getCurrentArrangement() >= 0 && scp->isInAppearanceSlot() && inAppearanceInv) + { + ConstCharCrcString clientSharedTemplateNameCrcString = ObjectTemplateList::lookUp(tangibleObject->getClientSharedTemplateName()); + if (clientSharedTemplateNameCrcString.isEmpty()) + WARNING(true, ("Could not find crc for %s. Wearable will not be streamed to client", tangibleObject->getClientSharedTemplateName())); + else + addPackedAppearanceWearable(tangibleObject->getAppearanceData(), scp->getCurrentArrangement(), tangibleObject->getNetworkId(), clientSharedTemplateNameCrcString.getCrc()); + } + } + } + +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::forceNotifyRegionsCheck() +{ + m_lastRegionNotifyPosition.x += 1.0f; // force a check +} + +//------------------------------------------------------------------------------------------ + +void CreatureObject::checkNotifyRegions() +{ + // if the object is player controlled, check for a change of regions that have their + // notify field set to true. + static const bool allowChecks = ConfigServerGame::getCheckNotifyRegions(); + if(! allowChecks) + return; + + if(! isPlayerControlled() || !isAuthoritative()) + return; + + if (! isInWorld()) + return; + bool forceCheckRegions = m_regionFlagTimer.isExpired(); + + if(m_lastRegionNotifyPosition == getPosition_w() && !forceCheckRegions) + return; + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if(! playerObject) + return; + + PROFILER_AUTO_BLOCK_DEFINE("CreatureObject::checkNotifyRegions()"); + // region containers populated by region master getRegionsAtPoint() + + static std::vector newRegions; + newRegions.clear(); + RegionMaster::getRegionsAtPoint(ServerWorld::getSceneId(), getPosition_w().x, getPosition_w().z, newRegions); + + if(forceCheckRegions) + { + m_regionFlagTimer.reset(); + + std::vector::iterator regionIter = newRegions.begin(); + EnvironmentInfo flags = static_cast(0); + for(; regionIter != newRegions.end(); ++regionIter) + { + if((*regionIter)->getNotify()) + flags = flags | (*regionIter)->getEnvironmentFlags(); + } + + playerObject->setEnvironmentFlags(flags); + + if(m_lastRegionNotifyPosition == getPosition_w()) + return; + } + + static std::vector newNotifyRegions; + newNotifyRegions.clear(); + + static std::vector newNotifyRegionsEntered; + newNotifyRegionsEntered.clear(); + + static std::vector > notifyRegionsExited; + notifyRegionsExited.clear(); + + // look for region enter events + std::vector::const_iterator i; + + bool teleport = false; + static const bool allowOverride = ConfigServerGame::getAllowRegionTriggerOverride(); + + // iterate through the new regions looking for a "notify" region that is not in the + // list of regions found during the last check. + for(i = newRegions.begin(); i != newRegions.end(); ++i) + { + if((*i)->getNotify()) + { + // this is a region that requires a notification be sent + // to scripts on the player's creature object + std::string regionName = Unicode::wideToNarrow((*i)->getName()); + newNotifyRegions.push_back(regionName); + + // check the notify regions from the last pass + // to see if this is a new region + if (!m_notifyRegions.contains(std::make_pair(ServerWorld::getSceneId(), regionName))) + { + // the region was not in the list, this is a new region + // and TRIG_ENTER_REGION should be generated + ScriptParams params; + params.addParam(ServerWorld::getSceneId().c_str()); + params.addParam(regionName.c_str()); + if(getScriptObject()) + { + // allow scripts to prevent entry into the region if they + // return SCRIPT_OVERRIDE + if (getScriptObject()->trigAllScripts(Scripting::TRIG_ENTER_REGION, params) == SCRIPT_OVERRIDE) + { + // don't disallow admins, don't disallow if the server + // config has it disabled + if((!getClient() || !getClient()->isGod()) && allowOverride) + { + teleport = true; + + Vector teleportTarget = getPosition_w(); + Vector regionCenter = (*i)->getCenter(); + + // if, somehow, a player starts in a forbidden region, allow them to walk out + if(teleportTarget.magnitudeXZBetweenSquared(regionCenter) < m_lastRegionNotifyPosition.magnitudeXZBetweenSquared(regionCenter)) + { + // the current position is further into the region, + // push the player back + teleportObject(m_lastRegionNotifyPosition, NetworkId::cms_invalid, "", Vector(), ""); + } + else + { + // the current position is closer to the region edge, + // allow the player to move normally in this direction + m_lastRegionNotifyPosition = teleportTarget; + } + + // if the player is on a mount/vehicle but is + // not the driver of the mount/vehicle, then + // eject the (passenger) player so he doesn't + // keep trying to enter the region because the + // mount/vehicle will keep taking him into the + // region as long as he remains mounted + CreatureObject const * const mountedCreature = getMountedCreature(); + if (mountedCreature && (this != mountedCreature->getPrimaryMountingRider())) + { + static uint32 const commandHash = Crc::normalizeAndCalculate("dismount"); + const Command &command = CommandTable::getCommand(static_cast(commandHash)); + if (!command.isNull()) + { + commandQueueEnqueue(command, mountedCreature->getNetworkId(), mountedCreature->getObjectName(), 0, false, static_cast(Command::CP_Front), true); + } + } + } + } + } + + // if a teleport didn't happen, + // keep this region on the list + // of notify regions the client + // just entered + if(! teleport) + newNotifyRegionsEntered.push_back(regionName); + } + } + } + + // look for for region exit events. If a region from the last pass + // is not in the new region list, the player has left the region + Archive::AutoDeltaSet >::const_iterator i2; + for(i2 = m_notifyRegions.begin(); i2 != m_notifyRegions.end(); ++i2) + { + if((i2->first != ServerWorld::getSceneId()) || (std::find(newNotifyRegions.begin(), newNotifyRegions.end(), i2->second) == newNotifyRegions.end())) + { + // the player is exiting the region, send a TRIG_EXIT_REGION + // to all scripts attached to the player's creature object + ScriptParams params; + params.addParam(i2->first.c_str()); + params.addParam(i2->second.c_str()); + if(getScriptObject()) + { + if(getScriptObject()->trigAllScripts(Scripting::TRIG_EXIT_REGION, params) == SCRIPT_OVERRIDE) + { + // don't override movement of god characters, or if the + // server config disables move overrides + if((!getClient() || !getClient()->isGod()) && allowOverride && (i2->first == ServerWorld::getSceneId())) + { + teleport = true; + + Vector teleportTarget = getPosition_w(); + + // if the current position is outside the region, fix the + // teleport target to prevent the player from exiting + Region * r = RegionMaster::getRegionByName(i2->first, Unicode::narrowToWide(i2->second)); + if (r) + { + if(! r->getBounds().isPointIn(teleportTarget.x, teleportTarget.z)) + { + // find a point along the path that is in the retion + Vector heading = r->getCenter() - teleportTarget; + heading.normalize(); + + int tries = 0; + while(! r->getBounds().isPointIn(teleportTarget.x, teleportTarget.z) && tries < 300) + { + ++tries; + teleportTarget += heading; + } + teleportObject(teleportTarget, NetworkId::cms_invalid, "", Vector(), ""); + } + } + m_lastRegionNotifyPosition = teleportTarget; + } + } + else + { + notifyRegionsExited.push_back(std::make_pair(i2->first, i2->second)); + } + } + } + } + + if(!teleport) + { + m_lastRegionNotifyPosition = getPosition_w(); + } + + std::vector >::const_iterator i3; + for(i3 = notifyRegionsExited.begin(); i3 != notifyRegionsExited.end(); ++i3) + { + m_notifyRegions.erase(*i3); + } + + std::vector::const_iterator i4; + for(i4 = newNotifyRegionsEntered.begin(); i4 != newNotifyRegionsEntered.end(); ++i4) + { + m_notifyRegions.insert(std::make_pair(ServerWorld::getSceneId(), *i4)); + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::hasCertificationsForItem(const TangibleObject & item) const +{ + std::vector requiredCerts; + item.getRequiredCertifications(requiredCerts); + + for (std::vector::const_iterator i=requiredCerts.begin(); i!=requiredCerts.end(); ++i) + { + if (!hasCommand(*i)) + return false; + } + + return true; +} + +//----------------------------------------------------------------------- + +CreatureObject * CreatureObject::getCreatureObject(NetworkId const & networkId) +{ + return asCreatureObject(NetworkIdManager::getObjectById(networkId)); +} + +// ---------------------------------------------------------------------- + +CreatureObject const * CreatureObject::asCreatureObject(Object const * object) +{ + ServerObject const * const serverObject = (object != NULL) ? object->asServerObject() : NULL; + + return (serverObject != NULL) ? serverObject->asCreatureObject() : NULL; +} + +// ---------------------------------------------------------------------- + +CreatureObject * CreatureObject::asCreatureObject(Object * object) +{ + ServerObject * serverObject = (object != NULL) ? object->asServerObject() : NULL; + + return (serverObject != NULL) ? serverObject->asCreatureObject() : NULL; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::addMissionCriticalObject(NetworkId const & networkId) +{ + if (isAuthoritative()) + { + if (m_missionCriticalObjectSet.find(networkId) == m_missionCriticalObjectSet.end()) + { + m_missionCriticalObjectSet.insert(networkId); + GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); + ServerObject * const serverObject = safe_cast(NetworkIdManager::getObjectById(networkId)); + if (serverObject) + ObserveTracker::onMissionCriticalObjectAdded(*this, *serverObject); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::removeMissionCriticalObject(NetworkId const & networkId) +{ + if (isAuthoritative()) + { + MissionCriticalObjectSet::const_iterator iter = m_missionCriticalObjectSet.find(networkId); + if (iter != m_missionCriticalObjectSet.end()) + { + m_missionCriticalObjectSet.erase(iter); + GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::clearMissionCriticalObjects() +{ + if (isAuthoritative()) + { + m_missionCriticalObjectSet.clear(); + GroupMissionCriticalObjectsBuilder::updateGroupMissionCriticalObjects(*this, true); + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::isMissionCriticalObject(NetworkId const & networkId) const +{ + if (isAuthoritative()) + return m_missionCriticalObjectSet.find(networkId) != m_missionCriticalObjectSet.end(); + + return false; +} + +// ---------------------------------------------------------------------- + +CreatureObject::MissionCriticalObjectSet const & CreatureObject::getMissionCriticalObjects() const +{ + return m_missionCriticalObjectSet.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setGroupMissionCriticalObjects(GroupMissionCriticalObjectSet const & groupMissionCriticalObjectSet) +{ + DEBUG_FATAL(!isAuthoritative(), ("CreatureObject::setGroupMissionCriticalObjects: called on non-authoritative object %s", getDebugInformation(true).c_str())); + if (isAuthoritative()) + { + //-- Anything that is not in our set, we need to add + { + for (GroupMissionCriticalObjectSet::const_iterator iter = groupMissionCriticalObjectSet.begin(); iter != groupMissionCriticalObjectSet.end(); ++iter) + if (!m_groupMissionCriticalObjectSet.contains(*iter)) + m_groupMissionCriticalObjectSet.insert(*iter); + } + + //-- Anything that is not in the original set, we need to remove + { + for (GroupMissionCriticalObjectSet::const_iterator iter(m_groupMissionCriticalObjectSet.begin()); iter != m_groupMissionCriticalObjectSet.end(); ++iter) + if (groupMissionCriticalObjectSet.find(*iter) == groupMissionCriticalObjectSet.end()) + m_groupMissionCriticalObjectSet.erase(*iter); + } + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::getCoverVisibility() const +{ + return m_coverVisibility.get(); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setCoverVisibility(bool isVisible) +{ + if (isAuthoritative()) + { + m_coverVisibility.set(isVisible); + } + else + { + sendControllerMessageToAuthServer(CM_setCoverVisibility, new MessageQueueGenericValueType(isVisible)); + } +} + +// ---------------------------------------------------------------------- + +/** + * Called when an attack pushes us away from the attacker. This gets called + * due to a message from the client (which sucks, btw). + * + * @param attackerId the attacker + * @param attackerPos where the client thought the attacker was + * @param defenderPos where the client thought the defender (us) was + * @param distance the distance we are pushed away from the attacker + */ +void CreatureObject::pushedMe(const NetworkId & attackerId, + const Vector & attackerPos, const Vector & defenderPos, float distance) +{ + if (isAuthoritative()) + { + const ServerObject * attacker = safe_cast(NetworkIdManager::getObjectById(attackerId)); + + //@todo: add a whole bunch of security checks here + // for now, push us away from the defender, using the server positions + + // do a bare minimum sanity check + static const float MAX_DISTANCE = 20.0f; + if (distance > MAX_DISTANCE) + { + WARNING(true, ("CreatureObject::pushedMe told defender %s was pushed by %s %f meters (max = %f)", + getNetworkId().getValueString().c_str(), attackerId.getValueString().c_str(), distance, MAX_DISTANCE)); + return; + } + + + UNREF(defenderPos); + + Vector offset(getPosition_w()); + if (attacker != NULL) + offset -= attacker->getPosition_w(); + else + offset -= attackerPos; + offset.normalize(); + offset *= distance; + + // this is a hack due to the controller move command needing to know the destination cell + // @todo: change creature movement to always use the CellProperty notification system for moving across cell boundaries + const Vector oldPos(getPosition_p()); + + // note: unlike the client, this call will not cause us to change cells + move_p(rotate_w2p(offset)); + + AICreatureController *controller = dynamic_cast(getController()); + if (controller != NULL) + { + // we only need to do this for npcs, because we'll use the update from a player's client for players + // we need to do this for npcs to prevent the ai from moving them back to their previous position + const Vector newPos(getPosition_p()); + float closestPortalT = 0.0f; + const CellProperty * destinationCell = getParentCell()->getDestinationCell(oldPos, newPos, closestPortalT); + if (destinationCell == NULL || destinationCell == getParentCell()) + { + // no cell change + controller->warpTo(getParentCell(), newPos); + } + else + { + Vector warpPos(destinationCell->getOwner().rotateTranslate_w2p(rotateTranslate_p2w(newPos))); + controller->warpTo(destinationCell, warpPos); + } + } + } + else + { + sendControllerMessageToAuthServer(CM_pushCreature, + new MessageQueuePushCreature(attackerId, getNetworkId(), attackerPos, defenderPos, distance)); + } +} + +// ---------------------------------------------------------------------- + +/** + * Creates a "slow down" effect between this creature and a defender. The effect acts as if + * there was a hill between the combatants, with the attacker at the top and the defender + * at the bottom. The area of the effect is a cone between the attacker and defender. + * The "hill" will be maintained between the combatants even if they move. + * + * @param defender the target that defines the direction of the "hill" + * @param coneLength the length of the effect cone + * @param coneAngle the angle of the effect cone, in radians + * @param slopeAngle the angle of the "hill", in radians + * @param expireTime the game time when the effect expires + */ +void CreatureObject::addSlowDownEffect(const TangibleObject & defender, float coneLength, float coneAngle, float slopeAngle, unsigned long expireTime) +{ + if (isAuthoritative()) + { + if (addSlowDownEffectProxy(defender, coneLength, coneAngle, slopeAngle, expireTime)) + { + // tell everyone who can see us that we are doing the effect + Controller * const controller = getController(); + if (controller) + { + controller->appendMessage(CM_slowDownEffect, + 0, + new MessageQueueSlowDownEffect(defender.getNetworkId(), coneLength, coneAngle, slopeAngle, expireTime), + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_PROXY_SERVER | + GameControllerMessageFlags::DEST_ALL_CLIENT); + } + } + } + else + { + sendControllerMessageToAuthServer(CM_slowDownEffect, + new MessageQueueSlowDownEffect(defender.getNetworkId(), coneLength, coneAngle, slopeAngle, expireTime)); + } +} + +// ---------------------------------------------------------------------- + +/** + * Creates a "slow down" effect between this creature and a defender. The effect acts as if + * there was a hill between the combatants, with the attacker at the top and the defender + * at the bottom. The area of the effect is a cone between the attacker and defender. + * The "hill" will be maintained between the combatants even if they move. + * + * @param defender the target that defines the direction of the "hill" + * @param coneLength the length of the effect cone + * @param coneAngle the angle of the effect cone, in radians + * @param slopeAngle the angle of the "hill", in radians + * @param expireTime the game time when the effect expires + * + * @return true if the effect was added, false if the creature already had a slow down effect + */ +bool CreatureObject::addSlowDownEffectProxy(const TangibleObject & defender, float coneLength, float coneAngle, float slopeAngle, unsigned long expireTime) +{ + // if we already are doing a slowdown, don't do another + Property * property = getProperty(SlowDownProperty::getClassPropertyId()); + if (property != NULL) + return false; + + property = new SlowDownProperty(*this, CachedNetworkId(defender), coneLength, coneAngle, slopeAngle, expireTime); + addProperty(*property, true); + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Causes any slow down effect being used by us to be canceled early. + */ +void CreatureObject::removeSlowDownEffect() +{ + if (isAuthoritative()) + { + removeSlowDownEffectProxy(); + + // tell all my proxies (client and server) to remove the effect + Controller * const controller = getController(); + if (controller) + controller->appendMessage(CM_removeSlowDownEffectProxy, 0, NULL, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT | GameControllerMessageFlags::DEST_PROXY_SERVER); + } + else + { + sendControllerMessageToAuthServer(CM_removeSlowDownEffect, NULL); + } +} + +// ---------------------------------------------------------------------- + +/** + * Causes any slow down effect being used by us to be canceled early. + */ +void CreatureObject::removeSlowDownEffectProxy() +{ + if (getProperty(SlowDownProperty::getClassPropertyId()) != NULL) + removeProperty(SlowDownProperty::getClassPropertyId()); +} + +// ---------------------------------------------------------------------- + +/** + * Adds an additional terrain slope effect that will be taken into account the + * next time we alter this creature. Note that this function only affects non-player + * creatures. + * + * @param normal the normal vector of the "terrain" that is affecting us + */ +void CreatureObject::addTerrainSlopeEffect(const Vector & normal) +{ + if (isAuthoritative() && !isPlayerControlled()) + { + Property * property = getProperty(SlopeEffectProperty::getClassPropertyId()); + if (property == NULL) + { + property = new SlopeEffectProperty(*this); + addProperty(*property, true); + } + safe_cast(property)->addNormal(normal); + } +} + +// ---------------------------------------------------------------------- + +char const * CreatureObject::getMentalStateString(MentalStates::Enumerator const mentalState) +{ + switch (mentalState) + { + case MentalStates::Fear: { return "FEAR"; } + case MentalStates::Anger: { return "ANGER"; } + case MentalStates::Interest: { return "INTEREST"; } + case MentalStates::Distress: { return "DISTRESS"; } + default: {} + } + + return "ERROR"; +} + +// ---------------------------------------------------------------------- + +char const * CreatureObject::getBehaviorString(Behaviors::Enumerator const behavior) +{ + switch (behavior) + { + case Behaviors::Calm: { return "CALM"; } + case Behaviors::Alert: { return "ALERT"; } + case Behaviors::Threaten: { return "THREATEN"; } + case Behaviors::Retreat: { return "RETREAT"; } + case Behaviors::Flee: { return "FLEE"; } + case Behaviors::Attack: { return "ATTACK"; } + case Behaviors::Frenzy: { return "FRENZY"; } + default: {} + } + + return "ERROR"; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::alterPseudoPlayedTime(float time) +{ + if (isAuthoritative()) + { + m_pseudoPlayedTime += time; + } + else + { + WARNING(true, ("CreatureObject::alterPlayedTime called on non-authoritative creature")); + } +} // updatePlayedTime + +// ---------------------------------------------------------------------- + +void CreatureObject::setPseudoPlayedTime(float playedTime) +{ + m_pseudoPlayedTime = playedTime; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::addBuff(uint32 buffNameCrc, float duration, float dynamicValue, NetworkId caster, uint32 stackCount) +{ + addBuff( buffNameCrc, duration, dynamicValue, duration, caster, stackCount); +} + +void CreatureObject::addBuff(uint32 buffNameCrc, float timeTillRemoval, float dynamicValue, float totalDuration, NetworkId caster, uint32 stackCount) +{ + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_addBuff, new MessageQueueGenericValueType > > > >(std::make_pair(static_cast(buffNameCrc), std::make_pair(timeTillRemoval, std::make_pair(dynamicValue, std::make_pair(totalDuration, caster)))))); + return; + } + uint32 timestamp = internalGetPlayedTime(); + + if (BuffManager::getBuffIsCelestial(buffNameCrc)) + { + timestamp = ServerClock::getInstance().getGameTimeSeconds(); + } + + int newStackCount = stackCount; + + if(timeTillRemoval < 0.0f) + timestamp = 0xFFFFFFFF; + else if (timeTillRemoval == 0.0f) + { + float defaultDuration = BuffManager::getBuffDefaultDuration(buffNameCrc); + if(defaultDuration < 0.0f) + timestamp = 0xFFFFFFFF; + else + { + timestamp += static_cast(defaultDuration); + totalDuration = defaultDuration; + } + } + else + { + timestamp += static_cast(timeTillRemoval); + } + bool reapply = false; + if(hasBuff(buffNameCrc)) + { + Buff b; + getBuff(buffNameCrc, b); + + newStackCount += b.m_stackCount; + + if((timestamp != 0xFFFFFFFF) && (b.m_timestamp > timestamp)) + { + //We don't need to do anything; the buff we're adding has less time than the one we have + return; + } + std::map::const_iterator i = m_buffs.find(buffNameCrc); + if (i != m_buffs.end()) + { + m_buffs.erase(i); + } + m_persistedBuffs.erase(buffNameCrc); + reapply = true; + } + + newStackCount = std::max(0, std::min(newStackCount, static_cast(BuffManager::getBuffMaxStacks(buffNameCrc)))); + + Buff::PackedBuff packedValue = Buff(buffNameCrc, timestamp, dynamicValue, static_cast(totalDuration), caster, newStackCount).getPackedBuffValue(); + + m_buffs.insert(buffNameCrc, packedValue); + if (BuffManager::getIsBuffPersisted(buffNameCrc)) + { + m_persistedBuffs.insert(buffNameCrc, packedValue); + } + if(reapply) + BuffManager::reapplyBuffEffects(this, buffNameCrc, timeTillRemoval, dynamicValue, newStackCount, caster); + else + BuffManager::applyBuffEffects(this, buffNameCrc, timeTillRemoval, dynamicValue, newStackCount, caster); + //If there was a state, add that state to this creature + int buffState = BuffManager::getBuffState(buffNameCrc); + if(buffState != -1) + setState(static_cast(buffState), true); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::removeBuff(uint32 buffNameCrc) +{ + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_removeBuff, new MessageQueueGenericValueType(static_cast(buffNameCrc))); + return; + } + + std::map::const_iterator i = m_buffs.find(buffNameCrc); + if (i != m_buffs.end()) + { + NetworkId caster = (*i).second.caster; + m_buffs.erase(i); + int buffState = BuffManager::getBuffState(buffNameCrc); + BuffManager::removeBuffEffects(this, buffNameCrc, caster); + if (!stillHasBuffState(buffNameCrc, buffState)) + setState(static_cast(buffState), false); + std::string const &callback = BuffManager::getBuffCallback(buffNameCrc); + ScriptParams params; + params.addParam(static_cast(buffNameCrc), "buffCrc"); + ScriptDictionaryPtr dictionary; + getScriptObject()->makeScriptDictionary(params, dictionary); + dictionary->serialize(); + getScriptObject()->handleMessage(callback, dictionary); + } + + // clean up any persistance + m_persistedBuffs.erase(buffNameCrc); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::decrementBuff(uint32 const buffNameCrc, uint32 const stacksToRemove) +{ + std::map::const_iterator i = m_buffs.find(buffNameCrc); + if (i != m_buffs.end()) + { + + Buff::PackedBuff b = (*i).second; + + b.stackCount -= stacksToRemove; + + removeBuff(buffNameCrc); + + if (static_cast(b.stackCount) > 0) + { + uint32 currentTime = internalGetPlayedTime(); + + if (BuffManager::getBuffIsCelestial(buffNameCrc)) + { + currentTime = ServerClock::getInstance().getGameTimeSeconds(); + } + + float endTime = static_cast (b.endtime) - static_cast (currentTime); + addBuff( buffNameCrc, endTime , b.value, static_cast (b.duration), b.caster, b.stackCount); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::decayBuff(uint32 buffNameCrc, float decayPercentage) +{ + std::map::const_iterator i = m_buffs.find(buffNameCrc); + if (i != m_buffs.end()) + { + Buff::PackedBuff b = (*i).second; + + float decayValue = b.duration * decayPercentage; // decayPercentage should be a value between 0.0 and 1.0 + + removeBuff(buffNameCrc); + + uint32 currentTime = internalGetPlayedTime(); + + float endTime = (static_cast (b.endtime) - decayValue) - static_cast (currentTime); + + if(endTime > 0.0f) + addBuff( buffNameCrc, endTime , b.value, static_cast (b.duration), b.caster, b.stackCount); + } +} + +uint32 CreatureObject::internalGetPlayedTime() const +{ + if (isPlayerControlled()) + { + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + return static_cast(playerObject->getPlayedTime()); + } + } + return static_cast(ServerClock::getInstance().getGameTimeSeconds()); +} + +// ---------------------------------------------------------------------- + +// This functions expires buffs as needed +void CreatureObject::updateBuffs() +{ + uint32 timestamp = internalGetPlayedTime(); + std::list< Buff > buffsToRemove; + + for (std::map::const_iterator i = m_buffs.begin(); i != m_buffs.end(); ) + { + const std::pair & p = *i++; + Buff b(p.first, p.second); + + if (BuffManager::getBuffIsCelestial(b.m_nameCrc)) + { + timestamp = ServerClock::getInstance().getGameTimeSeconds(); + } + else + { + timestamp = internalGetPlayedTime(); + } + + if (b.m_timestamp < timestamp) + { + buffsToRemove.push_back(b); + } + } + + std::list< Buff >::iterator iter = buffsToRemove.begin(); + for( ; iter != buffsToRemove.end(); ++iter) + { + removeBuff((*iter).m_nameCrc); + } + +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::stillHasBuffState(uint32 buffNameCrc, int state) const +{ + for (std::map::const_iterator i = m_buffs.begin(); i != m_buffs.end(); ++i) + { + const std::pair & p = *i; + if ((p.first != buffNameCrc) && (BuffManager::getBuffState(p.first) == state)) + return true; + } + return false; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::getAllBuffs(stdvector::fwd & buffCrcs) const +{ + buffCrcs.clear(); + buffCrcs.reserve(m_buffs.size()); + for (std::map::const_iterator i = m_buffs.begin(); i != m_buffs.end(); ++i) + { + const std::pair & p = *i; + buffCrcs.push_back(p.first); + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::getBuff(uint32 buffNameCrc, Buff & buff) const +{ + std::map::const_iterator found = m_buffs.find(buffNameCrc); + if (found == m_buffs.end()) + return false; + + buff.set((*found).first, (*found).second); + return true; +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::hasBuff(uint32 buffNameCrc) const +{ + std::map::const_iterator found = m_buffs.find(buffNameCrc); + return (found != m_buffs.end()); +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::isInTutorial() const +{ + return NewbieTutorial::isInTutorial(this); +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::isJedi() const +{ + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + return playerObject->isJedi(); + else + return false; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setLevel(int level) +{ + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + controller->appendMessage( + CM_setLevel, + 0.0f, + new MessageQueueGenericValueType(level), + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + } + else + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject == NULL) + { + // this is an ai, so just set the level + m_level = (int16) level; + } + else + { + LevelManager::LevelData levelData; + LevelManager::setLevelDataFromLevel(levelData, level); + + setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::recalculateLevel() +{ + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + { + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + controller->appendMessage( + CM_recalculateLevel, + 0.0f, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + } + else + { + LevelManager::LevelData levelData; + LevelManager::calculateLevelData(getLevelXp(), levelData); + + setLevelData(levelData.currentLevel, levelData.currentLevelXp, levelData.currentHealth); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setLevelData(int16 level, int levelXp, int health) +{ + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + { + m_totalLevelXp = levelXp; + + m_levelHealthGranted = health; + + m_level = level; + + GroupObject *group = getGroup(); + if (group != 0) + { + group->setMemberLevel(getNetworkId(), level); + } + + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); + if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.level != static_cast(level))) + ServerUniverse::setConnectedCharacterLevelData(getNetworkId(), static_cast(level)); + + // update and sync + computeTotalAttributes(); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::levelChanged() const +{ + return; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setClientUsesAnimationLocomotion(bool const enabled) +{ + m_clientUsesAnimationLocomotion = enabled; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::fixupPersistentBuffsAfterLoading() +{ + // initialize persisted buffs + if(m_fixedupPersistentBuffsAfterLoading) + return; // don't want to do it twice + m_fixedupPersistentBuffsAfterLoading = true; + DEBUG_WARNING(isPlayerControlled() && PlayerCreatureController::getPlayerObject(this) && !PlayerCreatureController::getPlayerObject(this)->isInitialized(), + ("CreatureObject::fixupPersistentBuffsAfterLoading trying to use an uninitialized player object")); + uint32 currentTime = internalGetPlayedTime(); + std::vector tempPersistedHolder; + for (std::map::const_iterator ip = m_persistedBuffs.begin(); ip != m_persistedBuffs.end(); ++ip) + { + Buff b((*ip).first, (*ip).second); + tempPersistedHolder.push_back(b); + } + m_persistedBuffs.clear(); + for (std::vector::const_iterator i = tempPersistedHolder.begin(); i != tempPersistedHolder.end(); ++i) + { + const Buff & b = (*i); + + if (BuffManager::getBuffIsCelestial(b.m_nameCrc)) + { + currentTime = ServerClock::getInstance().getGameTimeSeconds(); + } + else + currentTime = internalGetPlayedTime(); + + if (b.m_timestamp > currentTime || b.m_timestamp == 0xFFFFFFFF) + { + float timeTillRemoval = -1.0f; + if (b.m_timestamp != 0xFFFFFFFF) + timeTillRemoval = static_cast(b.m_timestamp - currentTime); + + + addBuff(b.m_nameCrc, timeTillRemoval, b.m_value, static_cast(b.m_duration), b.m_caster, b.m_stackCount); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::fixupLevelXpAfterLoading() +{ + // initialize persisted buffs + if(m_fixedupLevelXpAfterLoading) + return; // don't want to do it twice + + m_fixedupLevelXpAfterLoading = true; + + DEBUG_FATAL(!isPlayerControlled(), + ("CreatureObject::fixupLevelXpAfterLoading trying to be called for a non-player controlled object")); + + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + + DEBUG_FATAL(!playerObject, + ("CreatureObject::fixupLevelXpAfterLoading trying to use a non-existent player object")); + + DEBUG_FATAL(playerObject && !playerObject->isInitialized(), + ("CreatureObject::fixupLevelXpAfterLoading trying to use an uninitialized player object")); + + // The level XP and level are not persisted in the database, so when we + // are done loading, we will calculate the current level XP and level + if (playerObject && playerObject->isInitialized()) + { + LevelManager::LevelData levelData; + + // Level XP due to experience points + std::map const & experienceMap = playerObject->getExperiencePoints(); + std::map::const_iterator i; + for (i = experienceMap.begin(); i != experienceMap.end(); ++i) + { + LevelManager::addXpToLevelData(levelData, i->first, i->second); + } + + // Level XP due to skills + for (SkillList::const_iterator skillIter = m_skills.begin(); skillIter != m_skills.end(); ++skillIter) + { + SkillObject const * skill = *skillIter; + if (skill) + { + LevelManager::addSkillToLevelData(levelData, skill->getSkillName()); + } + } + + // Update the skill info directly (we do not want scripts triggered) + m_level = levelData.currentLevel; + m_previousLevel = levelData.currentLevel; + m_totalLevelXp = levelData.currentLevelXp; + m_levelHealthGranted = levelData.currentHealth; + + levelChanged(); + } +} + +// ---------------------------------------------------------------------- + +CreatureObject::Difficulty CreatureObject::getDifficulty() const +{ + return static_cast(m_difficulty.get()); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setDifficulty(Difficulty const difficulty) +{ + m_difficulty = static_cast(difficulty); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setHologramType(int32 const newHologramType) +{ + if (isAuthoritative()) + { + m_hologramType = newHologramType; + } + else + { + sendControllerMessageToAuthServer(CM_modifyHologramType, new MessageQueueGenericValueType(newHologramType)); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setVisibleOnMapAndRadar(bool const newVal) +{ + if (isAuthoritative()) + { + m_visibleOnMapAndRadar = newVal; + } + else + { + sendControllerMessageToAuthServer(CM_modifyVisibleOnMapAndRadar, new MessageQueueGenericValueType(newVal)); + } +} + +// ---------------------------------------------------------------------- + +float CreatureObject::getRegenRate(Attributes::Enumerator poolAttrib) const +{ + if (!Attributes::isAttribPool(poolAttrib)) + return 0; + + // we've stored the rate as an int, convert back to float + int fixedFloatRate = m_attributes[poolAttrib+1]; + return static_cast(fixedFloatRate); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setRegenRate(Attributes::Enumerator poolAttrib, float value) +{ + if (Attributes::isAttribPool(poolAttrib)) + { + if (value < 0) + value = 0; + if (isAuthoritative()) + { + // store the value as an int + m_attributes.set(poolAttrib+1, static_cast(floor(value))); + } + else + { + sendControllerMessageToAuthServer(CM_setRegenRate, new MessageQueueGenericValueType >(std::make_pair(static_cast(poolAttrib), value))); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::setLastWaterDamageTime(unsigned long newTime) +{ + m_lastWaterDamageTime = newTime; +} + +// ---------------------------------------------------------------------- + +bool CreatureObject::doesLocomotionInvalidateCommand(Command const &cmd) const +{ + Locomotions::Enumerator locomotion = getLocomotion(); + if((locomotion != Locomotions::Running) || cmd.m_locomotionPermissions[locomotion]) + return !cmd.m_locomotionPermissions[locomotion]; + if(!isPlayerControlled()) + return true; + PlayerCreatureController const *playerCreatureController = safe_cast(getController()); + if(playerCreatureController) + return (playerCreatureController->getLastSpeed() > ConfigSharedGame::getMovementThresholdForActionValidation()); + return true; +} + +// ---------------------------------------------------------------------- + +CommandQueue * CreatureObject::getCommandQueue() const +{ + if (m_commandQueue == NULL) + { + m_commandQueue = CommandQueue::getCommandQueue(*const_cast(this)); + } + + return m_commandQueue; +} + +// ---------------------------------------------------------------------- + +void CreatureObject::clearCommands() +{ + m_commands.clear(); +} + +// ---------------------------------------------------------------------- + +std::map const & CreatureObject::getCommandList() const +{ + return m_commands.getMap(); +} + +// ---------------------------------------------------------------------- + +/** + Multiple skills can grant the same command. Commands can be granted + apart from skills. When a skill is removed, it must remove the command + it granted, but it probably shouldn't remove the command if is granted + by another skill or commands granted via other methods + (items/quests, etc...) +*/ +bool CreatureObject::grantCommand(std::string const & commandName, bool const fromSkill) +{ + bool result = false; + if(isAuthoritative()) + { + result = true; + // check if we already have the command + Archive::AutoDeltaMap::const_iterator found = m_commands.find(commandName); + if (found == m_commands.end()) + { + m_commands.set(commandName, 1); + + if(getClient()) + { + GrantCommand grant(commandName); + getClient()->send(grant, true); + } + if (!fromSkill) + { + // save command as objvar + setObjVarItem(OBJVAR_NOT_SKILL_COMMANDS + "." + commandName, 1); + } + } + else + { + m_commands.set(commandName, (*found).second + 1); + } + } + else + { + result = true; + sendControllerMessageToAuthServer(CM_grantCommand, new MessageQueueGenericValueType(commandName)); + } + return result; +} + +//----------------------------------------------------------------------- + +void CreatureObject::revokeCommand(std::string const & command, bool const fromSkill, bool const ignoreCount) +{ + if(isAuthoritative()) + { + Archive::AutoDeltaMap::const_iterator found = m_commands.find(command); + if (found != m_commands.end()) + { + if ((*found).second > 1 && !ignoreCount) + { + m_commands.set(command, (*found).second - 1); + } + else + { + m_commands.erase(found); + + if(getClient()) + { + RevokeCommand revoke(command); + getClient()->send(revoke, true); + } + if (!fromSkill) + { + // remove commands from objvars + removeObjVarItem(OBJVAR_NOT_SKILL_COMMANDS + "." + command); + } + } + } + } + else + { + sendControllerMessageToAuthServer(CM_revokeCommand, new MessageQueueGenericValueType(command)); + } +} + +//----------------------------------------------------------------------- + +bool CreatureObject::hasCommand(std::string const & commandName) const +{ + bool result = false; + if (commandName == "unskilled") + result = true; + else + { + const Archive::AutoDeltaMap::const_iterator f = m_commands.find(commandName); + result = (f != m_commands.end()); + } + return result; +} + +//----------------------------------------------------------------------- + +/** + * Called when our observer count changes. Will bring us into or out of hibernation + * if needed. + */ +void CreatureObject::observersCountChanged() +{ + if (isAuthoritative()) + { + CreatureController * controller = getCreatureController(); + int observers = getObserversCount(); + bool hibernating = controller->getHibernate(); + if ((observers > 0 && hibernating) || + (observers <= 0 && !hibernating)) + { + // attempt to change our hibernate state + controller->updateHibernate(); + } + } +} + +//----------------------------------------------------------------------- + +bool CreatureObject::isStopped() const +{ + return (m_stopWalkRun.get() == 0); +} + +//----------------------------------------------------------------------- + +bool CreatureObject::isWalking() const +{ + return (m_stopWalkRun.get() == 1); +} + +//----------------------------------------------------------------------- + +bool CreatureObject::isRunning() const +{ + return (m_stopWalkRun.get() == 2); +} + +//----------------------------------------------------------------------- + +void CreatureObject::setLookAtYaw(const float lookAtYaw, bool useLookAtYaw) +{ + if(useLookAtYaw && (m_lookAtYaw != lookAtYaw)) + setTransformChanged(true); + m_lookAtYaw = lookAtYaw; + m_useLookAtYaw = useLookAtYaw; +} + +//----------------------------------------------------------------------- + +float CreatureObject::getLookAtYaw() const +{ + return m_lookAtYaw; +} + +//----------------------------------------------------------------------- + +bool CreatureObject::getUseLookAtYaw() const +{ + return m_useLookAtYaw; +} + +//----------------------------------------------------------------------- + +int CreatureObject::getExpertiseRankForPlayer(std::string const & expertiseName) +{ + int result = 0; + + int rankMax = ExpertiseManager::getExpertiseRankMax(expertiseName); + + int tree = ExpertiseManager::getExpertiseTree(expertiseName); + int tier = ExpertiseManager::getExpertiseTier(expertiseName); + int grid = ExpertiseManager::getExpertiseGrid(expertiseName); + int rank = 1; + + while (rank <= rankMax) + { + SkillObject const * skill = ExpertiseManager::getExpertiseSkillAt(tree, tier, grid, rank); + if (skill && hasSkill(*skill)) + { + result = rank; + rank++; + } + else + { + break; + } + } + return result; +} + +//----------------------------------------------------------------------- + +void CreatureObject::getExpertisesForPlayer(SkillList & expertiseList) const +{ + expertiseList.clear(); + + SkillList const & skillList = this->getSkillList(); + + for (SkillList::const_iterator i = skillList.begin(); i != skillList.end(); ++i) + { + if (*i) + { + if (ExpertiseManager::isExpertise(*i)) + { + expertiseList.insert(*i); + } + } + } +} + +//----------------------------------------------------------------------- + +int CreatureObject::getExpertisePointsSpentForPlayerInTree(int tree) +{ + int spentPoints = 0; + + SkillList expertiseList; + getExpertisesForPlayer(expertiseList); + + for (SkillList::const_iterator i = expertiseList.begin(); i != expertiseList.end(); ++i) + { + SkillObject const * expertise = *i; + if (expertise) + { + std::string const & expertiseName = expertise->getSkillName(); + if (ExpertiseManager::getExpertiseTree(expertiseName) == tree) + { + spentPoints += getExpertiseRankForPlayer(expertiseName); + } + } + } + return spentPoints; +} + +//---------------------------------------------------------------------- + +int CreatureObject::getRemainingExpertisePoints() const +{ + int const numPointsAvail = ExpertiseManager::getExpertisePointsForLevel(getLevel()); + + CreatureObject::SkillList expertiseList; + getExpertisesForPlayer(expertiseList); + int const numPointsUsed = expertiseList.size() - 1; // subtract 1 for skill "expertise" + + return numPointsAvail - numPointsUsed; +} + +//----------------------------------------------------------------------- + +bool CreatureObject::processExpertiseRequest(std::vector const &addExpertisesNamesList, bool clearAllExpertisesFirst) +{ + for(std::vector::const_iterator i = addExpertisesNamesList.begin(); i != addExpertisesNamesList.end(); ++i) + { + std::string const &s = *i; + const SkillObject *skill = SkillManager::getInstance().getSkill(s); + if(skill) + { + //Check prerequisites + SkillObject::SkillVector const prereqs = skill->getPrerequisiteSkills(); + for (SkillObject::SkillVector::const_iterator i = prereqs.begin(); i != prereqs.end(); ++i) + { + SkillObject const * prereq = (*i); + if (!prereq || !hasSkill(*prereq)) + { + DEBUG_WARNING(true, ("player %s tried to get expertise %s but doesn't have expertise %s", getNetworkId().getValueString().c_str(), + skill->getSkillName().c_str(), prereq->getSkillName().c_str())); + return false; + } + } + //Check tier points + //Check if the player has enough points for a skill of this tier + int tree = ExpertiseManager::getExpertiseTree(s); + int pointsInTree = getExpertisePointsSpentForPlayerInTree(tree); + int tier = ExpertiseManager::getExpertiseTier(s); + if (pointsInTree < (tier - 1) * POINTS_PER_TIER) + { + DEBUG_WARNING(true, ("player %s tried to get expertise %s but only has %d points in tree %d, needs %d", getNetworkId().getValueString().c_str(), + s.c_str(), pointsInTree, tree, (tier - 1) * POINTS_PER_TIER + )); + return false; + } + + if (getRemainingExpertisePoints() < 1) + { + LOG("CustomerService", + ("SuspectedCheaterChannel: %s attempted to gain more expertise than allowed.", + PlayerObject::getAccountDescription(this).c_str()) + ); + + return false; + } + + //Check faction column + + //Grant skill + grantSkill(*skill); + } + } + return true; +} + +//----------------------------------------------------------------------- + +bool CreatureObject::clearAllExpertises() +{ + int numTries = 0; + while(numTries < 50) + { + //@TODO: guard this however design wants + const SkillList &skills = getSkillList(); + std::vector skillsToRevoke; + for(std::set::const_iterator i(skills.begin()); i != skills.end(); ++i) + { + const SkillObject *skill = *i; + if(skill && ExpertiseManager::isExpertise(skill)) + skillsToRevoke.push_back(skill); + } + if(skillsToRevoke.empty()) + return true; + for(std::vector::iterator i2 = skillsToRevoke.begin(); i2 != skillsToRevoke.end(); ++i2) + { + const SkillObject *skill = *i2; + revokeSkill(*skill, true); + } + numTries++; + } + return false; +} + +//----------------------------------------------------------------------- + +void CreatureObject::recomputeCommandSeries() +{ + for(std::vector::iterator i = s_commandSeriesRecords.begin(); i != s_commandSeriesRecords.end(); ++i) + { + CommandSeriesRecord const & csr = *i; + bool hasLevel = getLevel() >= csr.level; + if(csr.baseCommandName.empty()) + { + if(!hasLevel) + LOG("CustomerService",("Player %s of level %d has command %s from command series, but should not have it until level %d", + getNetworkId().getValueString().c_str(), getLevel(), csr.baseCommandName.c_str(), csr.level)); + } + else + { + if(hasCommand(csr.commandName) && (!hasCommand(csr.baseCommandName) || !hasLevel)) + { + revokeCommand(csr.commandName, true); + } + else if(!hasCommand(csr.commandName) && hasCommand(csr.baseCommandName) && hasLevel) + { + grantCommand(csr.commandName, true); + } + } + + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::incrementKillMeter(int amount) +{ + if (isPlayerControlled()) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject != NULL) + { + playerObject->incrementKillMeter(amount); + } + } +} + +//----------------------------------------------------------------------- + +void CreatureObject::getLfgCharacterData(LfgCharacterData & lfgCharacterData) const +{ + lfgCharacterData.characterId = getNetworkId(); + lfgCharacterData.characterName = getAssignedObjectName(); + lfgCharacterData.characterLowercaseFirstName = Unicode::wideToNarrow(Unicode::toLower(getAssignedObjectFirstName())); + + lfgCharacterData.species = getSpecies(); + lfgCharacterData.gender = getGender(); + + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); + if (iterFind != connectedCharacterLfgData.end()) + { + lfgCharacterData.characterInterests = iterFind->second.characterInterests; + lfgCharacterData.characterCreateTime = iterFind->second.characterCreateTime; + lfgCharacterData.characterAge = iterFind->second.characterAge; + } + else + { + lfgCharacterData.characterInterests.clear(); + lfgCharacterData.characterCreateTime = -1; + lfgCharacterData.characterAge = -1; + } + + if (lfgCharacterData.characterCreateTime <= 0) + lfgCharacterData.characterCreateTime = static_cast(NameManager::getInstance().getPlayerCreateTime(getNetworkId())); + + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(this); + if (playerObject) + { + lfgCharacterData.characterAge = playerObject->getAgeInDays(); + + lfgCharacterData.profession = LfgCharacterData::convertSkillTemplateToProfession(playerObject->getSkillTemplate()); + + MatchMakingId const & id = playerObject->getMatchMakingCharacterProfileId(); + lfgCharacterData.anonymous = id.isBitSet(MatchMakingId::B_anonymous); + lfgCharacterData.searchableByCtsSourceGalaxy = id.isBitSet(MatchMakingId::B_searchableByCtsSourceGalaxy); + lfgCharacterData.displayLocationInSearchResults = id.isBitSet(MatchMakingId::B_displayLocationInSearchResults); + + if (id.isBitSet(MatchMakingId::B_lookingForGroup)) + LfgDataTable::setBit("lfg", lfgCharacterData.characterInterests); + else + LfgDataTable::clearBit("lfg", lfgCharacterData.characterInterests); + + if (id.isBitSet(MatchMakingId::B_helper)) + LfgDataTable::setBit("helper", lfgCharacterData.characterInterests); + else + LfgDataTable::clearBit("helper", lfgCharacterData.characterInterests); + + if (id.isBitSet(MatchMakingId::B_rolePlay)) + LfgDataTable::setBit("rp", lfgCharacterData.characterInterests); + else + LfgDataTable::clearBit("rp", lfgCharacterData.characterInterests); + + if (id.isBitSet(MatchMakingId::B_lookingForWork)) + LfgDataTable::setBit("lfw", lfgCharacterData.characterInterests); + else + LfgDataTable::clearBit("lfw", lfgCharacterData.characterInterests); + + lfgCharacterData.active = (playerObject->getSessionLastActiveTime() != 0); + lfgCharacterData.sessionActivity = playerObject->getSessionActivity(); + } + else + { + lfgCharacterData.profession = LfgCharacterData::Prof_Unknown; + lfgCharacterData.anonymous = false; + lfgCharacterData.displayLocationInSearchResults = false; + lfgCharacterData.active = false; + lfgCharacterData.sessionActivity = 0; + } + + SkillObject const * skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_novice"); + if (skill && hasSkill(*skill)) + { + lfgCharacterData.pilot = LfgCharacterData::Pilot_Rebel; + } + else + { + skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_novice"); + if (skill && hasSkill(*skill)) + { + lfgCharacterData.pilot = LfgCharacterData::Pilot_Imperial; + } + else + { + skill = SkillManager::getInstance().getSkill("pilot_neutral_novice"); + if (skill && hasSkill(*skill)) + { + lfgCharacterData.pilot = LfgCharacterData::Pilot_Neutral; + } + else + { + lfgCharacterData.pilot = LfgCharacterData::Pilot_None; + } + } + } + + lfgCharacterData.level = getLevel(); + lfgCharacterData.faction = getPvpFaction(); + + int const guildId = getGuildId(); + if (guildId == 0) + { + lfgCharacterData.guildName.clear(); + lfgCharacterData.guildAbbrev.clear(); + } + else + { + lfgCharacterData.guildName = GuildInterface::getGuildName(guildId); + lfgCharacterData.guildAbbrev = GuildInterface::getGuildAbbrev(guildId); + } + + std::vector const & cityIds = CityInterface::getCitizenOfCityId(getNetworkId()); + if (!cityIds.empty()) + { + lfgCharacterData.citizenOfCity = CityInterface::getCityInfo(cityIds.front()).getCityName(); + } + else + { + lfgCharacterData.citizenOfCity.clear(); + } + + lfgCharacterData.groupId = m_group.get(); + lfgCharacterData.locationPlanet = ServerWorld::getSceneId(); + + lfgCharacterData.locationRegion.clear(); + lfgCharacterData.locationFactionalPresenceGcwRegion.clear(); + lfgCharacterData.locationFactionalPresenceGridX = 0; + lfgCharacterData.locationFactionalPresenceGridZ = 0; + lfgCharacterData.locationPlayerCity.clear(); + PlanetObject const * const planetObject = ServerUniverse::getInstance().getPlanetByName(lfgCharacterData.locationPlanet); + if (planetObject) + { + Vector const creaturePosition = findPosition_w(); + Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(planetObject->getName(), creaturePosition.x, creaturePosition.z); + + if (region != NULL) + lfgCharacterData.locationRegion = Unicode::wideToNarrow(region->getName()); + + // handle factional presence + Client const * const client = getClient(); + if (client && (!ConfigServerGame::getGcwFactionalPresenceDisableForSecuredLogin() || !client->isGodValidated())) + { + std::string const & playerCurrentGcwRegion = playerObject->getCurrentGcwRegion(); + if (!playerCurrentGcwRegion.empty()) + { + if (!ServerWorld::isSpaceScene()) + { + // ground factional presence + // + // character contributes to ground GCW factional presence if he is actively + // playing the game, is declared factional, is not in a cell, is not + // cloaked/incapped/dead/swimming, and is not hidden from the overhead map/radar + if (lfgCharacterData.active && !PvpData::isNeutralFactionId(lfgCharacterData.faction) && PvpInternal::isDeclared(*this) && !isHidden() && isVisible() && getCoverVisibility() && !isIncapacitated() && !isDead() && !getState(States::Swimming) && getVisibleOnMapAndRadar()) + { + bool inCell = false; + ServerObject const * o = safe_cast(ContainerInterface::getContainedByObject(*this)); + while (o) + { + if (o->asCellObject()) + { + inCell = true; + break; + } + + o = safe_cast(ContainerInterface::getContainedByObject(*o)); + } + + if (!inCell) + { + // make sure he (or his vehicle/mount) is standing on the + // ground, and not on a roof/balcony/storyteller platform/etc + Object const * playerOrMount = getMountedCreature(); + if (playerOrMount) + { + // is factional presence allowed while mounted? + if (ConfigServerGame::getGcwFactionalPresenceMountedPct() <= 0) + playerOrMount = NULL; + } + else + { + playerOrMount = this; + } + + if (playerOrMount) + { + CollisionProperty const * const collisionProperty = playerOrMount->getCollisionProperty(); + Footprint const * const footprint = (collisionProperty ? collisionProperty->getFootprint() : NULL); + bool isOnSolidFloor = (footprint && footprint->isOnSolidFloor()); + if (isOnSolidFloor) + { + // make sure the player/mount is actually standing on the floor for it to count + float groundHeight, floorHeight; + if (footprint->getGroundHeight(groundHeight) && footprint->getFloorHeight(floorHeight) && (groundHeight == floorHeight)) + { + // really standing on the floor + } + else + { + // not really standing on the floor + isOnSolidFloor = false; + } + } + + // standing on the ground + if (!isOnSolidFloor) + { + lfgCharacterData.locationFactionalPresenceGcwRegion = playerCurrentGcwRegion; + + // if there's factional presence, calculate the grid in which it is occurring + // clamp to -8000 - 7999 + int posX = std::min(std::max(static_cast(creaturePosition.x), -8000), 7999); + + // clamp to -8000 - 7999 + int posZ = std::min(std::max(static_cast(creaturePosition.z), -8000), 7999); + + if (posX < 0) + posX -= (PvpData::getGcwFactionalPresenceGridSize() - 1); + + if (posZ < 0) + posZ -= (PvpData::getGcwFactionalPresenceGridSize() - 1); + + lfgCharacterData.locationFactionalPresenceGridX = ((posX / PvpData::getGcwFactionalPresenceGridSize()) * PvpData::getGcwFactionalPresenceGridSize()) + (PvpData::getGcwFactionalPresenceGridSize() / 2); + lfgCharacterData.locationFactionalPresenceGridZ = ((posZ / PvpData::getGcwFactionalPresenceGridSize()) * PvpData::getGcwFactionalPresenceGridSize()) + (PvpData::getGcwFactionalPresenceGridSize() / 2); + } + } + } + } + } + else if (lfgCharacterData.active && !isIncapacitated() && !isDead()) + { + // space factional presence + // + // character contributes to space GCW factional presence if he is actively playing the + // game, is not incapped/dead, is on board a player ship that's open to attack from + // other player ships, and is the same faction as the ship + ShipObject const * const ship = ShipObject::getContainingShipObject(this); + if (ship && ship->isPlayerShip() && !ship->isInvulnerable() && PvpInternal::isDeclared(*ship)) + { + uint32 const shipFaction = ship->getSpaceFaction(); + if ((PvpData::isImperialFactionId(shipFaction) || PvpData::isRebelFactionId(shipFaction)) && (lfgCharacterData.faction == shipFaction)) + lfgCharacterData.locationFactionalPresenceGcwRegion = playerCurrentGcwRegion; + } + } + } + } + + int const cityId = CityInterface::getCityAtLocation(planetObject->getName(), static_cast(creaturePosition.x), static_cast(creaturePosition.z), 0); + if (cityId > 0) + lfgCharacterData.locationPlayerCity = CityInterface::getCityInfo(cityId).getCityName(); + } + + // CTS transferred from galaxy + lfgCharacterData.ctsSourceGalaxy.clear(); + if (getObjVars().hasItem("ctsHistory")) + { + DynamicVariableList::NestedList const ctsTransactions(getObjVars(), "ctsHistory"); + for (DynamicVariableList::NestedList::const_iterator i = ctsTransactions.begin(); i != ctsTransactions.end(); ++i) + { + Unicode::String ctsTransactionDetail; + if (i.getValue(ctsTransactionDetail)) + { + Unicode::UnicodeStringVector tokens; + if (Unicode::tokenize(ctsTransactionDetail, tokens, NULL, NULL) && (tokens.size() >= 4)) + { + IGNORE_RETURN(lfgCharacterData.ctsSourceGalaxy.insert(Unicode::wideToNarrow(tokens[1]))); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObjectNamespace::GroupHelpers::creatureIsContainedInPOBShip(CreatureObject const * const creatureObject) +{ + NOT_NULL(creatureObject); + + ShipObject const * const shipObject = ShipObject::getContainingShipObject(creatureObject); + return shipObject && shipObject->getPortalProperty(); +} + +// ---------------------------------------------------------------------- + +void CreatureObjectNamespace::GroupHelpers::findAllTargetsForGroup(CreatureObject * const targetObj, std::vector & targets) +{ + typedef std::vector Targets; + + NOT_NULL(targetObj); + + ShipObject * const shipObject = ShipObject::getContainingShipObject(targetObj); + GroupObject const * const groupObject = targetObj->getGroup(); + + if ((shipObject != 0) && (groupObject != 0)) + { + Targets passengers; + + shipObject->findAllPassengers(passengers, true); + + Targets::const_iterator ii = passengers.begin(); + Targets::const_iterator iiEnd = passengers.end(); + + for (; ii != iiEnd; ++ii) + { + CreatureObject * const passenger = *ii; + + if (passenger != 0) + { + NetworkId const & passengerId = passenger->getNetworkId(); + + if (groupObject->isGroupMember(passengerId)) + { + targets.push_back(passenger); + } + } + NOT_NULL(passenger); + } + } + else + { + targets.push_back(targetObj); + } +} + +// ---------------------------------------------------------------------- + +bool CreatureObjectNamespace::GroupHelpers::roomInGroup(GroupObject const * groupObj, int additionalMembers) +{ + if (groupObj != 0) + { + return groupObj->doesGroupHaveRoomFor(additionalMembers); + } + + additionalMembers = std::max(0, additionalMembers); + return additionalMembers < GroupObject::maximumMembersInGroup(); +} + +// ---------------------------------------------------------------------- + +GroupMemberParam const CreatureObjectNamespace::GroupHelpers::buildGroupMemberParam(CreatureObject const * const creatureObject) +{ + NOT_NULL(creatureObject); + + ShipObject const * const shipObject = ShipObject::getContainingShipObject(creatureObject); + NetworkId const & memberId = creatureObject->getNetworkId(); + std::string const & name = Unicode::wideToNarrow(creatureObject->getEncodedObjectName()); + int const level = creatureObject->getLevel(); + bool const memberIsPC = creatureObject->isPlayerControlled(); + LfgCharacterData::Profession profession = LfgCharacterData::Prof_Unknown; + if (!memberIsPC) + { + profession = LfgCharacterData::Prof_NPC; + } + else + { + PlayerObject const * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if (playerObject) + profession = LfgCharacterData::convertSkillTemplateToProfession(playerObject->getSkillTemplate()); + } + + NetworkId const & shipId = (shipObject != 0) ? shipObject->getNetworkId() : NetworkId::cms_invalid; + bool const shipIsPOB = shipObject != 0 && shipObject->getPortalProperty() != 0; + bool const ownsPOB = shipObject != 0 && shipObject->getOwnerId() == memberId; + + return GroupMemberParam(memberId, name, level, profession, memberIsPC, shipId, shipIsPOB, ownsPOB); +} + +// ---------------------------------------------------------------------- + +void CreatureObjectNamespace::GroupHelpers::buildGroupMemberParamsFromCreatures(std::vector const & targets, GroupObject::GroupMemberParamVector & targetMemberParams) +{ + std::vector::const_iterator ii = targets.begin(); + std::vector::const_iterator iiEnd = targets.end(); + + for (; ii != iiEnd; ++ii) + { + CreatureObject const * const creatureObject = *ii; + if (creatureObject != 0) + { + targetMemberParams.push_back(GroupHelpers::buildGroupMemberParam(creatureObject)); + } + } +} + +// ---------------------------------------------------------------------- + +void CreatureObjectNamespace::restoreItemDecorationLayout(CreatureObject & decorator, PlayerObject & decoratorPlayerObject, CachedNetworkId const & item, TangibleObject const & pob, CachedNetworkId const & cell, Vector const & position, Quaternion const & orientation) +{ + // make sure item is around + ServerObject const * const itemSo = safe_cast(item.getObject()); + if (!itemSo) + return; + + // make sure item is immediately in a cell/room + ServerObject const * const itemContainingCell = safe_cast(ContainerInterface::getContainedByObject(*itemSo)); + if (!itemContainingCell || !itemContainingCell->asCellObject()) + return; + + // make sure item is in the pob + if (&pob != ContainerInterface::getContainedByObject(*itemContainingCell)) + return; + + // make sure the cell is around + ServerObject const * const cellSo = safe_cast(cell.getObject()); + if (!cellSo) + return; + + CellObject const * const cellCo = cellSo->asCellObject(); + if (!cellCo) + return; + + // make sure cell is in the pob + if (&pob != ContainerInterface::getContainedByObject(*cellCo)) + return; + + // item is not currently in the target room, need to move it + bool needToMoveItem = false; + bool needToRotateItem = false; + Transform const * itemCurrentTransform = NULL; + if (itemContainingCell->getNetworkId() != cellSo->getNetworkId()) + { + needToMoveItem = true; + } + else + { + // if the item is not currently at the desired position, need to move it + itemCurrentTransform = &(itemSo->getTransform_o2p()); + Vector const currentPosition = itemCurrentTransform->getPosition_p(); + if (currentPosition.magnitudeBetweenSquared(position) > 0.0025) // not within 0.05m + { + needToMoveItem = true; + } + else + { + // if the item is not currently at the desired orientation, need to rotate it + Quaternion const currentOrientation(*itemCurrentTransform); + if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) + { + needToRotateItem = true; + } + } + } + + if (!needToMoveItem && !needToRotateItem) + return; + + // if the item needs to be moved, check to see if it needs to be rotated as well + if (needToMoveItem) + { + if (!itemCurrentTransform) + itemCurrentTransform = &(itemSo->getTransform_o2p()); + + Quaternion const currentOrientation(*itemCurrentTransform); + if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) + { + needToRotateItem = true; + } + } + + // if the item needs to be moved, find the "best" valid position for the item + if (needToMoveItem) + { + CellProperty const * const cellProperty = cellCo->getCellProperty(); + if (!cellProperty) + return; + + Floor const * const floor = cellProperty->getFloor(); + if (!floor) + return; + + BaseExtent const * const floorExtent = floor->getExtent_l(); + if (!floorExtent) + return; + + AxialBox const floorExtentBoundingBox = floorExtent->getBoundingBox(); + Vector floorExtentBoundingBoxCenter = floorExtentBoundingBox.getCenter(); + floorExtentBoundingBoxCenter.y = position.y + 1.0f; + + Vector goodLocation(position); + goodLocation.y = floorExtentBoundingBoxCenter.y; + + bool foundGoodPoint = true; + FloorLocator flResult; + if (!floor->intersectClosest(Ray3d(goodLocation, Vector::negativeUnitY), flResult)) + { + // do a "binary" search of points on the line starting at the floor bounding + // box center location (which may be a good location) and ending at the target + // location (which is a bad location) until a point on the line is found + // that is a good location, and that point is "up against" the wall of the cell + Vector badLocation(goodLocation); + goodLocation = floorExtentBoundingBoxCenter; + foundGoodPoint = floor->intersectClosest(Ray3d(goodLocation, Vector::negativeUnitY), flResult); + + Vector midpointPosition; + while (true) + { + // stop when the 2 closest "good" and "bad" location points are .2m apart, + // meaning we have gotten close enough to "up against" the wall of the cell + if (goodLocation.magnitudeXZBetweenSquared(badLocation) <= 0.04f) + break; + + midpointPosition = Vector::midpoint(goodLocation, badLocation); + midpointPosition.y = floorExtentBoundingBoxCenter.y; + if (floor->intersectClosest(Ray3d(midpointPosition, Vector::negativeUnitY), flResult)) + { + foundGoodPoint = true; + goodLocation = midpointPosition; + } + else + { + badLocation = midpointPosition; + } + } + } + + // couldn't find any valid position for the item + if (!foundGoodPoint) + return; + + // set the height of the item + goodLocation.y = position.y; + + // trigger script to move the item, which will perform the remaining validation + GameScriptObject * const gameScriptObject = decorator.getScriptObject(); + if (!gameScriptObject) + return; + + ScriptParams sp; + sp.addParam(itemSo->getNetworkId()); + sp.addParam(cellSo->getNetworkId()); + sp.addParam(goodLocation); + sp.addParam(needToRotateItem); + sp.addParam(orientation.w); + sp.addParam(orientation.x); + sp.addParam(orientation.y); + sp.addParam(orientation.z); + + // set the id of the object being restored, so that we can bypass the LOS check for it + decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(itemSo->getNetworkId()); + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_DO_RESTORE_ITEM_DECORATION_LAYOUT, sp)); + decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(NetworkId::cms_invalid); + + // check to see if the item got restored + bool itemGotRestored = true; + if (itemContainingCell->getNetworkId() == cellSo->getNetworkId()) + { + Transform const & itemCurrentTransform = itemSo->getTransform_o2p(); + Vector const currentPosition = itemCurrentTransform.getPosition_p(); + if (currentPosition.magnitudeBetweenSquared(goodLocation) > 0.0025) // not within 0.05m + { + itemGotRestored = false; + } + else if (needToRotateItem) + { + Quaternion const currentOrientation(itemCurrentTransform); + if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) + { + itemGotRestored = false; + } + } + } + else if (cellSo != ContainerInterface::getContainedByObject(*itemSo)) + { + itemGotRestored = false; + } + + if (itemGotRestored) + decoratorPlayerObject.setRestoreDecorationSuccessCount(decoratorPlayerObject.getRestoreDecorationSuccessCount() + 1); + } + else if (needToRotateItem) + { + // trigger script to rotate the item, which will perform the remaining validation + GameScriptObject * const gameScriptObject = decorator.getScriptObject(); + if (!gameScriptObject) + return; + + ScriptParams sp; + sp.addParam(itemSo->getNetworkId()); + sp.addParam(orientation.w); + sp.addParam(orientation.x); + sp.addParam(orientation.y); + sp.addParam(orientation.z); + + // set the id of the object being restored, so that we can bypass the LOS check for it + decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(itemSo->getNetworkId()); + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_DO_RESTORE_ITEM_DECORATION_LAYOUT_ROTATION_ONLY, sp)); + decoratorPlayerObject.setRestoreDecorationObjectBeingRestored(NetworkId::cms_invalid); + + // check to see if the item got restored + bool itemGotRestored = true; + Transform const & itemCurrentTransform = itemSo->getTransform_o2p(); + Quaternion const currentOrientation(itemCurrentTransform); + if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) + { + itemGotRestored = false; + } + + if (itemGotRestored) + decoratorPlayerObject.setRestoreDecorationSuccessCount(decoratorPlayerObject.getRestoreDecorationSuccessCount() + 1); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::clientMinigameOpen(ValueDictionary const & messageData) +{ + typedef ValueDictionary Payload; + MessageQueueGenericValueType * msg = new MessageQueueGenericValueType(messageData); + + if (isAuthoritative()) + { + appendMessage(CM_clientMinigameOpen, 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + else + { + sendControllerMessageToAuthServer(CM_clientMinigameOpen, msg); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::clientMinigameClose(ValueDictionary const & messageData) +{ + typedef ValueDictionary Payload; + MessageQueueGenericValueType * msg = new MessageQueueGenericValueType(messageData); + + if (isAuthoritative()) + { + appendMessage(CM_clientMinigameClose, 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + else + { + sendControllerMessageToAuthServer(CM_clientMinigameClose, msg); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::addPackedAppearanceWearable(std::string const &appearanceData, int arrangementIndex, NetworkId const &networkId, uint32 sharedTemplateCrcValue) +{ + //-- Check if this network id already exists in the wearable list. + size_t const length = m_wearableAppearanceData.size(); + for (size_t i = 0; i < length; ++i) + { + WearableEntry const &entry = m_wearableAppearanceData[i]; + if (entry.m_networkId == networkId) + { + // Check if this entry exists but in a different configuration. + WARNING((entry.m_arrangement != arrangementIndex), ("attempted to add object id=[%s] in packed wearable list multiple times in different arrangements, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_arrangement, arrangementIndex)); + WARNING((static_cast(entry.m_objectTemplate) != sharedTemplateCrcValue), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by shared object template crc value, existing=[%d],new=[%d].", appearanceData.c_str(), entry.m_objectTemplate, static_cast(sharedTemplateCrcValue))); + DEBUG_WARNING((entry.m_appearanceString != appearanceData), ("attempted to add object id=[%s] in packed wearable list multiple times differing only by appearance customization data.", appearanceData.c_str())); + + return; + } + } + //-- Add the new entry. + m_wearableAppearanceData.push_back(WearableEntry(appearanceData, arrangementIndex, networkId, sharedTemplateCrcValue, NULL, NULL)); +} + +// ---------------------------------------------------------------------- + +void CreatureObject::saveDecorationLayout(ServerObject const & pobSourceObject, int saveSlotNumber, std::string const & description) +{ + int debugNumItems = 0; + const unsigned long debugStartTimeMs = Clock::timeMs(); + + if (!isAuthoritative()) + return; + + if (!getClient()) + return; + + // only slots 1-3 are currently supported + if ((saveSlotNumber < 1) || (saveSlotNumber > 3)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + if (!pobSourceObject.isAuthoritative()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(this); + if (!playerObj) + return; + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (containingPOBso != &pobSourceObject) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); + return; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + if (!containingPOB->isOnAdminList(*this)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + Container const * const pobContainer = ContainerInterface::getContainer(*containingPOB); + if (pobContainer) + { + std::string objvarValue; + int objvarValueIndex = 0; + + char buffer1[64]; + buffer1[sizeof(buffer1)-1] = '\0'; + + char buffer2[1024]; + buffer2[sizeof(buffer2)-1] = '\0'; + + std::set rooms; + + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d", saveSlotNumber); + playerObj->removeObjVarItem(buffer1); + + for (ContainerConstIterator i = pobContainer->begin(); i != pobContainer->end(); ++i) + { + ServerObject const * const cell = safe_cast((*i).getObject()); + if (cell && cell->asCellObject()) + { + CellProperty const * const cellContainer = cell->getCellProperty(); + if (cellContainer) + { + std::map, std::pair >::const_iterator const iterFindCellHeight = s_mapCellHeightRestriction.find(std::make_pair(containingPOB->getTemplateCrc(), cellContainer->getCellNameCrc())); + if (iterFindCellHeight == s_mapCellHeightRestriction.end()) + continue; + + Floor const * const floor = cellContainer->getFloor(); + if (!floor) + continue; + + BaseExtent const * const floorExtent = floor->getExtent_l(); + if (!floorExtent) + continue; + + AxialBox const floorExtentBoundingBox = floorExtent->getBoundingBox(); + Vector const floorExtentBoundingBoxCenter = floorExtentBoundingBox.getCenter(); + + for (ContainerConstIterator j = cellContainer->begin(); j != cellContainer->end(); ++j) + { + ServerObject const * const cellContent = safe_cast((*j).getObject()); + if (cellContent && cellContent->isPersisted() && !cellContent->asCreatureObject() && !cellContent->isVendor()) + { + ++debugNumItems; + IGNORE_RETURN(rooms.insert(cellContainer->getCellName())); + + Transform const & transform = cellContent->getTransform_o2p(); + Vector const position = transform.getPosition_p(); + Quaternion const quaternion(transform); + + snprintf(buffer2, sizeof(buffer2)-1, "%s~%s~%.10g~%.10g~%.10g~%.10g~%.10g~%.10g~%.10g", cellContent->getNetworkId().getValueString().c_str(), cellContainer->getCellName(), position.x - floorExtentBoundingBoxCenter.x, position.y - iterFindCellHeight->second.first, position.z - floorExtentBoundingBoxCenter.z, quaternion.w, quaternion.x, quaternion.y, quaternion.z); + if ((objvarValue.size() + ::strlen(buffer2) + 2) > DynamicVariable::MAX_DYNAMIC_VARIABLE_UTF8_LENGTH) + { + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); + playerObj->setObjVarItem(buffer1, objvarValue); + ++objvarValueIndex; + objvarValue = buffer2; + } + else + { + if (!objvarValue.empty()) + objvarValue += "~"; + + objvarValue += buffer2; + } + } + } + } + } + } + + if (rooms.empty()) + { + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d", saveSlotNumber); + playerObj->removeObjVarItem(buffer1); + + Chat::sendSystemMessage(*this, Unicode::narrowToWide("There is currently no decoration in the structure or POB ship to save."), Unicode::emptyString); + } + else + { + if (!objvarValue.empty()) + { + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); + playerObj->setObjVarItem(buffer1, objvarValue); + } + + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.saveTime", saveSlotNumber); + playerObj->setObjVarItem(buffer1, static_cast(::time(NULL))); + + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.pobName", saveSlotNumber); + playerObj->setObjVarItem(buffer1, containingPOB->getObjectNameStringId().localize()); + + std::vector roomsVector; + for (std::set::const_iterator iterRoom = rooms.begin(); iterRoom != rooms.end(); ++iterRoom) + roomsVector.push_back(Unicode::narrowToWide(*iterRoom)); + + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.rooms", saveSlotNumber); + playerObj->setObjVarItem(buffer1, roomsVector); + + std::string validatedDescription = description; + if (!validatedDescription.empty()) + { + if (validatedDescription.size() > 40) + validatedDescription = validatedDescription.substr(0, 40); + + snprintf(buffer1, sizeof(buffer1)-1, "savedDecoration%d.description", saveSlotNumber); + playerObj->setObjVarItem(buffer1, validatedDescription); + } + + if (validatedDescription.empty()) + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("The decoration layout of the structure or POB ship has been saved in slot %d.", saveSlotNumber)), Unicode::emptyString); + else + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("The decoration layout of the structure or POB ship has been saved in slot %d (%s).", saveSlotNumber, validatedDescription.c_str())), Unicode::emptyString); + } + } + else + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + } + + if ((debugNumItems > 0) && getClient()->isGod()) + { + const unsigned long debugEndTimeMs = Clock::timeMs(); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("!!!GOD MODE STATISTICS!!! %d items saved in %lums", debugNumItems, (debugEndTimeMs - debugStartTimeMs))), Unicode::emptyString); + } +} + +// ---------------------------------------------------------------------- + +void CreatureObject::restoreDecorationLayout(ServerObject const & pobTargetObject, int saveSlotNumber) +{ + const unsigned long debugStartTimeMs = Clock::timeMs(); + + if (!isAuthoritative()) + return; + + if (!getClient()) + return; + + // only slots 1-3 are currently supported + if ((saveSlotNumber < 1) || (saveSlotNumber > 3)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + if (!pobTargetObject.isAuthoritative()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + PlayerObject * const playerObj = PlayerCreatureController::getPlayerObject(this); + if (!playerObj) + return; + + ServerObject const * const containingCell = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (!containingCell || !containingCell->asCellObject()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + ServerObject const * const containingPOBso = safe_cast(ContainerInterface::getContainedByObject(*containingCell)); + if (!containingPOBso) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (!containingPOBso->isInWorldCell()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + if (containingPOBso != &pobTargetObject) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be standing inside the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + // don't allow another restore on the pob while one is still in progress + int const timeNow = static_cast(::time(NULL)); + int restoreDecorationOperationTimeout = 0; + if (getObjVars().getItem("restoreDecorationOperation.timeout", restoreDecorationOperationTimeout) && (restoreDecorationOperationTimeout > timeNow)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are already performing a restore decoration layout operation. Please wait for the current operation to complete, or if the current operation does not complete in %s, you can try another operation.", CalendarTime::convertSecondsToMS(static_cast(restoreDecorationOperationTimeout - timeNow)).c_str())), Unicode::emptyString); + return; + } + + if (containingPOBso->asBuildingObject() && !containingPOBso->asBuildingObject()->getContentsLoaded()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("Please wait until the building has loaded its contents and try again."), Unicode::emptyString); + return; + } + + TangibleObject const * const containingPOB = containingPOBso->asTangibleObject(); + if (!containingPOB) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + // check for lot overlimit drop restriction + if ((playerObj->getAccountNumLots() > getMaxNumberOfLots()) && getObjVars().hasItem("lotOverlimit.structure_id")) + { + NetworkId lotOverlimitStructure; + if (getObjVars().getItem("lotOverlimit.structure_id", lotOverlimitStructure) && lotOverlimitStructure.isValid()) + { + if (GameObjectTypes::isTypeOf(containingPOB->getGameObjectType(), SharedObjectTemplate::GOT_building) && (containingPOB->getNetworkId() != lotOverlimitStructure)) + { + std::string lotOverlimitStructureName; + std::string lotOverlimitStructureLocation; + + IGNORE_RETURN(getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); + IGNORE_RETURN(getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); + + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("You are currently over the lot limit, and cannot drop any item into (or move around items within) any factory or structure, other than the %s structure located at %s that caused you to exceed the lot limit.", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); + return; + } + } + } + + if (!containingPOB->isOnAdminList(*this)) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("You must be the owner or an admin of the structure or POB ship to do this."), Unicode::emptyString); + return; + } + + // build the list of rooms in the target pob + std::map, std::pair > > > pobTargetObjectRoomsToCells; + Container const * const pobContainer = ContainerInterface::getContainer(*containingPOB); + if (pobContainer) + { + for (ContainerConstIterator i = pobContainer->begin(); i != pobContainer->end(); ++i) + { + ServerObject const * const cell = safe_cast((*i).getObject()); + if (!cell || !cell->asCellObject()) + continue; + + CellProperty const * const cellContainer = cell->getCellProperty(); + if (!cellContainer) + continue; + + std::map, std::pair >::const_iterator const iterFindCellHeight = s_mapCellHeightRestriction.find(std::make_pair(containingPOB->getTemplateCrc(), cellContainer->getCellNameCrc())); + if (iterFindCellHeight == s_mapCellHeightRestriction.end()) + continue; + + Floor const * const floor = cellContainer->getFloor(); + if (!floor) + continue; + + BaseExtent const * const floorExtent = floor->getExtent_l(); + if (!floorExtent) + continue; + + AxialBox const floorExtentBoundingBox = floorExtent->getBoundingBox(); + Vector const floorExtentBoundingBoxCenter = floorExtentBoundingBox.getCenter(); + + pobTargetObjectRoomsToCells[cellContainer->getCellName()] = std::make_pair(cell->asCellObject(), std::make_pair(std::make_pair(iterFindCellHeight->second.first, iterFindCellHeight->second.second), std::make_pair(floorExtentBoundingBoxCenter.x, floorExtentBoundingBoxCenter.z))); + } + } + else + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + // build the list of source room to target room mapping, telling us where to move/restore the items + DynamicVariableList const & objVars = playerObj->getObjVars(); + char buffer[64]; + buffer[sizeof(buffer)-1] = '\0'; + + std::vector savedSourceRooms; + snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.rooms", saveSlotNumber); + if (!objVars.getItem(buffer, savedSourceRooms) || savedSourceRooms.empty()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + std::vector savedTargetRooms; + snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.targetRooms", saveSlotNumber); + if (!objVars.getItem(buffer, savedTargetRooms) || savedTargetRooms.empty()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + if (savedSourceRooms.size() != savedTargetRooms.size()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + std::map sourceRoomToTargetRoomMapping; + for (size_t i = 0, size = savedSourceRooms.size(); i < size; ++i) + { + if (savedTargetRooms[i].empty()) + continue; + + std::string savedTargetRoomNarrow = Unicode::wideToNarrow(savedTargetRooms[i]); + if (pobTargetObjectRoomsToCells.count(savedTargetRoomNarrow) <= 0) + continue; + + sourceRoomToTargetRoomMapping[Unicode::wideToNarrow(savedSourceRooms[i])] = savedTargetRoomNarrow; + } + + if (sourceRoomToTargetRoomMapping.empty()) + { + Chat::sendSystemMessage(*this, Unicode::narrowToWide("An internal error has been encountered."), Unicode::emptyString); + return; + } + + int debugNumItems = 0; + int numItemsToBeMoved = 0; + + unsigned int pos; + NetworkId itemId; + ServerObject const * itemObj; + ServerObject const * itemObjContainingCell; + std::string room; + Vector position, currentPosition; + Quaternion orientation; + std::map::const_iterator iterFindSourceRoomToTargetRoomMapping; + std::map, std::pair > > >::const_iterator iterFindPobTargetObjectRoomsToCells; + + std::string objvarValue; + int objvarValueIndex = 0; + + std::list, std::pair > > & restoreDecorationLayoutList = playerObj->getRestoreDecorationLayoutList(); + restoreDecorationLayoutList.clear(); + + snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); + while (objVars.getItem(buffer, objvarValue) && !objvarValue.empty()) + { + pos = 0; + while (objvarValue[pos]) + { + ++debugNumItems; + + nextOid(objvarValue, pos, itemId); + nextString(objvarValue, pos, room); + nextFloat(objvarValue, pos, position.x); + nextFloat(objvarValue, pos, position.y); + nextFloat(objvarValue, pos, position.z); + nextFloat(objvarValue, pos, orientation.w); + nextFloat(objvarValue, pos, orientation.x); + nextFloat(objvarValue, pos, orientation.y); + nextFloat(objvarValue, pos, orientation.z); + + itemObj = ServerWorld::findObjectByNetworkId(itemId); + if (!itemObj) + continue; + + itemObjContainingCell = safe_cast(ContainerInterface::getContainedByObject(*itemObj)); + if (!itemObjContainingCell || !itemObjContainingCell->asCellObject()) + continue; + + if (ContainerInterface::getContainedByObject(*itemObjContainingCell) != containingPOB) + continue; + + // what destination room should this item go in? + iterFindSourceRoomToTargetRoomMapping = sourceRoomToTargetRoomMapping.find(room); + if (iterFindSourceRoomToTargetRoomMapping == sourceRoomToTargetRoomMapping.end()) + { + // no destination room specified, item should not be moved + continue; + } + + // find the cell in the target structure corresponding to the target room + iterFindPobTargetObjectRoomsToCells = pobTargetObjectRoomsToCells.find(iterFindSourceRoomToTargetRoomMapping->second); + if (iterFindPobTargetObjectRoomsToCells == pobTargetObjectRoomsToCells.end()) + { + // target room not found, cannot move the item + continue; + } + + // the height is saved as the offset from the floor + position.y += iterFindPobTargetObjectRoomsToCells->second.second.first.first; + + if (position.y < iterFindPobTargetObjectRoomsToCells->second.second.first.first) + position.y = iterFindPobTargetObjectRoomsToCells->second.second.first.first; + else if (position.y > iterFindPobTargetObjectRoomsToCells->second.second.first.second) + position.y = iterFindPobTargetObjectRoomsToCells->second.second.first.second; + + // x and z are saved as offset from the "center" + position.x += iterFindPobTargetObjectRoomsToCells->second.second.second.first; + position.z += iterFindPobTargetObjectRoomsToCells->second.second.second.second; + + // item is not currently in the target room, need to move it + if (itemObjContainingCell->getNetworkId() != iterFindPobTargetObjectRoomsToCells->second.first->getNetworkId()) + { + ++numItemsToBeMoved; + restoreDecorationLayoutList.push_back(std::make_pair(std::make_pair(CachedNetworkId(*itemObj), CachedNetworkId(*iterFindPobTargetObjectRoomsToCells->second.first)), std::make_pair(position, orientation))); + continue; + } + + // if the item is not currently at the desired position, need to move it + Transform const & itemCurrentTransform = itemObj->getTransform_o2p(); + currentPosition = itemCurrentTransform.getPosition_p(); + if (currentPosition.magnitudeBetweenSquared(position) > 0.0025) // not within 0.05m + { + ++numItemsToBeMoved; + restoreDecorationLayoutList.push_back(std::make_pair(std::make_pair(CachedNetworkId(*itemObj), CachedNetworkId(*iterFindPobTargetObjectRoomsToCells->second.first)), std::make_pair(position, orientation))); + continue; + } + + // if the item is not currently at the desired orientation, need to move it + Quaternion const currentOrientation(itemCurrentTransform); + if (!WithinEpsilonInclusive(currentOrientation.w, orientation.w, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.x, orientation.x, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.y, orientation.y, 0.01f) || + !WithinEpsilonInclusive(currentOrientation.z, orientation.z, 0.01f)) + { + ++numItemsToBeMoved; + restoreDecorationLayoutList.push_back(std::make_pair(std::make_pair(CachedNetworkId(*itemObj), CachedNetworkId(*iterFindPobTargetObjectRoomsToCells->second.first)), std::make_pair(position, orientation))); + continue; + } + } + + ++objvarValueIndex; + snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.%d", saveSlotNumber, objvarValueIndex); + } + + snprintf(buffer, sizeof(buffer)-1, "savedDecoration%d.description", saveSlotNumber); + std::string saveSlotDescription; + IGNORE_RETURN(objVars.getItem(buffer, saveSlotDescription)); + if (restoreDecorationLayoutList.empty()) + { + if (saveSlotDescription.empty()) + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("No items in the structure or POB ship could be (or need to be) moved/restored using the saved decoration layout in slot %d.", saveSlotNumber)), Unicode::emptyString); + else + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("No items in the structure or POB ship could be (or need to be) moved/restored using the saved decoration layout in slot %d (%s).", saveSlotNumber, saveSlotDescription.c_str())), Unicode::emptyString); + } + else + { + if (saveSlotDescription.empty()) + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("Please remain in the structure or POB ship while the system attempts to move/restore %d items using the saved decoration layout in slot %d. You will be notified when the operation is complete.", numItemsToBeMoved, saveSlotNumber)), Unicode::emptyString); + else + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<1024>().sprintf("Please remain in the structure or POB ship while the system attempts to move/restore %d items using the saved decoration layout in slot %d (%s). You will be notified when the operation is complete.", numItemsToBeMoved, saveSlotNumber, saveSlotDescription.c_str())), Unicode::emptyString); + + // start messageTo loop to do the decoration layout restore, + // spread out over a period of time so it doesn't lag out the server + int restoreDecorationOperationId = ::rand(); + while (restoreDecorationOperationId == 0) + restoreDecorationOperationId = ::rand(); + + playerObj->setRestoreDecorationOperationId(restoreDecorationOperationId); + playerObj->setRestoreDecorationPobId(containingPOB->getNetworkId()); + playerObj->setRestoreDecorationTotalCount(numItemsToBeMoved); + playerObj->setRestoreDecorationAttemptedCount(0); + playerObj->setRestoreDecorationSuccessCount(0); + + IGNORE_RETURN(setObjVarItem("restoreDecorationOperation.timeout", timeNow + (5 * 60))); + IGNORE_RETURN(setObjVarItem("restoreDecorationOperation.operationId", restoreDecorationOperationId)); + + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++RestoreDecorationLayout", + "", + 0, + false); + } + + if ((debugNumItems > 0) && getClient()->isGod()) + { + const unsigned long debugEndTimeMs = Clock::timeMs(); + Chat::sendSystemMessage(*this, Unicode::narrowToWide(FormattedString<256>().sprintf("!!!GOD MODE STATISTICS!!! %d items read (%d will be moved) in %lums", debugNumItems, numItemsToBeMoved, (debugEndTimeMs - debugStartTimeMs))), Unicode::emptyString); + } +} + +// ====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/object/DraftSchematicObject.cpp b/src/engine/server/library/serverGame/src/shared/object/DraftSchematicObject.cpp index a4f59a54e..feba149fc 100644 --- a/src/engine/server/library/serverGame/src/shared/object/DraftSchematicObject.cpp +++ b/src/engine/server/library/serverGame/src/shared/object/DraftSchematicObject.cpp @@ -1,566 +1,566 @@ -//======================================================================== -// -// DraftSchematicObject.cpp -// -// copyright 2001 Sony Online Entertainment -// -//======================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/DraftSchematicObject.h" - -#include "UnicodeUtils.h" -#include "serverGame/ManufactureSchematicObject.h" -#include "serverGame/ObjectIdManager.h" -#include "serverGame/ServerController.h" -#include "serverGame/ServerManufactureSchematicObjectTemplate.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptParameters.h" -#include "sharedFile/TreeFile.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/Crc.h" -#include "sharedGame/SharedObjectTemplate.h" -#include "sharedNetworkMessages/MessageQueueResourceWeights.h" -#include "sharedObject/NetworkController.h" -#include "sharedObject/ObjectTemplateList.h" - -// ====================================================================== -// local constants - - -static const int MAX_ATTRIBUTES = 32; -static const std::string REQUEST_RESOURCE_WEIGHTS_SCRIPT_METHOD("OnRequestResourceWeights"); - - -// ====================================================================== -// static members - -DraftSchematicObject::SchematicMap * DraftSchematicObject::m_schematics = NULL; -const SharedObjectTemplate * DraftSchematicObject::m_defaultSharedTemplate = NULL; - - -// ====================================================================== - -/** - * Class constructor. - * - * @param newTemplate template to create the schematic from. - */ -DraftSchematicObject::DraftSchematicObject( - const ServerDraftSchematicObjectTemplate* newTemplate) : - IntangibleObject(newTemplate), - m_slots(), - m_attributes(), - m_experimentalAttributes(), - m_combinedCrc(newTemplate->getCrcName().getCrc(), getSharedTemplate()->getCrcName().getCrc()) -{ -int i; -ServerDraftSchematicObjectTemplate::IngredientSlot slot; - - // put the slots in the name lookup map - int count = newTemplate->getSlotsCount(); - for (i = 0; i < count; ++i) - { - newTemplate->getSlots(slot, i); - m_slots.insert(std::make_pair(slot.name, i)); - } - - // get the experimental attributes from the attributes, and create a map - // between them - int minValue = 0, maxValue = 0; - count = getAttribsCount(); - for (i = 0; i < count; ++i) - { - const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = - getAttrib(i); - - m_attributes[attrib.name] = i; - if (!attrib.experiment.getTable().empty() && !attrib.experiment.getText().empty()) - { - getAttribMinMax(i, minValue, maxValue); - if (minValue != maxValue) - m_experimentalAttributes[attrib.experiment].push_back(attrib.name); - } - } -} // DraftSchematicObject::DraftSchematicObject - -//----------------------------------------------------------------------- - -/** - * Class destructor. - */ -DraftSchematicObject::~DraftSchematicObject() -{ -} // DraftSchematicObject::~DraftSchematicObject - -//----------------------------------------------------------------------- - -/** - * Returns a shared template if none was given for this object. - * - * @return the shared template - */ -const SharedObjectTemplate * DraftSchematicObject::getDefaultSharedTemplate(void) const -{ -static const ConstCharCrcLowerString templateName("object/draft_schematic/base/shared_draft_schematic_default.iff"); - - if (m_defaultSharedTemplate == NULL) - { - m_defaultSharedTemplate = safe_cast( - ObjectTemplateList::fetch(templateName)); - WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create " - "default shared object template %s", templateName.getString())); - if (m_defaultSharedTemplate != NULL) - ExitChain::add (removeDefaultTemplate, "DraftSchematicObject::removeDefaultTemplate"); - } - return m_defaultSharedTemplate; -} // DraftSchematicObject::getDefaultSharedTemplate - -//----------------------------------------------------------------------- - -/** - * Cleans up the default shared template. - */ -void DraftSchematicObject::removeDefaultTemplate(void) -{ - if (m_defaultSharedTemplate != NULL) - { - m_defaultSharedTemplate->releaseReference(); - m_defaultSharedTemplate = NULL; - } -} // DraftSchematicObject::removeDefaultTemplate - -//----------------------------------------------------------------------- - -/** - * Requests info about resource weights for a given draft schematic. - * - * @param requester the player making the request - * @param draftSchematicName the schematic the player wants to know about - */ -void DraftSchematicObject::requestResourceWeights(ServerObject & requester, uint32 draftSchematicCrc) -{ - if (requester.getClient() == NULL) - { - WARNING (true, ("DraftSchematicObject::requestResourceWeights invalid client for [%s]", requester.getNetworkId ().getValueString ().c_str ())); - return; - } - - const DraftSchematicObject * const schematic = getSchematic(draftSchematicCrc); - if (schematic == NULL) - { - WARNING (true, ("DraftSchematicObject::requestResourceWeights invalid schematic [%lu] for [%s]", draftSchematicCrc, requester.getNetworkId ().getValueString ().c_str ())); - return; - } - - const ServerDraftSchematicObjectTemplate * const schematicTemplate = safe_cast(schematic->getObjectTemplate()); - if (schematicTemplate == NULL) - { - WARNING (true, ("DraftSchematicObject::requestResourceWeights invalid schematic template [%lu] for [%s]", draftSchematicCrc, requester.getNetworkId ().getValueString ().c_str ())); - return; - } - - std::vector desiredAttribs; - { - for (NameToIndexMap::const_iterator i = schematic->m_attributes.begin(); i != schematic->m_attributes.end(); ++i) - desiredAttribs.push_back((*i).first.getText().c_str()); - } - - std::vector attributes(MAX_ATTRIBUTES * 2, static_cast(NULL)); - std::vector slots(MAX_ATTRIBUTES * 2, 0); - std::vector counts(MAX_ATTRIBUTES * 2, 0); - std::vector weights(MAX_ATTRIBUTES * 2 * Crafting::RA_numResourceAttributes * 2, 0); - ScriptParams params; - params.addParam(requester.getNetworkId()); - params.addParam(desiredAttribs); - params.addParam(attributes); - params.addParam(slots); - params.addParam(counts); - params.addParam(weights); - - // call script function - GameScriptObject::runOneScript(schematicTemplate->getManufactureScripts(0), REQUEST_RESOURCE_WEIGHTS_SCRIPT_METHOD, "Os[s*[i*[i*[i*[", params); - - const std::vector & newAttributes = params.getStringArrayParam(2); - const std::vector & newSlots = params.getIntArrayParam(3); - const std::vector & newCounts = params.getIntArrayParam(4); - const std::vector & newWeights = params.getIntArrayParam(5); - std::vector::const_iterator slotIter(newSlots.begin()); - std::vector::const_iterator countIter(newCounts.begin()); - std::vector::const_iterator weightIter(newWeights.begin()); - - MessageQueueResourceWeights * const message = new MessageQueueResourceWeights(schematic->getCombinedCrc()); - - // find out how many attributes were returned - int attribCount = 0; - { - for (std::vector::const_iterator i(newAttributes.begin()); - i != newAttributes.end(); ++i, ++attribCount) - { - if (*i == NULL) - break; - } - } - attribCount /= 2; - - for (int i = 0; i < 2; ++i) - { - for (int j = 0; j < attribCount; ++j) - { - const StringId sid("crafting", newAttributes[j + i * attribCount]);; - const int attrib = schematic->getAttribIndex(sid); - if (attrib == -1) - { - // skip over the data for that attrib - slotIter++; - const int weightCount = *countIter++; - weightIter += weightCount * 2; - continue; - } - const int slot = *slotIter++; - const int weightCount = *countIter++; - for (int k = 0; k < weightCount; ++k) - { - const int resource = *weightIter++; - const int weight = *weightIter++; - if (i == 0) - { - message->addAssemblyWeight(attrib, slot, resource, weight); - } - else - { - message->addResourceMaxWeight(attrib, slot, resource, weight); - } - } - } - } - - (safe_cast(requester.getController()))->appendMessage( - static_cast(CM_resourceWeights), 0.0f, message, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); -} // DraftSchematicObject::requestResourceWeights - -//----------------------------------------------------------------------- - -/** - * Creates a manufacture schematic based on this schematic. - * - * @param creator the player creating the schematic - * - * @return the manufacture schematic - */ -ManufactureSchematicObject * DraftSchematicObject::createManufactureSchematic( - const CachedNetworkId & creator) const -{ - Object * object = ServerManufactureSchematicObjectTemplate::createObject( - "object/manufacture_schematic/generic_schematic.iff", *this); - if (object == NULL) - return NULL; - ManufactureSchematicObject * schematic = safe_cast(object); - schematic->init(*this, creator); - schematic->setNetworkId(ObjectIdManager::getInstance().getNewObjectId()); - - return schematic; -} // DraftSchematicObject::createManufactureSchematic - -//----------------------------------------------------------------------- - -/** - * Gets a draft scrematic slot by name. - * - * @param slot slot info to be filled - * @param name name of the slot to get - * - * @return true on success, false if the slot wasn't found - */ -bool DraftSchematicObject::getSlot( - ServerDraftSchematicObjectTemplate::IngredientSlot & slot, int index) const -{ - if (index < 0 || index >= static_cast((safe_cast< - const ServerDraftSchematicObjectTemplate*>( - getObjectTemplate()))->getSlotsCount())) - { - return false; - } - - slot.options.clear(); - (safe_cast(getObjectTemplate()))->getSlots(slot, index); - return true; -} - -//----------------------------------------------------------------------- - -/** - * Gets a draft scrematic slot by name. - * - * @param slot slot info to be filled - * @param name name of the slot to get - * - * @return true on success, false if the slot wasn't found - */ -bool DraftSchematicObject::getSlot( - ServerDraftSchematicObjectTemplate::IngredientSlot & slot, const StringId & name) const -{ - NameToIndexMap::const_iterator iter = m_slots.find(name); - if (iter != m_slots.end()) - return getSlot(slot, (*iter).second); - return false; -} // DraftSchematicObject::getSlot(const StringId &) - -//----------------------------------------------------------------------- - -/** - * Gets the min and max values for an attribute of the schematic. - * - * @param index index of the object attribute - * @param minValue value that will be filled in with the min attribute value - * @param maxValue value that will be filled in with the max attribute value - * - * @return true on success, false if the name is not a valid attribute - */ -bool DraftSchematicObject::getAttribMinMax(int index, int & minValue, - int & maxValue) const -{ - const SharedDraftSchematicObjectTemplate::SchematicAttribute & minAttrib = - getAttribMin(index); - minValue = minAttrib.value; - const SharedDraftSchematicObjectTemplate::SchematicAttribute & maxAttrib = - getAttribMax(index); - - minValue = minAttrib.value; - maxValue = maxAttrib.value; - return true; -} // DraftSchematicObject::getAttribMinMax(int) - -//----------------------------------------------------------------------- - -/** - * Gets the min and max values for an attribute of the schematic. - * - * @param name the attribute name - * @param minValue value that will be filled in with the min attribute value - * @param maxValue value that will be filled in with the max attribute value - * - * @return true on success, false if the name is not a valid attribute - */ -bool DraftSchematicObject::getAttribMinMax(const StringId & name, int & minValue, - int & maxValue) const -{ - NameToIndexMap::const_iterator iter = m_attributes.find(name); - if (iter == m_slots.end()) - return false; - - int index = (*iter).second; - return getAttribMinMax(index, minValue, maxValue); -} // DraftSchematicObject::getAttribMinMax(const StringId &) - -//----------------------------------------------------------------------- - -/** - * Returns the name of a experimental attribute associated with an object attribute. - * - * @param index index of the object attribute - * - * @return the experimental attribute name - */ -const StringId DraftSchematicObject::getExperimentalAttributeFromAttribute( - int index) const -{ -static const StringId NO_EXPERIMENTATION; - - const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = - getAttrib(index); - if (attrib.experiment == NO_EXPERIMENTATION) - return NO_EXPERIMENTATION; - - // make sure we can really experiment with the attribute - int minValue, maxValue; - if (!getAttribMinMax(index, minValue, maxValue)) - return NO_EXPERIMENTATION; - - if (minValue == maxValue) - { - WARNING(true, ("Draft schematic %s has attribute %s with experimental " - "attribute %s even though the attribute min/max values are the " - "same! Not allowing experimentation.", getObjectTemplateName(), - attrib.name.getCanonicalRepresentation().c_str(), - attrib.experiment.getCanonicalRepresentation().c_str())); - return NO_EXPERIMENTATION; - } - - return attrib.experiment; -} // DraftSchematicObject::getExperimentalAttributeFromAttribute - -//----------------------------------------------------------------------- - -/** - * Returns the name of a experimental attribute associated with an object attribute. - * - * @param attribName the object attribute name - * - * @return the experimental attribute name - */ -const StringId DraftSchematicObject::getExperimentalAttributeFromAttribute( - const StringId & attribName) const -{ -static const StringId NO_EXPERIMENTATION; - - const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = - getAttrib(attribName); - - if (attrib.experiment == NO_EXPERIMENTATION) - return NO_EXPERIMENTATION; - - // make sure we can really experiment with the attribute - int minValue, maxValue; - if (!getAttribMinMax(attribName, minValue, maxValue)) - return NO_EXPERIMENTATION; - - if (minValue == maxValue) - { - WARNING(true, ("Draft schematic %s has attribute %s with experimental " - "attribute %s even though the attribute min/max values are the " - "same! Not allowing experimentation.", getObjectTemplateName(), - attrib.name.getCanonicalRepresentation().c_str(), - attrib.experiment.getCanonicalRepresentation().c_str())); - return NO_EXPERIMENTATION; - } - - return attrib.experiment; -} // DraftSchematicObject::getExperimentalAttributeFromAttribute - -//----------------------------------------------------------------------- - -/** - * Returns the names of object attributes associated with an experimental attribute. - * - * @param attribName the experimental attribute name - * - * @return the object attribute name list - */ -const std::vector & DraftSchematicObject::getFromAttributeFromExperimentalAttribute( - const StringId & experimentAttribName) const -{ - return (*m_experimentalAttributes.find(experimentAttribName)).second; -} // DraftSchematicObject::getFromAttributeFromExperimentalAttribute - - -// ====================================================================== -// factory methods - -/** - * Returns a draft schematic with a given name. If the schematic isn't loaded, - * loads it. - * - * @param name name of the schematic to load - * - * @return the draft schematic - */ -const DraftSchematicObject * DraftSchematicObject::getSchematic( - const std::string & name) -{ - NOT_NULL(m_schematics); - return getSchematic(Crc::calculate(name.c_str())); -} // DraftSchematicObject::getSchematic(const std::string &) - -//----------------------------------------------------------------------- - -/** - * Returns a draft schematic with a given name. If the schematic isn't loaded, - * loads it. - * - * @param crc crc of name of the schematic to load - * - * @return the draft schematic - */ -const DraftSchematicObject * DraftSchematicObject::getSchematic(uint32 crc) -{ - NOT_NULL(m_schematics); - if (m_schematics == NULL || crc == 0) - return NULL; - - // see if the schematic is already loaded - SchematicMap::iterator result = m_schematics->find(crc); - if (result != m_schematics->end()) - return (*result).second; - - // get the template name from the crc - const ConstCharCrcString & name = ObjectTemplateList::lookUp(crc); - if (name.isEmpty()) - { - WARNING(true, ("Unable to find template name for crc %u", crc)); - return NULL; - } - - // create a new schematic - if (!TreeFile::exists(name.getString())) - { - WARNING(true, ("Draft schematic template %s file not found", name.getString())); - return NULL; - } - - const ObjectTemplate * objTemplate = ObjectTemplateList::fetch(name); - if (objTemplate == NULL) - { - WARNING(true, ("Can't create object template %s", name.getString())); - return NULL; - } - - const ServerDraftSchematicObjectTemplate * schematicTemplate = - dynamic_cast(objTemplate); - if (schematicTemplate == NULL) - { - WARNING(true, ("Template %s is not a draft schematic", name.getString())); - objTemplate->releaseReference(); - return NULL; - } - - const DraftSchematicObject * schematic = new DraftSchematicObject(schematicTemplate); - objTemplate->releaseReference(); - - m_schematics->insert(std::make_pair(crc, schematic)); - return schematic; -} // DraftSchematicObject::getSchematic(uint32) - -//----------------------------------------------------------------------- - -/** - * Sets up the draft schematic factory. - */ -void DraftSchematicObject::install() -{ - if (m_schematics == NULL) - m_schematics = new SchematicMap(); -} // DraftSchematicObject::install - -//----------------------------------------------------------------------- - -/** - * Cleans up the draft schematic factory - */ -void DraftSchematicObject::remove() -{ - if (m_schematics != NULL) - { - SchematicMap::iterator iter; - for (iter = m_schematics->begin(); iter != m_schematics->end(); ++iter) - { - delete (*iter).second; - (*iter).second = NULL; - } - delete m_schematics; - m_schematics = NULL; - } -} // DraftSchematicObject::remove - -// ---------------------------------------------------------------------- - -void DraftSchematicObject::getAttributes(stdvector >::fwd &data) const -{ - IntangibleObject::getAttributes(data); -} - -// ====================================================================== +//======================================================================== +// +// DraftSchematicObject.cpp +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/DraftSchematicObject.h" + +#include "UnicodeUtils.h" +#include "serverGame/ManufactureSchematicObject.h" +#include "serverGame/ObjectIdManager.h" +#include "serverGame/ServerController.h" +#include "serverGame/ServerManufactureSchematicObjectTemplate.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptParameters.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/Crc.h" +#include "sharedGame/SharedObjectTemplate.h" +#include "sharedNetworkMessages/MessageQueueResourceWeights.h" +#include "sharedObject/NetworkController.h" +#include "sharedObject/ObjectTemplateList.h" + +// ====================================================================== +// local constants + + +static const int MAX_ATTRIBUTES = 32; +static const std::string REQUEST_RESOURCE_WEIGHTS_SCRIPT_METHOD("OnRequestResourceWeights"); + + +// ====================================================================== +// static members + +DraftSchematicObject::SchematicMap * DraftSchematicObject::m_schematics = NULL; +const SharedObjectTemplate * DraftSchematicObject::m_defaultSharedTemplate = NULL; + + +// ====================================================================== + +/** + * Class constructor. + * + * @param newTemplate template to create the schematic from. + */ +DraftSchematicObject::DraftSchematicObject( + const ServerDraftSchematicObjectTemplate* newTemplate) : + IntangibleObject(newTemplate), + m_slots(), + m_attributes(), + m_experimentalAttributes(), + m_combinedCrc(newTemplate->getCrcName().getCrc(), getSharedTemplate()->getCrcName().getCrc()) +{ +int i; +ServerDraftSchematicObjectTemplate::IngredientSlot slot; + + // put the slots in the name lookup map + int count = newTemplate->getSlotsCount(); + for (i = 0; i < count; ++i) + { + newTemplate->getSlots(slot, i); + m_slots.insert(std::make_pair(slot.name, i)); + } + + // get the experimental attributes from the attributes, and create a map + // between them + int minValue = 0, maxValue = 0; + count = getAttribsCount(); + for (i = 0; i < count; ++i) + { + const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = + getAttrib(i); + + m_attributes[attrib.name] = i; + if (!attrib.experiment.getTable().empty() && !attrib.experiment.getText().empty()) + { + getAttribMinMax(i, minValue, maxValue); + if (minValue != maxValue) + m_experimentalAttributes[attrib.experiment].push_back(attrib.name); + } + } +} // DraftSchematicObject::DraftSchematicObject + +//----------------------------------------------------------------------- + +/** + * Class destructor. + */ +DraftSchematicObject::~DraftSchematicObject() +{ +} // DraftSchematicObject::~DraftSchematicObject + +//----------------------------------------------------------------------- + +/** + * Returns a shared template if none was given for this object. + * + * @return the shared template + */ +const SharedObjectTemplate * DraftSchematicObject::getDefaultSharedTemplate(void) const +{ +static const ConstCharCrcLowerString templateName("object/draft_schematic/base/shared_draft_schematic_default.iff"); + + if (m_defaultSharedTemplate == NULL) + { + m_defaultSharedTemplate = safe_cast( + ObjectTemplateList::fetch(templateName)); + WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create " + "default shared object template %s", templateName.getString())); + if (m_defaultSharedTemplate != NULL) + ExitChain::add (removeDefaultTemplate, "DraftSchematicObject::removeDefaultTemplate"); + } + return m_defaultSharedTemplate; +} // DraftSchematicObject::getDefaultSharedTemplate + +//----------------------------------------------------------------------- + +/** + * Cleans up the default shared template. + */ +void DraftSchematicObject::removeDefaultTemplate(void) +{ + if (m_defaultSharedTemplate != NULL) + { + m_defaultSharedTemplate->releaseReference(); + m_defaultSharedTemplate = NULL; + } +} // DraftSchematicObject::removeDefaultTemplate + +//----------------------------------------------------------------------- + +/** + * Requests info about resource weights for a given draft schematic. + * + * @param requester the player making the request + * @param draftSchematicName the schematic the player wants to know about + */ +void DraftSchematicObject::requestResourceWeights(ServerObject & requester, uint32 draftSchematicCrc) +{ + if (requester.getClient() == NULL) + { + WARNING (true, ("DraftSchematicObject::requestResourceWeights invalid client for [%s]", requester.getNetworkId ().getValueString ().c_str ())); + return; + } + + const DraftSchematicObject * const schematic = getSchematic(draftSchematicCrc); + if (schematic == NULL) + { + WARNING (true, ("DraftSchematicObject::requestResourceWeights invalid schematic [%lu] for [%s]", draftSchematicCrc, requester.getNetworkId ().getValueString ().c_str ())); + return; + } + + const ServerDraftSchematicObjectTemplate * const schematicTemplate = safe_cast(schematic->getObjectTemplate()); + if (schematicTemplate == NULL) + { + WARNING (true, ("DraftSchematicObject::requestResourceWeights invalid schematic template [%lu] for [%s]", draftSchematicCrc, requester.getNetworkId ().getValueString ().c_str ())); + return; + } + + std::vector desiredAttribs; + { + for (NameToIndexMap::const_iterator i = schematic->m_attributes.begin(); i != schematic->m_attributes.end(); ++i) + desiredAttribs.push_back((*i).first.getText().c_str()); + } + + std::vector attributes(MAX_ATTRIBUTES * 2, static_cast(NULL)); + std::vector slots(MAX_ATTRIBUTES * 2, 0); + std::vector counts(MAX_ATTRIBUTES * 2, 0); + std::vector weights(MAX_ATTRIBUTES * 2 * Crafting::RA_numResourceAttributes * 2, 0); + ScriptParams params; + params.addParam(requester.getNetworkId()); + params.addParam(desiredAttribs); + params.addParam(attributes); + params.addParam(slots); + params.addParam(counts); + params.addParam(weights); + + // call script function + GameScriptObject::runOneScript(schematicTemplate->getManufactureScripts(0), REQUEST_RESOURCE_WEIGHTS_SCRIPT_METHOD, "Os[s*[i*[i*[i*[", params); + + const std::vector & newAttributes = params.getStringArrayParam(2); + const std::vector & newSlots = params.getIntArrayParam(3); + const std::vector & newCounts = params.getIntArrayParam(4); + const std::vector & newWeights = params.getIntArrayParam(5); + std::vector::const_iterator slotIter(newSlots.begin()); + std::vector::const_iterator countIter(newCounts.begin()); + std::vector::const_iterator weightIter(newWeights.begin()); + + MessageQueueResourceWeights * const message = new MessageQueueResourceWeights(schematic->getCombinedCrc()); + + // find out how many attributes were returned + int attribCount = 0; + { + for (std::vector::const_iterator i(newAttributes.begin()); + i != newAttributes.end(); ++i, ++attribCount) + { + if (*i == NULL) + break; + } + } + attribCount /= 2; + + for (int i = 0; i < 2; ++i) + { + for (int j = 0; j < attribCount; ++j) + { + const StringId sid("crafting", newAttributes[j + i * attribCount]);; + const int attrib = schematic->getAttribIndex(sid); + if (attrib == -1) + { + // skip over the data for that attrib + slotIter++; + const int weightCount = *countIter++; + weightIter += weightCount * 2; + continue; + } + const int slot = *slotIter++; + const int weightCount = *countIter++; + for (int k = 0; k < weightCount; ++k) + { + const int resource = *weightIter++; + const int weight = *weightIter++; + if (i == 0) + { + message->addAssemblyWeight(attrib, slot, resource, weight); + } + else + { + message->addResourceMaxWeight(attrib, slot, resource, weight); + } + } + } + } + + (safe_cast(requester.getController()))->appendMessage( + static_cast(CM_resourceWeights), 0.0f, message, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); +} // DraftSchematicObject::requestResourceWeights + +//----------------------------------------------------------------------- + +/** + * Creates a manufacture schematic based on this schematic. + * + * @param creator the player creating the schematic + * + * @return the manufacture schematic + */ +ManufactureSchematicObject * DraftSchematicObject::createManufactureSchematic( + const CachedNetworkId & creator) const +{ + Object * object = ServerManufactureSchematicObjectTemplate::createObject( + "object/manufacture_schematic/generic_schematic.iff", *this); + if (object == NULL) + return NULL; + ManufactureSchematicObject * schematic = safe_cast(object); + schematic->init(*this, creator); + schematic->setNetworkId(ObjectIdManager::getInstance().getNewObjectId()); + + return schematic; +} // DraftSchematicObject::createManufactureSchematic + +//----------------------------------------------------------------------- + +/** + * Gets a draft scrematic slot by name. + * + * @param slot slot info to be filled + * @param name name of the slot to get + * + * @return true on success, false if the slot wasn't found + */ +bool DraftSchematicObject::getSlot( + ServerDraftSchematicObjectTemplate::IngredientSlot & slot, int index) const +{ + if (index < 0 || index >= static_cast((safe_cast< + const ServerDraftSchematicObjectTemplate*>( + getObjectTemplate()))->getSlotsCount())) + { + return false; + } + + slot.options.clear(); + (safe_cast(getObjectTemplate()))->getSlots(slot, index); + return true; +} + +//----------------------------------------------------------------------- + +/** + * Gets a draft scrematic slot by name. + * + * @param slot slot info to be filled + * @param name name of the slot to get + * + * @return true on success, false if the slot wasn't found + */ +bool DraftSchematicObject::getSlot( + ServerDraftSchematicObjectTemplate::IngredientSlot & slot, const StringId & name) const +{ + NameToIndexMap::const_iterator iter = m_slots.find(name); + if (iter != m_slots.end()) + return getSlot(slot, (*iter).second); + return false; +} // DraftSchematicObject::getSlot(const StringId &) + +//----------------------------------------------------------------------- + +/** + * Gets the min and max values for an attribute of the schematic. + * + * @param index index of the object attribute + * @param minValue value that will be filled in with the min attribute value + * @param maxValue value that will be filled in with the max attribute value + * + * @return true on success, false if the name is not a valid attribute + */ +bool DraftSchematicObject::getAttribMinMax(int index, int & minValue, + int & maxValue) const +{ + const SharedDraftSchematicObjectTemplate::SchematicAttribute & minAttrib = + getAttribMin(index); + minValue = minAttrib.value; + const SharedDraftSchematicObjectTemplate::SchematicAttribute & maxAttrib = + getAttribMax(index); + + minValue = minAttrib.value; + maxValue = maxAttrib.value; + return true; +} // DraftSchematicObject::getAttribMinMax(int) + +//----------------------------------------------------------------------- + +/** + * Gets the min and max values for an attribute of the schematic. + * + * @param name the attribute name + * @param minValue value that will be filled in with the min attribute value + * @param maxValue value that will be filled in with the max attribute value + * + * @return true on success, false if the name is not a valid attribute + */ +bool DraftSchematicObject::getAttribMinMax(const StringId & name, int & minValue, + int & maxValue) const +{ + NameToIndexMap::const_iterator iter = m_attributes.find(name); + if (iter == m_slots.end()) + return false; + + int index = (*iter).second; + return getAttribMinMax(index, minValue, maxValue); +} // DraftSchematicObject::getAttribMinMax(const StringId &) + +//----------------------------------------------------------------------- + +/** + * Returns the name of a experimental attribute associated with an object attribute. + * + * @param index index of the object attribute + * + * @return the experimental attribute name + */ +const StringId DraftSchematicObject::getExperimentalAttributeFromAttribute( + int index) const +{ +static const StringId NO_EXPERIMENTATION; + + const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = + getAttrib(index); + if (attrib.experiment == NO_EXPERIMENTATION) + return NO_EXPERIMENTATION; + + // make sure we can really experiment with the attribute + int minValue, maxValue; + if (!getAttribMinMax(index, minValue, maxValue)) + return NO_EXPERIMENTATION; + + if (minValue == maxValue) + { + WARNING(true, ("Draft schematic %s has attribute %s with experimental " + "attribute %s even though the attribute min/max values are the " + "same! Not allowing experimentation.", getObjectTemplateName(), + attrib.name.getCanonicalRepresentation().c_str(), + attrib.experiment.getCanonicalRepresentation().c_str())); + return NO_EXPERIMENTATION; + } + + return attrib.experiment; +} // DraftSchematicObject::getExperimentalAttributeFromAttribute + +//----------------------------------------------------------------------- + +/** + * Returns the name of a experimental attribute associated with an object attribute. + * + * @param attribName the object attribute name + * + * @return the experimental attribute name + */ +const StringId DraftSchematicObject::getExperimentalAttributeFromAttribute( + const StringId & attribName) const +{ +static const StringId NO_EXPERIMENTATION; + + const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = + getAttrib(attribName); + + if (attrib.experiment == NO_EXPERIMENTATION) + return NO_EXPERIMENTATION; + + // make sure we can really experiment with the attribute + int minValue, maxValue; + if (!getAttribMinMax(attribName, minValue, maxValue)) + return NO_EXPERIMENTATION; + + if (minValue == maxValue) + { + WARNING(true, ("Draft schematic %s has attribute %s with experimental " + "attribute %s even though the attribute min/max values are the " + "same! Not allowing experimentation.", getObjectTemplateName(), + attrib.name.getCanonicalRepresentation().c_str(), + attrib.experiment.getCanonicalRepresentation().c_str())); + return NO_EXPERIMENTATION; + } + + return attrib.experiment; +} // DraftSchematicObject::getExperimentalAttributeFromAttribute + +//----------------------------------------------------------------------- + +/** + * Returns the names of object attributes associated with an experimental attribute. + * + * @param attribName the experimental attribute name + * + * @return the object attribute name list + */ +const std::vector & DraftSchematicObject::getFromAttributeFromExperimentalAttribute( + const StringId & experimentAttribName) const +{ + return (*m_experimentalAttributes.find(experimentAttribName)).second; +} // DraftSchematicObject::getFromAttributeFromExperimentalAttribute + + +// ====================================================================== +// factory methods + +/** + * Returns a draft schematic with a given name. If the schematic isn't loaded, + * loads it. + * + * @param name name of the schematic to load + * + * @return the draft schematic + */ +const DraftSchematicObject * DraftSchematicObject::getSchematic( + const std::string & name) +{ + NOT_NULL(m_schematics); + return getSchematic(Crc::calculate(name.c_str())); +} // DraftSchematicObject::getSchematic(const std::string &) + +//----------------------------------------------------------------------- + +/** + * Returns a draft schematic with a given name. If the schematic isn't loaded, + * loads it. + * + * @param crc crc of name of the schematic to load + * + * @return the draft schematic + */ +const DraftSchematicObject * DraftSchematicObject::getSchematic(uint32 crc) +{ + NOT_NULL(m_schematics); + if (m_schematics == NULL || crc == 0) + return NULL; + + // see if the schematic is already loaded + SchematicMap::iterator result = m_schematics->find(crc); + if (result != m_schematics->end()) + return (*result).second; + + // get the template name from the crc + const ConstCharCrcString & name = ObjectTemplateList::lookUp(crc); + if (name.isEmpty()) + { + WARNING(true, ("Unable to find template name for crc %u", crc)); + return NULL; + } + + // create a new schematic + if (!TreeFile::exists(name.getString())) + { + WARNING(true, ("Draft schematic template %s file not found", name.getString())); + return NULL; + } + + const ObjectTemplate * objTemplate = ObjectTemplateList::fetch(name); + if (objTemplate == NULL) + { + WARNING(true, ("Can't create object template %s", name.getString())); + return NULL; + } + + const ServerDraftSchematicObjectTemplate * schematicTemplate = + dynamic_cast(objTemplate); + if (schematicTemplate == NULL) + { + WARNING(true, ("Template %s is not a draft schematic", name.getString())); + objTemplate->releaseReference(); + return NULL; + } + + const DraftSchematicObject * schematic = new DraftSchematicObject(schematicTemplate); + objTemplate->releaseReference(); + + m_schematics->insert(std::make_pair(crc, schematic)); + return schematic; +} // DraftSchematicObject::getSchematic(uint32) + +//----------------------------------------------------------------------- + +/** + * Sets up the draft schematic factory. + */ +void DraftSchematicObject::install() +{ + if (m_schematics == NULL) + m_schematics = new SchematicMap(); +} // DraftSchematicObject::install + +//----------------------------------------------------------------------- + +/** + * Cleans up the draft schematic factory + */ +void DraftSchematicObject::remove() +{ + if (m_schematics != NULL) + { + SchematicMap::iterator iter; + for (iter = m_schematics->begin(); iter != m_schematics->end(); ++iter) + { + delete (*iter).second; + (*iter).second = NULL; + } + delete m_schematics; + m_schematics = NULL; + } +} // DraftSchematicObject::remove + +// ---------------------------------------------------------------------- + +void DraftSchematicObject::getAttributes(stdvector >::fwd &data) const +{ + IntangibleObject::getAttributes(data); +} + +// ====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.cpp b/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.cpp index 0f21840a4..6d7b57c48 100644 --- a/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.cpp +++ b/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.cpp @@ -404,7 +404,7 @@ void IntangibleObject::onPermanentlyDestroyed() * Persists this object in the database. Will also persist all the objects it * is keeping track of. */ -void IntangibleObject::persist() +bool IntangibleObject::persist() { if (isAuthoritative() && isTheater()) { @@ -412,11 +412,11 @@ void IntangibleObject::persist() { // we are not finished creating our objects, prevent persistance WARNING(true, ("IntangibleObject::persist called before all objects created")); - return; + return false; } if (isPersisted()) - return; + return true; ServerObject::persist(); @@ -470,9 +470,15 @@ void IntangibleObject::persist() } } + return true; + } - else + else { ServerObject::persist(); + return true; + } + + return false; } // IntangibleObject::persist //------------------------------------------------------------------------------------------ diff --git a/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.h b/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.h index 1d5a0b854..fc2d4cd42 100644 --- a/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.h +++ b/src/engine/server/library/serverGame/src/shared/object/IntangibleObject.h @@ -44,7 +44,7 @@ public: virtual float alter(float time); virtual void onPermanentlyDestroyed(); - virtual void persist(); + virtual bool persist(); virtual bool isVisibleOnClient (const Client & client) const; virtual void getAttributes (stdvector >::fwd &data) const; virtual bool onContainerAboutToTransfer(ServerObject * destination, ServerObject* transferer); diff --git a/src/engine/server/library/serverGame/src/shared/object/PlayerObject.cpp b/src/engine/server/library/serverGame/src/shared/object/PlayerObject.cpp index b9b8c07aa..76c64d746 100644 --- a/src/engine/server/library/serverGame/src/shared/object/PlayerObject.cpp +++ b/src/engine/server/library/serverGame/src/shared/object/PlayerObject.cpp @@ -1,9171 +1,9171 @@ -// ====================================================================== -// -// PlayerObject.cpp -// copyright (c) 2001 Sony Online Entertainment -// -// ====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/PlayerObject.h" - -#include "LocalizationManager.h" -#include "serverGame/BiographyManager.h" -#include "serverGame/Chat.h" -#include "serverGame/CitizenInfo.h" -#include "serverGame/CityInfo.h" -#include "serverGame/CityInterface.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/DestroyMessageManager.h" -#include "serverGame/FactoryObject.h" -#include "serverGame/GameServer.h" -#include "serverGame/GroupObject.h" -#include "serverGame/GroupWaypointBuilder.h" -#include "serverGame/GuildInfo.h" -#include "serverGame/GuildInterface.h" -#include "serverGame/GuildMemberInfo.h" -#include "sharedGame/GuildRankDataTable.h" -#include "serverGame/ManufactureSchematicObject.h" -#include "serverGame/MessageToQueue.h" -#include "serverGame/NameManager.h" -#include "serverGame/ObjectIdManager.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PgcRatingInfo.h" -#include "serverGame/PlanetObject.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/ProsePackageManagerServer.h" -#include "serverGame/RegionMaster.h" -#include "serverGame/ResourceContainerObject.h" -#include "serverGame/ResourceTypeObject.h" -#include "serverGame/ServerController.h" -#include "serverGame/ServerPlayerObjectTemplate.h" -#include "serverGame/ServerResourceClassObject.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/TangibleObject.h" -#include "serverNetworkMessages/LoginUpgradeAccountMessage.h" -#include "serverNetworkMessages/MessageToPayload.h" -#include "serverScript/ConfigServerScript.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptDictionary.h" -#include "serverScript/ScriptParameters.h" -#include "serverUtility/ConfigServerUtility.h" -#include "serverUtility/ServerClock.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/Crc.h" -#include "sharedFoundation/DynamicVariableList.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/Os.h" -#include "sharedGame/CitizenRankDataTable.h" -#include "sharedGame/CityData.h" -#include "sharedGame/DraftSchematicGroupManager.h" -#include "sharedGame/GameLanguageManager.h" -#include "sharedGame/LfgDataTable.h" -#include "sharedGame/OutOfBandPackager.h" -#include "sharedGame/ProsePackage.h" -#include "sharedGame/PvpData.h" -#include "sharedGame/Quest.h" -#include "sharedGame/QuestManager.h" -#include "sharedGame/QuestTask.h" -#include "sharedGame/SharedObjectTemplate.h" -#include "sharedGame/TextIterator.h" -#include "sharedGame/TextManager.h" -#include "sharedLog/Log.h" -#include "sharedNetworkMessages/ChatAvatarId.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/MessageQueueDraftSchematics.h" -#include "sharedNetworkMessages/MessageQueueDraftSlots.h" -#include "sharedNetworkMessages/MessageQueueDraftSlotsQueryResponse.h" -#include "sharedNetworkMessages/MessageQueueGenericValueType.h" -#include "sharedNetworkMessages/PlayMusicMessage.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedObject/SlotIdManager.h" -#include "sharedObject/SlottedContainer.h" -#include "sharedObject/VolumeContainer.h" -#include "sharedSkillSystem/SkillManager.h" -#include "sharedSkillSystem/SkillObject.h" -#include "sharedUtility/Location.h" -#include "sharedUtility/LocationArchive.h" -#include "UnicodeUtils.h" - -#include -#include - -const SharedObjectTemplate * PlayerObject::m_defaultSharedTemplate = NULL; -bool PlayerObject::m_allowEmptySlot = false; - - -//----------------------------------------------------------------------- -PlayerObject::ChatLogEntry::ChatLogEntry() - : m_index(0) - , m_time(0) -// , m_serverProcessId(0) -{ -} - -// ====================================================================== - -namespace PlayerObjectNamespace -{ - // slot that holds the datapad - const ConstCharCrcLowerString DATAPAD_SLOT_NAME("datapad"); - - // objvars for crafting - const std::string OBJVAR_CRAFTING_STATION("crafting.station"); - const std::string OBJVAR_PRIVATE_STATION("crafting.private"); - const std::string OBJVAR_CRAFTING_PROTOTYPE_TIME("crafting.prototypeTime"); - const std::string OBJVAR_CRAFTING_PROTOTYPE_START_TIME("crafting.prototypeStartTime"); - const std::string OBJVAR_CRAFTING_PROTOTYPE_OBJECT("crafting.prototypeObject"); - const std::string OBJVAR_CRAFTING_PROTOTYPE_CRAFTER("crafting.prototypeCrafter"); - const std::string OBJVAR_CRAFTING_FAKE_PROTOTYPE("crafting.isFakePrototype"); - const std::string OBJVAR_CRAFTING_COMPONENT_CAN_BE_DAMAGED("crafting.damaged_ok"); - const std::string OBJVAR_FORCE_CRITICAL_ASSEMBLY("crafting.force_critical_assembly"); - const std::string OBJVAR_FORCE_CRITICAL_EXPERIMENT("crafting.force_critical_experiment"); - const std::string OBJVAR_FORCE_CRITICAL_SUCCESS("crafting.force_critical_success"); - const std::string OBJVAR_IN_CRAFTING_SESSION("crafting.inCraftingSession"); - - // objvars for chat spam info - const std::string OBJVAR_CHAT_SPAM_TIME_END_INTERVAL("chatSpam.timeEndInterval"); - const std::string OBJVAR_CHAT_SPAM_SPATIAL("chatSpam.spatial"); - const std::string OBJVAR_CHAT_SPAM_NON_SPATIAL("chatSpam.nonSpatial"); - - // objvars for privileged title - const std::string OBJVAR_PRIVILEGED_TITLE("privilegedTitle"); - - // objvars for squelch info - const std::string OBJVAR_SQUELCH_ID("squelch.id"); - const std::string OBJVAR_SQUELCH_NAME("squelch.name"); - const std::string OBJVAR_SQUELCH_EXPIRE("squelch.expire"); - - // skill data granted independently from skills - const std::string OBJVAR_NOT_SKILL_SCHEMATICS("_notskill.schematics"); - - const std::string OBJVAR_EXPERIENCE_MULTIPLIER("xp_multiplier"); - const std::string OBJVAR_GAME_FACTION_RANKINGS("gcw"); - - const std::string OBJVAR_DELETED_QUEST_COUNT("quests.numQuestsDeleted"); - - const StringId COMPONENT_LOST_MSG("system_msg", "lost_component"); - - const int MAX_KILL_METER = 50; - - //---------------------------------------------------------------------- - - std::set s_allPlayerObjects; - - //---------------------------------------------------------------------- - - bool isNestedInContainer (const NetworkId & itemId, const NetworkId & containerId) - { - NetworkId theItemId = itemId; - for (;;) - { - if (theItemId == containerId) - return true; - - const Object * const item = NetworkIdManager::getObjectById (theItemId); - if (!item) - break; - - const Object * const parent = ContainerInterface::getContainedByObject (*item); - if (!parent) - break; - - theItemId = parent->getNetworkId (); - } - - return false; - } - - void refScript(CreatureObject & owner, const std::string & scriptName) - { - GameScriptObject * script = owner.getScriptObject(); - if(script) - { - if(! script->hasScript(scriptName)) - { - script->attachScript(scriptName, false); - } - - int scriptRefCount = 0; - const DynamicVariableList & objvars = owner.getObjVars(); - - const std::string itemName = "quest.script." + scriptName; - if (objvars.getItem(itemName, scriptRefCount)) - { - scriptRefCount++; - } - else - { - scriptRefCount = 1; - } - - owner.setObjVarItem(itemName, scriptRefCount); - } - } - - void derefScript(CreatureObject & owner, const std::string & scriptName) - { - int scriptRefCount = 0; - const DynamicVariableList & objvars = owner.getObjVars(); - - const std::string itemName = "quest.script." + scriptName; - if (objvars.getItem(itemName, scriptRefCount)) - { - scriptRefCount--; - if(scriptRefCount < 0) - { - scriptRefCount = 0; - } - } - else - { - scriptRefCount = 0; - } - - if(scriptRefCount > 0) - { - owner.setObjVarItem(itemName, scriptRefCount); - } - else - { - owner.removeObjVarItem(itemName); - GameScriptObject * script = owner.getScriptObject(); - if(script) - { - if(script->hasScript(scriptName)) - { - script->detachScript(scriptName); - } - } - } - } - - //---------------------------------------------------------------------- - - void checkAndSetCharacterAgeTitle(PlayerObject & player, bool thoroughCheck); - void checkAndSetAccountAgeTitle(PlayerObject & player); - - //---------------------------------------------------------------------- - -// size_t s_waypointLimit = 10; - size_t s_questLimit = 1000; - - //---------------------------------------------------------------------- - - // Class to help us sort quest data by age - class QuestDataToSort - { - public: - QuestDataToSort() : - m_key(0) - {} - - QuestDataToSort( uint32 key, PlayerQuestData const& questData ) : - m_key(key), - m_questData(questData) - {} - - bool operator<(QuestDataToSort const & rhs) const - { - return (m_questData.getRelativeAgeIndex() < rhs.m_questData.getRelativeAgeIndex()); - } - - uint32 GetPlayerQuestDataKey() const { return m_key; } - PlayerQuestData const& GetPlayerQuestData() const { return m_questData; } - - private: - uint32 m_key; - PlayerQuestData m_questData; - }; - - typedef std::list SortableQuestList; - typedef std::vector< std::pair > TaskChanceVector; - - void grantGcwFactionalPresenceScore(std::string const & gcwCategory, PlayerObject const & po, CreatureObject const & co); -}; - -using namespace PlayerObjectNamespace; - -// ====================================================================== - -PlayerObject::PlayerObject(const ServerPlayerObjectTemplate* newTemplate) : - IntangibleObject(newTemplate), - m_callback(new MessageDispatch::Callback), - m_stationId(0), - m_houseId(CachedNetworkId(NetworkId::cms_invalid)), - m_accountNumLots(0), - m_accountNumLotsOverLimitSpam(0), - m_accountMaxLotsAdjustment(0), - m_accountIsOutcast(false), - m_accountCheaterLevel(0.0f), - m_draftSchematics(), - m_experiencePoints(), - m_expModified(0), - m_maxForcePower(0), - m_forcePower(0), - m_forceRegenRate(0), - m_forceRegenValue(0), - m_craftingLevel(0), - m_experimentPoints(8), - m_craftingStage(static_cast(Crafting::CS_none)), - m_craftingTool(), - m_craftingStation(), - m_craftingComponentBioLink(), - m_useableDraftSchematics(), - m_draftSchematic(NULL), - m_matchMakingPersonalProfileId(), - m_matchMakingCharacterProfileId(), - m_friendList(), - m_ignoreList(), - m_skillTitle(), - m_spokenLanguage(GameLanguageManager::getBasicLanguageId()), - m_waypoints(), - m_groupWaypoints(), - m_bornDate(0), - m_playedTime(0), - m_playedTimeAccum(0), - m_sessionStartPlayTime(0), - m_sessionLastActiveTime(0), - m_sessionActivePlayTimeDuration(0), - m_food(0), - m_maxFood(100), - m_drink(0), - m_maxDrink(100), - m_meds(0), - m_maxMeds(100), - m_privledgedTitle(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)), - m_completedQuests(), - m_activeQuests(), - m_currentQuest(0), - m_theaterDatatable(), - m_theaterPosition(), - m_theaterScene(), - m_theaterScript(), - m_theaterNumObjects(), - m_theaterRadius(), - m_theaterCreator(), - m_theaterName(), - m_theaterId(), - m_theaterLocationType(IntangibleObject::TLT_getGoodLocation), - m_roleIconChoice(0), - m_aggroImmuneDuration(0), - m_aggroImmuneStartTime(0), - m_chatLog(new ChatLog), - m_chatLogPurgeTime(0), - m_isUnsticking(false), - m_pendingRequestQuestCrc(0), - m_pendingRequestQuestGiver(NetworkId::cms_invalid), - m_skillTemplate(), - m_workingSkill(), - m_isFromLogin(true), - m_currentGcwPoints(0), - m_currentGcwRating(-1), - m_currentPvpKills(0), - m_lifetimeGcwPoints(0), - m_maxGcwImperialRating(-1), - m_maxGcwRebelRating(-1), - m_lifetimePvpKills(0), - m_nextGcwRatingCalcTime(0), - m_currentGcwRank(0), - m_currentGcwRankProgress(0.0f), - m_maxGcwImperialRank(0), - m_maxGcwRebelRank(0), - m_gcwRatingActualCalcTime(0), - m_playerHateList(), - m_sessionActivity(0), - m_killMeter(0), - m_killMeterRemainder(0.0f), - m_petId(NetworkId::cms_invalid), - m_petCommandList(0), - m_petToggledCommands(0), - m_collections(), - m_collections2(), - m_chatSpamSpatialNumCharacters(0), - m_chatSpamNonSpatialNumCharacters(0), - m_chatSpamTimeEndInterval(0), - m_chatSpamNextTimeToSyncWithChatServer(0), - m_chatSpamNextTimeToNotifyPlayerWhenLimited(0), - m_citizenshipCity(), - m_citizenshipType(static_cast(CityDataCitizenType::NotACitizen)), - m_currentGcwRegion(), - m_cityGcwDefenderRegion(std::make_pair(std::string(), std::make_pair(false, false))), - m_guildGcwDefenderRegion(std::make_pair(std::string(), std::make_pair(false, false))), - m_squelchedById(NetworkId::cms_invalid), - m_squelchedByName(), - m_squelchExpireTime(0), - m_showBackpack(true), - m_showHelmet(true), - m_environmentFlags(0), - m_defaultAttackOverride(), - m_guildRank(), - m_citizenRank(), - m_pickupDropAllItemsOperationId(0), - m_pickupDropAllItemsCellId(NetworkId::cms_invalid), - m_pickupAllItemsAllowInventoryOverload(false), - m_pickupDropAllItemsNumItemsSoFar(0), - m_pickupDropAllItemsProcessedItemsSoFar(), - m_restoreDecorationOperationId(0), - m_restoreDecorationPobId(NetworkId::cms_invalid), - m_restoreDecorationObjectBeingRestored(NetworkId::cms_invalid), - m_restoreDecorationTotalCount(0), - m_restoreDecorationAttemptedCount(0), - m_restoreDecorationSuccessCount(0), - m_restoreDecorationLayoutList(), - m_galacticReserveDeposit(0), - m_pgcRatingCount(0), - m_pgcRatingTotal(0), - m_pgcLastRatingTime(0) -{ - m_allCollections[0] = &m_collections; - m_allCollections[1] = &m_collections2; - - addMembersToPackages(); - m_waypoints.setOnInsert(this, &PlayerObject::onWaypointCreated); - m_waypoints.setOnSet(this, &PlayerObject::onWaypointSet); - m_waypoints.setOnErase(this, &PlayerObject::onWaypointRemoved); - IGNORE_RETURN(s_allPlayerObjects.insert(this)); -} - -//----------------------------------------------------------------------- - -PlayerObject::~PlayerObject() -{ - delete m_callback; - delete m_chatLog; - IGNORE_RETURN(s_allPlayerObjects.erase(this)); -} - -//----------------------------------------------------------------------- - -/** - * Returns a shared template if none was given for this object. - * - * @return the shared template - */ -const SharedObjectTemplate * PlayerObject::getDefaultSharedTemplate() const -{ -static const ConstCharCrcLowerString templateName("object/player/base/shared_player_default.iff"); - - if (m_defaultSharedTemplate == NULL) - { - m_defaultSharedTemplate = safe_cast( - ObjectTemplateList::fetch(templateName)); - WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create " - "default shared object template %s", templateName.getString())); - if (m_defaultSharedTemplate != NULL) - ExitChain::add (removeDefaultTemplate, "PlayerObject::removeDefaultTemplate"); - } - return m_defaultSharedTemplate; -} // PlayerObject::getDefaultSharedTemplate - -//----------------------------------------------------------------------- - -/** - * Cleans up the default shared template. - */ -void PlayerObject::removeDefaultTemplate() -{ - if (m_defaultSharedTemplate != NULL) - { - m_defaultSharedTemplate->releaseReference(); - m_defaultSharedTemplate = NULL; - } -} // PlayerObject::removeDefaultTemplate - -// ---------------------------------------------------------------------- - -void PlayerObject::setStationId(StationId account) -{ - DEBUG_FATAL(!isAuthoritative(),("PlayerObject %s wasn't authoritative in setStationId.\n",getNetworkId().getValueString().c_str())); - m_stationId=account; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setCheaterLevel(float level) -{ - m_accountCheaterLevel = level; -} - -//----------------------------------------------------------------------- - -/** - * Returns the current "birth" date. The birth date is defined as the number - * of days since Jan 1st, 2001 (Jan 1st, 2001 = 0) - */ -int PlayerObject::getCurrentBornDate() -{ - // get the base date of Jan 1st, 2001 - struct tm baseTimeData; - baseTimeData.tm_hour = 0; - baseTimeData.tm_isdst = 0; - baseTimeData.tm_mday = 1; - baseTimeData.tm_min = 0; - baseTimeData.tm_mon = 0; - baseTimeData.tm_sec = 0; - baseTimeData.tm_wday = 0; - baseTimeData.tm_yday = 0; - baseTimeData.tm_year = 101; - time_t baseTime = mktime(&baseTimeData); - - // get the current time and compute the birth date - time_t currentTime = time(NULL); - time_t delta = (currentTime - baseTime) / (60 * 60 * 24); - delta += ((currentTime - baseTime) % (60 * 60 * 24) != 0 ? 1 : 0); - return int(delta); -} // PlayerObject::getCurrentBornDate - -//----------------------------------------------------------------------- - -/** - * Sets the "birth" date of the player to the current date. The birth date is - * defined as the number of days since Jan 1st, 2001 (Jan 1st, 2001 = 0) - */ -void PlayerObject::setBornDate() -{ - if (m_bornDate.get() != 0) - return; - - if (isAuthoritative()) - { - m_bornDate = (int)getCurrentBornDate(); - } - else - { - WARNING(true, ("PlayerObject::setBornDate called on non-authoritative player")); - } -} // PlayerObject::setBornDate - -//----------------------------------------------------------------------- - -/** -* Adjust the "birth" date of the player by the specified number of days -* -* @param adjustment the number of days (can be negative) to adjust the "birth" date by -*/ -void PlayerObject::adjustBornDate(int adjustment) -{ - if (m_bornDate.get() == 0) - return; - - if (isAuthoritative()) - { - const int newBornDate = m_bornDate.get() + adjustment; - if ((newBornDate <= 0) || (newBornDate > getCurrentBornDate())) - return; - - m_bornDate = newBornDate; - } - else - { - WARNING(true, ("PlayerObject::adjustBornDate called on non-authoritative player")); - } -} // PlayerObject::adjustBornDate - -//----------------------------------------------------------------------- - -/** - * Changes the count of the amount of time this player has been online. Note we only - * update the time every 30 secs. - * - * @param time since last call to this function - */ -void PlayerObject::alterPlayedTime(float time) -{ -static const float TIME_LIMIT = 30.0f; - - if (isAuthoritative()) - { - m_playedTimeAccum += time; - if (m_playedTimeAccum >= TIME_LIMIT) - { - m_playedTime = m_playedTime.get() + static_cast(TIME_LIMIT); - m_playedTimeAccum -= TIME_LIMIT; - } - } - else - { - WARNING(true, ("PlayerObject::alterPlayedTime called on non-authoritative player")); - } -} // updatePlayedTime - -//----------------------------------------------------------------------- - -CreatureObject *PlayerObject::getCreatureObject() -{ - Object * const owner = ContainerInterface::getContainedByObject(*this); - if (owner) - { - ServerObject * const serverOwner = owner->asServerObject(); - if (serverOwner) - return serverOwner->asCreatureObject(); - } - return 0; -} - -//----------------------------------------------------------------------- - -CreatureObject const * PlayerObject::getCreatureObject() const -{ - Object const * const owner = ContainerInterface::getContainedByObject(*this); - if (owner) - { - ServerObject const * const serverOwner = owner->asServerObject(); - if (serverOwner) - return serverOwner->asCreatureObject(); - } - return 0; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::virtualOnSetAuthority() -{ - IntangibleObject::virtualOnSetAuthority(); - - if (isCrafting()) - { - const TangibleObject * tool = safe_cast(getCraftingTool().getObject()); - if (tool != NULL) - { - const ManufactureSchematicObject * manfSchematic = tool->getCraftingManufactureSchematic(); - if (manfSchematic != NULL) - { - m_draftSchematic = DraftSchematicObject::getSchematic( - manfSchematic->getDraftSchematic()); - if (m_draftSchematic.getPointer() == NULL) - { - WARNING(true, ("PlayerObject::virtualOnSetAuthority object " - "%s is flagged as crafting, but has bad manf schematic %lu", - getNetworkId().getValueString().c_str(), - manfSchematic->getDraftSchematic())); - } - } - else - { - WARNING(true, ("PlayerObject::virtualOnSetAuthority object " - "%s is flagged as crafting, but has no manf schematic", - getNetworkId().getValueString().c_str())); - } - } - else - { - WARNING(true, ("PlayerObject::virtualOnSetAuthority object " - "%s is flagged as crafting, but has no crafting tool", - getNetworkId().getValueString().c_str())); - } - } - - GroupWaypointBuilder::updateGroupWaypoints(*this, true); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::virtualOnLogout() -{ - IntangibleObject::virtualOnLogout(); - - // stop crafting - if (isCrafting()) - stopCrafting(false); - - // destroy any theater associated with us - if (m_theaterId.get() != NetworkId::cms_invalid) - { - MessageToQueue::getInstance().sendMessageToC(m_theaterId.get(), - "C++DestroySelf", "", 0, false); - m_theaterId = NetworkId::cms_invalid; - } - - // persist chat statistics - setObjVarItem(OBJVAR_CHAT_SPAM_TIME_END_INTERVAL, m_chatSpamTimeEndInterval.get()); - setObjVarItem(OBJVAR_CHAT_SPAM_SPATIAL, m_chatSpamSpatialNumCharacters.get()); - setObjVarItem(OBJVAR_CHAT_SPAM_NON_SPATIAL, m_chatSpamNonSpatialNumCharacters.get()); - - // persist privileged title - if (m_privledgedTitle.get() != static_cast(PlayerDataPriviledgedTitle::NormalPlayer)) - setObjVarItem(OBJVAR_PRIVILEGED_TITLE, static_cast(m_privledgedTitle.get())); - else - removeObjVarItem(OBJVAR_PRIVILEGED_TITLE); - - // persist squelch info - int const secondsUntilUnsquelched = getSecondsUntilUnsquelched(); - if (secondsUntilUnsquelched != 0) - { - setObjVarItem(OBJVAR_SQUELCH_ID, m_squelchedById.get()); - setObjVarItem(OBJVAR_SQUELCH_NAME, m_squelchedByName.get()); - if (secondsUntilUnsquelched < 0) - setObjVarItem(OBJVAR_SQUELCH_EXPIRE, -1); - else - setObjVarItem(OBJVAR_SQUELCH_EXPIRE, static_cast(ServerClock::getInstance().getGameTimeSeconds()) + secondsUntilUnsquelched); - } - else - { - removeObjVarItem(OBJVAR_SQUELCH_ID); - removeObjVarItem(OBJVAR_SQUELCH_NAME); - removeObjVarItem(OBJVAR_SQUELCH_EXPIRE); - } -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getExperiencePoints(const std::string & experienceType) const -{ - int result = 0; - std::map::const_iterator f = m_experiencePoints.find(experienceType); - if(f != m_experiencePoints.end()) - { - result = (*f).second; - } - return result; -} - -// ---------------------------------------------------------------------- - -const std::map & PlayerObject::getExperiencePoints() const -{ - return m_experiencePoints.getMap(); -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getExperienceLimit(const std::string & experienceType) const -{ - uint32 limit = static_cast(-1); - CreatureObject const * const owner = getCreatureObject(); - - if(owner) - { - // find out the xp limit based on the player's skills - const CreatureObject::SkillList & skills = owner->getSkillList(); - for (CreatureObject::SkillList::const_iterator iter = skills.begin(); - iter != skills.end(); ++iter) - { - if((*iter)) - { - const SkillObject::ExperiencePair * xpInfo = (*iter)->getPrerequisiteExperience(); - if (xpInfo != NULL && experienceType == xpInfo->first && xpInfo->second.second > 0) - { - if (limit == static_cast(-1) || - limit < static_cast(xpInfo->second.second)) - { - limit = xpInfo->second.second; - } - } - } - } - if (limit == static_cast(-1)) - { - // use the default limit - limit = SkillManager::getInstance().getDefaultXpLimit(experienceType); - WARNING(limit == static_cast(-1), ("No default xp limit defined " - "for xp type %s for player object %s", experienceType.c_str(), getNetworkId().getValueString().c_str())); - } - } - - WARNING(limit == static_cast(-1), ("No xp limit defined " - "for xp type %s for player object %s", experienceType.c_str(), getNetworkId().getValueString().c_str())); - - return limit; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::grantExperiencePoints(const std::string & experienceType, int amount) -{ - CreatureObject * const owner = getCreatureObject(); - NOT_NULL(owner); - - int amountGranted = amount; - - if(isAuthoritative()) - { - if (amount > 0) - { - int multiplier = 1; - - if (!getObjVars().getItem(OBJVAR_EXPERIENCE_MULTIPLIER, multiplier)) - multiplier = ConfigServerGame::getXpMultiplier(); - - amount *= multiplier; - - // adjust the xp based on what faction is doing best - // NOTE: HACK HACK HACK! - const PlanetObject * tatooine = ServerUniverse::getInstance().getTatooinePlanet(); - if (tatooine == NULL) - tatooine = ServerUniverse::getInstance().getPlanetByName("Tatooine"); - if (tatooine == NULL) - { - WARNING(true, ("Can't find planet tatooine from ServerUniverse")); - } - else - { - std::string factionName; - int factionPoints = 0; - bool tie = false; - const DynamicVariableList::NestedList factions(tatooine->getObjVars(), - OBJVAR_GAME_FACTION_RANKINGS); - for (DynamicVariableList::NestedList::const_iterator i(factions.begin()); - i != factions.end(); ++i) - { - int points = 0; - if (i.getValue(points)) - { - if (points > factionPoints) - { - tie = false; - factionPoints = points; - factionName = i.getName(); - } - else if (points == factionPoints) - tie = true; - } - else - { - WARNING(true, ("GCW faction %s value not stored as int", - i.getName().c_str())); - } - } - if (!tie && factionPoints > 0) - { - uint32 factionCrc = Crc::calculate(factionName.c_str()); - if (factionCrc == owner->getPvpFaction()) - { - amount += static_cast(amount * ConfigServerGame::getGcwXpBonus()); - } - } - } - - } - - // find out the xp limit based on the player's skills - int const limit = getExperienceLimit(experienceType); - - // get the current xp - int const current = getExperiencePoints(experienceType); - - // calculate the new xp - int total = current + amount; - - // cap the total xp, if necessary - if ((total > limit) && (limit >= 0)) - total = limit; - - if (ConfigServerScript::getLogBalance() && (total != current)) - { - // log the grant - unsigned long time = ServerClock::getInstance().getGameTimeSeconds(); - LOG("GameBalance", ("balancelog:%d:XP;%lu;%s;%s;%d;%d;%d;%d", - static_cast(GameServer::getInstance().getProcessId()), time, - owner->getNetworkId().getValueString().c_str(), experienceType.c_str(), - amount, current, total, (m_expModified.get()+1))); - } - - // calculate the actual xp granted - amountGranted = total - current; - - // only update the XP if it actually changed - if (total != current) - { - m_experiencePoints.set(experienceType, total); - m_expModified.set(m_expModified.get() + 1); - } - } - else - { - owner->sendControllerMessageToAuthServer(CM_grantExperiencePoints, new MessageQueueGenericValueType >(std::make_pair(experienceType, amount))); - } - - return amountGranted; -} - -//----------------------------------------------------------------------- - -bool PlayerObject::grantSchematicGroup(const std::string & groupNameWithModifier, bool fromSkill) -{ - if (groupNameWithModifier.size() <= 1 || (groupNameWithModifier[0] != '+' && groupNameWithModifier[0] != '-')) - return true; - - if (isAuthoritative()) - { - const std::string & groupName = groupNameWithModifier.substr (1); - static DraftSchematicGroupManager::SchematicVector drafts; - drafts.clear (); - if (!DraftSchematicGroupManager::getSchematicsForGroup (groupName, drafts)) - { - WARNING (true, ("Invalid schematic group [%s]", groupName.c_str ())); - return false; - } - - const bool addGroup = (groupNameWithModifier[0] == '+'); - - for (DraftSchematicGroupManager::SchematicVector::const_iterator it = drafts.begin (); it != drafts.end (); ++it) - { - const std::pair & schematic = *it; - if (addGroup) - grantSchematic(schematic.first, fromSkill); - else - revokeSchematic(schematic.first, fromSkill); - } - } - else - { - WARNING_STRICT_FATAL(true, ("Did not assign schematic group to proxy object %s", getNetworkId().getValueString().c_str())); - } - return true; -} - -//----------------------------------------------------------------------- - -bool PlayerObject::grantSchematic(uint32 schematicCrc, bool fromSkill) -{ - if (isAuthoritative()) - { - // if we are crafting, end the crafting session - if (isCrafting()) - stopCrafting(false); - - const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic( - schematicCrc); - if (schematic != NULL) - { - // add the schematic to the player's draft schematic list - Archive::AutoDeltaMap, int>::const_iterator found = m_draftSchematics.find(schematic->getCombinedCrc()); - if (found == m_draftSchematics.end()) - { - m_draftSchematics.set(schematic->getCombinedCrc(), 1); - CreatureObject * owner = dynamic_cast(ContainerInterface::getContainedByObject(*this)); - NOT_NULL(owner); - if (!fromSkill) - { - // save schematic as objvar - char buffer[256]; - sprintf(buffer, "%s.%lu", OBJVAR_NOT_SKILL_SCHEMATICS.c_str(), - schematicCrc); - owner->setObjVarItem(buffer, 1); - } - - // tell scripts the schematic was given - NOT_NULL(owner->getScriptObject()); - ScriptParams params; - params.addParam(static_cast(schematic->getCombinedCrc().first)); - params.addParam(fromSkill); - IGNORE_RETURN(owner->getScriptObject()->trigAllScripts( - Scripting::TRIG_GRANT_SCHEMATIC, params)); - } - else if (fromSkill) - { - m_draftSchematics.set(schematic->getCombinedCrc(), (*found).second + 1); - } - } - } - else - { - WARNING_STRICT_FATAL(true, ("Did not assign schematic to proxy object %s", getNetworkId().getValueString().c_str())); - } - return true; -} - -//----------------------------------------------------------------------- - -bool PlayerObject::revokeSchematic(uint32 schematicCrc, bool fromSkill) -{ - if (isAuthoritative()) - { - // if we are crafting, end the crafting session - if (isCrafting()) - stopCrafting(false); - - const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic(schematicCrc); - if (schematic != NULL) - { - // remove the schematic from the player's draft schematic list - Archive::AutoDeltaMap, int>::const_iterator found = m_draftSchematics.find(schematic->getCombinedCrc()); - if ((*found).second > 1 && fromSkill) - { - m_draftSchematics.set(schematic->getCombinedCrc(), (*found).second - 1); - } - else - { - WARNING((*found).second > 1, ("PlayerObject::revokeSchematic revoking schematic %s that has a ref count of %d from player %s, due to it being revoked outside the skill system", - schematic->getObjectTemplateName(), (*found).second, getAccountDescription().c_str())); - m_draftSchematics.erase(found); - CreatureObject * owner = dynamic_cast(ContainerInterface::getContainedByObject(*this)); - NOT_NULL(owner); - if (!fromSkill) - { - // remove schematic from objvars - char buffer[256]; - sprintf(buffer, "%s.%lu", OBJVAR_NOT_SKILL_SCHEMATICS.c_str(), - schematicCrc); - owner->removeObjVarItem(buffer); - } - - // tell scripts the schematic was removed - NOT_NULL(owner->getScriptObject()); - ScriptParams params; - params.addParam(static_cast(schematic->getCombinedCrc().first)); - params.addParam(fromSkill); - IGNORE_RETURN(owner->getScriptObject()->trigAllScripts( - Scripting::TRIG_REVOKE_SCHEMATIC, params)); - } - } - } - else - { - WARNING_STRICT_FATAL(true, ("Did not remove schematic from proxy object %s", getNetworkId().getValueString().c_str())); - } - return true; -} - -//----------------------------------------------------------------------- - -bool PlayerObject::hasSchematic(uint32 schematicCrc) -{ - const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic(schematicCrc); - if (schematic != NULL) - { - std::map,int>::const_iterator found = m_draftSchematics.find(schematic->getCombinedCrc()); - if (found != m_draftSchematics.end()) - return true; - } - return false; -} - - -// ====================================================================== -// ====================================================================== -// -// Crafting functions -// -// ====================================================================== -// ====================================================================== - -/** - * Sets the player's crafting tool. - * - * @param tool the crafting tool - */ -void PlayerObject::setCraftingTool(const TangibleObject & tool) -{ - m_craftingTool = CachedNetworkId(tool); -} // PlayerObject::setCraftingTool - -//----------------------------------------------------------------------- - -/** - * Sets the player's crafting station. - * - * @param station the crafting station - */ -void PlayerObject::setCraftingStation(const TangibleObject * station) -{ - if (station != NULL) - { - // verify the crafting station is valid - if (station->getObjVars().hasItem(OBJVAR_CRAFTING_STATION)) - { - m_craftingStation = CachedNetworkId(*station); - - // if we are private, make sure we have an ingredient hopper - int privateStation = 0; - station->getObjVars().getItem(OBJVAR_PRIVATE_STATION, privateStation); - if (privateStation == 1 && getCraftingLevel() == 3 && station->getIngredientHopper() == NULL) - { - CreatureObject * const owner = getCreatureObject(); - NOT_NULL(owner); - - WARNING(true, ("Player %s crafting near private station %s that " - "has no ingredient hopper! The crafting session level will " - "be reduced to 2", - owner->getNetworkId().getValueString().c_str(), - station->getNetworkId().getValueString().c_str())); - setCraftingLevel(2); - } - return; - } - } - m_craftingStation = CachedNetworkId::cms_cachedInvalid; -} // PlayerObject::setCraftingStation - -//----------------------------------------------------------------------- - -/** - * Called when the player wants to start crafting. - * - * @param toolId the crafting tool the player wants to use - * - * @return true if the session was started, false if not - */ -bool PlayerObject::requestCraftingSession(const NetworkId & toolId) -{ - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return false; - - const std::string myId = getNetworkId().getValueString(); - const char * const myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - const std::string toolIdStdString = toolId.getValueString(); - const char * const toolIdString = toolIdStdString.c_str(); - UNREF(toolIdString); // needed for release mode - - if (getCraftingTool() != NetworkId::cms_invalid) - { - if (m_craftingStage.get() == Crafting::CS_none || - m_craftingStage.get() == Crafting::CS_selectDraftSchematic) - { - stopCrafting(false); - } - else - { - DEBUG_WARNING(true, ("Player %s requesting crafting session with tool " - "%s while crafting with tool %s", myIdString, toolIdString, - getCraftingTool().getValueString().c_str())); - return false; - } - } - - TangibleObject * const tool = dynamic_cast(CachedNetworkId(toolId).getObject()); - if (tool == NULL) - { - DEBUG_WARNING(true, ("Player %s requesting crafting session with invalid " - "object %s", myIdString, toolIdString)); - return false; - } - - // If the tool is a crafting station, try to find a compatible crafting tool to launch. - if (tool->isCraftingStation()) - { - int const toolType = tool->getCraftingType(); - - ServerObject const * const inventory = owner->getInventory(); - if (inventory) - { - VolumeContainer const * const inventoryContainer = ContainerInterface::getVolumeContainer(*inventory); - if (inventoryContainer) - { - std::vector objList; - for (ContainerConstIterator iter(inventoryContainer->begin()); iter != inventoryContainer->end(); ++iter) - { - CachedNetworkId const & objId = (*iter); - TangibleObject * const obj = safe_cast(objId.getObject()); - if ((obj != NULL) && obj->isCraftingTool() && (toolType & obj->getCraftingType())) - { - return requestCraftingSession(objId) ; - } - } - } - } - } - else - { - return tool->startCraftingSession(*owner); - } - - return false; -} // PlayerObject::requestCraftingSession - -//----------------------------------------------------------------------- - -/** - * Sends a list of draft schematic names that a player may craft with to the - * player. - * - * @param schematicNames draft schematic template names the player can use - */ -void PlayerObject::sendUseableDraftSchematics(std::vector & schematicNames) -{ - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return; - - // keep around the names since we are just going to get an index back from - // the client; the calling function will free up the old names - m_useableDraftSchematics.swap(schematicNames); - - MessageQueueDraftSchematics * message = new MessageQueueDraftSchematics(getCraftingTool(), getCraftingStation()); - - // get the name of each schematic and put it in the network message - std::vector::iterator iter; - for (iter = m_useableDraftSchematics.begin(); iter != m_useableDraftSchematics.end();) - { - if (*iter != 0) - { - const DraftSchematicObject * const schematic = DraftSchematicObject::getSchematic(*iter); - if (schematic != NULL) - { - message->addSchematic(schematic->getCombinedCrc(), - static_cast(schematic->getCategory())); - ++iter; - } - else - { - const ConstCharCrcString & name = ObjectTemplateList::lookUp(*iter); - if (!name.isEmpty()) - { - WARNING(true, ("PlayerObject::sendUseableDraftSchematics bad draft " - "schematic name %s", name.getString())); - } - else - { - WARNING(true, ("PlayerObject::sendUseableDraftSchematics bad draft " - "schematic crc %u", *iter)); - } - iter = m_useableDraftSchematics.erase(iter); - } - } - else - iter = m_useableDraftSchematics.erase(iter); - } - - // send the names to the player - (safe_cast(owner->getController()))->appendMessage( - static_cast(CM_draftSchematicsMessage), 0.0f, message, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - - m_craftingStage = static_cast(Crafting::CS_selectDraftSchematic); -} // PlayerObject::sendUseableDraftSchematics - -//---------------------------------------------------------------------- - -/** - * Sends the player info about a draft schematic's slots, filtered by the - * player's skills. - * - * @param draftSchematicCrc the crc of the schematic to send - * @param message message to be sent to the player if we are getting slots for an object we are crafting - * @param queryMessage message to be sent to the player if we are getting slots for an arbitrary object - * - * @return true on success, false if draftSchematicName is not a valid schematic - */ -bool PlayerObject::requestDraftSlots(uint32 draftSchematicCrc, MessageQueueDraftSlots * message, MessageQueueDraftSlotsQueryResponse * queryMessage) -{ - ManufactureSchematicObject * manfSchematic = NULL; - MessageQueueDraftSlots::Slot slotInfo; - MessageQueueDraftSlots::Option optionInfo; - - if ((message == NULL && queryMessage == NULL) || - (message != NULL && queryMessage != NULL)) - { - return false; - } - - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return false; - - const ConstCharCrcString & schematicName = ObjectTemplateList::lookUp(draftSchematicCrc); - UNREF(schematicName); - - const DraftSchematicObject * const draftSchematic = DraftSchematicObject::getSchematic(draftSchematicCrc); - if (draftSchematic == NULL) - { - DEBUG_WARNING(true, ("Player %s requested invalid draft schematic %s", owner->getNetworkId().getValueString().c_str(), schematicName.getString())); - return false; - } - - if (message != NULL) - { - m_draftSchematic = draftSchematic; - - TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); - NOT_NULL(tool); - if (tool == NULL) - return false; - - tool->clearCraftingManufactureSchematic(); - tool->clearCraftingPrototype(); - - // make a temporary manufacturing schematic based on the draft scematic - manfSchematic = ServerWorld::createNewManufacturingSchematic(CachedNetworkId( - *owner), *tool, tool->getCraftingManufactureSchematicSlotId(), false); - if (manfSchematic == NULL) - { - DEBUG_WARNING(true, ("Error creating manufacturing schematic!")); - return false; - } - message->setManfSchemId(manfSchematic->getNetworkId ()); - tool->setCraftingManufactureSchematic(*manfSchematic); - - // flag that the schematic is being used in a crafting session - manfSchematic->setObjVarItem(OBJVAR_IN_CRAFTING_SESSION, 1); - - // reset the experiment points - m_experimentPoints = -1; - - // create a test prototype so the client will know what object is - // being made - ServerObject * prototype = manfSchematic->manufactureObject(owner->getNetworkId(), - *tool, tool->getCraftingPrototypeSlotId(), true); - if (prototype == NULL) - { - DEBUG_WARNING(true, ("Error creating temp prototype!")); - return false; - } - tool->setCraftingPrototype(*prototype); - message->setPrototypeId(prototype->getNetworkId()); - message->setVolume(draftSchematic->getVolume()); - message->setCanManufacture(draftSchematic->getItemsPerContainer() > 0); - - DEBUG_LOG("crafting", ("PlayerObject::requestDraftSlots, created schematic " - "%s, prototype %s for player %s", - manfSchematic->getNetworkId().getValueString().c_str(), - prototype->getNetworkId().getValueString().c_str(), - getAccountDescription().c_str())); - } - - if (queryMessage != NULL) - { - queryMessage->setComplexity(static_cast(draftSchematic->getComplexity())); - queryMessage->setVolume(draftSchematic->getVolume()); - queryMessage->setCanManufacture(draftSchematic->getItemsPerContainer() > 0); - } - - // get info about each slot in the schematic - Crafting::IngredientSlot manfSlot; - ServerDraftSchematicObjectTemplate::IngredientSlot slot; - const int slotCount = draftSchematic->getSlotsCount(); - for (int i = 0; i < slotCount; ++i) - { - if (!draftSchematic->getSlot(slot, i)) - { - DEBUG_WARNING(true, ("draft schematic slot %d for schematic %s not found!",i, schematicName.getString())); - continue; - } - if (!slot.optional || slot.optionalSkillCommand.empty() || - owner->hasCommand(slot.optionalSkillCommand)) - { - if (manfSchematic != NULL) - { - // create the slot - IGNORE_RETURN(manfSchematic->getSlot(slot.name, manfSlot)); - // set the manufacturing slot->draft slot map - manfSchematic->setSlotIndex(slot.name, i); - } - - slotInfo.name = slot.name; - slotInfo.optional = slot.optional; - bool componentSlot = false; - const int optionsCount = static_cast(slot.options.size()); - for (int j = 0; j < optionsCount; ++j) - { - const ServerIntangibleObjectTemplate::Ingredient & option = slot.options[static_cast(j)]; - - if (option.skillCommand.empty() || owner->hasCommand(option.skillCommand)) - { - const ServerIntangibleObjectTemplate::SimpleIngredient & simple = option.ingredients[0]; - - switch (option.ingredientType) - { - case Crafting::IT_template: - case Crafting::IT_templateGeneric: - { - // get the default object name from the shared template - const ObjectTemplate *const ingredientTemplate = ObjectTemplateList::fetch(simple.ingredient); - if (ingredientTemplate == NULL) - { - DEBUG_WARNING(true, ("draft schematic component ingredient %s not found!", simple.ingredient.c_str())); - continue; - } - const SharedObjectTemplate * const sharedTemplate = safe_cast(ObjectTemplateList::fetch((safe_cast(ingredientTemplate))->getSharedTemplate())); - if (sharedTemplate == NULL) - { - DEBUG_WARNING(true, ("draft schematic component ingredient %s shared template not found!", simple.ingredient.c_str())); - continue; - } - optionInfo.ingredient = Unicode::narrowToWide(sharedTemplate->DataResource::getName()); - sharedTemplate->releaseReference(); - ingredientTemplate->releaseReference(); - } - break; - case Crafting::IT_schematic: - case Crafting::IT_schematicGeneric: - { - // get the default object name from the shared template of the crafted object - const ObjectTemplate * const ingredientTemplate = ObjectTemplateList::fetch(simple.ingredient); - if (ingredientTemplate == NULL) - { - DEBUG_WARNING(true, ("draft schematic schematic ingredient %s not found!", simple.ingredient.c_str())); - continue; - } - const ServerObjectTemplate * const craftedTemplate = safe_cast(ingredientTemplate)->getCraftedObjectTemplate(); - if (craftedTemplate == NULL) - { - DEBUG_WARNING(true, ("draft schematic schematic ingredient %s not found!", simple.ingredient.c_str())); - continue; - } - const SharedObjectTemplate * const sharedTemplate = safe_cast(ObjectTemplateList::fetch((safe_cast(craftedTemplate))->getSharedTemplate())); - if (sharedTemplate == NULL) - { - DEBUG_WARNING(true, ("draft schematic component ingredient %s shared template not found!", simple.ingredient.c_str())); - continue; - } - optionInfo.ingredient = Unicode::narrowToWide(sharedTemplate->DataResource::getName()); - sharedTemplate->releaseReference(); - craftedTemplate->releaseReference(); - ingredientTemplate->releaseReference(); - } - break; - default: - optionInfo.ingredient = Unicode::narrowToWide(simple.ingredient); - break; - } - optionInfo.name = simple.name; - optionInfo.type = static_cast(static_cast(option.ingredientType)); - optionInfo.amountNeeded = simple.count; - slotInfo.options.push_back(optionInfo); - if (static_cast(option.ingredientType) == static_cast(Crafting::IT_template) || - static_cast(option.ingredientType) == static_cast(Crafting::IT_templateGeneric) || - static_cast(option.ingredientType) == static_cast(Crafting::IT_item) || - static_cast(option.ingredientType) == static_cast(Crafting::IT_schematic) || - static_cast(option.ingredientType) == static_cast(Crafting::IT_schematicGeneric)) - { - componentSlot = true; - } - } // if (hasCommand(option.skillCommand)) - } // for (int j = 0; j < optionsCount; ++j) - if (componentSlot) - slotInfo.hardpoint = slot.appearance; - if (message != NULL) - message->addSlot(slotInfo); - else - queryMessage->addSlot(slotInfo); - slotInfo.options.clear(); - } // if (hasCommand(slot.skillCommand)) - } // for (int i = 0; i < slotCount; ++i) - - // send the slot info to the player - if (message != NULL) - { - (safe_cast(owner->getController()))->appendMessage( - static_cast(CM_draftSlotsMessage), 0.0f, message, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - else - { - (safe_cast(owner->getController()))->appendMessage( - static_cast(CM_draftSlotsQueryResponse), 0.0f, queryMessage, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - return true; -} // PlayerObject::requestDraftSlots - -//---------------------------------------------------------------------- - -/** - * Called when a player has selected a draft schematic to use in a crafting - * tool. We send the player info about the slots that need to be filled - * in the schematic, filtered by his skills. - * - * @param index index into the available schematics the player can use. The - * index will be clipped if it is out of range. - */ -void PlayerObject::selectDraftSchematic(int index) -{ - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return; - - const std::string myId = getNetworkId().getValueString(); - const char * const myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // check the crafting tool - if (getCraftingTool() == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Player %s trying to select draft schematic with " - "no crafting tool!", myIdString)); - } - else if (m_craftingStage.get() != static_cast(Crafting::CS_selectDraftSchematic)) - { - DEBUG_WARNING(true, ("Player %s trying to select draft schematic in wrong " - "crafting stage %d!", myIdString, static_cast(m_craftingStage.get()))); - } - else - { - // check the available draft schematics - if (m_useableDraftSchematics.empty ()) - { - DEBUG_WARNING(true, ("Player %s selected a draft schematic to craft " - "when none are available!", myIdString)); - } - else - { - if (index < 0) - index = 0; - else if (index >= static_cast(m_useableDraftSchematics.size())) - index = static_cast(m_useableDraftSchematics.size()) - 1; - - MessageQueueDraftSlots * message = new MessageQueueDraftSlots( - getCraftingTool(), NetworkId::cms_invalid); - if (requestDraftSlots(m_useableDraftSchematics[static_cast(index)], message, NULL)) - { - m_craftingStage = static_cast(Crafting::CS_assembly); - m_craftingComponentBioLink = NetworkId::cms_invalid; - } - else - delete message; - } - } -} // PlayerObject::selectDraftSchematic - -//---------------------------------------------------------------------- - -/** - * Tries to fill the current manufacturing schematic with an ingredient in the player's - * inventory or the crafting station's input hopper. - * - * @param slotIndex index of the slot to fill - * @param slotOptionIndex index of the slot option to use - * @param ingredientId id of the ingredient to use - * - * @return CE_success on success, error code if the ingredient wasn't added - */ -Crafting::CraftingError PlayerObject::fillSlot(int slotIndex, int slotOptionIndex, const NetworkId & ingredientId) -{ - std::string myId = getNetworkId().getValueString(); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return Crafting::CE_noOwner; - - // check the draft schematic - if (m_draftSchematic.getPointer() == NULL) - { - WARNING(true, ("Player %s trying to fill slot with no draft schematic!", myIdString)); - return Crafting::CE_noDraftSchematic; - } - - if (m_draftSchematic->getGameObjectType() == SharedObjectTemplate::GOT_data_draft_schematic_read_only) - { - return Crafting::CE_readOnlyDraftSchematic; - } - - if (getCraftingStage() != Crafting::CS_assembly) - { - WARNING(true, ("Player %s trying to fill slot when not in assembly stage! " - "Stage = %d, schematic = %s, ingredient = %s, slot = %d", myIdString, - getCraftingStage(), m_draftSchematic->getTemplateName(), - ingredientId.getValueString().c_str(), slotIndex)); - return Crafting::CE_notAssemblyStage; - } - - // check the crafting tool - if (getCraftingTool() == NetworkId::cms_invalid) - { - WARNING(true, ("Player %s trying to fill slot with no crafting tool!", myIdString)); - return Crafting::CE_noCraftingTool; - } - - TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); - if (tool == NULL) - { - WARNING(true, ("Player %s trying to fill slot with crafting tool %s, but tool is NULL!", myIdString, getCraftingTool().getValueString().c_str())); - return Crafting::CE_noCraftingTool; - } - - // get the crafting station (if any) - TangibleObject * const station = dynamic_cast(getCraftingStation().getObject()); - - // check the manufacturing schematic - ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); - if (manfSchematic == NULL) - { - WARNING(true, ("Player %s trying to fill slot with no manufacturing schematic!", myIdString)); - return Crafting::CE_noManfSchematic; - } - - // verify the slot index - if (slotIndex < 0 || slotIndex >= manfSchematic->getSlotsCount()) - { - WARNING(true, ("Player %s trying to fill invalid slot %d",myIdString, slotIndex)); - return Crafting::CE_invalidSlot; - } - - // get the manufacturing schematic object - Crafting::IngredientSlot manfSlot; - if (!manfSchematic->getSlot(slotIndex, manfSlot, false)) - { - WARNING(true, ("Got invalid slot %d result for manf schematic %s, but we were told it was ok! What's going on?", slotIndex, manfSchematic->getNetworkId().getValueString().c_str())); - return Crafting::CE_invalidSlot; - } - - // get the draft schematic slot - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - if (!m_draftSchematic->getSlot(draftSlot, manfSlot.draftSlotIndex)) - { - return Crafting::CE_invalidSlot; - } - - // get the draft schematic option, convert the passed-in option index to the - // unfiltered index - int i, j; - const ServerIntangibleObjectTemplate::Ingredient * slotOption = NULL; - const int optionsCount = static_cast(draftSlot.options.size()); - for (i = 0, j = 0; i < optionsCount; ++i) - { - const ServerIntangibleObjectTemplate::Ingredient & tempOption = draftSlot.options[static_cast(i)]; - if (tempOption.skillCommand.empty() || owner->hasCommand(tempOption.skillCommand)) - { - if (j == slotOptionIndex) - { - slotOption = &tempOption; - break; - } - else - ++j; - } - } - if (i == optionsCount) - { - WARNING(true, ("Player %s selected invalid slot option %d for slot %d", myIdString, slotOptionIndex, slotIndex)); - return Crafting::CE_invalidSlotOption; - } - slotOptionIndex = i; - - if (slotOption->ingredients.size() != 1) - { - WARNING(true, ("Ingredient %d for draft schematic %s, slot %s, has ingredient count != 1", - slotOptionIndex, m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str())); - return Crafting::CE_invalidIngredientSize; - } - const ServerIntangibleObjectTemplate::SimpleIngredient & slotIngredient = slotOption->ingredients[0]; - - // see if the slot is already filled - also get how many ingredients are - // needed and how many we already have - int neededIngredientCount = slotIngredient.count; - int currentIngredientCount = 0; - if (manfSlot.ingredientType != Crafting::IT_none) - { - // the slot has something in it, see if it is full or not - for (Crafting::Ingredients::const_iterator iter = - manfSlot.ingredients.begin(); iter != manfSlot.ingredients.end(); ++iter) - { - currentIngredientCount += (*iter)->count; - } - if (currentIngredientCount >= neededIngredientCount) - { - DEBUG_WARNING(currentIngredientCount == neededIngredientCount, ( - "Player %s trying to fill filled slot %d", myIdString, slotIndex)); - WARNING_STRICT_FATAL(currentIngredientCount > neededIngredientCount, - ("HEY! Player %s trying to fill OVER filled slot %d (required = " - "%d, current = %d)", myIdString, slotIndex, neededIngredientCount, - currentIngredientCount)); - return Crafting::CE_slotFull; - } - } - int numIngredientsToAdd = neededIngredientCount - currentIngredientCount; - - TangibleObject * const ingredient = dynamic_cast(NetworkIdManager::getObjectById(ingredientId)); - if (ingredient == NULL) - { - WARNING(true, ("No object for ingredient id %s", ingredientId.getValueString().c_str())); - return Crafting::CE_invalidIngredient; - } - - // check if the ingredient is bio-linked - NetworkId bioLinkId(ingredient->getBioLink()); - if (bioLinkId != NetworkId::cms_invalid) - { - if (m_craftingComponentBioLink.get() == NetworkId::cms_invalid) - { - // this component defines the bio-link for the object - m_craftingComponentBioLink = bioLinkId; - } - else - { - return Crafting::CE_invalidBioLink; - } - } - else - m_craftingComponentBioLink = NetworkId::cms_invalid; - - // see if the ingredient is in the player's inventory - if (!owner->isIngredientInInventory(*ingredient)) - { - // if we are crafting level 3, also check the crafting station's hopper - if (getCraftingLevel() != 3 || (station != NULL && - !station->isIngredientInHopper(ingredientId))) - { - DEBUG_WARNING(true, ("Player %s chose invalid ingredient %s", myIdString, ingredientId.getValueString().c_str())); - return Crafting::CE_ingredientNotInInventory; - } - - } - - // see if the ingredient is a resource or component - ResourceContainerObject * const crate = dynamic_cast(ingredient); - if (crate != NULL) - { - // get the resource type name and class name - ResourceTypeObject const * const resource = crate->getResourceType(); - NetworkId const resourceId = resource ? resource->getNetworkId() : NetworkId::cms_invalid; - - bool slotOk = false; - - if (resource) - { - // make sure the selected slot is the right type - if (currentIngredientCount == 0) - { - if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_resourceType) - { - const std::string typeName(resource->getResourceName()); - if (typeName == slotIngredient.ingredient) - slotOk = true; - } - else if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_resourceClass) - { - ResourceClassObject const * resourceClass = &(resource->getParentClass()); - while (resourceClass != NULL) - { - const std::string className (resourceClass->getResourceClassName()); - if (className == slotIngredient.ingredient) - { - slotOk = true; - break; - } - resourceClass = resourceClass->getParent(); - } - } - } - else - { - // the resource type must be the exact one currently in the slot - if (resource->getNetworkId() == manfSlot.ingredients.front()->ingredient) - slotOk = true; - } - } - - if (slotOk) - { - // if we need more resources than we have, just empty the crate - if (crate->getQuantity() < numIngredientsToAdd) - numIngredientsToAdd = crate->getQuantity(); - - // we can put the resource in the manufacturing schematic - std::vector > sources; - if (crate->removeResource(resourceId, numIngredientsToAdd, &sources)) - { - if (currentIngredientCount == 0) - { - manfSchematic->setSlotOption(manfSlot.name, slotOptionIndex); - manfSchematic->modifySlotComplexity(manfSlot.name, slotOption->complexity); - manfSchematic->setSlotType(manfSlot.name, static_cast(slotOption->ingredientType)); - } - int count = sources.size(); - for (int i = 0; i < count; ++i) - { - manfSchematic->addSlotResource(manfSlot.name, resourceId, sources[i].second, sources[i].first); - manfSchematic->addIngredient(resourceId, sources[i].second, sources[i].first); - } - } - else - { - return Crafting::CE_cantRemoveResource; - } - } - else - { - DEBUG_WARNING(true, ("Invalid resource ingredient for draft schematic %s, slot %s, option %d", - m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), slotOptionIndex)); - return Crafting::CE_wrongResource; - } - } - else - { - if (manfSchematic->hasIngredient (ingredient->getNetworkId ())) - { - DEBUG_WARNING(true, ("Attempt to add ingredient multiple times.")); - return Crafting::CE_invalidIngredient; - } - - // see if the ingredient is a stacked loot item - // @todo: stacked loot should work the same as FactoryObject objects - if (ingredient->getScriptObject()->hasScript("object.onewayunstack")) - { - return Crafting::CE_stackedLoot; - } - - // test if the component is a factory - FactoryObject * factory = dynamic_cast(ingredient); - - // if this is an old-style factory, we can't use it directly in crafting - if (factory != NULL && !factory->getLoadContents()) - factory = NULL; - - // make sure the component isn't damaged - if (factory == NULL && ingredient->getDamageTaken() != 0 && - !ingredient->getObjVars().hasItem(OBJVAR_CRAFTING_COMPONENT_CAN_BE_DAMAGED)) - { - DEBUG_WARNING(true, ("Tried to use damaged component %s for draft schematic %s, slot %s, option %d", - ingredientId.getValueString().c_str(), - m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), - slotOptionIndex)); - return Crafting::CE_damagedComponent; - } - - // make sure the ingredient is crafted, if required - if ((slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematic || - slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematicGeneric) && - !ingredient->isCrafted()) - { - DEBUG_WARNING(true, ("Invalid component ingredient for draft schematic %s, slot %s, option %d", - m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), slotOptionIndex)); - return Crafting::CE_wrongComponent; - } - - // find the matching ingredient for the draft slot - bool slotOk = false; - if (currentIngredientCount == 0) - { - if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_item) - { - std::string tempName(Unicode::wideToNarrow(ingredient->getObjectName())); - if (tempName == slotIngredient.ingredient) - { - slotOk = true; - } - } - // for slots that require multiple non-generic components, make - // sure the component being added is crafted - else if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_templateGeneric || - ((slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_template || - slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematic || - slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematicGeneric) && - ingredient->isCrafted())) - { - std::string requiredIngredientName(slotIngredient.ingredient); - - // check the ingredient template name for every template in it's - // heirarchy - const ObjectTemplate * testTemplate = NULL; - if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_template || - slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_templateGeneric) - { - if (factory == NULL) - testTemplate = ingredient->getObjectTemplate(); - else - testTemplate = factory->getContainedObjectTemplate(); - } - else - { - const DraftSchematicObject * itemSchematic = NULL; - if (factory == NULL) - itemSchematic = DraftSchematicObject::getSchematic(ingredient->getSourceDraftSchematic()); - else - itemSchematic = DraftSchematicObject::getSchematic(factory->getDraftSchematic()); - if (itemSchematic != NULL) - testTemplate = itemSchematic->getObjectTemplate(); - } - - while (testTemplate != NULL) - { - const std::string ingredientName(testTemplate->getName()); - if (ingredientName == requiredIngredientName) - { - slotOk = true; - break; - } - else - { - // travel down the ingredient template heirarchy - testTemplate = testTemplate->getBaseTemplate(); - } - } - } - } - else - { - // the ingredient must either be from the same template, or from the - // same manufacturing schematic as the ingredient currently in the slot; - // this is a configureable setting - const Crafting::ComponentIngredient * testComponent = dynamic_cast< - const Crafting::ComponentIngredient *>(manfSlot.ingredients.front().get()); - if (testComponent != NULL) - { - if (ConfigServerGame::getCraftingComponentStrict() && - (slotOption->ingredientType != ServerIntangibleObjectTemplate::IT_templateGeneric && - slotOption->ingredientType != ServerIntangibleObjectTemplate::IT_schematicGeneric)) - { - // component from same manf schematic - if (ingredient->getCraftedId() == testComponent->ingredient) - slotOk = true; - } - else - { - // component from same template - if (factory == NULL) - { - if (ingredient->getObjectTemplateName() != NULL && - ingredient->getObjectTemplateName() == testComponent->templateName) - { - slotOk = true; - } - } - else if (factory->getContainedTemplateName() != NULL && - factory->getContainedTemplateName() == testComponent->templateName) - { - slotOk = true; - } - } - } - } - if (slotOk) - { - if (factory == NULL || factory->getCount() <= numIngredientsToAdd) - { - // adding normal component or a complete factory object - if (manfSchematic->addIngredient(*ingredient)) - { - if (manfSlot.ingredientType == Crafting::IT_none) - { - manfSchematic->setSlotType(manfSlot.name, static_cast(slotOption->ingredientType)); - manfSchematic->setSlotOption(manfSlot.name, slotOptionIndex); - manfSchematic->modifySlotComplexity(manfSlot.name, slotOption->complexity); - } - if (factory == NULL) - { - manfSchematic->addSlotComponent(manfSlot.name, *ingredient, - slotOption->ingredientType); - } - else - { - int count = factory->getCount(); - for (i = 0; i < count; ++i) - { - manfSchematic->addSlotComponent(manfSlot.name, - *factory, slotOption->ingredientType); - } - } - } - else - return Crafting::CE_cantTransferComponent; - } - else - { - // adding component(s) from a factory - if (!factory->inCraftingSession()) - { - if (!factory->startCraftingSession(*manfSchematic)) - return Crafting::CE_cantTransferComponent; - } - if (!factory->removeCraftingReferences(numIngredientsToAdd)) - { - return Crafting::CE_cantTransferComponent; - } - if (manfSlot.ingredientType == Crafting::IT_none) - { - manfSchematic->setSlotType(manfSlot.name, static_cast(slotOption->ingredientType)); - manfSchematic->setSlotOption(manfSlot.name, slotOptionIndex); - manfSchematic->modifySlotComplexity(manfSlot.name, slotOption->complexity); - } - for (i = 0; i < numIngredientsToAdd; ++i) - { - manfSchematic->addSlotComponent(manfSlot.name, *factory, - slotOption->ingredientType); - } - } - } - else - { - DEBUG_WARNING(true, ("Invalid component ingredient for draft schematic %s, slot %s, option %d", - m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), slotOptionIndex)); - return Crafting::CE_wrongComponent; - } - } - - manfSchematic->computeComplexity(); - manfSchematic->signalClientChange(); - return Crafting::CE_success; -} // PlayerObject::fillSlot - -//---------------------------------------------------------------------- - -/** - * Removes the ingredients in a schematic slot and returns them to the crafting - * tool's ingredient hopper. - * - * @param slotIndex schematic slot to empty - * @param targetContainerId the container the player wants to unload the slot into. - * If NetworkId::cms_invalid, then unload the slot into - * the same container it was loaded from. - * - * @return CE_success on success, error code if the ingredient wasn't removed - */ -Crafting::CraftingError PlayerObject::emptySlot(int slotIndex, const NetworkId & targetContainerId) -{ - const std::string & myId = getNetworkId().getValueString(); - const char * const myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return Crafting::CE_noOwner; - - if (getCraftingStage() != Crafting::CS_assembly && !m_allowEmptySlot) - { - WARNING(true, ("Player %s trying to empty slot when not in assembly stage!", myIdString)); - return Crafting::CE_notAssemblyStage; - } - - // check the draft schematic - if (m_draftSchematic.getPointer() == NULL) - { - WARNING(true, ("Player %s trying to empty slot with no draft schematic!", myIdString)); - return Crafting::CE_noDraftSchematic; - } - - // check the crafting tool - if (getCraftingTool() == NetworkId::cms_invalid) - { - WARNING(true, ("Player %s trying to empty slot with no crafting tool!", myIdString)); - return Crafting::CE_noCraftingTool; - } - TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); - if (tool == NULL) - { - WARNING(true, ("Player %s trying to empty slot with crafting tool %s, but tool is NULL!", myIdString, getCraftingTool().getValueString().c_str())); - return Crafting::CE_noCraftingTool; - } - - // get the crafting station (if any) - TangibleObject * station = dynamic_cast(getCraftingStation().getObject()); - if (station != NULL && getCraftingLevel() == 3 && station->getIngredientHopper() == NULL) - { - WARNING_STRICT_FATAL(true, ("Player %s trying to empty crafting slot near " - "a crafting station %s that has no ingredient hopper!", - owner->getNetworkId().getValueString().c_str(), - station->getNetworkId().getValueString().c_str())); - return Crafting::CE_badTargetHopper; - } - - ServerObject * const inventory = owner->getInventory(); - if (inventory == NULL) - { - WARNING (true, ("Player %s has no inventory.", myIdString)); - return Crafting::CE_noInventory; - } - - //-- if the player specified a target container, try to use that - ServerObject * targetContainer = 0; - if (targetContainerId.isValid ()) - { - if (!isNestedInContainer (targetContainerId, inventory->getNetworkId())) - { - // check worn containers, such as backpacks, but only check one level down so we don't catch the datapad - bool containerIsWorn = false; - Object const * const possibleContainer = NetworkIdManager::getObjectById (targetContainerId); - if (possibleContainer) - { - containerIsWorn = owner->isItemEquipped (*possibleContainer); - } - - // if we are crafting level 3, also check the crafting station's hopper - if (!containerIsWorn && - (getCraftingLevel() != 3 || (station != NULL && - !isNestedInContainer (targetContainerId, station->getIngredientHopper()->getNetworkId())))) - { - WARNING (true, ("Player %s attempted to empty slot into invalid container [%s].", myIdString, targetContainerId.getValueString().c_str())); - return Crafting::CE_badTargetHopper; - } - } - - targetContainer = safe_cast(NetworkIdManager::getObjectById (targetContainerId)); - - if (targetContainer == NULL) - { - WARNING (true, ("Player %s attempted to empty slot into non-existant container [%s].", myIdString, targetContainerId.getValueString ().c_str ())); - return Crafting::CE_badTargetContainer; - } - } - //-- otherwise use the container that the ingredient came from in the first place - else - { - //@todo: this needs to find the target container from which the slot was originally populated - targetContainer = inventory; - } - - // check the manufacturing schematic - ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); - if (manfSchematic == NULL) - { - WARNING(true, ("Player %s trying to empty slot with no manufacturing schematic!", myIdString)); - return Crafting::CE_noManfSchematic; - } - - if (manfSchematic->mustDestroyIngredients() && - getCraftingStage() != Crafting::CS_assembly) - { - WARNING(true, ("Player %s trying to empty slot when not in assembly stage!", myIdString)); - return Crafting::CE_notAssemblyStage; - } - - // verify the slot index - if (slotIndex < 0 || slotIndex >= manfSchematic->getSlotsCount()) - { - WARNING(true, ("Player %s trying to empty invalid slot %d", myIdString, slotIndex)); - return Crafting::CE_invalidSlot; - } - - // get the manufacturing schematic object - Crafting::IngredientSlot manfSlot; - if (!manfSchematic->getSlot(slotIndex, manfSlot, true)) - { - return Crafting::CE_invalidSlot; - } - Crafting::IngredientType ingredientType = manfSlot.ingredientType; - if (ingredientType == Crafting::IT_none || manfSlot.ingredients.empty()) - { - DEBUG_WARNING(true, ("Player %s trying to empty already empty slot %d", myIdString, slotIndex)); - return Crafting::CE_emptySlot; - } - - // get the draft schematic slot - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - if (!m_draftSchematic->getSlot(draftSlot, manfSlot.draftSlotIndex)) - { - return Crafting::CE_invalidSlot; - } - - if (ingredientType == Crafting::IT_item || ingredientType == Crafting::IT_template || - ingredientType == Crafting::IT_templateGeneric || ingredientType == Crafting::IT_schematic || - ingredientType == Crafting::IT_schematicGeneric) - { - // ingredient is a component - Crafting::Ingredients::const_iterator iter; - for (iter = manfSlot.ingredients.begin(); iter != manfSlot.ingredients.end(); - ++iter) - { - const Crafting::ComponentIngredient * const componentInfo = dynamic_cast((*iter).get()); - NOT_NULL(componentInfo); - TangibleObject * const component = manfSchematic->getComponent(*componentInfo); - if (component != NULL) - { - // move the component from the schematic to the player - if (!manfSchematic->removeIngredient(*component, *targetContainer)) - { - Unicode::String oob; - { - ProsePackage pp; - ProsePackageManagerServer::createSimpleProsePackage (*component, COMPONENT_LOST_MSG, pp); - OutOfBandPackager::pack(pp, -1, oob); - } - Chat::sendSystemMessage(*owner, Unicode::emptyString, oob); - } - // if this component is bio-linked, clear our link data - NetworkId bioLinkId(component->getBioLink()); - if (bioLinkId != NetworkId::cms_invalid && bioLinkId == m_craftingComponentBioLink.get()) - { - m_craftingComponentBioLink = NetworkId::cms_invalid; - } - } - } - } - else - { - // ingredient is a resource - VolumeContainer * const targetVolumeContainer = ContainerInterface::getVolumeContainer(*targetContainer); - if (targetVolumeContainer == NULL) - { - DEBUG_WARNING(true, ("PlayerObject::emptySlot: targetContainer %s does not have a volume container", - targetContainer->getNetworkId().getValueString().c_str())); - return Crafting::CE_badTargetContainer; - } - Crafting::Ingredients::const_iterator iter; - for (iter = manfSlot.ingredients.begin(); iter != manfSlot.ingredients.end(); - ++iter) - { - Crafting::SimpleIngredient * resource = const_cast((*iter).get()); - const NetworkId resourceId(resource->ingredient); - if (resourceId != NetworkId::cms_invalid) - { - // find a resource crate in the targetContainer containing the resourceId - ContainerIterator iter2; - for (iter2 = targetVolumeContainer->begin(); iter2 != targetVolumeContainer->end(); - ++iter2) - { - if (*iter2 != NetworkId::cms_invalid) - { - ResourceContainerObject * crate = dynamic_cast< - ResourceContainerObject *>(NetworkIdManager::getObjectById((*iter2))); - if (crate != NULL && crate->getResourceTypeId() == resourceId) - { - int emptySpace = crate->getMaxQuantity() - crate->getQuantity(); - if (emptySpace > 0) - { - if (emptySpace >= resource->count) - { - // we can put all of the resource in the crate - IGNORE_RETURN(manfSchematic->removeIngredient( - resourceId, resource->count, *crate)); - break; - } - else - { - // fill up the crate an keep looking - IGNORE_RETURN(manfSchematic->removeIngredient( - resourceId, emptySpace, *crate)); - resource->count -= emptySpace; - } - } - } - } - } - if (iter2 == targetVolumeContainer->end()) - { - // create a new crate(s) in the target container - std::string crateTemplateName; - ResourceTypeObject const * const resourceType = ServerUniverse::getInstance().getResourceTypeById(resourceId); - resourceType->getCrateTemplate(crateTemplateName); - while (resource->count > 0) - { - ServerObject * crateObject = ServerWorld::createNewObject( - crateTemplateName, *targetContainer, true); - if (crateObject == NULL) - { - // @todo: inform the player - DEBUG_WARNING(true, ("PlayerObject::emptySlot tried to " - "create a new resource crate %s in container %s but " - "failed!", crateTemplateName.c_str(), - targetContainerId.getValueString().c_str())); - return Crafting::CE_cantCreateResourceCrate; - } - ResourceContainerObject * crate = safe_cast< - ResourceContainerObject *>(crateObject); - if (crate->getMaxQuantity() >= resource->count) - { - IGNORE_RETURN(manfSchematic->removeIngredient(resourceId, - resource->count, *crate)); - resource->count = 0; - } - else - { - IGNORE_RETURN(manfSchematic->removeIngredient(resourceId, - crate->getMaxQuantity(), *crate)); - resource->count -= crate->getMaxQuantity(); - } - } - } - } - } - } - - // empty the slot - manfSchematic->clearSlot(draftSlot.name); - - manfSchematic->computeComplexity(); - manfSchematic->signalClientChange(); - - return Crafting::CE_success; -} // PlayerObject::emptySlot - -//---------------------------------------------------------------------- - -/** - * Goes from the current stage in a crafting session to the next one. - * - * @return error code - */ -int PlayerObject::goToNextCraftingStage () -{ - int result = Crafting::CR_failure; - - switch (m_craftingStage.get()) - { - case Crafting::CS_assembly: - result = startCraftingExperiment(); - break; - case Crafting::CS_experiment: - m_craftingStage = static_cast(Crafting::CS_customize); - result = Crafting::CR_success; - break; - case Crafting::CS_customize: - m_craftingStage = static_cast(Crafting::CS_finish); - result = Crafting::CR_success; - break; - case Crafting::CS_none: - case Crafting::CS_selectDraftSchematic: - case Crafting::CS_finish: - default: - break; - } - return result; -} // PlayerObject::goToNextCraftingStage - -//---------------------------------------------------------------------- - -/** - * Moves a crafting session to the experimentation phase. This only occurs if - * all non-optional slots of the draft schematic have been filled. The ingredients - * used in the schematic will be destroyed unless the draft schematic is flagged - * as non-destroying. - * - * @return returns the success state of the assembly on success, -error code on fail - */ -int PlayerObject::startCraftingExperiment () -{ - int i; - - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return -Crafting::CE_noOwner; - - std::string myId = getNetworkId().getValueString(); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - if (m_draftSchematic.getPointer() == NULL) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with invalid schematic.", myIdString)); - return -Crafting::CE_noDraftSchematic; - } - if (getCraftingTool() == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with invalid crafting tool.", myIdString)); - return -Crafting::CE_noCraftingTool; - } - - if (m_draftSchematic->getGameObjectType() == SharedObjectTemplate::GOT_data_draft_schematic_read_only) - { - return -Crafting::CE_readOnlyDraftSchematic; - } - - TangibleObject * tool = safe_cast(getCraftingTool().getObject()); - NOT_NULL(tool); - - if (!tool) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with null crafting tool [%s].", myIdString, getCraftingTool().getValueString().c_str())); - return -Crafting::CE_noCraftingTool; - } - - // check the manufacturing schematic - ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); - if (manfSchematic == NULL) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with invalid manufacture schematic.", myIdString)); - return -Crafting::CE_noManfSchematic; - } - - // make sure all the manufacturing schematic slots are filled - Crafting::IngredientSlot slot; - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - int count = manfSchematic->getSlotsCount(); - for (i = 0; i < count; ++i) - { - if (!manfSchematic->getSlot(i, slot, false)) - { - return -Crafting::CE_invalidSlot; - } - - // get the draft schematic slot - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - if (!m_draftSchematic->getSlot(draftSlot, slot.draftSlotIndex)) - return -Crafting::CE_invalidSlot; - - Crafting::IngredientType type = slot.ingredientType; - if (type == Crafting::IT_none) - { - if (!draftSlot.optional) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with empty slot #%d.", myIdString, i)); - return -Crafting::CE_emptySlotAssembly; - } - } - else - { - int currentIngredientCount = 0; - for (Crafting::Ingredients::const_iterator iter = - slot.ingredients.begin(); iter != slot.ingredients.end(); ++iter) - { - currentIngredientCount += (*iter)->count; - } - if (currentIngredientCount != draftSlot.options[static_cast(slot.draftSlotOption)].ingredients[0].count) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with partially full slot #%d.", myIdString, i)); - return -Crafting::CE_partialSlotAssembly; - } - } - } - - // remove unused optional slots from the schematic - for (i = 0; i < count;) - { - if (!manfSchematic->getSlot(i, slot, false)) - { - continue; - } - - // get the draft schematic slot - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - IGNORE_RETURN(m_draftSchematic->getSlot(draftSlot, slot.draftSlotIndex)); - - if (slot.ingredientType == Crafting::IT_none && draftSlot.optional) - { - manfSchematic->removeSlot(slot.name); - --count; - } - else - ++i; - } - - ServerObject * prototype = tool->getCraftingPrototype(); - if (prototype == NULL) - { - DEBUG_WARNING(true, ("PlayerObject::startCraftingExperiment crafting " - "tool %s has no prototype object!", - tool->getNetworkId().getValueString().c_str())); - return -Crafting::CE_noPrototype; - } - - // bio-link the prototype - if (m_craftingComponentBioLink.get() != NetworkId::cms_invalid) - safe_cast(prototype)->setBioLink(m_craftingComponentBioLink.get()); - else - safe_cast(prototype)->clearBioLink(); - - // if the tool we are using has the special crit success objvar, store that - // info on the schematic - int forceCritSuccess = 0; - if (tool->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_ASSEMBLY, forceCritSuccess)) - { - if (forceCritSuccess > 0) - manfSchematic->setObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS, forceCritSuccess); - } - - // call the trigger OnManufacturingSchematicCreation - int successState = static_cast(Crafting::CR_internalFailure); - m_experimentPoints = 0; - ScriptParams params; - params.addParam(owner->getNetworkId()); - params.addParam(prototype->getNetworkId()); - params.addParam(*manfSchematic); - params.addParam(successState); - params.addParam(m_experimentPoints.get()); - IGNORE_RETURN(manfSchematic->getScriptObject()->trigAllScripts( - Scripting::TRIG_MANUFACTURING_SCHEMATIC_CREATION, params)); - successState = params.getIntParam(3); - m_experimentPoints = params.getIntParam(4); - - if (successState == static_cast(Crafting::CR_internalFailure)) - { - // either the script crashed or we didn't even make it to the script - WARNING(true, ("PlayerObject::startCraftingExperiment failed calling OnManufacturingSchematicCreation on schematic %s (%s). Prepare for no owner for player!", - manfSchematic->getNetworkId().getValueString().c_str(), - m_draftSchematic->getObjectTemplateName())); - return successState; - } - - if (forceCritSuccess > 0) - { - // if the forced crit success count has changed, update the tool - int newForceCritSuccess = 0; - if (manfSchematic->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_SUCCESS, newForceCritSuccess)) - { - if (newForceCritSuccess != forceCritSuccess) - { - if (newForceCritSuccess > 0) - tool->setObjVarItem(OBJVAR_FORCE_CRITICAL_ASSEMBLY, newForceCritSuccess); - else - tool->removeObjVarItem(OBJVAR_FORCE_CRITICAL_ASSEMBLY); - } - } - manfSchematic->removeObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS); - } - - // important: we need to set the crafting stage here so restartCrafting - // will destroy the ingredients if we crit failed - m_craftingStage = static_cast(Crafting::CS_experiment); - - if (successState == static_cast(Crafting::CR_criticalFailure)) - { - // destroy the ingredients, restart the session at the assembly stage - IGNORE_RETURN(restartCrafting()); - m_craftingStage = static_cast(Crafting::CS_assembly); - } - else if (successState != static_cast(Crafting::CR_internalFailure) && - (getCraftingLevel() <= 1 || ((m_draftSchematic->getItemsPerContainer() == 0 || - m_craftingComponentBioLink.get() != NetworkId::cms_invalid) && - m_draftSchematic->getExperimentalAttributesCount() == 0))) - { - // if we are not near a station, we cannot experiment - m_craftingStage = static_cast(Crafting::CS_customize); - } - // if we crit failed but don't want to destroy the object, change the success - // back to crit fail to the ui will show the right thing - if (successState == static_cast(Crafting::CR_criticalFailureNoDestroy)) - { - successState = static_cast(Crafting::CR_criticalFailure); - m_craftingStage = static_cast(Crafting::CS_assembly); - } - - return successState; -} // PlayerObject::startCraftingExperiment - -//---------------------------------------------------------------------- - -/** - * Tries to experiment on a schematic attribute. - * - * @param experiments list of attributes and points assigned to them - * @param totalPoints total experimentation points used - * - * @return error code - */ -Crafting::CraftingResult PlayerObject::experiment(const std::vector & experiments, int totalPoints, int corelevel) -{ - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return Crafting::CR_internalFailure; - - std::string myId = getNetworkId().getValueString(); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // verify we are experimenting - if (m_craftingStage.get() != static_cast(Crafting::CS_experiment)) - { - DEBUG_WARNING(true, ("Player %s tried to experiment when not in " - "experimentation phase", myIdString)); - return Crafting::CR_internalFailure; - } - - // verify the points allocated - if (totalPoints < 1 || totalPoints > m_experimentPoints.get()) - { - DEBUG_WARNING(true, ("Player %s sent invalid number of experiment points " - "= %d (%d)", myIdString, totalPoints, m_experimentPoints.get() )); - return Crafting::CR_internalFailure; - } - - // verify the tool - if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation " - "with invalid schematic or crafting tool.", myIdString)); - return Crafting::CR_internalFailure; - } - TangibleObject * tool = safe_cast(getCraftingTool().getObject()); - NOT_NULL(tool); - if (!tool) - return Crafting::CR_internalFailure; - - // check the manufacturing schematic - ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); - if (manfSchematic == NULL) - { - DEBUG_WARNING(true, ("Player %s tried to experiment with invalid " - "manufacture schematic.", myIdString)); - return Crafting::CR_internalFailure; - } - const std::vector & attribNames = manfSchematic->getExperimentAttributeNames(); - - // check the test prototype - ServerObject * prototype = tool->getCraftingPrototype(); - if (prototype == NULL) - { - DEBUG_WARNING(true, ("Player %s tried to experiment with invalid test " - "prototype.", myIdString)); - return Crafting::CR_internalFailure; - } - - std::vector scriptAttributes; - std::vector scriptPoints; - - std::vector::const_iterator iter; - for (iter = experiments.begin(); iter != experiments.end(); ++iter) - { - int attributeIndex = (*iter).attributeIndex; - int points = (*iter).experimentPoints; - - // verify points - if (points <= 0) - { - DEBUG_WARNING(true, ("Player %s sent invalid experiment point count %d", - myIdString, points)); - return Crafting::CR_internalFailure; - } - - // verify attribute index - if (attributeIndex < 0 || attributeIndex >= static_cast(attribNames.size())) - { - DEBUG_WARNING(true, ("Player %s sent invalid attribute index %d", - myIdString, attributeIndex)); - return Crafting::CR_internalFailure; - } - - // set the experiment data for the index - scriptAttributes.push_back(&attribNames[static_cast(attributeIndex)]); - scriptPoints.push_back(points); - } - - m_experimentPoints = m_experimentPoints.get() - totalPoints; - - // if the tool we are using has the special crit success objvar, store that - // info on the schematic - int forceCritSuccess = 0; - if (tool->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_EXPERIMENT, forceCritSuccess)) - { - if (forceCritSuccess > 0) - manfSchematic->setObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS, forceCritSuccess); - } - - Crafting::CraftingResult experimentResult = Crafting::CR_failure; - ScriptParams params; - params.addParam(owner->getNetworkId()); - params.addParam(prototype->getNetworkId()); - params.addParam(scriptAttributes); - params.addParam(scriptPoints); - params.addParam(totalPoints); - params.addParam(static_cast(experimentResult)); - params.addParam(corelevel); - IGNORE_RETURN(manfSchematic->getScriptObject()->trigAllScripts(Scripting::TRIG_CRAFTING_EXPERIMENT, params)); - experimentResult = static_cast(params.getIntParam(5)); - - if (forceCritSuccess > 0) - { - // if the forced crit success count has changed, update the tool - int newForceCritSuccess = 0; - if (manfSchematic->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_SUCCESS, newForceCritSuccess)) - { - if (newForceCritSuccess != forceCritSuccess) - { - if (newForceCritSuccess > 0) - tool->setObjVarItem(OBJVAR_FORCE_CRITICAL_EXPERIMENT, newForceCritSuccess); - else - tool->removeObjVarItem(OBJVAR_FORCE_CRITICAL_EXPERIMENT); - } - } - manfSchematic->removeObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS); - } - - return experimentResult; -} // PlayerObject::experiment - -//---------------------------------------------------------------------- - -/** - * Sets a customization property value for the current manufacturing schematic. - * - * @param property index of the customization property - * @param value value the property - * - * @return true if the property was set, false if not - */ -bool PlayerObject::customize(int property, int value) const -{ - std::string myId = getNetworkId().getValueString(); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - if (m_craftingStage.get() != static_cast(Crafting::CS_customize)) - { - DEBUG_WARNING(true, ("Player %s tried to customize when not in " - "customization phase", myIdString)); - return false; - } - - if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Player %s tried to customize with invalid " - "schematic or crafting tool.", myIdString)); - return false; - } - - TangibleObject * tool = safe_cast(getCraftingTool().getObject()); - NOT_NULL(tool); - if (!tool) - return false; - ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); - NOT_NULL(manfSchematic); - ServerObject * prototype = tool->getCraftingPrototype(); - NOT_NULL(prototype); - - return manfSchematic->setCustomization(property, value, *prototype); -} // PlayerObject::customize - -//---------------------------------------------------------------------- - -/** - * Sets the customization data for a crafter's current manufacturing schematic. - * - * @param name the name of the object being crafted - * @param appearanceIndex index of the appearance of the object - * @param customizations customization information - * @param itemCount if making a manf schematic, the number of items the - * schematic can make - * - * @return error code - */ -int PlayerObject::setCustomizationData(const Unicode::String & name, - int appearanceIndex, const std::vector & customizations, - int itemCount) const -{ - // Strip any color codes from the text - - TextIterator textIterator(name); - Unicode::String strippedText(textIterator.getPrintableText()); - - std::string myId = getNetworkId().getValueString(); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - if (m_craftingStage.get() != static_cast(Crafting::CS_customize)) - { - DEBUG_WARNING(true, ("Player %s tried to customize when not in " - "customization phase", myIdString)); - return Crafting::CE_notCustomizeStage; - } - - if (m_draftSchematic.getPointer() == NULL) - { - DEBUG_WARNING(true, ("Player %s tried to customize with invalid schematic.", myIdString)); - return Crafting::CE_noDraftSchematic; - } - if (getCraftingTool() == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Player %s tried to customize with invalid crafting tool.", myIdString)); - return Crafting::CE_noCraftingTool; - } - - // make sure the object name is ok - if (!strippedText.empty() && (strippedText.size() >= 127 || !TextManager::isAppropriateText(strippedText))) - { - return Crafting::CE_invalidCraftedName; - } - - TangibleObject * tool = safe_cast(getCraftingTool().getObject()); - NOT_NULL(tool); - if (!tool) - { - LOG("Crafting", ("We should have FATALd in debug, but we didn't...no tool for player %s tool %s", myIdString, getCraftingTool().getValueString().c_str())); - return Crafting::CE_noCraftingTool; - } - - ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); - NOT_NULL(manfSchematic); - if (!manfSchematic) - { - LOG("Crafting", ("We should have FATALd in debug, but we didn't...no manfschem for player %s", myIdString)); - return Crafting::CE_noDraftSchematic; - } - TangibleObject * prototype = safe_cast(tool->getCraftingPrototype()); - NOT_NULL(prototype); - - if (!prototype) - { - LOG("Crafting", ("We should have FATALd in debug, but we didn't...no prototype for player %s", myIdString)); - return Crafting::CE_noCraftingTool; - } - - if (!strippedText.empty()) - { - prototype->setObjectName(strippedText); - manfSchematic->setObjectName(strippedText); - } - - manfSchematic->setCustomAppearance(appearanceIndex); - manfSchematic->setCount(std::min (1000, itemCount)); - prototype->setCustomAppearance(manfSchematic->getCustomAppearance()); - - std::vector::const_iterator iter; - for (iter = customizations.begin(); iter != customizations.end(); ++iter) - { - IGNORE_RETURN(manfSchematic->setCustomization((*iter).property, (*iter).value, *prototype)); - } - return Crafting::CE_success; -} // PlayerObject::setCustomizationData - -//---------------------------------------------------------------------- - -/** - * Creates a prototype object from the current manufacturing schematic. - * - * @param keepPrototype flag that this is a real prototype; if this is false - * we don't persist the prototype or give it to the player. - * - * @return true on success, false on fail - */ -bool PlayerObject::createPrototype(bool keepPrototype) -{ - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return false; - - std::string myId = getNetworkId().getValueString(); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // @todo: need to filter the name - - // verify we are in the final crafting phase - if (m_craftingStage.get() != static_cast(Crafting::CS_finish)) - { - DEBUG_WARNING(true, ("Player %s tried to create prototype when not in " - "final phase", myIdString)); - return false; - } - - if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Player %s tried to create prototype with invalid " - "schematic or crafting tool.", myIdString)); - return false; - } - - TangibleObject * tool = safe_cast(getCraftingTool().getObject()); - if (!tool) - { - WARNING_STRICT_FATAL(true, ("Could not find tool during create prototype phase.")); - return false; - } - TangibleObject * prototype = safe_cast(tool->getCraftingPrototype()); - if (!prototype) - { - WARNING_STRICT_FATAL(true, ("Could not find prototype during create prototype phase.")); - return false; - } - - ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); - if (manfSchematic == NULL) - { - WARNING_STRICT_FATAL(true, ("No manf schematic in crafting tool %s", - tool->getNetworkId().getValueString().c_str())); - return false; - } - - // double-check the schematic data - Crafting::IngredientSlot sourceSlot; - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - int numSlots = manfSchematic->getSlotsCount(); - for (int i = 0; i < numSlots; ++i) - { - if (!manfSchematic->getSlot(i, sourceSlot, true)) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " - "%s has invalid manf schematic: cannot get slot info for slot %d", - owner->getNetworkId().getValueString().c_str(), i)); - return false; - } - if (!m_draftSchematic->getSlot(draftSlot, sourceSlot.name)) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " - "%s has invalid manf schematic: cannot get draft info for slot %s", - owner->getNetworkId().getValueString().c_str(), - sourceSlot.name.getCanonicalRepresentation().c_str())); - return false; - } - if (sourceSlot.ingredientType == Crafting::IT_invalid || - sourceSlot.ingredientType == Crafting::IT_none) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " - "%s has invalid manf schematic: slot %d has invalid ingredient " - "type %d", owner->getNetworkId().getValueString().c_str(), i, - static_cast(sourceSlot.ingredientType))); - return false; - } - if (sourceSlot.draftSlotOption < 0 || - sourceSlot.draftSlotOption >= static_cast(draftSlot.options.size())) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " - "%s has invalid manf schematic: slot %d has invalid slot option %d", - owner->getNetworkId().getValueString().c_str(), i, - sourceSlot.draftSlotOption)); - return false; - } - if (sourceSlot.draftSlotIndex < 0) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " - "%s has invalid manf schematic: slot %d has invalid slot index %d", - owner->getNetworkId().getValueString().c_str(), i, - sourceSlot.draftSlotIndex)); - return false; - } - } - - // call the trigger OnManufactureObject on the manf schematic to allow the - // script to initialize the prototype - ScriptParams params; - params.addParam(owner->getNetworkId()); - params.addParam(prototype->getNetworkId()); - params.addParam(*manfSchematic); - params.addParam(true); - params.addParam(keepPrototype); - if (manfSchematic->getScriptObject()->trigAllScripts( - Scripting::TRIG_MANUFACTURE_OBJECT, params) == SCRIPT_OVERRIDE) - { - return false; - } - - if (!tool->addObjectToOutputSlot(*prototype, owner)) - return false; - - if (!manfSchematic->setObjectComponents(prototype, false)) - { - return false; - } - - // tell the client to delete the prototype - we will recreate it when it is - // finished being "built"; this is so that the client can be updated with - // the prototype's appearance, which may change during the crafting process - ObserveTracker::onCraftingPrototypeCreated(*owner, *prototype); - - if (keepPrototype) - { - // save the prototype to the database - prototype->persist(); - - ScriptParams craftparams; - craftparams.addParam(prototype->getNetworkId()); - craftparams.addParam(*manfSchematic); - - GameScriptObject * scriptObject = owner->getScriptObject(); - if(scriptObject) - { - scriptObject->trigAllScripts(Scripting::TRIG_CRAFTED_PROTOTYPE, craftparams); - } - } - else - { - prototype->setObjVarItem(OBJVAR_CRAFTING_FAKE_PROTOTYPE, 1); - } - - // remove the manufacturing schematic - tool->clearCraftingManufactureSchematic(); - m_experimentPoints = -1; - m_craftingStage = static_cast(Crafting::CS_none); - - // lock the tool for the time needed to create the prototype - float prototypeTime = m_draftSchematic->getPrototypeTime() * prototype->getComplexity(); - if (prototypeTime < 1.0f) - prototypeTime = 1.0f; - - // send a message to ourself that will unlock the prototype - params.clear(); - params.addParam(owner->getNetworkId(), "crafter"); - params.addParam(prototype->getNetworkId(), "prototype"); - ScriptDictionaryPtr dictionary; - getScriptObject()->makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - - if (owner->getObjVars().hasItem("crafting_qa")) - { - Client * client = owner->getClient(); - - if (client != NULL && client->isGod()) - { - Chat::sendSystemMessage(*owner, Unicode::narrowToWide("Crafting time changed due to god mode and crafting_qa objvar."), Unicode::emptyString); - prototypeTime = 1; - } - } - -// MessageToQueue::getInstance().sendMessageToJava(tool->getNetworkId(), "prototypeDone", dictionary->getSerializedData(), prototypeTime, true); - MessageToQueue::getInstance().sendMessageToJava(tool->getNetworkId(), "prototypeDone", dictionary->getSerializedData(), static_cast(prototypeTime), false); - - tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_TIME, prototypeTime); - tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_START_TIME, static_cast(ServerClock::getInstance().getGameTimeSeconds())); - tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_OBJECT, prototype->getNetworkId()); - tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_CRAFTER, owner->getNetworkId()); - - // message the object to update it's counter for the amount of time left - // before the prototype is done -// MessageToQueue::getInstance().sendMessageToC(tool->getNetworkId(), "C++updateCounter", "", 1.0f, true); - MessageToQueue::getInstance().sendMessageToC(tool->getNetworkId(), "C++updateCounter", "", 1, false); - } - else - { -// DEBUG_WARNING(true, ("Could not make script dictionary for prototype delay")); - WARNING(true, ("PlayerObject::createPrototype for player %s could not " - "make script dictionary for prototype delay", - owner->getNetworkId().getValueString().c_str())); - } - - LOG("CustomerService", ("Crafting:%s has crafted a prototype item %s", -// PlayerObject::getAccountDescription(owner->getNetworkId()).c_str(), ServerObject::getLogDescription(prototype).c_str())); - PlayerObject::getAccountDescription(owner->getNetworkId()).c_str(), - ServerObject::getLogDescription(prototype).c_str())); - - return true; -} // PlayerObject::createPrototype - -//---------------------------------------------------------------------- - -/** - * Moves the manufacturing schematic from it's temporary container to the output - * hopper of the crafting tool. - * - * @return true on success, false on fail - */ -bool PlayerObject::createManufacturingSchematic() -{ - static SlotId datapadSlotId = SlotIdManager::findSlotId(DATAPAD_SLOT_NAME); - - // if we are not near a station, we cannot make a manf schematic - if (getCraftingLevel() <= 1) - return false; - - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return false; - - // @todo: need to filter the name - - // verify we are in the final crafting phase - if (m_craftingStage.get() != static_cast(Crafting::CS_finish)) - { - WARNING(true, ("Player %s tried to create manf schematic when not in final phase", getNetworkId().getValueString().c_str ())); - return false; - } - - if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) - { - WARNING(true, ("Player %s tried to create manf schematic with invalid schematic or crafting tool.", getNetworkId().getValueString().c_str ())); - return false; - } - if (m_draftSchematic->getItemsPerContainer() == 0) - { - WARNING(true, ("Player %s tried to create manf schematic with schematic " - "%s that disallows manufacturing.", getAccountDescription().c_str(), - m_draftSchematic->getObjectTemplateName())); - return false; - } - - TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); - if (tool == NULL) - { - WARNING_STRICT_FATAL(true, ("Could not find crafting tool during create manf schematic phase.")); - return false; - } - ManufactureSchematicObject * const manfSchematic = tool->removeCraftingManufactureSchematic(); - if (manfSchematic == NULL) - { - WARNING_STRICT_FATAL(true, ("Could not find manf schematic during create manf schematic phase.")); - return false; - } - TangibleObject * const prototype = safe_cast(tool->getCraftingPrototype()); - if (prototype == NULL) - { - WARNING_STRICT_FATAL(true, ("Could not find prototype during create manf schematic phase.")); - return false; - } - - // no manufacturing a bio-linked item - if (m_craftingComponentBioLink.get() != NetworkId::cms_invalid) - { - WARNING(true, ("Player %s tried to create manf schematic while using a " - "bio-linked component %s.", getAccountDescription().c_str(), - m_craftingComponentBioLink.get().getValueString().c_str())); - return false; - } - - // double-check the schematic data - Crafting::IngredientSlot sourceSlot; - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - int numSlots = manfSchematic->getSlotsCount(); - for (int i = 0; i < numSlots; ++i) - { - if (!manfSchematic->getSlot(i, sourceSlot, true)) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " - "%s has invalid manf schematic: cannot get slot info for slot %d", - getAccountDescription().c_str(), i)); - return false; - } - if (!m_draftSchematic->getSlot(draftSlot, sourceSlot.name)) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " - "%s has invalid manf schematic: cannot get draft info for slot %s", - getAccountDescription().c_str(), - sourceSlot.name.getCanonicalRepresentation().c_str())); - return false; - } - if (sourceSlot.ingredientType == Crafting::IT_invalid || - sourceSlot.ingredientType == Crafting::IT_none) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " - "%s has invalid manf schematic: slot %d has invalid ingredient " - "type %d", getAccountDescription().c_str(), i, - static_cast(sourceSlot.ingredientType))); - return false; - } - if (sourceSlot.draftSlotOption < 0 || - sourceSlot.draftSlotOption >= static_cast(draftSlot.options.size())) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " - "%s has invalid manf schematic: slot %d has invalid slot option %d", - getAccountDescription().c_str(), i, - sourceSlot.draftSlotOption)); - return false; - } - if (sourceSlot.draftSlotIndex < 0) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " - "%s has invalid manf schematic: slot %d has invalid slot index %d", - getAccountDescription().c_str(), i, - sourceSlot.draftSlotIndex)); - return false; - } - } - - // call the trigger OnFinalizeSchematic on the manf schematic to allow the - // script to initialize it - ScriptParams params; - params.addParam(owner->getNetworkId()); - params.addParam(prototype->getNetworkId()); - params.addParam(*manfSchematic); - if (manfSchematic->getScriptObject()->trigAllScripts(Scripting::TRIG_FINALIZE_SCHEMATIC, params) == SCRIPT_OVERRIDE) - { - return false; - } - - manfSchematic->clearSlotSources(); - manfSchematic->storeObjectAttributes (*prototype); - manfSchematic->removeObjVarItem(OBJVAR_IN_CRAFTING_SESSION); - manfSchematic->persist(); - - ServerObject * const datapad = owner->getDatapad (); - if (datapad == NULL) - { - DEBUG_WARNING(true, ("Can't find datapad for player %s", getAccountDescription().c_str())); - return false; - } - - Container::ContainerErrorCode tmp = Container::CEC_Success; - if (!ContainerInterface::transferItemToVolumeContainer(*datapad, *manfSchematic, NULL, tmp)) - { - return false; - } - - tool->clearCraftingPrototype(); - m_experimentPoints = -1; - m_craftingStage = static_cast(Crafting::CS_none); - - LOG("CustomerService", ("Crafting:%s has crafted a manufacturing schematic %s", - getAccountDescription().c_str(), ServerObject::getLogDescription(manfSchematic).c_str())); - - return true; -} // PlayerObject::createManufacturingSchematic - -//---------------------------------------------------------------------- - -/** - * Restarts the crafting session with the same draft schematic as this one. - * - * @return true on success, false on fail - */ -bool PlayerObject::restartCrafting () -{ - CreatureObject * const owner = getCreatureObject(); - if (owner == NULL) - return false; - - std::string myId = getNetworkId().getValueString(); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are crafting - if (m_craftingStage.get() == static_cast(Crafting::CS_none)) - { - DEBUG_WARNING(true, ("Player %s tried to restart crafting when not crafting", - myIdString)); - return false; - } - if (m_craftingStage.get() == static_cast(Crafting::CS_finish)) - { - DEBUG_WARNING(true, ("Player %s tried to restart crafting when crafting over", - myIdString)); - return false; - } - - // verify the tool - if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation " - "with invalid schematic or crafting tool.", myIdString)); - return false; - } - TangibleObject * tool = safe_cast(getCraftingTool().getObject()); - NOT_NULL(tool); - if (!tool) - return false; - - // reset the manf schematic - ManufactureSchematicObject * manfSchematic = tool->getCraftingManufactureSchematic(); - if (manfSchematic == NULL) - { - DEBUG_WARNING(true, ("Player %s has no manufacturing schematic!", myIdString)); - return false; - } - - // if we are at the assembly stage of crafting, or the draft schematic says - // not to destroy the ingredients, put the ingredients in the schematic back - // in the player's inventory or station hopper - if (!manfSchematic->mustDestroyIngredients() || - m_craftingStage.get() == static_cast(Crafting::CS_assembly)) - { - setAllowEmptySlot(true); - int count = manfSchematic->getSlotsCount(); - // note this loop is odd because when we clear a slot it may - // actually be removed if it was optional - for (int i = 0; i < count;) - { - if (emptySlot(i, NetworkId::cms_invalid)) - { - if (count == manfSchematic->getSlotsCount()) - ++i; - else - count = manfSchematic->getSlotsCount(); - } - else - ++i; - } - setAllowEmptySlot(false); - } - else - { - manfSchematic->destroyAllIngredients(); - } - - // reset the manf schematic data - manfSchematic->reset(); - m_craftingComponentBioLink = NetworkId::cms_invalid; - - m_craftingStage = static_cast(Crafting::CS_assembly); - return true; -} // PlayerObject::restartCrafting - -//---------------------------------------------------------------------- - -/** - * Ends a crafting session. - * - * @param normalExit flag that we are exiting due to normal circumstances - */ -void PlayerObject::stopCrafting (bool normalExit) -{ - CreatureObject * const owner = getCreatureObject(); - - if (getCraftingTool().getObject() != NULL) - { - TangibleObject * tool = dynamic_cast(getCraftingTool().getObject()); - if (tool != NULL) - { - IGNORE_RETURN(tool->stopCraftingSession()); - } - - // tell scripts that the session has ended - ScriptParams params; - if (owner != NULL) - params.addParam(owner->getNetworkId()); - else - params.addParam(getNetworkId()); - if (getCurrentDraftSchematic() != NULL) - params.addParam(getCurrentDraftSchematic()->getTemplateName()); - else - params.addParam(""); - params.addParam(static_cast(m_craftingStage.get())); - params.addParam(normalExit); - IGNORE_RETURN(tool->getScriptObject()->trigAllScripts( - Scripting::TRIG_CRAFTING_DONE, params)); - } - - m_craftingStage = static_cast(Crafting::CS_none); - m_useableDraftSchematics.clear(); - m_craftingTool = CachedNetworkId::cms_cachedInvalid; - m_craftingComponentBioLink = NetworkId::cms_invalid; - - // tell the player crafting has ended - if (owner != NULL && owner->getController() != NULL) - { - (safe_cast(owner->getController()))->appendMessage( - static_cast(CM_craftingSessionEnded), 0.0f, - new MessageQueueGenericValueType(normalExit), - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } -} // PlayerObject::stopCrafting - -// ---------------------------------------------------------------------- - -void PlayerObject::getAttributes(stdvector >::fwd &data) const -{ - IntangibleObject::getAttributes(data); -} - -/** - * Sets the player's friend list - * - * @param friendList - The new player's friend list - */ -void PlayerObject::setFriendList(const StringVector &friendList) -{ - //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - Old Friend List\n")); - //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - %d\n", m_friendList.size())); - //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - New Friend List\n")); - //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - %d\n", friendList.size())); - - if (isAuthoritative()) - { - // construct lowercase, sorted friend list - size_t const size = friendList.size(); - StringVector friendListLowercaseSorted(size); - for (size_t index = 0; index < size; ++index) - { - friendListLowercaseSorted[index] = Unicode::toLower(friendList[index]); - } - - if (!friendListLowercaseSorted.empty()) - { - std::sort(friendListLowercaseSorted.begin(), friendListLowercaseSorted.end()); - } - - LOG("ChatFriendIgnoreList", ("Friend=%d, %s", friendListLowercaseSorted.size(), getAccountDescription().c_str())); - m_friendList.set(friendListLowercaseSorted); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::requestFriendList() const -{ - CreatureObject const *owner = safe_cast(ContainerInterface::getContainedByObject(*this)); - - if (owner != NULL) - { - ChatAvatarId chatAvatarId(Chat::constructChatAvatarId(*owner)); - - DEBUG_WARNING(chatAvatarId.name.empty(), ("Chat avatar id name is empty")); - - Chat::getFriendsList(chatAvatarId.getFullName()); - } -} - -/** - * Determines whether the specified name is a friend of this player - * - * @param name - The name of the friend - */ -bool PlayerObject::isFriend(const std::string &name) const -{ - std::string firstName; - size_t pos = 0; - IGNORE_RETURN(Unicode::getFirstToken(name, 0, pos, firstName)); - - return std::binary_search(m_friendList.begin(), m_friendList.end(), Unicode::toLower(firstName)); -} - -/** - * Sets the player's list of people to ignore - * - * @param ignoreList - The new player's list of people to ignore - */ -void PlayerObject::setIgnoreList(const StringVector &ignoreList) -{ - //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - Old Ignore List\n")); - //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - %d\n", m_ignoreList.size())); - //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - New Ignore List\n")); - //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - %d\n", ignoreList.size())); - - if (isAuthoritative ()) - { - // construct lowercase, sorted ignore list - size_t const size = ignoreList.size(); - StringVector ignoreListLowercaseSorted(size); - for (size_t index = 0; index < size; ++index) - { - ignoreListLowercaseSorted[index] = Unicode::toLower(ignoreList[index]); - } - - if (!ignoreListLowercaseSorted.empty()) - { - std::sort(ignoreListLowercaseSorted.begin(), ignoreListLowercaseSorted.end()); - } - - LOG("ChatFriendIgnoreList", ("Ignore=%d, %s", ignoreListLowercaseSorted.size(), getAccountDescription().c_str())); - m_ignoreList.set(ignoreListLowercaseSorted); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::requestIgnoreList() const -{ - CreatureObject const *owner = safe_cast(ContainerInterface::getContainedByObject(*this)); - - if (owner != NULL) - { - ChatAvatarId chatAvatarId(Chat::constructChatAvatarId(*owner)); - - DEBUG_WARNING(chatAvatarId.name.empty(), ("Chat avatar id name is empty")); - - Chat::getIgnoreList(chatAvatarId.getFullName()); - } -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::isIgnoring(const std::string &name) const -{ - std::string firstName; - size_t pos = 0; - IGNORE_RETURN(Unicode::getFirstToken(name, 0, pos, firstName)); - - return std::binary_search(m_ignoreList.begin(), m_ignoreList.end(), Unicode::toLower(firstName)); -} - -/** - * Sets a player's personal matchmaking id - * - * @param matchMakingId - The new match making id which describes their personality - */ -void PlayerObject::setMatchMakingPersonalProfileId(MatchMakingId const &id) -{ - if (isAuthoritative ()) - { - //DEBUG_REPORT_LOG(true, ("PlayerObject::setMatchMakingPersonalProfileId() %s %s\n", m_matchMakingPersonalProfileId.get().getDebugIntString().c_str(), id.getDebugIntString().c_str())); - - m_matchMakingPersonalProfileId = id; - } -} - -// ---------------------------------------------------------------------- - -MatchMakingId const &PlayerObject::getMatchMakingPersonalProfileId() const -{ - return m_matchMakingPersonalProfileId.get(); -} - -/** - * Sets a player's character matchmaking id - * - * @param matchMakingId - The new match making id which describes their character - */ -void PlayerObject::setMatchMakingCharacterProfileId(MatchMakingId const &id) -{ - if (isAuthoritative()) - { - m_matchMakingCharacterProfileId = id; - - //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_anonymous) ? "Yes" : "No")); - //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_helper) ? "Yes" : "No")); - //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_rolePlay) ? "Yes" : "No")); - //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_lookingForGroup) ? "Yes" : "No")); - - CreatureObject const * const owner = getCreatureObject(); - if (owner) - { - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(owner->getNetworkId()); - if (iterFind != connectedCharacterLfgData.end()) - { - bool const anonymous = id.isBitSet(MatchMakingId::B_anonymous); - if (iterFind->second.anonymous != anonymous) - ServerUniverse::setConnectedCharacterAnonymousData(owner->getNetworkId(), anonymous); - - bool const searchableByCtsSourceGalaxy = id.isBitSet(MatchMakingId::B_searchableByCtsSourceGalaxy); - if (iterFind->second.searchableByCtsSourceGalaxy != searchableByCtsSourceGalaxy) - ServerUniverse::setConnectedCharacterSearchableByCtsSourceGalaxyData(owner->getNetworkId(), searchableByCtsSourceGalaxy); - - bool const displayLocationInSearchResults = id.isBitSet(MatchMakingId::B_displayLocationInSearchResults); - if (iterFind->second.displayLocationInSearchResults != displayLocationInSearchResults) - ServerUniverse::setConnectedCharacterDisplayLocationInSearchResultsData(owner->getNetworkId(), displayLocationInSearchResults); - - BitArray characterInterests = iterFind->second.characterInterests; - - if (id.isBitSet(MatchMakingId::B_lookingForGroup)) - LfgDataTable::setBit("lfg", characterInterests); - else - LfgDataTable::clearBit("lfg", characterInterests); - - if (id.isBitSet(MatchMakingId::B_helper)) - LfgDataTable::setBit("helper", characterInterests); - else - LfgDataTable::clearBit("helper", characterInterests); - - if (id.isBitSet(MatchMakingId::B_rolePlay)) - LfgDataTable::setBit("rp", characterInterests); - else - LfgDataTable::clearBit("rp", characterInterests); - - if (id.isBitSet(MatchMakingId::B_lookingForWork)) - LfgDataTable::setBit("lfw", characterInterests); - else - LfgDataTable::clearBit("lfw", characterInterests); - - if (iterFind->second.characterInterests != characterInterests) - ServerUniverse::setConnectedCharacterInterestsData(owner->getNetworkId(), characterInterests); - } - } - } -} - -MatchMakingId const &PlayerObject::getMatchMakingCharacterProfileId() const -{ - return m_matchMakingCharacterProfileId.get(); -} - -/** -* Toggles the player's SearchableByCtsSourceGalaxy status. -*/ -void PlayerObject::toggleSearchableByCtsSourceGalaxy() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_searchableByCtsSourceGalaxy); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -/** -* Toggles the player's DisplayLocationInSearchResults status. -*/ -void PlayerObject::toggleDisplayLocationInSearchResults() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_displayLocationInSearchResults); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -/** - * Toggles the player's anonymous status. - */ -void PlayerObject::toggleAnonymous() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_anonymous); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -/** - * Toggles the player's helper status. - */ -void PlayerObject::toggleHelper() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_helper); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -/** - * Toggles the player's roleplay status. - */ -void PlayerObject::toggleRolePlay() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_rolePlay); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -// ---------------------------------------------------------------------- -bool PlayerObject::isLookingForGroup() const -{ - return m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_lookingForGroup); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setLookingForGroup(bool const lookingForGroup) -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.resetBit(MatchMakingId::B_lookingForGroup); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -/** - * Toggles the player's looking for group status. - */ -void PlayerObject::toggleLookingForGroup() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_lookingForGroup); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -/** - * Returns the player's away from keyboard status. - */ -bool PlayerObject::isAwayFromKeyBoard() const -{ - return m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_awayFromKeyBoard); -} - -/** - * Toggles the player's away from keyboard status. - */ -void PlayerObject::toggleAwayFromKeyBoard() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_awayFromKeyBoard); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -/** - * Toggles the player's display of their faction rank. - */ -void PlayerObject::toggleDisplayingFactionRank() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_displayingFactionRank); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - - -// ---------------------------------------------------------------------- - -void PlayerObject::setLinkDead(bool const linkDead) -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - if (linkDead) - { - matchMakingId.setBit(MatchMakingId::B_linkDead); - } - else - { - matchMakingId.resetBit(MatchMakingId::B_linkDead); - } - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::getLinkDead() const -{ - MatchMakingId const matchMakingId(m_matchMakingCharacterProfileId.get()); - return matchMakingId.isBitSet(MatchMakingId::B_linkDead); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::adjustLotCount(int adjustment) -{ - CreatureObject * const owner = getCreatureObject(); - if (!owner) - return false; - - if (isAuthoritative()) - { - if (adjustment > 0 && - (m_accountNumLots.get() + adjustment) > (ConfigServerGame::getMaxLotsPerAccount() + m_accountMaxLotsAdjustment.get())) - { - DEBUG_REPORT_LOG(true,("Account %lu is not allowed to use any more lots. (Already has %i, limit is %i, tried to use %i more.)\n", - m_stationId.get(), m_accountNumLots.get(), ConfigServerGame::getMaxLotsPerAccount() + m_accountMaxLotsAdjustment.get(), adjustment)); - return false; - } - else - { - m_accountNumLots = m_accountNumLots.get() + adjustment; - // make sure the number of used lot doesn't go below 0, because - // it means we would be giving the player extra lots - if (m_accountNumLots.get() < 0) - m_accountNumLots = 0; - - // if no longer over the lot limit, remove lot over limit restriction - if (m_accountNumLots.get() <= owner->getMaxNumberOfLots()) - { - m_accountNumLotsOverLimitSpam = 0; - owner->removeObjVarItem("lotOverlimit"); - } - - return true; - } - } - else - { - owner->sendControllerMessageToAuthServer(CM_adjustLotCount, new MessageQueueGenericValueType(adjustment)); - return true; - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setTitle(std::string const &title) -{ - if (isAuthoritative()) - { - // Make sure the skill title requested is valid - if (title == "city_gcw_region_defender") - { - std::pair > const & cityGcwDefenderRegionInfo = getCityGcwDefenderRegionInfo(); - if (!cityGcwDefenderRegionInfo.first.empty() && cityGcwDefenderRegionInfo.second.second) - { - if (title != m_skillTitle.get()) - m_skillTitle = title; - } - } - else if (title == "guild_gcw_region_defender") - { - std::pair > const & guildGcwDefenderRegionInfo = getGuildGcwDefenderRegionInfo(); - if (!guildGcwDefenderRegionInfo.first.empty() && guildGcwDefenderRegionInfo.second.second) - { - if (title != m_skillTitle.get()) - m_skillTitle = title; - } - } - else if (title.empty() || (title == "citizenship") || (SkillManager::getInstance().getSkill(title) != NULL) || (CollectionsDataTable::isASlotTitle(title) != NULL) || (CollectionsDataTable::isACollectionTitle(title) != NULL) || (CollectionsDataTable::isAPageTitle(title) != NULL) || (GuildRankDataTable::isARankTitle(title) != NULL) || (CitizenRankDataTable::isARankTitle(title) != NULL)) - { - if (title != m_skillTitle.get()) - m_skillTitle = title; - } - else - { - WARNING(true, ("The player is trying to set a title that does not exist in the SkillManager or the CollectionsDataTable or the GuildRankDataTable or the CitizenRankDataTable: [%s]", title.c_str())); - } - } -} - -// ---------------------------------------------------------------------- - -std::string const &PlayerObject::getTitle() const -{ - return m_skillTitle.get(); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setSpokenLanguage(int const languageId) -{ - if (isAuthoritative() && GameLanguageManager::isLanguageValid(languageId)) - { - m_spokenLanguage = languageId; - } -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getSpokenLanguage() const -{ - return m_spokenLanguage.get(); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::isIgnoring(NetworkId const &target, NetworkId const &source) -{ - std::string const &sourceName = NameManager::getInstance().getPlayerName(source); - if (!sourceName.empty()) - { - Object const * const o = NetworkIdManager::getObjectById(target); - - if (o) - { - ServerObject const * const so = o->asServerObject(); - if (so) - { - CreatureObject const * const co = so->asCreatureObject(); - if (co) - { - PlayerObject const * const targetPlayerObject = PlayerCreatureController::getPlayerObject(co); - if (targetPlayerObject) - return targetPlayerObject->isIgnoring(sourceName); - } - } - } - } - - return false; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setMaxForcePower(int value) -{ - if (isAuthoritative()) - { - if (value < 0) - value = 0; - m_maxForcePower = value; - if (m_forcePower.get() > value) - m_forcePower = value; - } - else - { - sendControllerMessageToAuthServer(CM_setMaxForcePower, - new MessageQueueGenericValueType(value)); - } -} - -//---------------------------------------------------------------------- - -void PlayerObject::setForcePower(int value) -{ - if (isAuthoritative()) - { - if (value < 0) - value = 0; - else if (value > m_maxForcePower.get()) - value = m_maxForcePower.get(); - m_forcePower = value; - } - else - { - sendControllerMessageToAuthServer(CM_setForcePower, - new MessageQueueGenericValueType(value)); - } -} - -//---------------------------------------------------------------------- - -void PlayerObject::setForcePowerRegenRate(float value) -{ - if ((isJedi() == 0) && (getMaxForcePower() == 0)) - return; - - if (isAuthoritative()) - { - if (value < ConfigServerGame::getMinForcePowerRegenRate()) - value = ConfigServerGame::getMinForcePowerRegenRate(); - - m_forceRegenRate = value; - } - else - { - sendControllerMessageToAuthServer(CM_setForceRegenRate, - new MessageQueueGenericValueType(value)); - } -} - -//---------------------------------------------------------------------- - -void PlayerObject::regenerateForcePower(float time) -{ - int forcePower = getForcePower(); - if (forcePower < getMaxForcePower()) - { - setForcePower(forcePower + getForcePowerRegen(time)); - } -} - -//---------------------------------------------------------------------- - -/** - * Returns the amount of force power regenerated for a given timeslice. - * - * @param time amount of time that has passed - * - * @return the amount of force power regenerated - */ -int PlayerObject::getForcePowerRegen(float time) -{ - // make sure we are force sensitive - if ((isJedi() == 0) && (getMaxForcePower() == 0)) - return 0; - - if (time <= 0) - { - WARNING(true, ("PlayerObject::getForcePowerRegen called for player %s " - "with time %f <= 0", getAccountDescription().c_str(), time)); - return 0; - } - - // double-check the regen rate - float minRate = ConfigServerGame::getMinForcePowerRegenRate(); - if (minRate <= 0) - { - WARNING_STRICT_FATAL(true, ("PlayerObject::getForcePowerRegen: min regen " - "rate = %f", minRate)); - minRate = 0.1f; - } - float rate = getForcePowerRegenRate(); - if (rate < minRate) - { - WARNING(true, ("PlayerObject::getForcePowerRegen called for player %s " - "with regen rate %f < min rate %f", getAccountDescription().c_str(), - rate, minRate)); - setForcePowerRegenRate(minRate); - rate = minRate; - } - - float regenValue = 0; - - // compute the amount of regen power accumulated; if it is over the threshold, - // we regenerate - float newValue = m_forceRegenValue.get() + rate * time; - if (newValue > ConfigServerGame::getRegenThreshold()) - { - regenValue = static_cast(floor(newValue)); - newValue -= regenValue; - - } - m_forceRegenValue = newValue; - - return static_cast(regenValue); -} // PlayerObject::getForcePowerRegen - -//---------------------------------------------------------------------- - -/** - * Grant a Jedi slot to this account. (Calling this function more than - * once will not create multiple Jedi slots.) - * NOTE: Not guaranteed to succeed, because it depends on a connection to - * a LoginServer, which is not guaranteed to be up. Call this function - * again if you don't get addJediToAccountAck() in a reasonable amount of time. - */ -void PlayerObject::addJediToAccount() const -{ - const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (owner) - { - LOG("CustomerService", ("Jedi: Requesting extra character slot for player %s", getAccountDescription().c_str())); - LoginUpgradeAccountMessage const luam(LoginUpgradeAccountMessage::UT_addJedi,m_stationId.get(),owner->getNetworkId(),getNetworkId(),"C++JediAdded","",false); - GameServer::getInstance().sendToCentralServer(luam); - } -} - -// ---------------------------------------------------------------------- - -/** - * Acknowledgement to addJediToAccount(). Until this function is called, - * it is not guaranteed that the account is enabled for Jedi. - */ -void PlayerObject::addJediToAccountAck() const -{ - CreatureObject * owner = const_cast(safe_cast< - const CreatureObject *>(ContainerInterface::getContainedByObject(*this))); - if (owner) - { - LOG("CustomerService", ("Jedi: Got extra character slot ack for player %s", getAccountDescription().c_str())); - owner->addJediToAccountAck(); - } -} - -// ---------------------------------------------------------------------- - -/** - * Flags that this character is spectral in the account database. Not - * guaranteed -- repeat the call if makeSpectralOnAccountAck() is not called. - */ -void PlayerObject::makeSpectralOnAccount() const -{ - const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (owner) - { - LoginUpgradeAccountMessage const luam(LoginUpgradeAccountMessage::UT_setSpectral,m_stationId.get(),owner->getNetworkId(), getNetworkId(),"C++SpectralSet","",false); - GameServer::getInstance().sendToCentralServer(luam); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::makeSpectralOnAccountAck() const -{ - const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (owner) - { - Chat::sendSystemMessage(*owner,Unicode::narrowToWide("Character marked as spectral in the login database."),Unicode::String()); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::handleCMessageTo(const MessageToPayload &message) -{ - if (message.getMethod() == "C++JediAdded") - { - addJediToAccountAck(); - } - else if (message.getMethod() == "C++SpectralSet") - { - makeSpectralOnAccountAck(); - } - else if (message.getMethod() == "C++ClearTheater") - { - clearTheater(); - } - else if (message.getMethod() == "C++TheaterDestroyed") - { - const std::vector & data = message.getPackedDataVector(); - std::string theaterIdString(data.begin(), data.end()); - if (theaterIdString == m_theaterId.get().getValueString()) - m_theaterId = NetworkId::cms_invalid; - } - else if (message.getMethod() == "C++RecalculateGcwRating") - { - m_gcwRatingActualCalcTime = 0; - handleRecalculateGcwRating(); - } - else if (message.getMethod() == "C++updateConnectedCharacterLfgData") - { - CreatureObject * const owner = getCreatureObject(); - if (m_sessionStartPlayTime.get() != 0) - { - if (owner) - { - // check for changes to the player's GCW Region information, and update if necessary; must be - // called first as it updates information that is used later by other stuff in this function - updateGcwRegionInfo(); - - { - LfgCharacterData lfgCharacterData; - owner->getLfgCharacterData(lfgCharacterData); - - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFindLfg = connectedCharacterLfgData.find(owner->getNetworkId()); - if ((iterFindLfg == connectedCharacterLfgData.end()) || (iterFindLfg->second != lfgCharacterData)) - ServerUniverse::setConnectedCharacterLfgData(owner->getNetworkId(), lfgCharacterData); - - // grant GCW factional presence score - if (!lfgCharacterData.locationFactionalPresenceGcwRegion.empty()) - grantGcwFactionalPresenceScore(lfgCharacterData.locationFactionalPresenceGcwRegion, *this, *owner); - } - - { - BiographyManager::requestBiography(owner->getNetworkId(), NULL); - } - - bool needsTitleCheck = false; - - // if the character is a guild member (or just sponsored), make sure the guild member - // profession and level matches the actual profession and level of the character - - // also check to see if the guild member rank has changed, and if so, update the guild member rank information - { - int guildId = owner->getGuildId(); - bool const isGuildMember = (guildId != 0); - - // if character is not a guild member, see if character has been sponsored for guild membership - if (guildId == 0) - { - guildId = GuildInterface::getGuildIdForSponsored(owner->getNetworkId()); - - // no longer a guild member, so make sure guild rank is empty - if (!m_guildRank.get().empty()) - { - setGuildRank(BitArray()); - - // force a title check to make sure the character isn't - // using a guild rank title he is no longer entitled to - needsTitleCheck = true; - } - } - - if (guildId > 0) - { - GuildMemberInfo const * const guildMemberInfo = GuildInterface::getGuildMemberInfo(guildId, owner->getNetworkId()); - if (guildMemberInfo) - { - std::string const & professionSkillTemplate = getSkillTemplate(); - bool const professionSkillTemplateDiffers = (!professionSkillTemplate.empty() && (guildMemberInfo->m_professionSkillTemplate != professionSkillTemplate)); - - int const level = owner->getLevel(); - bool const levelDifers = ((level > 0) && (guildMemberInfo->m_level != level)); - - if (professionSkillTemplateDiffers || levelDifers) - { - GuildInterface::setGuildMemberProfessionInfo(guildId, owner->getNetworkId(), (professionSkillTemplateDiffers ? professionSkillTemplate : guildMemberInfo->m_professionSkillTemplate), (levelDifers ? level : guildMemberInfo->m_level)); - } - - // check to see if guild rank has changed - if (isGuildMember && (m_guildRank.get() != guildMemberInfo->m_rank)) - { - setGuildRank(guildMemberInfo->m_rank); - - // force a title check to make sure the character isn't - // using a guild rank title he is no longer entitled to - needsTitleCheck = true; - } - } - } - } - - // if the character is a citizen, make sure the citizen profession and - // level matches the actual profession and level of the character - - // also check to see if the citizen rank has changed, and if so, update the citizen rank information - { - std::vector const & cityIds = CityInterface::getCitizenOfCityId(owner->getNetworkId()); - CitizenInfo const * const citizenInfo = (!cityIds.empty() ? CityInterface::getCitizenInfo(cityIds.front(), owner->getNetworkId()) : NULL); - if (!citizenInfo) - { - // not a citizen, so make sure the citizen rank is empty - if (!m_citizenRank.get().empty()) - { - setCitizenRank(BitArray()); - - // force a title check to make sure the character isn't - // using a citizen rank title he is no longer entitled to - needsTitleCheck = true; - } - } - else - { - std::string const & professionSkillTemplate = getSkillTemplate(); - bool const professionSkillTemplateDiffers = (!professionSkillTemplate.empty() && (citizenInfo->m_citizenProfessionSkillTemplate != professionSkillTemplate)); - - int const level = owner->getLevel(); - bool const levelDifers = ((level > 0) && (citizenInfo->m_citizenLevel != level)); - - if (professionSkillTemplateDiffers || levelDifers) - { - CityInterface::setCitizenProfessionInfo(cityIds.front(), owner->getNetworkId(), (professionSkillTemplateDiffers ? professionSkillTemplate : citizenInfo->m_citizenProfessionSkillTemplate), (levelDifers ? level : citizenInfo->m_citizenLevel)); - } - - // check to see if citizen rank has changed - if (m_citizenRank.get() != citizenInfo->m_citizenRank) - { - setCitizenRank(citizenInfo->m_citizenRank); - - // force a title check to make sure the character isn't - // using a citizen rank title he is no longer entitled to - needsTitleCheck = true; - } - } - } - - // if necessary, force a title check to make sure the character isn't - // using a guild or citizen rank title he is no longer entitled to - if (needsTitleCheck) - { - MessageToQueue::getInstance().sendMessageToC(owner->getNetworkId(), - "C++CheckCharacterTitle", "", 5, false); - } - - // check for changes to the player's citizenship information, and update if necessary - updateCitizenshipInfo(); - - // check for changes to the player's GCW Region Defender information, and update if necessary - updateGcwDefenderRegionInfo(); - - // check for update to the player's PGC rating information - PgcRatingInfo const * const pgcRatingInfo = CityInterface::getPgcRating(owner->getNetworkId()); - if (pgcRatingInfo) - { - if (m_pgcRatingCount.get() != pgcRatingInfo->m_ratingCount) - { - m_pgcRatingCount.set(pgcRatingInfo->m_ratingCount); - } - - if (m_pgcRatingTotal.get() != pgcRatingInfo->m_ratingTotal) - { - m_pgcRatingTotal.set(pgcRatingInfo->m_ratingTotal); - } - - if (m_pgcLastRatingTime.get() != pgcRatingInfo->m_lastRatingTime) - { - m_pgcLastRatingTime.set(pgcRatingInfo->m_lastRatingTime); - } - } - } - - // check/set the character's proper "character age" title - checkAndSetCharacterAgeTitle(*this, false); - } - - // check to see if the character needs to get (delay) flagged as enabled/disabled for guild war - // - // check to see if the guild member's guild war pvp status has changed, and if so, set the - // delay time to start counting down to when the guild war pvp status will get changed - if (owner) - { - if (owner->getTimeToUpdateGuildWarPvpStatus()) - { - if (ServerClock::getInstance().getGameTimeSeconds() > owner->getTimeToUpdateGuildWarPvpStatus()) - owner->setGuildWarEnabled(GuildInterface::getGuildMemberGuildWarEnabled(owner->getGuildId(), owner->getNetworkId())); - } - else if (owner->getGuildId()) - { - // see if guild war pvp status has changed, and if yes, start countdown timer to change the status - if (GuildInterface::getGuildMemberGuildWarEnabled(owner->getGuildId(), owner->getNetworkId()) != owner->getGuildWarEnabled()) - owner->setTimeToUpdateGuildWarPvpStatus(ServerClock::getInstance().getGameTimeSeconds() + static_cast(ConfigServerGame::getPvpGuildWarExemptionExclusiveDelaySeconds())); - } - else if (owner->getGuildWarEnabled()) - { - // not in a guild, so should be guild war pvp disabled - owner->setGuildWarEnabled(false); - } - } - - // check for over lot limit condition - setAccountNumLotsOverLimitSpam(); - } - else if (message.getMethod() == "C++RequestChatFriendsList") - { - requestFriendList(); - } - else if (message.getMethod() == "C++RequestChatIgnoreList") - { - requestIgnoreList(); - } - else - { - IntangibleObject::handleCMessageTo(message); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::endBaselines() -{ - IntangibleObject::endBaselines(); - - const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); - - if (owner != NULL) - { - SharedCreatureObjectTemplate::Species const species = owner->getSpecies(); - setSpokenLanguage(GameLanguageManager::getStartingLanguage(species)); - -// if (owner->isAuthoritative() && ServerUniverse::getInstance().getXpManager() != NULL) -// { -// // get any xp we earned while offline -// ServerUniverse::getInstance().getXpManager()->requestXp(*this); -// } - } - - // check for empty force values from the db - if (m_maxForcePower.get() < 0) - m_maxForcePower = 0; - if (m_forcePower.get() < 0) - m_forcePower = 0; - if (m_forceRegenRate.get() < 0) - m_forceRegenRate = 0; - - if (isAuthoritative()) - { - GroupWaypointBuilder::updateGroupWaypoints(*this, true); - - // calculate rank values when loaded for the first time from DB - Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); - m_currentGcwRank = pvpRankInfo.rank; - - if (pvpRankInfo.rank > 0) - { - m_currentGcwRankProgress = static_cast(std::min(static_cast(m_currentGcwRating.get()), pvpRankInfo.maxRating) - pvpRankInfo.minRating) * 100.0f / static_cast(pvpRankInfo.maxRating - pvpRankInfo.minRating + 1); - } - else - { - m_currentGcwRankProgress = 0.0f; - } - - m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; - m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; - - // depersist chat statistics - int temp; - DynamicVariableList const & objVars = getObjVars(); - if (objVars.getItem(OBJVAR_CHAT_SPAM_TIME_END_INTERVAL, temp)) - { - m_chatSpamTimeEndInterval = temp; - - if (objVars.getItem(OBJVAR_CHAT_SPAM_SPATIAL, temp)) - m_chatSpamSpatialNumCharacters = temp; - else - m_chatSpamSpatialNumCharacters = 0; - - if (objVars.getItem(OBJVAR_CHAT_SPAM_NON_SPATIAL, temp)) - m_chatSpamNonSpatialNumCharacters = temp; - else - m_chatSpamNonSpatialNumCharacters = 0; - - m_chatSpamNextTimeToSyncWithChatServer = 0; - } - else - { - m_chatSpamTimeEndInterval = static_cast(::time(NULL)) + (ConfigServerGame::getChatSpamLimiterIntervalMinutes() * 60); - m_chatSpamSpatialNumCharacters = 0; - m_chatSpamNonSpatialNumCharacters = 0; - m_chatSpamNextTimeToSyncWithChatServer = 0; - } - - // depersist privileged title - if (objVars.getItem(OBJVAR_PRIVILEGED_TITLE, temp)) - m_privledgedTitle.set(static_cast(temp)); - else - m_privledgedTitle.set(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)); - - // depersist squelch info - m_squelchedById = NetworkId::cms_invalid; - m_squelchedByName = std::string(); - m_squelchExpireTime = 0; - - NetworkId tempNetworkId; - std::string tempString; - if ((objVars.getItem(OBJVAR_SQUELCH_ID, tempNetworkId)) && (objVars.getItem(OBJVAR_SQUELCH_NAME, tempString)) && (objVars.getItem(OBJVAR_SQUELCH_EXPIRE, temp))) - { - if (tempNetworkId.isValid()) - { - if (temp < 0) - { - m_squelchedById = tempNetworkId; - m_squelchedByName = tempString; - m_squelchExpireTime = -1; - } - else if (temp > 0) - { - int const gameTimeNow = static_cast(ServerClock::getInstance().getGameTimeSeconds()); - if (gameTimeNow < temp) - { - m_squelchedById = tempNetworkId; - m_squelchedByName = tempString; - m_squelchExpireTime = static_cast(::time(NULL)) + (temp - gameTimeNow); - } - } - } - } - - // remove expired GCW contribution - { - DynamicVariableList::NestedList const gcwContribution(getObjVars(), "gcwContributionTracking"); - if (!gcwContribution.empty()) - { - int const timeExpired = static_cast(::time(NULL)) - (60 * 60 * 24 * 30); // 30 days - std::list gcwContributionToRemove; - int timeLastContributed; - for (DynamicVariableList::NestedList::const_iterator i = gcwContribution.begin(); i != gcwContribution.end(); ++i) - { - if (!Pvp::getGcwScoreCategory(i.getName()) || !i.getValue(timeLastContributed) || (timeLastContributed < timeExpired)) - gcwContributionToRemove.push_back(std::string("gcwContributionTracking.") + i.getName()); - } - - if (!gcwContributionToRemove.empty()) - { - for (std::list::const_iterator iterRemove = gcwContributionToRemove.begin(); iterRemove != gcwContributionToRemove.end(); ++iterRemove) - removeObjVarItem(*iterRemove); - } - } - } - - // check/set the character's proper "character age" title (age may/will changed while the character was logged out) - checkAndSetCharacterAgeTitle(*this, true); - - // start timer to periodically update logged in character global data - MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++updateConnectedCharacterLfgData", std::string(), 60); - } -} - -//----------------------------------------------------------------------- - -void PlayerObject::onLoadedFromDatabase() -{ - IntangibleObject::onLoadedFromDatabase(); - - // clear any deprecated quests - { - static std::vector deprecatedQuests; - for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) - { - if (!QuestManager::getQuest(i->first)) - deprecatedQuests.push_back(i->first); - } - - for (std::vector::const_iterator oldQuest=deprecatedQuests.begin(); oldQuest!=deprecatedQuests.end(); ++oldQuest) - questClearQuest(*oldQuest); - - deprecatedQuests.clear(); - } - CreatureObject * const owner = getCreatureObject(); - if(owner && owner->isInitialized()) - { - owner->fixupPersistentBuffsAfterLoading(); - owner->fixupLevelXpAfterLoading(); - } -} - -//----------------------------------------------------------------------- - -Waypoint const PlayerObject::createWaypoint(const Location & location, bool ignoreLimits) -{ - float const maxSaneCoordinate = 100000; - Vector const & where = location.getCoordinates(); - if ((where.x < -maxSaneCoordinate) || - (where.x > maxSaneCoordinate) || - (where.y < -maxSaneCoordinate) || - (where.y > maxSaneCoordinate) || - (where.z < -maxSaneCoordinate) || - (where.z > maxSaneCoordinate)) - { - WARNING(true,("INSANE_WAYPOINT_COORDINATES: PlayerObject %s attempted to create a waypoint with coordinates that were way out of range", getNetworkId().getValueString().c_str())); - return Waypoint(); - } - - if (ignoreLimits || m_waypoints.size() < static_cast(ConfigServerGame::getMaxWaypointsPerCharacter())) - { - Waypoint waypoint(ObjectIdManager::getNewObjectId()); - waypoint.setLocation(location); - m_waypoints.set(waypoint.getNetworkId(), waypoint); - Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(waypoint.getNetworkId()); - if(f != m_waypoints.end()) - { - Waypoint & w = const_cast(f->second); - m_callback->connect(w.getChangeNotification(), *this, &PlayerObject::onWaypointChanged); - - // call TRIG_WAYPOINT_CREATED - CreatureObject * const owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - ScriptParams params; - params.addParam(w.getNetworkId()); - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_WAYPOINT_CREATED, params)); - } - } - - // set a reasonable default color (the caller can change it) - if (strncmp("space_",location.getSceneId(),6)==0) - w.setColor(Waypoint::Space); - else - w.setColor(Waypoint::Blue); - - return w; - } - } - - return Waypoint(); -} - -//----------------------------------------------------------------------- - -Waypoint const PlayerObject::createOrUpdateReusableWaypoint(const Location & location, const std::string & objvarTrackingName, const Unicode::String & waypointNameIfCreated, int waypointColorIfCreated /*= -1*/) -{ - const std::string objvarName = std::string("reuseableWp.") + objvarTrackingName; - const DynamicVariableList & objvars = getObjVars(); - NetworkId waypointId; - bool newWpCreated = false; - if (!objvars.hasItem(objvarName) || (objvars.getType(objvarName) != DynamicVariable::NETWORK_ID)) - { - // create a new waypoint - Waypoint waypoint(createWaypoint(location, true)); - newWpCreated = true; - waypointId = waypoint.getNetworkId(); - setObjVarItem(objvarName, waypointId); - } - else - { - objvars.getItem(objvarName, waypointId); - - // find the existing waypoint in the datapad - std::vector waypointsInDatapad; - getWaypointsInDatapad(waypointsInDatapad); - if(std::find(waypointsInDatapad.begin(), waypointsInDatapad.end(), waypointId) == waypointsInDatapad.end()) - { - // original waypoint has been destroyed, create a new one - Waypoint waypoint(createWaypoint(location, true)); - newWpCreated = true; - waypointId = waypoint.getNetworkId(); - setObjVarItem(objvarName, waypointId); - } - } - - if (waypointId != NetworkId::cms_invalid) - { - Waypoint waypoint = Waypoint::getWaypointById(waypointId); - waypoint.setActive(true); - waypoint.setLocation(location); - - if (newWpCreated) - { - if (!waypointNameIfCreated.empty()) - waypoint.setName(waypointNameIfCreated); - - if ((waypointColorIfCreated >= 0) && (waypointColorIfCreated < static_cast(Waypoint::NumColors))) - waypoint.setColor(static_cast(waypointColorIfCreated)); - } - - return waypoint; - } - - return Waypoint(); -} - -//----------------------------------------------------------------------- - -void PlayerObject::destroyWaypoint(const NetworkId & id) -{ - // call TRIG_WAYPOINT_DESTROYED - Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(id); - if(f != m_waypoints.end()) - { - Waypoint & w = const_cast(f->second); - CreatureObject * const owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - ScriptParams params; - params.addParam(w.getNetworkId()); - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_WAYPOINT_DESTROYED, params)); - } - } - } - m_waypoints.erase(id); -} - -//----------------------------------------------------------------------- - -void PlayerObject::onWaypointChanged(const Waypoint & waypointData) -{ - Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(waypointData.getNetworkId()); - if(f != m_waypoints.end()) - { - if(isAuthoritative()) - m_waypoints.set(waypointData.getNetworkId(), waypointData); - } -} - -//----------------------------------------------------------------------- - -void PlayerObject::onWaypointCreated(const NetworkId &, const Waypoint & w) -{ - m_callback->connect(const_cast(w).getChangeNotification(), *this, &PlayerObject::onWaypointChanged); - GroupWaypointBuilder::updateGroupWaypoints(*this, true); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::onWaypointSet(NetworkId const &, Waypoint const &, Waypoint const &) -{ - GroupWaypointBuilder::updateGroupWaypoints(*this, true); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::onWaypointRemoved(NetworkId const &, Waypoint const &) -{ - GroupWaypointBuilder::updateGroupWaypoints(*this, true); -} - -//----------------------------------------------------------------------- - -Waypoint & PlayerObject::getWaypoint(const NetworkId & id) -{ - Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(id); - if(f != m_waypoints.end()) - { - return const_cast(f->second); - } - - static const Waypoint empty; - static Waypoint notFound; - notFound = empty; - return notFound; -} - -//----------------------------------------------------------------------- - -void PlayerObject::getWaypointsInDatapad(std::vector & target) -{ - Archive::AutoDeltaMap::const_iterator i; - for(i = m_waypoints.begin(); i != m_waypoints.end(); ++i) - { - target.push_back(i->second.getNetworkId()); - } -} - -//----------------------------------------------------------------------- - -void PlayerObject::getWaypointAttributes(const NetworkId & waypointId, ServerObject::AttributeVector & data) -{ - CreatureObject * const owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(waypointId); - if(f != m_waypoints.end()) - { - if (script->hasTrigger (Scripting::TRIG_WAYPOINT_ON_GET_ATTRIBUTES)) - { - static const int MAX_ATTRIBS = 20; - - // allow scripts to add attribute data to the vector - static std::vector names (MAX_ATTRIBS, static_cast(0)); - static std::vector attribs (MAX_ATTRIBS, static_cast(0)); - - //-- clear the vectors - names.clear (); - attribs.clear (); - names.resize (MAX_ATTRIBS, static_cast(0)); - attribs.resize (MAX_ATTRIBS, static_cast(0)); - - ScriptParams params; - params.addParam (waypointId); - params.addParam (owner->getNetworkId()); - params.addParam (names); - params.addParam (attribs); - - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_WAYPOINT_ON_GET_ATTRIBUTES, params)); - - const std::vector & newNames = params.getStringArrayParam (2); - const std::vector & newAttribs = params.getUnicodeArrayParam (3); - - // copy the returned strings to data - for (int i = 0; i < MAX_ATTRIBS; ++i) - { - const char * const newName = newNames [i]; - const Unicode::String * const newAttrib = newAttribs [i]; - - if (newName && *newName && newAttrib && !newAttrib->empty ()) - { - data.push_back (std::make_pair (std::string (newName), *newAttrib)); - } - else - break; - } - } - - } - } - } -} - -//----------------------------------------------------------------------- - -std::string PlayerObject::getAccountDescription(const NetworkId & creatureId) -{ - std::string result = getAccountDescription(safe_cast(NetworkIdManager::getObjectById(creatureId))); - if (result.empty() || result == "UNKNOWN") - result = creatureId.getValueString(); - return result; -} - -//----------------------------------------------------------------------- - -std::string PlayerObject::getAccountDescription(const ServerObject * creature) -{ - std::string desc = ""; - if (creature) - { - const PlayerObject * player = PlayerCreatureController::getPlayerObject(creature->asCreatureObject()); - if (creature->asCreatureObject() && player) - { - return player->getAccountDescription(); - } - else if (creature->asCreatureObject()) - { - desc += "Non-Player "; - desc += Unicode::wideToNarrow(creature->getObjectName()); - desc += "("; - desc += creature->getNetworkId().getValueString(); - desc += ") "; - desc += creature->getObjectTemplateName(); - } - else - desc = creature->getNetworkId().getValueString(); - } - else - { - desc = "UNKNOWN"; - } - return desc; -} - -//----------------------------------------------------------------------- - -std::string PlayerObject::getAccountDescription() const -{ - const ServerObject * owner = safe_cast( - ContainerInterface::getContainedByObject(*this)); - if (owner == NULL) - return "UNKNOWN"; - - bool isGod = false; - bool isSecure = false; - Client * client = NULL; - if (owner && owner->getClient()) - { - client = owner->getClient(); - if (client->isGod()) - isGod = true; - if (client->isGodValidated()) - isSecure = true; - } - - std::string desc; - desc += "Player "; - desc += Unicode::wideToNarrow(owner->getObjectName()); - desc += "("; - desc += owner->getNetworkId().getValueString(); - desc += ") StationId("; - char stationIdBuf[32] = {"\0"}; - snprintf(stationIdBuf, sizeof(stationIdBuf), "%lu", m_stationId.get()); - stationIdBuf[sizeof(stationIdBuf) - 1] = 0; - desc += stationIdBuf; - if (isGod) - desc += " isGod"; - else if (isSecure) - desc += " isSecure"; - - if (client && client->isFreeTrialAccount()) - { - desc += " isFreeTrial"; - } - - desc += ")"; - - return desc; -} - -//----------------------------------------------------------------------- - -void PlayerObject::logChat(int const logIndex) -{ - if (m_chatLog != NULL) - { - time_t const logTime = Os::getRealSystemTime(); - - ChatLogEntry chatLogEntry; - - chatLogEntry.m_index = logIndex; - chatLogEntry.m_time = logTime; - - m_chatLog->push_back(chatLogEntry); - - cleanChatLog(); - } -} - -//----------------------------------------------------------------------- - -PlayerObject::ChatLog const &PlayerObject::getChatLog() const -{ - NOT_NULL(m_chatLog); - - return *m_chatLog; -} - -//----------------------------------------------------------------------- - -void PlayerObject::checkStomach() -{ - int temp = 0; - - const CreatureObject * const creature = getCreatureObject(); - - if(creature) - { - const DynamicVariableList & objvars = creature->getObjVars(); - - if (objvars.getItem("stomach.food", temp)) - { - m_food = temp; - } - if (objvars.getItem("stomach.drink",temp)) - { - m_drink = temp; - } - if (objvars.getItem("stomach.medicine",temp)) - { - m_meds = temp; - } - } -} - -//----------------------------------------------------------------------- - -void PlayerObject::cleanChatLog() -{ - // See if we need to purge any old messages - - time_t currentTime; - time(¤tTime); - - if (m_chatLogPurgeTime != currentTime) - { - m_chatLogPurgeTime = currentTime; - - // See if anything needs to be purged from the front of the logs - - time_t const chatLogTime = ConfigServerUtility::getChatLogMinutes() * 60; - int chatLogCount = static_cast(m_chatLog->size()); - - ChatLog::iterator iterChatLog = m_chatLog->begin(); - while (!m_chatLog->empty()) - { - const time_t messageTime = iterChatLog->m_time; - - if (messageTime < (currentTime - chatLogTime) || (chatLogCount > ConfigServerUtility::getPlayerMaxChatLogLines())) - { - iterChatLog = m_chatLog->erase(iterChatLog); - --chatLogCount; - } - else - { - break; - } - } - } -} - -//---------------------------------------------------------------------- - -bool PlayerObject::isJedi() const -{ - return false; -} - -//------------------------------------------------------------------------------------------ - -bool PlayerObject::getIsUnsticking() const -{ - return m_isUnsticking; -} - -//------------------------------------------------------------------------------------------ - -void PlayerObject::setIsUnsticking(bool value) -{ - m_isUnsticking = value; -} - -// ======================================================================================== -//---------------------------------------------------------------------- - -void PlayerObject::findFriend(const std::string & friendName) -{ - // ask the name manager for the network id of the friend - std::string normalizedName = NameManager::normalizeName(friendName); - NetworkId target = NameManager::getInstance().getPlayerId(normalizedName); - const CreatureObject * creatureObject = getCreatureObject(); - if(target != NetworkId::cms_invalid) - { - if(creatureObject) - { - std::string myName = Unicode::wideToNarrow(creatureObject->getAssignedObjectFirstName()); - - // shortcut: if the player is on this server, don't send a - // messageTo - CreatureObject * friendObject = safe_cast(NetworkIdManager::getObjectById(target)); - if(friendObject && friendObject->isAuthoritative() && PlayerCreatureController::getPlayerObject(friendObject)) - { - // extract the PlayerObject from the CreatureObject - PlayerObject * friendPlayer = PlayerCreatureController::getPlayerObject(friendObject); - if(friendPlayer) - { - // go ahead and invoke replyLocationToFriend on the - // local PlayerObject. - friendPlayer->replyLocationToFriend(myName, creatureObject->getNetworkId()); - } - } - else - { - // the player is not on this server, send a message to C for the - // friend's network ID. - Archive::ByteStream payload; - Archive::put(payload, creatureObject->getNetworkId()); - Archive::put(payload, myName); - - //@todo: This should really use sprintf to pack the data into a string, rather than reintrepreting a byte stream as a string - - MessageToQueue::getInstance().sendMessageToC(target, "FindFriend", std::string(reinterpret_cast(payload.getBuffer()), payload.getSize()), 0, false); - } - } - } - else - { - StringId noName("ui_cmnty", "friend_location_failed_noname"); - Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); - } -} - -//---------------------------------------------------------------------- - -void PlayerObject::replyLocationToFriend(const std::string & friendName, const NetworkId & friendNetworkId) -{ - // Do not send location information to players who are not - // on this player's friend list (e.g. the Bounty hunter trying - // to find a Jedi) - if(isFriend(friendName)) - { - // the requesting player is our friend, send the location - CreatureObject * creatureObject = getCreatureObject(); - if(creatureObject) - { - Vector coordinates = creatureObject->findPosition_w(); - std::string scene = ServerWorld::getSceneId(); - Location location(coordinates, NetworkId::cms_invalid, Location::getCrcBySceneName(scene)); - // If the requestor is on this server, invoke the response - // directly, otherwise send a message to the remote - // creature object with the data. - CreatureObject * friendCreatureObject = safe_cast(NetworkIdManager::getObjectById(friendNetworkId)); - if(friendCreatureObject && friendCreatureObject->isAuthoritative()) - { - // retrieve the PlayerObject associated with the - // character and give it the coordinates - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(friendCreatureObject); - if(playerObject) - { - playerObject->receiveLocationToFriend(creatureObject->getNetworkId(), location); - } - else - { - // send an error to the requesting player - failLocationToFriend(friendNetworkId); - } - } - else - { - // the character is not on this server, send the response - // to the requestor's network Id - Archive::ByteStream response; - Archive::put(response, location); - Archive::put(response, creatureObject->getNetworkId()); - MessageToQueue::getInstance().sendMessageToC(friendNetworkId, "LocationToFriend", std::string(reinterpret_cast(response.getBuffer()), response.getSize()), 0, false); - - } - } - else - { - // send an error to the requesting player - failLocationToFriend(friendNetworkId); - } - } - else - { - // send a failure to the requestor, let them know that - // both players must be on the friends list - failLocationToFriend(friendNetworkId); - } -} - -//---------------------------------------------------------------------- - -void PlayerObject::receiveLocationToFriend(const NetworkId & friendId, const Location & friendLocation) -{ - // receiving a response to the findFriend request - CreatureObject * creatureObject = getCreatureObject(); - if(creatureObject) - { - const DynamicVariableList & objvars = creatureObject->getObjVars(); - NetworkId friendWaypointId; - bool newWpCreated = false; - if(! objvars.hasItem("friend_waypoint_id")) - { - // create a new "friend" waypoint - Waypoint friendWaypoint(createWaypoint(friendLocation, true)); - newWpCreated = true; - friendWaypointId = friendWaypoint.getNetworkId(); - creatureObject->setObjVarItem("friend_waypoint_id", friendWaypointId); - } - else - { - objvars.getItem("friend_waypoint_id", friendWaypointId); - // find the existing waypoint in the datapad - std::vector waypointsInDatapad; - getWaypointsInDatapad(waypointsInDatapad); - if(std::find(waypointsInDatapad.begin(), waypointsInDatapad.end(), friendWaypointId) == waypointsInDatapad.end()) - { - // original waypoint has been destroyed, create a new one - Waypoint newWaypoint(createWaypoint(friendLocation, true)); - newWpCreated = true; - friendWaypointId = newWaypoint.getNetworkId(); - creatureObject->setObjVarItem("friend_waypoint_id", friendWaypointId); - } - } - - std::string friendName = NameManager::getInstance().getPlayerName(friendId); - if(friendWaypointId != NetworkId::cms_invalid) - { - Waypoint friendWaypoint = Waypoint::getWaypointById(friendWaypointId); - friendWaypoint.setActive(true); - friendWaypoint.setLocation(friendLocation); - friendWaypoint.setName(Unicode::narrowToWide(NameManager::getInstance().getPlayerName(friendId))); - - // findFriend waypoint is purple by default - if (newWpCreated) - friendWaypoint.setColor(Waypoint::Purple); - - Unicode::String oob; - ProsePackage pp; - if(! friendName.empty()) - { - if (newWpCreated) - { - pp.actor.str = Unicode::narrowToWide(friendName); - pp.stringId = StringId("ui_cmnty", "friend_location_create_new_wp"); - OutOfBandPackager::pack(pp, -1, oob); - Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); - } - else - { - pp.actor.str = Unicode::narrowToWide(friendName); - pp.stringId = StringId("ui_cmnty", "friend_location"); - OutOfBandPackager::pack(pp, -1, oob); - Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); - } - } - else - { - StringId noName("ui_cmnty", "friend_location_failed_noname"); - Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); - } - } - else - { - if( !friendName.empty()) - { - ProsePackage pp; - pp.actor.str = Unicode::narrowToWide(friendName); - pp.stringId = StringId("ui_cmnty", "friend_location_failed"); - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); - } - else - { - StringId noName("ui_cmnty", "friend_location_failed_noname"); - Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); - } - } - } -} - -//---------------------------------------------------------------------- - -void PlayerObject::failLocationToFriend(const NetworkId & friendId) -{ - CreatureObject * requestor = safe_cast(NetworkIdManager::getObjectById(friendId)); - if(requestor && requestor->isAuthoritative()) - { - PlayerObject * player = PlayerCreatureController::getPlayerObject(requestor); - if(player) - { - player->receiveFailLocationToFriend(getCreatureObject()->getNetworkId()); - } - } - else - { - Archive::ByteStream response; - Archive::put(response, getCreatureObject()->getNetworkId()); - MessageToQueue::getInstance().sendMessageToC(friendId, "FailLocationToFriend", std::string(reinterpret_cast(response.getBuffer()), response.getSize()), 0, false); - } -} - -//---------------------------------------------------------------------- - -void PlayerObject::receiveFailLocationToFriend(const NetworkId & friendId) -{ - CreatureObject * creatureObject = getCreatureObject(); - if(creatureObject) - { - std::string friendName = NameManager::getInstance().getPlayerName(friendId); - if(! friendName.empty()) - { - ProsePackage pp; - pp.actor.str = Unicode::narrowToWide(friendName); - pp.stringId = StringId("ui_cmnty", "friend_location_failed"); - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); - } - else - { - StringId noName("ui_cmnty", "friend_location_failed_noname"); - Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); - } - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setPriviledgedTitle(int8 priviledgedTitle) -{ - if (isAuthoritative()) - { - if (m_privledgedTitle.get() != priviledgedTitle) - { - // if becoming a warden, send system message and warden introduction mail - if (priviledgedTitle == static_cast(PlayerDataPriviledgedTitle::Warden)) - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - { - static const Unicode::String mailSubject = Unicode::narrowToWide("@" + StringId("warden", "warden_introduction_subject").getCanonicalRepresentation()); - - ProsePackage pp; - pp.stringId = StringId("warden", "warden_introduction_body"); - - Unicode::String oob; - OutOfBandPackager::pack(pp, -1, oob); - - Chat::sendPersistentMessage("system", Unicode::wideToNarrow(owner->getAssignedObjectName()), mailSubject, Unicode::emptyString, oob); - - Chat::sendSystemMessage(*owner, StringId("warden", "grant_warden"), Unicode::emptyString); - } - } - // if warden being revoked, send system message - else if (m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::Warden)) - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - Chat::sendSystemMessage(*owner, StringId("warden", "revoke_warden"), Unicode::emptyString); - } - - m_privledgedTitle.set(priviledgedTitle); - - // persist privileged title - if (priviledgedTitle != static_cast(PlayerDataPriviledgedTitle::NormalPlayer)) - setObjVarItem(OBJVAR_PRIVILEGED_TITLE, static_cast(priviledgedTitle)); - else - removeObjVarItem(OBJVAR_PRIVILEGED_TITLE); - } - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_setPriviledgedTitle, new MessageQueueGenericValueType(static_cast(priviledgedTitle))); - } -} - -//------------------------------------------------------------------------------------------ - -void PlayerObject::activateQuest(int questId) -{ - BitArray b = m_activeQuests.get(); - b.setBit(questId); - m_activeQuests.set(b); - ScriptParams params; - params.addParam(questId); - CreatureObject * creatureObject = getCreatureObject(); - if(creatureObject) - { - GameScriptObject * gameScriptObject = creatureObject->getScriptObject(); - if(gameScriptObject) - { - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_QUEST_ACTIVATED, params)); - } - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::deactivateQuest(int questId) -{ - BitArray b = m_activeQuests.get(); - b.clearBit(questId); - m_activeQuests.set(b); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::completeQuest(int questId) -{ - BitArray b = m_activeQuests.get(); - b.clearBit(questId); - m_activeQuests.set(b); - b = m_completedQuests.get(); - b.setBit(questId); - m_completedQuests.set(b); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::isQuestActive(int questId) const -{ - return m_activeQuests.get().testBit(questId); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::isQuestComplete(int questId) const -{ - return m_completedQuests.get().testBit(questId); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::clearCompletedQuest(int questId) -{ - BitArray b = m_completedQuests.get(); - b.clearBit(questId); - m_completedQuests.set(b); -} - -// ---------------------------------------------------------------------- - -/** - * Checks if the theater assigned to this player should be spawned. NOTE: if we - * spawn the theater, our theater data will be cleared. - * - * @param pos our position - * @param scene our scene - * @param speed our speed - * @param updateRadius distance when we start receiving objects - */ -void PlayerObject::checkTheater(const Vector & pos, const std::string & scene, - float speed, float updateRadius) -{ - if (!isAuthoritative()) - return; - - if (!hasTheater()) - return; - - if (m_theaterScene.get() != scene) - return; - - // we want to spawn the theater so that all the objects will have been created - // by the time the theater comes into view - float timeToCreate = (m_theaterNumObjects.get() / IntangibleObject::getObjectsCreatedPerFrame()) * 0.25f; - float creationDistance = m_theaterRadius.get() + updateRadius * 1.5f + speed * timeToCreate; - float distance = pos.magnitudeBetweenSquared(m_theaterPosition.get()); - if (distance < creationDistance * creationDistance) - { - DEBUG_LOG("Theater", ("PlayerObject spawning theater at a distance of " - "%f(%f, %f, %f, %f)\n", static_cast(sqrt(distance)), creationDistance, - speed, updateRadius, timeToCreate)); - IntangibleObject * theater = IntangibleObject::spawnTheater(m_theaterDatatable.get(), - m_theaterPosition.get(), m_theaterScript.get(), - static_cast(m_theaterLocationType.get())); - if (theater != NULL) - { - const CreatureObject * owner = getCreatureObject(); - if (owner != NULL) - theater->setPlayer(*owner); - theater->setTheaterCreator(m_theaterCreator.get()); - if (!theater->setTheaterName(m_theaterName.get())) - { - WARNING(true, ("PlayerObject::checkTheater could not create " - "theater with name %s", m_theaterName.get().c_str())); - theater->permanentlyDestroy(DeleteReasons::SetupFailed); - theater = NULL; - } - } - if (theater == NULL) - { - CreatureObject * creatureObject = getCreatureObject(); - if (creatureObject) - { - GameScriptObject * gameScriptObject = creatureObject->getScriptObject(); - if (gameScriptObject) - { - ScriptParams params; - params.addParam(m_theaterDatatable.get().c_str()); - params.addParam(m_theaterName.get().c_str()); - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_PLAYER_THEATER_FAIL, params)); - } - } - } - else - m_theaterId = theater->getNetworkId(); - - // there seems to be a problem if an objvar gets set and cleared in the - // same frame, so we message ourselves to clean up next frame - clearTheater(); - //m_theaterDatatable = ""; - //MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++ClearTheater", std::string(), 0.1f, true); - } -} // PlayerObject::checkTheater - -// ---------------------------------------------------------------------- - -/** - * Sets the data for a theater that will be created when this player gets near - * it. NOTE: we do not store the data if the player already has a theater. - * - * @param datatable the datatable where the theater info is stored - * @param position the general location of the theater (the actual location - * is determined by getGoodLocation() when the theater is spawned) - * @param scene the planet/scene where the theater is - * @param script the script to be attached to the theater object - * @param creator who's creating the theater - * @param name the theater's name - * @param locationType how to create the theater - * - * @return true on success, false on fail - */ -bool PlayerObject::setTheater(const std::string & datatable, const Vector & position, - const std::string & scene, const std::string & script, const NetworkId & creator, - const std::string & name, IntangibleObject::TheaterLocationType locationType) -{ - if (!isAuthoritative()) - { - WARNING(true, ("PlayerObject::setTheater called on unauthoritative player")); - return false; - } - - if (hasTheater()) - { - WARNING(true, ("PlayerObject::setTheater called on player with theater")); - return false; - } - - m_theaterNumObjects = IntangibleObject::getNumObjects(datatable); - if (m_theaterNumObjects.get() == 0) - { - WARNING(true, ("PlayerObject::setTheater called with invalid datatable %s", - datatable.c_str())); - return false; - } - - if (ServerUniverse::getInstance().getPlanetByName(scene) == NULL) - { - WARNING(true, ("PlayerObject::setTheater called with invalid scene %s", - scene.c_str())); - return false; - } - - m_theaterDatatable = datatable; - m_theaterPosition = position; - m_theaterScene = scene; - m_theaterScript = script; - m_theaterCreator = creator; - m_theaterName = name; - m_theaterLocationType = static_cast(locationType); - - // note that we set the radius to 3 times the radius returned since that is - // the area that the theater could be created in - m_theaterRadius = IntangibleObject::getRadius(datatable) * 3.0f; - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Clears the player's theater data. - */ -void PlayerObject::clearTheater() -{ - if (!isAuthoritative()) - return; - - m_theaterDatatable = ""; - m_theaterPosition = Vector(0,0,0); - m_theaterScene = ""; - m_theaterScript = ""; - m_theaterRadius = 0; - m_theaterCreator = NetworkId::cms_invalid; - m_theaterName = ""; - m_theaterLocationType = IntangibleObject::TLT_getGoodLocation; -} - -// ---------------------------------------------------------------------- - -/** - * Checks if the player has theater data. - */ -bool PlayerObject::hasTheater() const -{ - return !m_theaterDatatable.get().empty(); -} - -// ---------------------------------------------------------------------- - -PlayerObject *PlayerObject::asPlayerObject() -{ - return this; -} - -// ---------------------------------------------------------------------- - -PlayerObject const *PlayerObject::asPlayerObject() const -{ - return this; -} - -// ====================================================================== -// Quest System functions -// ====================================================================== - -PlayerObject::QuestResult PlayerObject::questCanActivateQuest(uint32 const questCrc) const -{ - Quest const * const quest=QuestManager::getQuest(questCrc); - if (!quest) - return QR_noSuchQuest; - - if (questHasActiveQuest(questCrc)) - return QR_alreadyActive; - - if (!quest->isRepeatable() && questHasCompletedQuest(questCrc)) - return QR_alreadyComplete; - - { - std::vector const & prerequisites = quest->getPrerequisiteQuests(); - for (std::vector::const_iterator i=prerequisites.begin(); i!=prerequisites.end(); ++i) - { - if (!questHasCompletedQuest(*i)) - return QR_failedPrerequisites; - } - } - - { - std::vector const & exclusion = quest->getExclusionQuests(); - for (std::vector::const_iterator i=exclusion.begin(); i!=exclusion.end(); ++i) - { - if (questHasCompletedQuest(*i) || questHasActiveQuest(*i)) - return QR_failedExclusion; - } - } - - return QR_success; -} - -// ---------------------------------------------------------------------- - - -PlayerObject::QuestResult PlayerObject::questActivateQuest(uint32 const questCrc, NetworkId const & questGiver) -{ - QuestResult canActivateResult = questCanActivateQuest(questCrc); - if (canActivateResult != QR_success) - return canActivateResult; - - questCheckQuestLimits(); - - PlayerQuestData playerQuestData(questGiver); - m_quests.set(questCrc, playerQuestData); - setCurrentQuest(questCrc); - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - ScriptParams params; - params.addParam(static_cast(questCrc)); - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_QUEST_ACTIVATED, params)); - } - } - - questActivateQuestTask(questCrc, 0); - - return QR_success; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::questCheckQuestLimits() -{ - if (m_quests.size() > s_questLimit) - { - // Randomly remove some quests to get the number back down to the limit - // Most of the quests in the list should be completed, so try - // to prefer completed quests when picking ones to delete - // - // The hope is that game mechanisms will keep the number of quests - // within the limits, and this code won't have to be used. - - CreatureObject * const owner = NON_NULL(getCreatureObject()); - - size_t numberToDelete = m_quests.size() - s_questLimit; - int previousNumberDeleted; - if (!owner->getObjVars().getItem(OBJVAR_DELETED_QUEST_COUNT, previousNumberDeleted)) - previousNumberDeleted=0; - IGNORE_RETURN(owner->setObjVarItem(OBJVAR_DELETED_QUEST_COUNT, previousNumberDeleted + static_cast(numberToDelete))); - - // We need to sort the quests to delete by age - SortableQuestList possibleQuestsToDelete; - - // First find all the completed quests than can be deleted - for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) - { - PlayerQuestData const& questData = i->second; - if (questData.isCompleted()) - { - possibleQuestsToDelete.push_back(QuestDataToSort(i->first, questData)); - } - } - - // Sort the possible quests by age - possibleQuestsToDelete.sort(); - - // Determine whether we found enough quests to delete - if (possibleQuestsToDelete.size() < numberToDelete) - { - SortableQuestList additionalPossibleQuestsToDelete; - - // Our failure case has hit a failure case! There aren't enough completed quests to stay within the limit. - for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end() && possibleQuestsToDelete.size() < numberToDelete; ++i) - { - PlayerQuestData const& questData = i->second; - if (!questData.isCompleted()) - { - additionalPossibleQuestsToDelete.push_back(QuestDataToSort(i->first, questData)); - } - } - - // Sort the additional quests by age - additionalPossibleQuestsToDelete.sort(); - - // Add the additional quests to the end of the possibilities list - possibleQuestsToDelete.splice(possibleQuestsToDelete.end(), - additionalPossibleQuestsToDelete, - additionalPossibleQuestsToDelete.begin(), - additionalPossibleQuestsToDelete.end()); - } - - while (numberToDelete > 0) - { - DEBUG_FATAL(possibleQuestsToDelete.empty(),("Programmer bug: there is an error in the questCheckQuestLimits logic such that possibleQuestsToDelete was unexpectedly empty")); - - // Remove the "oldest" quest from the beginning of the list - QuestDataToSort const& questDataToSort = possibleQuestsToDelete.front(); - uint32 const playerQuestDataKey = questDataToSort.GetPlayerQuestDataKey(); - questClearQuest(playerQuestDataKey); - possibleQuestsToDelete.pop_front(); - --numberToDelete; - - LOG("CustomerService",("Removed quest %lu from player %s because there were too many quests in the journal", playerQuestDataKey, NON_NULL(getCreatureObject())->getNetworkId().getValueString().c_str())); - } - } -} - -// ---------------------------------------------------------------------- - -PlayerObject::QuestResult PlayerObject::questCompleteQuest(uint32 const questCrc) -{ - Quest const * const quest = QuestManager::getQuest(questCrc); - if (!quest) - return QR_noSuchQuest; - - if(!questHasActiveQuest(questCrc)) - return QR_questNotActive; - - if(questHasCompletedQuest(questCrc)) - return QR_alreadyComplete; - - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - if (questData==m_quests.end()) - return QR_questNotActive; - - //clear any leftover tasks for this quest - int taskId = 0; - for(; taskId < quest->getNumberOfTasks(); ++taskId) - { - if(questHasActiveQuestTask(questCrc, taskId)) - questClearQuestTask(questCrc, taskId); - } - - PlayerQuestData newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators - setPlayerQuestDataComplete(questCrc, newQuestData); - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - ScriptParams params; - params.addParam(static_cast(questCrc)); - GameScriptObject * const scriptObject = owner->getScriptObject(); - if(scriptObject) - { - scriptObject->trigAllScripts(Scripting::TRIG_QUEST_COMPLETED, params); - } - } - - CreatureObject * const playerCreature = getCreatureObject(); - //see if this quest needs to go through our acceptance/completion UI flow - if(QuestManager::isQuestAcceptable(quest->getName().getString())) - { - //-- Request the recipient's client to have the emitter object render the text. - Controller * const controller = playerCreature->getController(); - if(controller) - { - setPendingRequestQuestInformation(questCrc, NetworkId::cms_invalid); - MessageQueueGenericValueType * const msg = new MessageQueueGenericValueType(static_cast(questCrc)); - controller->appendMessage(static_cast(CM_requestCompleteQuest), 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } - else - { - questGrantQuestReward(static_cast(questCrc), ""); - } - - return QR_success; -} - -// ---------------------------------------------------------------------- - -PlayerObject::QuestResult PlayerObject::questGrantQuestReward(uint32 const questCrc, std::string const & selectedReward) -{ - Quest const * const quest=QuestManager::getQuest(questCrc); - if (!quest) - return QR_noSuchQuest; - - if(!questHasCompletedQuest(questCrc)) - return QR_questNotCompleted; - - PlayerQuestDataMap::const_iterator questData = m_quests.find(questCrc); - - PlayerQuestData newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators - - if(newQuestData.hasReceivedReward()) - { - return QR_alreadyReceivedReward; - } - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - ScriptParams params; - params.addParam(static_cast(questCrc)); - if(quest->isAnExclusiveStaticLootReward(selectedReward)) - params.addParam(selectedReward.c_str()); - else - params.addParam(""); - GameScriptObject * const scriptObject = owner->getScriptObject(); - if(scriptObject) - { - if(scriptObject->trigAllScripts(Scripting::TRIG_QUEST_GRANT_REWARD, params) == SCRIPT_CONTINUE) - { - newQuestData.setHasReceivedReward(true); - setPlayerQuestDataComplete(questCrc, newQuestData); - } - } - } - - return QR_success; -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::questPlayerCanClaimRewardFor(uint32 const questCrc) -{ - PlayerQuestDataMap::const_iterator const questData = m_quests.find(questCrc); - - PlayerQuestData const newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators - - return (questHasCompletedQuest(questCrc) && !newQuestData.hasReceivedReward()); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::questClearQuest(uint32 const questCrc) -{ - Quest const * const quest=QuestManager::getQuest(questCrc); - if(quest) - { - //clear any leftover tasks for this quest - int taskId = 0; - for(; taskId < quest->getNumberOfTasks(); ++taskId) - { - if(questHasActiveQuestTask(questCrc, taskId)) - questClearQuestTask(questCrc, taskId); - } - } - - m_quests.erase(questCrc); - - //-- if the cleared quest is the current quest, pick a new one - if (questCrc == getCurrentQuest()) - { - pickNewCurrentQuest(); - } - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - ScriptParams params; - params.addParam(static_cast(questCrc)); - GameScriptObject * const scriptObject = owner->getScriptObject(); - if(scriptObject) - { - scriptObject->trigAllScripts(Scripting::TRIG_QUEST_CLEARED, params); - } - } -} - -// ---------------------------------------------------------------------- - -PlayerObject::QuestResult PlayerObject::questCanActivateQuestTask(uint32 const questCrc, int const taskId) const -{ - Quest const * const quest = QuestManager::getQuest(questCrc); - if (!quest) - return QR_noSuchQuest; - QuestTask const * const questTask = quest->getTask(taskId); - if (!questTask) - return QR_noSuchTask; - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - if (questData==m_quests.end()) - return QR_questNotActive; - if (questData->second.isTaskActive(taskId)) - return QR_alreadyActive; - if (!questTask->isRepeatable() && questData->second.isTaskCompleted(taskId)) - return QR_alreadyComplete; - - // check for prerequisites/exclusions - { - std::vector const & prerequisites = questTask->getPrerequisiteTasks(); - for(std::vector::const_iterator i = prerequisites.begin(); i!= prerequisites.end(); ++i) - { - if (!questData->second.isTaskCompleted(*i)) - return QR_failedPrerequisites; - } - } - { - std::vector const & exclustion = questTask->getExclusionTasks(); - for(std::vector::const_iterator i = exclustion.begin(); i!= exclustion.end(); ++i) - { - if (questData->second.isTaskCompleted(*i) || questData->second.isTaskActive(*i)) - return QR_failedExclusion; - } - } - - return QR_success; -} - -// ---------------------------------------------------------------------- - -PlayerObject::QuestResult PlayerObject::questActivateQuestTask(uint32 const questCrc, int const taskId) -{ - QuestResult canActivateResult = questCanActivateQuestTask(questCrc, taskId); - if (canActivateResult != QR_success) - return canActivateResult; - - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - DEBUG_FATAL(questData==m_quests.end(),("Programmer bug: questCanActivateQuestTask(%lu, %i) returned success, but the quest was not in m_quests", questCrc, taskId)); - - PlayerQuestData newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators - newQuestData.activateTask(taskId); - m_quests.set(questCrc, newQuestData); - - const Quest * const quest = QuestManager::getQuest(questCrc); - if(quest) - { - const QuestTask * const task = quest->getTask(taskId); - if(task) - { - ScriptParams params; - params.addParam(static_cast(questCrc)); - params.addParam(static_cast(taskId)); - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - const std::string & attachScript = task->getAttachScript(); - if(!attachScript.empty()) - { - refScript(*owner, attachScript); - { - IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_ACTIVATED, params)); - } - } - - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_ACTIVATED, params)); - } - } - - CreatureObject * const co = getCreatureObject(); - if(co) - { - if(!task->getMusicOnActivate().empty()) - { - Client * const c = co->getClient(); - if (c) - { - PlayMusicMessage const msg(task->getMusicOnActivate(), NetworkId::cms_invalid, 0, false); - c->send(msg, true); - } - } - } - } - } - - return QR_success; -} - -// ---------------------------------------------------------------------- - -PlayerObject::QuestResult PlayerObject::questCompleteQuestTask(uint32 const questCrc, int const taskId) -{ - Quest const * const quest = QuestManager::getQuest(questCrc); - if (!quest) - return QR_noSuchQuest; // Quest has been removed from the data table, apparently - QuestTask const * const questTask = quest->getTask(taskId); - if (!questTask) - return QR_noSuchTask; - - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - if (questData==m_quests.end()) - return QR_questNotActive; - if (!questData->second.isTaskActive(taskId)) - return QR_taskNotActive; - - PlayerQuestData newQuestData(questData->second); - newQuestData.completeTask(taskId); - m_quests.set(questCrc, newQuestData); - - ScriptParams params; - params.addParam(static_cast(questCrc)); - params.addParam(static_cast(taskId)); - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - const std::string & attachScript = questTask->getAttachScript(); - if(!attachScript.empty()) - { - IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_COMPLETED, params)); - derefScript(*owner, attachScript); - } - - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_COMPLETED, params)); - } - } - - if (questTask->questCompletesOnTaskCompletion()) - { - questCompleteQuest(questCrc); - return QR_success; - } - else if (questTask->questClearsOnTaskCompletion()) - { - questClearQuest(questCrc); - return QR_success; - } - - TaskChanceVector tasksWithChanceToActivate; - int totalChance = 0; - - QuestTask::TaskIdList const & nextTasks = questTask->getTasksOnComplete(); - for (QuestTask::TaskIdList::const_iterator i=nextTasks.begin(); i != nextTasks.end(); ++i) - { - QuestTask const * const taskOnComplete = quest->getTask(*i); - if (taskOnComplete) - { - int const chanceToActivate = taskOnComplete->getChanceToActivate(); - if (chanceToActivate <= 0) - IGNORE_RETURN(questActivateQuestTask(questCrc, *i)); // activate all that are possible, ignore the ones that aren't - else - { - tasksWithChanceToActivate.push_back(std::make_pair(*i, chanceToActivate)); - totalChance += chanceToActivate; - } - } - } - - if (totalChance) - { - int const winningChance = Random::random(totalChance - 1); - int previousChance = 0; - - TaskChanceVector::const_iterator currentTaskChance = tasksWithChanceToActivate.begin(); - - for (;currentTaskChance != tasksWithChanceToActivate.end(); ++currentTaskChance) - { - int const currentChance = previousChance + currentTaskChance->second; - - if (winningChance >= previousChance && winningChance < currentChance) - { - IGNORE_RETURN(questActivateQuestTask(questCrc, currentTaskChance->first)); - break; - } - - previousChance = currentChance; - } - } - - //closeout quest if they're done with all the tasks, if the quest is marked to allow this - //The "space quests" written using breinhart's quest backend will NOT use this, the "ground quests" will - bool questIsComplete = true; - for(int it = 0; it < quest->getNumberOfTasks(); ++it) - { - bool const completedTask = questHasCompletedQuestTask(questCrc, it); - if(!completedTask) - { - questIsComplete = false; - break; - } - } - if(questIsComplete && quest->getCompleteQuestWhenTasksComplete()) - { - questCompleteQuest(questCrc); - } - return QR_success; -} - -// ---------------------------------------------------------------------- - -PlayerObject::QuestResult PlayerObject::questFailQuestTask(uint32 const questCrc, int const taskId) -{ - Quest const * const quest = QuestManager::getQuest(questCrc); - if (!quest) - return QR_noSuchQuest; // Quest has been removed from the data table, apparently - QuestTask const * const questTask = quest->getTask(taskId); - if (!questTask) - return QR_noSuchTask; - - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - if (questData==m_quests.end()) - return QR_questNotActive; - if (!questData->second.isTaskActive(taskId)) - return QR_taskNotActive; - - PlayerQuestData newQuestData(questData->second); - newQuestData.clearTask(taskId); - m_quests.set(questCrc, newQuestData); - - ScriptParams params; - params.addParam(static_cast(questCrc)); - params.addParam(static_cast(taskId)); - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - const std::string & attachScript = questTask->getAttachScript(); - if(!attachScript.empty()) - { - IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_FAILED, params)); - derefScript(*owner, attachScript); - } - - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_FAILED, params)); - } - } - - if (questTask->questCompletesOnTaskFailure()) - { - questCompleteQuest(questCrc); - return QR_success; - } - else if (questTask->questClearsOnTaskFailure()) - { - questClearQuest(questCrc); - return QR_success; - } - - QuestTask::TaskIdList const & nextTasks = questTask->getTasksOnFail(); - for (QuestTask::TaskIdList::const_iterator i=nextTasks.begin(); i != nextTasks.end(); ++i) - { - IGNORE_RETURN(questActivateQuestTask(questCrc, *i)); // activate all that are possible, ignore the ones that aren't - } - - return QR_success; -} - -// ---------------------------------------------------------------------- - -PlayerObject::QuestResult PlayerObject::questClearQuestTask(uint32 const questCrc, int const taskId) -{ - Quest const * const quest = QuestManager::getQuest(questCrc); - if (!quest) - return QR_noSuchQuest; // Quest has been removed from the data table, apparently - QuestTask const * const questTask = quest->getTask(taskId); - if (!questTask) - return QR_noSuchTask; - - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - if (questData==m_quests.end()) - return QR_questNotActive; - if (!questData->second.isTaskActive(taskId)) - return QR_taskNotActive; - - PlayerQuestData newQuestData(questData->second); - newQuestData.clearTask(taskId); - m_quests.set(questCrc, newQuestData); - - ScriptParams params; - params.addParam(static_cast(questCrc)); - params.addParam(static_cast(taskId)); - - CreatureObject * owner = getCreatureObject(); - if(owner) - { - GameScriptObject * script = owner->getScriptObject(); - if(script) - { - const std::string & attachScript = questTask->getAttachScript(); - if(!attachScript.empty()) - { - IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_CLEARED, params)); - derefScript(*owner, attachScript); - } - - IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_CLEARED, params)); - } - } - - return QR_success; -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::questHasActiveQuest(uint32 const questCrc) const -{ - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - return (questData!=m_quests.end() && !questData->second.isCompleted()); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::questHasCompletedQuest(uint32 const questCrc) const -{ - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - return (questData!=m_quests.end() && questData->second.isCompleted()); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::questHasActiveQuestTask(uint32 const questCrc, int const taskId) const -{ - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - if (questData==m_quests.end()) - return false; - - return (questData->second.isTaskActive(taskId)); - -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::questHasCompletedQuestTask(uint32 const questCrc, int const taskId) const -{ - PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); - if (questData==m_quests.end()) - return false; - - return (questData->second.isTaskCompleted(taskId)); -} - -// ---------------------------------------------------------------------- - -uint32 PlayerObject::questGetQuestStatus(uint32 const questCrc) const -{ - PlayerQuestDataMap::const_iterator questData = m_quests.find(questCrc); - - if (questData == m_quests.end()) - return 0; - - return (questData->second.getActiveTasks() << 16) | (questData->second.getCompletedTasks() & 0xFFFF); -} - -// ---------------------------------------------------------------------- - -std::set const &PlayerObject::getAllPlayerObjects() // static -{ - return s_allPlayerObjects; -} - -// ---------------------------------------------------------------------- - -PlayerObject::WaypointMap const &PlayerObject::getWaypoints() const -{ - return m_waypoints.getMap(); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const -{ - if(name == "quests") - { - Archive::AutoDeltaMap(m_quests).pack(target); - } - else if(name == "completedQuests") - { - m_completedQuests.pack(target); - } - else if(name == "activeQuests") - { - m_activeQuests.pack(target); - } - else if(name == "currentQuest") - { - m_currentQuest.pack(target); - } - else if(name == "bornDate") - { - m_bornDate.pack(target); - } - else if(name == "playedTime") - { - m_playedTime.pack(target); - } - else if(name == "food") - { - m_food.pack(target); - } - else if(name == "maxFood") - { - m_maxFood.pack(target); - } - else if(name == "drink") - { - m_drink.pack(target); - } - else if(name == "maxDrink") - { - m_maxDrink.pack(target); - } - else if(name == "meds") - { - m_meds.pack(target); - } - else if(name == "maxMeds") - { - m_maxMeds.pack(target); - } - else if(name == "privledgedTitle") - { - m_privledgedTitle.pack(target); - } - else if(name == "matchMakingPersonalProfileId") - { - m_matchMakingPersonalProfileId.pack(target); - } - else if(name == "matchMakingCharacterProfileId") - { - m_matchMakingCharacterProfileId.pack(target); - } - else if(name == "workingSkill") - { - m_workingSkill.pack(target); - } - else if(name == "skillTemplate") - { - m_skillTemplate.pack(target); - } - else if(name == "collections") - { - m_collections.pack(target); - } - else if(name == "collections2") - { - m_collections2.pack(target); - } - else - { - IntangibleObject::getByteStreamFromAutoVariable(name, target); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source) -{ - Archive::ReadIterator ri(source); - if(name == "quests") - { - typedef Archive::AutoDeltaMap::Command Commands; - std::vector quests; - - m_quests.clear(); - Archive::AutoDeltaMap(m_quests).unpack(ri, quests); - - for (std::vector::const_iterator questIter = quests.begin(); questIter != quests.end(); ++questIter) - { - m_quests.set(questIter->key, questIter->value); - } - } - else if(name == "completedQuests") - { - m_completedQuests.unpackDelta(ri); - } - else if(name == "activeQuests") - { - m_activeQuests.unpackDelta(ri); - } - else if(name == "currentQuest") - { - m_currentQuest.unpackDelta(ri); - } - else if(name == "bornDate") - { - m_bornDate.unpackDelta(ri); - } - else if(name == "playedTime") - { - m_playedTime.unpackDelta(ri); - } - else if(name == "food") - { - m_food.unpackDelta(ri); - } - else if(name == "maxFood") - { - m_maxFood.unpackDelta(ri); - } - else if(name == "drink") - { - m_drink.unpackDelta(ri); - } - else if(name == "maxDrink") - { - m_maxDrink.unpackDelta(ri); - } - else if(name == "meds") - { - m_meds.unpackDelta(ri); - } - else if(name == "maxMeds") - { - m_maxMeds.unpackDelta(ri); - } - else if(name == "privledgedTitle") - { - m_privledgedTitle.unpackDelta(ri); - } - else if(name == "matchMakingPersonalProfileId") - { - m_matchMakingPersonalProfileId.unpackDelta(ri); - } - else if(name == "matchMakingCharacterProfileId") - { - m_matchMakingCharacterProfileId.unpackDelta(ri); - } - else if(name == "workingSkill") - { - m_workingSkill.unpackDelta(ri); - } - else if(name == "skillTemplate") - { - m_skillTemplate.unpackDelta(ri); - } - else if(name == "collections") - { - m_collections.unpackDelta(ri); - } - else if(name == "collections2") - { - m_collections2.unpackDelta(ri); - } - else - { - IntangibleObject::setAutoVariableFromByteStream(name, source); - } - addObjectToConcludeList(); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setGroupWaypoints(WaypointMap const &groupWaypoints) -{ - DEBUG_FATAL(!isAuthoritative(), ("PlayerObject::setGroupWaypoints: called on non-authoritative object %s", getDebugInformation().c_str())); - if (isAuthoritative()) - { - //-- Anything in the new set, we need to set (the AutoDeltaMap will throw out anything unchanged) - { - for (WaypointMap::const_iterator i = groupWaypoints.begin(); i != groupWaypoints.end(); ++i) - m_groupWaypoints.set((*i).first, (*i).second); - } - - //-- Anything that is not in the original set, we need to remove - { - for (WaypointMap::const_iterator i = m_groupWaypoints.begin(); i != m_groupWaypoints.end(); ++i) - if (groupWaypoints.find((*i).first) == groupWaypoints.end()) - m_groupWaypoints.erase((*i).first); - } - } -} - -// ---------------------------------------------------------------------- - -uint32 PlayerObject::getPlayedTime() const -{ - return static_cast(m_playedTime.get() + m_playedTimeAccum); -} - -// ---------------------------------------------------------------------- - -float PlayerObject::getPlayedTimeAccumOnly() const -{ - return m_playedTimeAccum; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setPlayedTimeAccumOnly(float playedTimeAccum) -{ - m_playedTimeAccum = playedTimeAccum; -} - -// ---------------------------------------------------------------------- - -unsigned long PlayerObject::getSessionPlayTimeDuration() const -{ - time_t const sessionStartPlayTime = static_cast(m_sessionStartPlayTime.get()); - if (sessionStartPlayTime > 0) - { - time_t const now = ::time(NULL); - if (now > sessionStartPlayTime) - return static_cast(now - sessionStartPlayTime); - } - - return 0; -} - -// ---------------------------------------------------------------------- - -unsigned long PlayerObject::getSessionActivePlayTimeDuration() const -{ - unsigned long activePlayTimeDuration = m_sessionActivePlayTimeDuration.get(); - - time_t const sessionLastActiveTime = static_cast(m_sessionLastActiveTime.get()); - if (sessionLastActiveTime > 0) - { - time_t const now = ::time(NULL); - if (now > sessionLastActiveTime) - activePlayTimeDuration += static_cast(now - sessionLastActiveTime); - } - - return activePlayTimeDuration; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setSessionPlayTimeInfo(int32 sessionStartPlayTime, int32 sessionLastActiveTime, unsigned long sessionActivePlayTimeDuration) -{ - // shouldn't be calling this on a non-auth object - if (!isAuthoritative()) - return; - - int32 const previousSessionStartPlayTime = m_sessionStartPlayTime.get(); - int32 const previousSessionLastActiveTime = m_sessionLastActiveTime.get(); - - m_sessionStartPlayTime = sessionStartPlayTime; - m_sessionLastActiveTime = sessionLastActiveTime; - m_sessionActivePlayTimeDuration = sessionActivePlayTimeDuration; - - // just connected - if ((previousSessionStartPlayTime == 0) && (sessionStartPlayTime != 0)) - { - CreatureObject const * const owner = getCreatureObject(); - if (owner) - { - LfgCharacterData lfgCharacterData; - owner->getLfgCharacterData(lfgCharacterData); - - ServerUniverse::setConnectedCharacterLfgData(owner->getNetworkId(), lfgCharacterData); - - BiographyManager::requestBiography(owner->getNetworkId(), NULL); - - // check/set "account age" title - checkAndSetAccountAgeTitle(*this); - } - } - // just disconnected - else if ((sessionStartPlayTime == 0) && (previousSessionStartPlayTime != 0)) - { - CreatureObject const * const owner = getCreatureObject(); - if (owner) - { - ServerUniverse::removeConnectedCharacterData(owner->getNetworkId()); - } - } - else if (sessionStartPlayTime != 0) - { - // just went active/inactive - if (((previousSessionLastActiveTime == 0) && (sessionLastActiveTime != 0)) || - ((sessionLastActiveTime == 0) && (previousSessionLastActiveTime != 0))) - { - CreatureObject const * const owner = getCreatureObject(); - if (owner) - { - LfgCharacterData lfgCharacterData; - owner->getLfgCharacterData(lfgCharacterData); - - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFindLfg = connectedCharacterLfgData.find(owner->getNetworkId()); - if ((iterFindLfg == connectedCharacterLfgData.end()) || (iterFindLfg->second != lfgCharacterData)) - ServerUniverse::setConnectedCharacterLfgData(owner->getNetworkId(), lfgCharacterData); - } - } - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setRoleIconChoice(int roleIconChoice) -{ - m_roleIconChoice = roleIconChoice; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getRoleIconChoice() const -{ - return m_roleIconChoice.get(); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setAggroImmuneDuration(int const time) -{ - m_aggroImmuneDuration = static_cast(time); - m_aggroImmuneStartTime = Os::getRealSystemTime(); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::isAggroImmune() const -{ - time_t const elapsedTime = Os::getRealSystemTime() - m_aggroImmuneStartTime.get(); - - return (elapsedTime < m_aggroImmuneDuration.get()); -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getAgeInDays() const -{ - return int(getCurrentBornDate() - getBornDate()); -} - -// ---------------------------------------------------------------------- - -std::string const & PlayerObject::getSkillTemplate() const -{ - return m_skillTemplate.get(); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::setSkillTemplate(std::string const & templateName, bool const clientRequest) -{ - std::string const previousTemplateName(m_skillTemplate.get()); - - // we need to pass an empty string to script to do cleanup, but we don't want to actually change the player's skill - if (!templateName.empty()) - m_skillTemplate.set(templateName); - - CreatureObject * const owner = getCreatureObject(); - if(owner) - { - GameScriptObject * const script = owner->getScriptObject(); - if(script) - { - ScriptParams params; - - params.addParam(templateName.c_str()); - params.addParam(clientRequest); - - if (script->trigAllScripts(Scripting::TRIG_SKILL_TEMPLATE_CHANGED, params) == SCRIPT_DEFAULT) - { - m_skillTemplate.set(previousTemplateName); - LOG("ScriptInvestigation", ("Scripts blocked setSkillTemplate( %s ) on Player( %s ). Reverting to %s.", templateName.c_str(), getAccountDescription().c_str(), previousTemplateName.c_str())); - } - } - - if (previousTemplateName != m_skillTemplate.get()) - { - uint8 const newProfession = static_cast(LfgCharacterData::convertSkillTemplateToProfession(m_skillTemplate.get())); - - GroupObject * const group = owner->getGroup(); - if (group) - { - uint8 const currentProfessionForGroup = group->getMemberProfession(owner->getNetworkId()); - - if (newProfession != currentProfessionForGroup) - group->setMemberProfession(owner->getNetworkId(), newProfession); - } - - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(owner->getNetworkId()); - if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.profession != static_cast(newProfession))) - ServerUniverse::setConnectedCharacterProfessionData(owner->getNetworkId(), static_cast(newProfession)); - } - } - - return (templateName != previousTemplateName); -} - -// ---------------------------------------------------------------------- - -std::string const & PlayerObject::getWorkingSkill() const -{ - return m_workingSkill.get(); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::setWorkingSkill(std::string const & skillName, bool const clientRequest) -{ - std::string const previousWorkingSkill(m_workingSkill.get()); - - m_workingSkill.set(skillName); - - CreatureObject * const owner = getCreatureObject(); - if(owner) - { - GameScriptObject * const script = owner->getScriptObject(); - if(script) - { - ScriptParams params; - - params.addParam(skillName.c_str()); - params.addParam(clientRequest); - - if (script->trigAllScripts(Scripting::TRIG_WORKING_SKILL_CHANGED, params) == SCRIPT_DEFAULT) - { - m_workingSkill.set(previousWorkingSkill); - LOG("ScriptInvestigation", ("Scripts blocked setWorkingSkill( %s ) on Player( %s ). Reverting to %s.", skillName.c_str(), getAccountDescription().c_str(), previousWorkingSkill.c_str())); - } - } - } - - - return (previousWorkingSkill != skillName); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setPendingRequestQuestInformation(uint32 questCrc, NetworkId const & questGiver) -{ - m_pendingRequestQuestCrc = questCrc; - m_pendingRequestQuestGiver = questGiver; -} - -// ---------------------------------------------------------------------- - -uint32 PlayerObject::getPendingRequestQuestCrc() const -{ - return m_pendingRequestQuestCrc; -} - -// ---------------------------------------------------------------------- - -NetworkId const & PlayerObject::getPendingRequestQuestGiver() const -{ - return m_pendingRequestQuestGiver; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getNumberOfActiveQuests() const -{ - int counter = 0; - for (PlayerQuestDataMap::const_iterator i = m_quests.begin(); i != m_quests.end(); ++i) - { - PlayerQuestData const questData(i->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators - if(!questData.isCompleted()) - { - ++counter; - } - } - return counter; -} - -// ---------------------------------------------------------------------- - -std::vector PlayerObject::questGetAllActiveQuestIds() const -{ - std::vector result; - for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) - { - if(!i->second.isCompleted()) - { - result.push_back(i->first); - } - } - return result; -} - -// ---------------------------------------------------------------------- - -std::vector PlayerObject::questGetAllCompletedQuestIds() const -{ - std::vector result; - for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) - { - if(i->second.isCompleted()) - { - result.push_back(i->first); - } - } - return result; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setPlayerQuestDataComplete(uint32 questCrc, PlayerQuestData & playerQuestData) -{ - playerQuestData.complete(); - m_quests.set(questCrc, playerQuestData); - - //-- if the completed quest is the current quest, pick a new one - if (questCrc == getCurrentQuest()) - { - pickNewCurrentQuest(); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::pickNewCurrentQuest() -{ - uint32 lastRelativeAgeIndex = 0; - uint32 lastQuestCrc = 0; - - for (PlayerQuestDataMap::const_iterator i = m_quests.begin(); i != m_quests.end(); ++i) - { - PlayerQuestData const & questData = i->second; - uint32 const questCrc = i->first; - - if (!questData.isCompleted() && questData.getRelativeAgeIndex() >= lastRelativeAgeIndex) - { - lastQuestCrc = questCrc; - lastRelativeAgeIndex = questData.getRelativeAgeIndex(); - } - } - - setCurrentQuest(lastQuestCrc); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyCurrentGcwPoints(int const count, bool modifyLifetimeValue) -{ - CreatureObject * const owner = getCreatureObject(); - if (!owner) - return; - - if (isAuthoritative()) - { - if (PvpData::isImperialFactionId(owner->getPvpFaction()) || PvpData::isRebelFactionId(owner->getPvpFaction())) - { - static int32 const max = std::numeric_limits::max(); - - // m_currentGcwPoints should always be >= 0 - int32 const currentValue = std::max(static_cast(0), m_currentGcwPoints.get()); - - // limit count so it doesn't cause overflow - int32 const adjustedCount = std::min(static_cast(count), max - currentValue); - - int32 temp = 0; - if (adjustedCount != 0) - { - temp = m_currentGcwPoints.get(); - m_currentGcwPoints = std::max(static_cast(0), currentValue + adjustedCount); - } - - if (modifyLifetimeValue && (count > 0)) - modifyLifetimeGcwPoints(count); - - if (adjustedCount != 0) - { - char buffer[256]; - sprintf(buffer, INT64_FORMAT_SPECIFIER, m_lifetimeGcwPoints.get()); - - LOG("CustomerService", ("PvP_Ranking:%s|adjust point=%d|current=%ld|new=%ld|lifetime=%s", - getAccountDescription().c_str(), - count, - temp, - m_currentGcwPoints.get(), - buffer)); - } - } - else - { - // non-factional characters is always at 0 - if (m_currentGcwPoints.get() != 0) - { - LOG("CustomerService", ("PvP_Ranking:%s|adjust point=%d|setting current points (%ld) to 0 because not factional", - getAccountDescription().c_str(), - count, - m_currentGcwPoints.get())); - - m_currentGcwPoints = 0; - } - } - - // make sure that m_nextGcwRatingCalcTime is set so that the - // rating will be recalculated at the next recalculation interval - setNextGcwRatingCalcTime(false); - } - else - { - owner->sendControllerMessageToAuthServer(CM_modifyCurrentGcwPoints, new MessageQueueGenericValueType >(std::make_pair(count, (modifyLifetimeValue ? 1 : 0)))); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyCurrentGcwRating(int const count, bool modifyMaxValue) -{ - CreatureObject * const owner = getCreatureObject(); - if (!owner) - return; - - if (isAuthoritative()) - { - if (PvpData::isImperialFactionId(owner->getPvpFaction()) || PvpData::isRebelFactionId(owner->getPvpFaction())) - { - static int32 const max = std::numeric_limits::max(); - - // m_currentGcwRating should always be >= 0 - int32 const currentValue = std::max(static_cast(Pvp::getMinRatingForRank()), m_currentGcwRating.get()); - - // limit count so it doesn't cause overflow - int32 const adjustedCount = std::min(static_cast(count), max - currentValue); - - if (adjustedCount != 0) - { - int32 const temp = m_currentGcwRating.get(); - - m_currentGcwRating = std::min(std::max(static_cast(Pvp::getMinRatingForRank()), currentValue + adjustedCount), static_cast(Pvp::getMaxRatingForRank())); - - // calculate new rank - Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); - int const oldRank = m_currentGcwRank.get(); - m_currentGcwRank = pvpRankInfo.rank; - - if (pvpRankInfo.rank > 0) - { - m_currentGcwRankProgress = static_cast(std::min(static_cast(m_currentGcwRating.get()), pvpRankInfo.maxRating) - pvpRankInfo.minRating) * 100.0f / static_cast(pvpRankInfo.maxRating - pvpRankInfo.minRating + 1); - } - else - { - m_currentGcwRankProgress = 0.0f; - } - - if (modifyMaxValue) - { - if (PvpData::isImperialFactionId(owner->getPvpFaction()) && (m_currentGcwRating.get() > m_maxGcwImperialRating.get())) - { - m_maxGcwImperialRating = m_currentGcwRating; - m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; - } - else if (PvpData::isRebelFactionId(owner->getPvpFaction()) && (m_currentGcwRating.get() > m_maxGcwRebelRating.get())) - { - m_maxGcwRebelRating = m_currentGcwRating; - m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; - } - } - - LOG("CustomerService", ("PvP_Ranking:%s|adjust rating=%d|current=%ld|new=%ld|max imp=%ld|max reb=%ld", - getAccountDescription().c_str(), - count, - temp, - m_currentGcwRating.get(), - m_maxGcwImperialRating.get(), - m_maxGcwRebelRating.get())); - - // notify script if rank changed - if (oldRank != m_currentGcwRank.get()) - { - GameScriptObject * const script = owner->getScriptObject(); - - if (script != 0) - { - ScriptParams params; - params.addParam(oldRank); - params.addParam(m_currentGcwRank.get()); - script->trigAllScripts(Scripting::TRIG_PVP_RANKING_CHANGED, params); - } - } - } - } - else - { - // non-factional characters is always at -1 - if (m_currentGcwRating.get() != -1) - { - LOG("CustomerService", ("PvP_Ranking:%s|adjust rating=%d|setting current rating (%ld) to -1 because not factional", - getAccountDescription().c_str(), - count, - m_currentGcwRating.get())); - - m_currentGcwRating = -1; - } - - int const oldRank = m_currentGcwRank.get(); - m_currentGcwRank = 0; - m_currentGcwRankProgress = 0.0f; - - // notify script if rank changed - if (oldRank != m_currentGcwRank.get()) - { - GameScriptObject * const script = owner->getScriptObject(); - - if (script != 0) - { - ScriptParams params; - params.addParam(oldRank); - params.addParam(m_currentGcwRank.get()); - script->trigAllScripts(Scripting::TRIG_PVP_RANKING_CHANGED, params); - } - } - } - - // make sure that m_nextGcwRatingCalcTime is set so that the - // rating will be recalculated at the next recalculation interval - setNextGcwRatingCalcTime(false); - } - else - { - owner->sendControllerMessageToAuthServer(CM_modifyCurrentGcwRating, new MessageQueueGenericValueType >(std::make_pair(count, (modifyMaxValue ? 1 : 0)))); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyCurrentPvpKills(int const count, bool modifyLifetimeValue) -{ - CreatureObject * const owner = getCreatureObject(); - if (!owner) - return; - - if (isAuthoritative()) - { - if (PvpData::isImperialFactionId(owner->getPvpFaction()) || PvpData::isRebelFactionId(owner->getPvpFaction())) - { - static int32 const max = std::numeric_limits::max(); - - // m_currentPvpKills should always be >= 0 - int32 const currentValue = std::max(static_cast(0), m_currentPvpKills.get()); - - // limit count so it doesn't cause overflow - int32 const adjustedCount = std::min(static_cast(count), max - currentValue); - - int32 temp = 0; - if (adjustedCount != 0) - { - temp = m_currentPvpKills.get(); - m_currentPvpKills = std::max(static_cast(0), currentValue + adjustedCount); - } - - if (modifyLifetimeValue && (count > 0)) - modifyLifetimePvpKills(count); - - if (adjustedCount != 0) - { - LOG("CustomerService", ("PvP_Ranking:%s|adjust pvp kill=%d|current=%ld|new=%ld|lifetime=%ld", - getAccountDescription().c_str(), - count, - temp, - m_currentPvpKills.get(), - m_lifetimePvpKills.get())); - } - } - else - { - // non-factional characters is always at 0 - if (m_currentPvpKills.get() != 0) - { - LOG("CustomerService", ("PvP_Ranking:%s|adjust pvp kill=%d|setting current pvp kill (%ld) to 0 because not factional", - getAccountDescription().c_str(), - count, - m_currentPvpKills.get())); - - m_currentPvpKills = 0; - } - } - - // make sure that m_nextGcwRatingCalcTime is set so that the - // rating will be recalculated at the next recalculation interval - setNextGcwRatingCalcTime(false); - } - else - { - owner->sendControllerMessageToAuthServer(CM_modifyCurrentPvpKills, new MessageQueueGenericValueType >(std::make_pair(count, (modifyLifetimeValue ? 1 : 0)))); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyLifetimeGcwPoints(int const count) -{ - if (isAuthoritative()) - { - static int64 const max = std::numeric_limits::max(); - - // m_lifetimeGcwPoints should always be >= 0 - int64 const currentValue = std::max(static_cast(0), m_lifetimeGcwPoints.get()); - - // limit count so it doesn't cause overflow - int64 const adjustedCount = std::min(static_cast(count), max - currentValue); - - if (adjustedCount != 0) - m_lifetimeGcwPoints = std::max(static_cast(0), currentValue + adjustedCount); - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_modifyLifetimeGcwPoints, new MessageQueueGenericValueType(count)); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyMaxGcwImperialRating(int const count) -{ - if (isAuthoritative()) - { - static int32 const min = std::numeric_limits::min() + 1; - static int32 const max = std::numeric_limits::max() - 1; - - // m_maxGcwImperialRating should always be >= -1 - int32 currentValue = std::max(static_cast(-1), m_maxGcwImperialRating.get()); - currentValue = std::min(currentValue, max); - - // limit count so it doesn't cause underflow or overflow - int32 adjustedCount = std::max(static_cast(count), min); - adjustedCount = std::min(adjustedCount, max - currentValue); - - if (adjustedCount != 0) - { - m_maxGcwImperialRating = std::min(std::max(static_cast(-1), currentValue + adjustedCount), static_cast(Pvp::getMaxRatingForRank())); - m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; - } - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_modifyMaxGcwImperialRating, new MessageQueueGenericValueType(count)); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyMaxGcwRebelRating(int const count) -{ - if (isAuthoritative()) - { - static int32 const min = std::numeric_limits::min() + 1; - static int32 const max = std::numeric_limits::max() - 1; - - // m_maxGcwRebelRating should always be >= -1 - int32 currentValue = std::max(static_cast(-1), m_maxGcwRebelRating.get()); - currentValue = std::min(currentValue, max); - - // limit count so it doesn't cause underflow or overflow - int32 adjustedCount = std::max(static_cast(count), min); - adjustedCount = std::min(adjustedCount, max - currentValue); - - if (adjustedCount != 0) - { - m_maxGcwRebelRating = std::min(std::max(static_cast(-1), currentValue + adjustedCount), static_cast(Pvp::getMaxRatingForRank())); - m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; - } - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_modifyMaxGcwRebelRating, new MessageQueueGenericValueType(count)); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyLifetimePvpKills(int const count) -{ - if (isAuthoritative()) - { - static int32 const max = std::numeric_limits::max(); - - // m_lifetimePvpKills should always be >= 0 - int32 const currentValue = std::max(static_cast(0), m_lifetimePvpKills.get()); - - // limit count so it doesn't cause overflow - int32 const adjustedCount = std::min(static_cast(count), max - currentValue); - - if (adjustedCount != 0) - m_lifetimePvpKills = std::max(static_cast(0), currentValue + adjustedCount); - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_modifyLifetimePvpKills, new MessageQueueGenericValueType(count)); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyNextGcwRatingCalcTime(int const weekCount) -{ - if (isAuthoritative()) - { - // don't need to do anything if the player doesn't need rating recalculated - if (!needsGcwRatingRecalculated()) - return; - - static int32 const max = std::numeric_limits::max(); - int32 const now = static_cast(::time(NULL)); - - // m_nextGcwRatingCalcTime should always be >= 0 - int32 const currentValue = std::max(static_cast(0), m_nextGcwRatingCalcTime.get()); - - // limit weekCount to -1000 to 1000 with 0 meaning "now" - int32 adjustedWeekCount = std::max(static_cast(-1000), static_cast(weekCount)); - adjustedWeekCount = std::min(static_cast(1000), adjustedWeekCount); - - // if necessary, cancel the currently pending messageTo for rating recalculation - if (m_nextGcwRatingCalcTime.get() > 0) - { - cancelMessageTo("C++RecalculateGcwRating"); - m_gcwRatingActualCalcTime = 0; - } - - if (adjustedWeekCount != 0) - { - int32 adjustedSeconds = 60 * 60 * 24 * 7 * adjustedWeekCount; - - // limit adjustedSeconds so it doesn't cause overflow - adjustedSeconds = std::min(adjustedSeconds, max - currentValue); - - // don't allow the recalc time to be too far in the past - if (adjustedSeconds != 0) - m_nextGcwRatingCalcTime = std::max(static_cast(CalendarTimeNamespace::g_CalendarTimeEarliestTime), currentValue + adjustedSeconds); - } - else // 0 means "now" - { - m_nextGcwRatingCalcTime = now; - } - - // if necessary, send messageTo to trigger rating recalculation - if (m_nextGcwRatingCalcTime.get() > 0) - { - // randomly spread out the recalculation so they don't all - // happen at exactly the same time and lag out the server, - // unless the recalculation time has passed in which case - // we want to do the recalculation much more quickly - if (m_nextGcwRatingCalcTime.get() <= now) - sendRecalculateGcwRatingMessageTo(5); - else - sendRecalculateGcwRatingMessageTo(std::max(30, static_cast(m_nextGcwRatingCalcTime.get() - now)) + 5 + (rand() % 60)); - } - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_modifyNextGcwRatingCalcTime, new MessageQueueGenericValueType(weekCount)); - } -} - -// ---------------------------------------------------------------------- -void PlayerObject::ctsUseOnlySetGcwInfo(int32 currentGcwPoints, int32 currentGcwRating, int32 currentPvpKills, int64 lifetimeGcwPoints, int32 maxGcwImperialRating, int32 maxGcwRebelRating, int32 lifetimePvpKills, int32 nextGcwRatingCalcTime) -{ - // should only be called on authoritative object - if (!isAuthoritative()) - return; - - // can't do anything if we're not attached to the creature object - if (!getCreatureObject()) - return; - - int32 const oldCurrentGcwPoints = m_currentGcwPoints.get(); - int32 const oldCurrentGcwRating = m_currentGcwRating.get(); - int32 const oldCurrentPvpKills = m_currentPvpKills.get(); - int64 const oldLifetimeGcwPoints = m_lifetimeGcwPoints.get(); - int32 const oldMaxGcwImperialRating = m_maxGcwImperialRating.get(); - int32 const oldMaxGcwRebelRating = m_maxGcwRebelRating.get(); - int32 const oldLifetimePvpKills = m_lifetimePvpKills.get(); - int32 const oldNextGcwRatingCalcTime = m_nextGcwRatingCalcTime.get(); - - m_currentGcwPoints = std::max(static_cast(0), currentGcwPoints); - m_currentGcwRating = std::min(std::max(static_cast(-1), currentGcwRating), static_cast(Pvp::getMaxRatingForRank())); - m_currentPvpKills = std::max(static_cast(0), currentPvpKills); - m_lifetimeGcwPoints = std::max(static_cast(0), lifetimeGcwPoints); - m_maxGcwImperialRating = std::min(std::max(static_cast(-1), maxGcwImperialRating), static_cast(Pvp::getMaxRatingForRank())); - m_maxGcwRebelRating = std::min(std::max(static_cast(-1), maxGcwRebelRating), static_cast(Pvp::getMaxRatingForRank())); - m_lifetimePvpKills = std::max(static_cast(0), lifetimePvpKills); - - // don't allow the recalc time to be too far in the past - m_nextGcwRatingCalcTime = ((nextGcwRatingCalcTime == 0) ? 0 : std::max(static_cast(CalendarTimeNamespace::g_CalendarTimeEarliestTime), nextGcwRatingCalcTime)); - - Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); - m_currentGcwRank = pvpRankInfo.rank; - - if (pvpRankInfo.rank > 0) - { - m_currentGcwRankProgress = static_cast(std::min(static_cast(m_currentGcwRating.get()), pvpRankInfo.maxRating) - pvpRankInfo.minRating) * 100.0f / static_cast(pvpRankInfo.maxRating - pvpRankInfo.minRating + 1); - } - else - { - m_currentGcwRankProgress = 0.0f; - } - - m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; - m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; - - char buffer1[128]; - char buffer2[128]; - sprintf(buffer1, INT64_FORMAT_SPECIFIER, oldLifetimeGcwPoints); - sprintf(buffer2, INT64_FORMAT_SPECIFIER, m_lifetimeGcwPoints.get()); - - LOG("CustomerService", ("PvP_Ranking:%s|applying info from CTS|point:%ld -> %ld|rating:%ld -> %ld|pvp kill:%ld -> %ld|lifetime point:%s -> %s|max imp rating:%ld -> %ld|max reb rating:%ld -> %ld|lifetime pvp kill:%ld -> %ld|calc time:%ld -> %ld", - getAccountDescription().c_str(), - oldCurrentGcwPoints, m_currentGcwPoints.get(), - oldCurrentGcwRating, m_currentGcwRating.get(), - oldCurrentPvpKills, m_currentPvpKills.get(), - buffer1, buffer2, - oldMaxGcwImperialRating, m_maxGcwImperialRating.get(), - oldMaxGcwRebelRating, m_maxGcwRebelRating.get(), - oldLifetimePvpKills, m_lifetimePvpKills.get(), - oldNextGcwRatingCalcTime, m_nextGcwRatingCalcTime.get())); - - // if necessary, cancel the currently pending messageTo for rating recalculation - if (oldNextGcwRatingCalcTime > 0) - { - cancelMessageTo("C++RecalculateGcwRating"); - m_gcwRatingActualCalcTime = 0; - } - - // make sure that m_nextGcwRatingCalcTime is set so that the - // rating will be recalculated at the next recalculation interval - setNextGcwRatingCalcTime(true); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setNextGcwRatingCalcTime(bool const alwaysSendMessageToForRecalc) -{ - // should only be called on authoritative object - if (!isAuthoritative()) - return; - - bool needToSendMessageTo = alwaysSendMessageToForRecalc; - int32 const now = static_cast(::time(NULL)); - - // if the player needs a rating recalculation, - // make sure that m_nextGcwRatingCalcTime is set so that the - // rating will be recalculated at the next recalculation interval - if (needsGcwRatingRecalculated()) - { - if (m_nextGcwRatingCalcTime.get() <= 0) - { - time_t const nextCalcTime = CalendarTime::getNextGMTTimeOcurrence(static_cast(now), ConfigServerGame::getGcwRecalcTimeDayOfWeek(), ConfigServerGame::getGcwRecalcTimeHour(), ConfigServerGame::getGcwRecalcTimeMinute(), ConfigServerGame::getGcwRecalcTimeSecond()); - if (nextCalcTime > 0) - { - m_nextGcwRatingCalcTime = static_cast(nextCalcTime); - needToSendMessageTo = true; - } - } - } - else - { - // if necessary, cancel the currently pending messageTo for rating recalculation - if (m_nextGcwRatingCalcTime.get() > 0) - { - cancelMessageTo("C++RecalculateGcwRating"); - m_gcwRatingActualCalcTime = 0; - } - - m_nextGcwRatingCalcTime = 0; - } - - // send messageTo to trigger rating recalculation - if (needToSendMessageTo && (m_nextGcwRatingCalcTime.get() > 0)) - { - // randomly spread out the recalculation so they don't all - // happen at exactly the same time and lag out the server, - // unless the recalculation time has passed in which case - // we want to do the recalculation much more quickly - if (m_nextGcwRatingCalcTime.get() <= now) - sendRecalculateGcwRatingMessageTo(5); - else - sendRecalculateGcwRatingMessageTo(std::max(30, static_cast(m_nextGcwRatingCalcTime.get() - now)) + 5 + (rand() % 60)); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::handleRecalculateGcwRating() -{ - // should only be called on authoritative object - if (!isAuthoritative()) - return; - - // can't do anything if we're not attached to the creature object - if (!getCreatureObject()) - return; - - // is it time to recalculate? - int32 const now = static_cast(::time(NULL)); - if ((m_nextGcwRatingCalcTime.get() > 0) && (m_nextGcwRatingCalcTime.get() <= now)) - { - // is recalculation required? - if (needsGcwRatingRecalculated()) - { - int32 nextCalcInterval = m_nextGcwRatingCalcTime.get(); - int32 points = std::max(static_cast(0), m_currentGcwPoints.get()); - int32 currentRating = m_currentGcwRating.get(); - int32 previousRating; - int totalRatingAdjustment, totalEarnedRating, totalEarnedRatingAfterDecay, cappedRatingAdjustment; - bool moreRecalculationNeeded = false; - while (true) - { - // calculate rating adjustment for interval - totalRatingAdjustment = Pvp::calculateRatingAdjustment(static_cast(points), static_cast(currentRating), totalEarnedRating, totalEarnedRatingAfterDecay, cappedRatingAdjustment); - - // don't apply rating loss if we are in a "rating loss exclusion interval" - if ((totalRatingAdjustment < 0) && (Pvp::isInGcwRankDecayExclusionInterval(static_cast(nextCalcInterval)))) - { - // CS log - LOG("CustomerService", ("PvP_Ranking:%s|NOT APPLYING RATING LOSS|interval %ld (%s) (%s)|current rating=%ld|points=%ld|total earned rating=%ld|total earned rating after decay=%ld|capped rating adjustment=%ld|final rating adjustment=%ld", - getAccountDescription().c_str(), - nextCalcInterval, - CalendarTime::convertEpochToTimeStringGMT(static_cast(nextCalcInterval)).c_str(), - CalendarTime::convertEpochToTimeStringLocal(static_cast(nextCalcInterval)).c_str(), - currentRating, - points, - totalEarnedRating, - totalEarnedRatingAfterDecay, - cappedRatingAdjustment, - totalRatingAdjustment)); - } - else - { - // update rating - previousRating = currentRating; - currentRating += static_cast(totalRatingAdjustment); - - // make sure updated rating is in range of valid rating - currentRating = std::max(currentRating, static_cast(Pvp::getMinRatingForRank())); - currentRating = std::min(currentRating, static_cast(Pvp::getMaxRatingForRank())); - - // CS log - LOG("CustomerService", ("PvP_Ranking:%s|interval %ld (%s) (%s)|current rating=%ld|new rating=%ld|points=%ld|total earned rating=%ld|total earned rating after decay=%ld|capped rating adjustment=%ld|final rating adjustment=%ld", - getAccountDescription().c_str(), - nextCalcInterval, - CalendarTime::convertEpochToTimeStringGMT(static_cast(nextCalcInterval)).c_str(), - CalendarTime::convertEpochToTimeStringLocal(static_cast(nextCalcInterval)).c_str(), - previousRating, - currentRating, - points, - totalEarnedRating, - totalEarnedRatingAfterDecay, - cappedRatingAdjustment, - totalRatingAdjustment)); - } - - // point have all been converted - points = 0; - - // check to see if we need to do another calculation for the next interval - nextCalcInterval = static_cast(CalendarTime::getNextGMTTimeOcurrence(static_cast(nextCalcInterval)+1, ConfigServerGame::getGcwRecalcTimeDayOfWeek(), ConfigServerGame::getGcwRecalcTimeHour(), ConfigServerGame::getGcwRecalcTimeMinute(), ConfigServerGame::getGcwRecalcTimeSecond())); - if (nextCalcInterval <= 0) - break; - - if (nextCalcInterval > now) - break; - - Pvp::PvpRankInfo const & pvpNewRankInfo = Pvp::getRankInfo(currentRating); - if (pvpNewRankInfo.rank < 1) - break; - - if (pvpNewRankInfo.ratingDecayBalance <= 0) - break; - - // if rating increased, then exit loop so that the new rating - // can be updated so that the max rating can be saved, and rank - // increase notification gets sent; otherwise, the rating - // increase may get "lost" with subsequent decrease due to decay - // as this loop iterates; if further calculation is required for more - // intervals, then send another messageTo to trigger more calculations - if (currentRating > m_currentGcwRating.get()) - { - moreRecalculationNeeded = true; - break; - } - } - - // decrementing the value by a really large - // number will cause it to reset to 0 - static int const min = std::numeric_limits::min(); - - // apply new GCW values - if (m_currentGcwPoints.get() != 0) - modifyCurrentGcwPoints(min, false); - - if (m_currentPvpKills.get() != 0) - modifyCurrentPvpKills(min, false); - - if (currentRating != m_currentGcwRating.get()) - modifyCurrentGcwRating((currentRating - m_currentGcwRating.get()), true); - - // if more recalculations are needed, send - // messageTo to trigger more recalculations - if (moreRecalculationNeeded) - { - m_nextGcwRatingCalcTime = nextCalcInterval; - sendRecalculateGcwRatingMessageTo(5); - } - else - { - // make sure that m_nextGcwRatingCalcTime is set so that the - // rating will be recalculated at the next recalculation interval - m_nextGcwRatingCalcTime = 0; - setNextGcwRatingCalcTime(false); - } - } - else - { - m_nextGcwRatingCalcTime = 0; - } - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::sendRecalculateGcwRatingMessageTo(int delay) -{ - // cancel any pending messageTo - cancelMessageTo("C++RecalculateGcwRating"); - - // send new messageTo - int const adjustedDelay = std::max(5, delay); - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++RecalculateGcwRating", "", adjustedDelay, false); - m_gcwRatingActualCalcTime = static_cast(::time(NULL) + adjustedDelay); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::needsGcwRatingRecalculated() const -{ - Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); - return ((m_currentGcwPoints.get() > 0) || (m_currentPvpKills.get() > 0) || ((pvpRankInfo.rank > 0) && (pvpRankInfo.ratingDecayBalance > 0))); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::clearSessionActivity() -{ - if (isAuthoritative()) - { - m_sessionActivity = 0; - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_clearSessionActivity, 0); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::addSessionActivity(uint32 activity) -{ - if (isAuthoritative()) - { - m_sessionActivity = m_sessionActivity.get() | activity; - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_addSessionActivity, new MessageQueueGenericValueType(static_cast(activity))); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setPetId(NetworkId const & newId) -{ - m_petId.set(newId); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setPetCommandList(std::vector const &commands) -{ - m_petCommandList.set(commands); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::setPetToggledCommands(std::vector const &commands) -{ - m_petToggledCommands.set(commands); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::updateKillMeter(float deltaTime) -{ - if(!isAuthoritative()) - return; - - if(m_killMeter.get() == 0) - return; - float currentValue = m_killMeter.get() + m_killMeterRemainder; - float newValue = (currentValue) - (m_killMeter.get() / 150.0f) * deltaTime; - int32 newValueInt = static_cast(newValue); - m_killMeterRemainder = (newValue - newValueInt); - if(m_killMeterRemainder > 0.01f) - { - newValueInt += 1; - m_killMeterRemainder -= 1.0f; - } - if(newValueInt != m_killMeter.get()) - m_killMeter = newValueInt; - - return; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::incrementKillMeter(int amount) -{ - if(isAuthoritative()) - { - if(m_killMeter.get() + amount > MAX_KILL_METER) - { - m_killMeter = MAX_KILL_METER; - m_killMeterRemainder = 0.0f; - } - else - { - m_killMeter = m_killMeter.get() + amount; - } - } - else - { - CreatureObject *owner = getCreatureObject(); - owner->sendControllerMessageToAuthServer(CM_incrementKillMeter, new MessageQueueGenericValueType(amount)); - } -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::modifyCollectionSlotValue(std::string const & slotName, int64 delta) -{ - CreatureObject * const owner = getCreatureObject(); - if (!owner) - return false; - - if (isAuthoritative()) - { - CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); - if (!slotInfo) - { - DEBUG_WARNING(true, ("Trying to modify a collection slot for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); - return false; - } - - Archive::AutoDeltaVariable * const collections = m_allCollections[slotInfo->slotIdIndex]; - - // bit-type slot - if (!slotInfo->counterTypeSlot) - { - // set bit-type slot - if (delta > 0) - { - if (!collections->get().testBit(slotInfo->beginSlotId)) - { - // check prereqs first - if (!hasCompletedCollectionSlotPrereq(*slotInfo)) - return false; - - BitArray b = collections->get(); - b.setBit(slotInfo->beginSlotId); - collections->set(b); - - LOG("CustomerService", ("Collection:%s added collection %d (%s/%s/%s/%s)", - getAccountDescription().c_str(), - slotInfo->absoluteBeginSlotId, - slotInfo->collection.page.book.name.c_str(), - slotInfo->collection.page.name.c_str(), - slotInfo->collection.name.c_str(), - slotInfo->name.c_str())); - - // for "server first" tracking, we need to check if the collection - // is completed *BEFORE* triggering script, because script may clear - // a completed collection (for repeatable collections), so that - // when we come back from triggering script, the collection will not - // appear to be completed, even though it really was completed and - // "server first" should have been granted - bool grantServerFirst = false; - if (slotInfo->collection.trackServerFirst && (slotInfo->collection.serverFirstClaimTime <= 0)) - { - bool const isSecuredLogin = (owner->getClient() && owner->getClient()->isGodValidated()); - if (!ConfigServerGame::getDisableCollectionServerFirstGrantForSecuredLogin() || !isSecuredLogin) - { - if (hasCompletedCollection(slotInfo->collection.name)) - { - grantServerFirst = true; - } - } - } - - GameScriptObject * gameScriptObject = owner->getScriptObject(); - if (gameScriptObject && slotInfo->notifyScriptOnModify) - { - ScriptParams params; - params.addParam(slotInfo->collection.page.book.name.c_str()); // book - params.addParam(slotInfo->collection.page.name.c_str()); // page - params.addParam(slotInfo->collection.name.c_str()); // collection - params.addParam(slotInfo->name.c_str()); // slot - params.addParam(false); // is counter-type slot? - params.addParam(static_cast(0)); // previous slot value - params.addParam(static_cast(1)); // current slot value - params.addParam(static_cast(1)); // max slot value - params.addParam(true); // slot completed? - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SLOT_MODIFIED, params)); - } - - // grant "server first", if necessary - if (grantServerFirst) - { - PlanetObject * const planetObject = ServerUniverse::getInstance().getTatooinePlanet(); - if (planetObject) - { - planetObject->setCollectionServerFirst(slotInfo->collection, owner->getNetworkId(), owner->getAssignedObjectName(), getAccountDescription()); - } - } - } - } - // clear bit-type slot - else if (delta < 0) - { - if (collections->get().testBit(slotInfo->beginSlotId)) - { - BitArray b = collections->get(); - b.clearBit(slotInfo->beginSlotId); - collections->set(b); - - LOG("CustomerService", ("Collection:%s removed collection %d (%s/%s/%s/%s)", - getAccountDescription().c_str(), - slotInfo->absoluteBeginSlotId, - slotInfo->collection.page.book.name.c_str(), - slotInfo->collection.page.name.c_str(), - slotInfo->collection.name.c_str(), - slotInfo->name.c_str())); - - GameScriptObject * gameScriptObject = owner->getScriptObject(); - if (gameScriptObject && slotInfo->notifyScriptOnModify) - { - ScriptParams params; - params.addParam(slotInfo->collection.page.book.name.c_str()); // book - params.addParam(slotInfo->collection.page.name.c_str()); // page - params.addParam(slotInfo->collection.name.c_str()); // collection - params.addParam(slotInfo->name.c_str()); // slot - params.addParam(false); // is counter-type slot? - params.addParam(static_cast(1)); // previous slot value - params.addParam(static_cast(0)); // current slot value - params.addParam(static_cast(1)); // max slot value - params.addParam(false); // slot completed? - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SLOT_MODIFIED, params)); - } - } - } - } - // counter-type slot - else if (delta != 0) - { - // check prereqs first - if ((delta > 0) && !hasCompletedCollectionSlotPrereq(*slotInfo)) - return false; - - int64 const currentSlotValue = static_cast(collections->get().getValue(slotInfo->beginSlotId, slotInfo->endSlotId)); - int64 const newSlotValue = clamp(static_cast(0), (currentSlotValue + delta), ((slotInfo->maxSlotValue > 0) ? static_cast(slotInfo->maxSlotValue) : static_cast(slotInfo->maxValueForNumBits))); - - // did slot value changed? - if (currentSlotValue != newSlotValue) - { - BitArray b = collections->get(); - b.setValue(slotInfo->beginSlotId, slotInfo->endSlotId, static_cast(newSlotValue)); - collections->set(b); - - LOG("CustomerService", ("Collection:%s modified collection %d-%d (%s/%s/%s/%s) from %lu to %lu", - getAccountDescription().c_str(), - slotInfo->absoluteBeginSlotId, - slotInfo->absoluteEndSlotId, - slotInfo->collection.page.book.name.c_str(), - slotInfo->collection.page.name.c_str(), - slotInfo->collection.name.c_str(), - slotInfo->name.c_str(), - static_cast(currentSlotValue), - static_cast(newSlotValue))); - - bool const completedCollectionSlot = hasCompletedCollectionSlot(*slotInfo, static_cast(newSlotValue)); - - // for "server first" tracking, we need to check if the collection - // is completed *BEFORE* triggering script, because script may clear - // a completed collection (for repeatable collections), so that - // when we come back from triggering script, the collection will not - // appear to be completed, even though it really was completed and - // "server first" should have been granted - bool grantServerFirst = false; - if (completedCollectionSlot && slotInfo->collection.trackServerFirst && (slotInfo->collection.serverFirstClaimTime <= 0)) - { - bool const isSecuredLogin = (owner->getClient() && owner->getClient()->isGodValidated()); - if (!ConfigServerGame::getDisableCollectionServerFirstGrantForSecuredLogin() || !isSecuredLogin) - { - if (hasCompletedCollection(slotInfo->collection.name)) - { - grantServerFirst = true; - } - } - } - - GameScriptObject * gameScriptObject = owner->getScriptObject(); - if (gameScriptObject && slotInfo->notifyScriptOnModify) - { - ScriptParams params; - params.addParam(slotInfo->collection.page.book.name.c_str()); // book - params.addParam(slotInfo->collection.page.name.c_str()); // page - params.addParam(slotInfo->collection.name.c_str()); // collection - params.addParam(slotInfo->name.c_str()); // slot - params.addParam(true); // is counter-type slot? - params.addParam(static_cast(currentSlotValue)); // previous slot value - params.addParam(static_cast(newSlotValue)); // current slot value - params.addParam(static_cast(slotInfo->maxSlotValue)); // max slot value - params.addParam(completedCollectionSlot); // slot completed? - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SLOT_MODIFIED, params)); - } - - // grant "server first", if necessary - if (grantServerFirst) - { - PlanetObject * const planetObject = ServerUniverse::getInstance().getTatooinePlanet(); - if (planetObject) - { - planetObject->setCollectionServerFirst(slotInfo->collection, owner->getNetworkId(), owner->getAssignedObjectName(), getAccountDescription()); - } - } - } - } - } - else - { - owner->sendControllerMessageToAuthServer(CM_modifyCollectionSlotValue, new MessageQueueGenericValueType >(std::make_pair(slotName, delta))); - } - - return true; -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::getCollectionSlotValue(std::string const & slotName, unsigned long & value) const -{ - value = 0; - - CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); - if (!slotInfo) - { - DEBUG_WARNING(true, ("Trying to get a collection slot value for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); - return false; - } - - return getCollectionSlotValue(*slotInfo, value); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::getCollectionSlotValue(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long & value) const -{ - // bit-type slot - if (!slotInfo.counterTypeSlot) - { - if (m_allCollections[slotInfo.slotIdIndex]->get().testBit(slotInfo.beginSlotId)) - value = 1; - else - value = 0; - } - else - { - value = m_allCollections[slotInfo.slotIdIndex]->get().getValue(slotInfo.beginSlotId, slotInfo.endSlotId); - } - - return true; -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollectionSlotPrereq(std::string const & slotName, std::vector * collectionInfo /*= NULL*/) const -{ - CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); - if (!slotInfo) - { - DEBUG_WARNING(true, ("Checking for collection slot prereq completion for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); - return false; - } - - return hasCompletedCollectionSlotPrereq(*slotInfo, collectionInfo); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollectionSlotPrereq(CollectionsDataTable::CollectionInfoSlot const & slotInfo, std::vector * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - if (slotInfo.prereqsPtr.empty()) - return true; - - bool completed = true; - for (std::vector::const_iterator iterPrereqs = slotInfo.prereqsPtr.begin(); iterPrereqs != slotInfo.prereqsPtr.end(); ++iterPrereqs) - { - if (!hasCompletedCollectionSlot(**iterPrereqs)) - { - if (!collectionInfo) - return false; - - collectionInfo->push_back(*iterPrereqs); - completed = false; - } - } - - return completed; -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollectionSlot(std::string const & slotName) const -{ - CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); - if (!slotInfo) - { - DEBUG_WARNING(true, ("Checking for collection slot completion for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); - return false; - } - - return hasCompletedCollectionSlot(*slotInfo); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo) const -{ - // bit-type slot - if (!slotInfo.counterTypeSlot) - return m_allCollections[slotInfo.slotIdIndex]->get().testBit(slotInfo.beginSlotId); - - // counter-type slot is only completed if a max slot value is - // specified and the current slot value equals the max slot value - return ((slotInfo.maxSlotValue > 0) && (m_allCollections[slotInfo.slotIdIndex]->get().getValue(slotInfo.beginSlotId, slotInfo.endSlotId) >= slotInfo.maxSlotValue)); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long slotValue) -{ - // bit-type slot - if (!slotInfo.counterTypeSlot) - return (slotValue > 0); - - // counter-type slot is only completed if a max slot value is - // specified and the current slot value equals the max slot value - return ((slotInfo.maxSlotValue > 0) && (slotValue >= slotInfo.maxSlotValue)); -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollection(std::string const & collectionName) const -{ - std::vector const & slots = CollectionsDataTable::getSlotsInCollection(collectionName); - - if (slots.empty()) - return false; - - for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) - { - if (!hasCompletedCollectionSlot(**iter)) - return false; - } - - return true; -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollectionPage(std::string const & pageName) const -{ - std::vector const & collections = CollectionsDataTable::getCollectionsInPage(pageName); - - if (collections.empty()) - return false; - - for (std::vector::const_iterator iter = collections.begin(); iter != collections.end(); ++iter) - { - if (!hasCompletedCollection((*iter)->name)) - return false; - } - - return true; -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::hasCompletedCollectionBook(std::string const & bookName) const -{ - std::vector const & pages = CollectionsDataTable::getPagesInBook(bookName); - - if (pages.empty()) - return false; - - for (std::vector::const_iterator iter = pages.begin(); iter != pages.end(); ++iter) - { - if (!hasCompletedCollectionPage((*iter)->name)) - return false; - } - - return true; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getCompletedCollectionSlotCountInCollection(std::string const & collectionName, stdvector::fwd * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - int count = 0; - std::vector const & slots = CollectionsDataTable::getSlotsInCollection(collectionName); - for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) - { - if (hasCompletedCollectionSlot(**iter)) - { - ++count; - - if (collectionInfo) - collectionInfo->push_back(*iter); - } - } - - return count; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getCompletedCollectionSlotCountInPage(std::string const & pageName, std::vector * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - int count = 0; - std::vector const & slots = CollectionsDataTable::getSlotsInPage(pageName); - for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) - { - if (hasCompletedCollectionSlot(**iter)) - { - ++count; - - if (collectionInfo) - collectionInfo->push_back(*iter); - } - } - - return count; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getCompletedCollectionCountInPage(std::string const & pageName, std::vector * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - int count = 0; - std::vector const & collections = CollectionsDataTable::getCollectionsInPage(pageName); - for (std::vector::const_iterator iter = collections.begin(); iter != collections.end(); ++iter) - { - if (hasCompletedCollection((*iter)->name)) - { - ++count; - - if (collectionInfo) - collectionInfo->push_back(*iter); - } - } - - return count; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getCompletedCollectionSlotCountInBook(std::string const & bookName, std::vector * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - int count = 0; - std::vector const & slots = CollectionsDataTable::getSlotsInBook(bookName); - for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) - { - if (hasCompletedCollectionSlot(**iter)) - { - ++count; - - if (collectionInfo) - collectionInfo->push_back(*iter); - } - } - - return count; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getCompletedCollectionCountInBook(std::string const & bookName, std::vector * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - int count = 0; - std::vector const & collections = CollectionsDataTable::getCollectionsInBook(bookName); - for (std::vector::const_iterator iter = collections.begin(); iter != collections.end(); ++iter) - { - if (hasCompletedCollection((*iter)->name)) - { - ++count; - - if (collectionInfo) - collectionInfo->push_back(*iter); - } - } - - return count; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getCompletedCollectionPageCountInBook(std::string const & bookName, std::vector * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - int count = 0; - std::vector const & pages = CollectionsDataTable::getPagesInBook(bookName); - for (std::vector::const_iterator iter = pages.begin(); iter != pages.end(); ++iter) - { - if (hasCompletedCollectionPage((*iter)->name)) - { - ++count; - - if (collectionInfo) - collectionInfo->push_back(*iter); - } - } - - return count; -} - -// ---------------------------------------------------------------------- - -int PlayerObject::getCompletedCollectionBookCount(std::vector * collectionInfo /*= NULL*/) const -{ - if (collectionInfo) - collectionInfo->clear(); - - int count = 0; - std::vector const & books = CollectionsDataTable::getAllBooks(); - for (std::vector::const_iterator iter = books.begin(); iter != books.end(); ++iter) - { - if (hasCompletedCollectionBook((*iter)->name)) - { - ++count; - - if (collectionInfo) - collectionInfo->push_back(*iter); - } - } - - return count; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::migrateLegacyBadgesToCollection(std::vector const & badges) -{ - if (badges.empty()) - return; - - // get the list of all possible collection id for the old badges - static std::map badgeCollectionIds; - if (badgeCollectionIds.empty()) - { - std::vector const & badgeCollectionInfo = CollectionsDataTable::getSlotsInBook("badge_book"); - for (std::vector::const_iterator iter = badgeCollectionInfo.begin(); iter != badgeCollectionInfo.end(); ++iter) - { - if ((*iter)->slotIdIndex == 0) - { - badgeCollectionIds[(*iter)->absoluteBeginSlotId] = *iter; - } - } - } - - BitArray ba = m_collections.get(); - bool anyBadgeMigrated = false; - - char buffer[32]; - std::string badgesString; - CollectionsDataTable::CollectionInfoSlot const * slotInfo; - int badgeIndex = 0; - for (std::vector::const_iterator iter = badges.begin(); iter != badges.end(); ++iter) - { - // for CS logging - snprintf(buffer, sizeof(buffer)-1, "%d", *iter); - buffer[sizeof(buffer)-1] = '\0'; - if (!badgesString.empty()) - badgesString += ", "; - badgesString += buffer; - - for (int i = 0; i < 32; ++i) - { - if (((*iter & (1 << i)) != 0) && (badgeCollectionIds.count(badgeIndex) >= 1) && (!ba.testBit(badgeIndex))) - { - anyBadgeMigrated = true; - ba.setBit(badgeIndex); - - slotInfo = badgeCollectionIds[badgeIndex]; - if (slotInfo) - { - LOG("CustomerService", ("Collection:%s migrated badge to collection %d (%s/%s/%s/%s)", - getAccountDescription().c_str(), - badgeIndex, - slotInfo->collection.page.book.name.c_str(), - slotInfo->collection.page.name.c_str(), - slotInfo->collection.name.c_str(), - slotInfo->name.c_str())); - } - else - { - LOG("CustomerService", ("Collection:%s migrated badge to collection %d", - getAccountDescription().c_str(), - badgeIndex)); - } - } - - ++badgeIndex; - } - } - - if (anyBadgeMigrated) - m_collections.set(ba); - - // CS log the badge objvars so we have a record of badges that were migrated - if (!badgesString.empty()) - LOG("CustomerService", ("Collection:%s migrated legacy badges (%s) over to collection system", getAccountDescription().c_str(), badgesString.c_str())); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::updateChatSpamSpatialNumCharacters(NetworkId const & character, int spatialNumCharacters) -{ - if (!isAuthoritative()) - return; - - int const timeNow = static_cast(::time(NULL)); - bool syncChatServer = false; - - // new interval, reset - if (timeNow > m_chatSpamTimeEndInterval.get()) - { - m_chatSpamTimeEndInterval = timeNow + (ConfigServerGame::getChatSpamLimiterIntervalMinutes() * 60); - m_chatSpamSpatialNumCharacters = spatialNumCharacters; - m_chatSpamNonSpatialNumCharacters = 0; - syncChatServer = true; - } - // update spatial character count - else - { - m_chatSpamSpatialNumCharacters = m_chatSpamSpatialNumCharacters.get() + spatialNumCharacters; - } - - // sync chat character count with chat server - if ((syncChatServer) || (timeNow > m_chatSpamNextTimeToSyncWithChatServer.get())) - { - time_t timeUnsquelch = static_cast(getSecondsUntilUnsquelched()); - if (timeUnsquelch > 0) - timeUnsquelch += ::time(NULL); - - GenericValueTypeMessage, int>, std::pair > > chatStatistics("ChatStatisticsGS", std::make_pair(std::make_pair(std::make_pair(character, static_cast(timeUnsquelch)), m_chatSpamTimeEndInterval.get()), std::make_pair(m_chatSpamSpatialNumCharacters.get(), m_chatSpamNonSpatialNumCharacters.get()))); - Chat::sendToChatServer(chatStatistics); - m_chatSpamNextTimeToSyncWithChatServer = timeNow + ConfigServerGame::getChatStatisticsReportIntervalSeconds(); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::handleChatStatisticsFromChatServer(NetworkId const & character, int chatSpamTimeEndInterval, int spatialNumCharacters, int nonSpatialNumCharacters) -{ - if (!isAuthoritative()) - return; - - int const timeNow = static_cast(::time(NULL)); - bool syncChatServer = false; - - // new interval, reset - if (timeNow > m_chatSpamTimeEndInterval.get()) - { - m_chatSpamTimeEndInterval = timeNow + (ConfigServerGame::getChatSpamLimiterIntervalMinutes() * 60); - m_chatSpamSpatialNumCharacters = 0; - m_chatSpamNonSpatialNumCharacters = 0; - syncChatServer = true; - } - // chat server is in sync with us, update non-spatial - // character count with value from chat server - else if (chatSpamTimeEndInterval == m_chatSpamTimeEndInterval.get()) - { - m_chatSpamNonSpatialNumCharacters = nonSpatialNumCharacters; - } - // chat server is out of sync, ignore data, and resync with chat server - else - { - syncChatServer = true; - } - - // sync chat character count with chat server - if (syncChatServer || ((spatialNumCharacters != m_chatSpamSpatialNumCharacters.get()) && (timeNow > m_chatSpamNextTimeToSyncWithChatServer.get()))) - { - time_t timeUnsquelch = static_cast(getSecondsUntilUnsquelched()); - if (timeUnsquelch > 0) - timeUnsquelch += ::time(NULL); - - GenericValueTypeMessage, int>, std::pair > > chatStatistics("ChatStatisticsGS", std::make_pair(std::make_pair(std::make_pair(character, static_cast(timeUnsquelch)), m_chatSpamTimeEndInterval.get()), std::make_pair(m_chatSpamSpatialNumCharacters.get(), m_chatSpamNonSpatialNumCharacters.get()))); - Chat::sendToChatServer(chatStatistics); - m_chatSpamNextTimeToSyncWithChatServer = timeNow + ConfigServerGame::getChatStatisticsReportIntervalSeconds(); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::updateCitizenshipInfo() -{ - if (!isAuthoritative()) - return; - - CreatureObject const * const owner = getCreatureObject(); - if (!owner) - return; - - std::string cityName; - int8 citizenType = static_cast(CityDataCitizenType::NotACitizen); - - std::vector const & cityIds = CityInterface::getCitizenOfCityId(owner->getNetworkId()); - if (!cityIds.empty()) - { - int const cityId = cityIds.front(); - CityInfo const & cityInfo = CityInterface::getCityInfo(cityId); - cityName = cityInfo.getCityName(); - if (!cityName.empty()) - { - if (owner->getNetworkId() == cityInfo.getLeaderId()) - citizenType = static_cast(CityDataCitizenType::Mayor); - else if (CityInterface::isCityMilitia(cityId, owner->getNetworkId())) - citizenType = static_cast(CityDataCitizenType::Militia); - else - citizenType = static_cast(CityDataCitizenType::Citizen); - } - } - - if (m_citizenshipCity.get() != cityName) - m_citizenshipCity = cityName; - - if (m_citizenshipType.get() != citizenType) - m_citizenshipType = citizenType; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::updateGcwRegionInfo() -{ - if (!isAuthoritative()) - return; - - CreatureObject const * const owner = getCreatureObject(); - if (!owner) - return; - - std::string const & sceneId = ServerWorld::getSceneId(); - Vector const pos = owner->findPosition_w(); - std::string const * currentGcwRegion = &(Pvp::getGcwScoreCategoryRegion(sceneId, pos)); - if (currentGcwRegion->empty()) - { - // if not in a GCW contested region, use the default region - Pvp::GcwScoreCategory const * const defaultGcwRegion = Pvp::getGcwScoreDefaultCategoryForPlanet(sceneId); - if (defaultGcwRegion) - currentGcwRegion = &(defaultGcwRegion->categoryName); - } - - // set the GCW region the character is currently in - m_currentGcwRegion.set(*currentGcwRegion); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::updateGcwDefenderRegionInfo() -{ - if (!isAuthoritative()) - return; - - CreatureObject const * const owner = getCreatureObject(); - if (!owner) - return; - - int timeQualifyForBonus = -1; - bool qualifyForWarPlannerTitle = false; - - std::string cityGcwDefenderRegion; - bool cityGcwDefenderRegionHasBonus = false;; - bool cityGcwDefenderRegionHasTitle = false;; - - std::vector const & cityIds = CityInterface::getCitizenOfCityId(owner->getNetworkId()); - if (!cityIds.empty()) - { - CityInfo const & cityInfo = CityInterface::getCityInfo(cityIds.front()); - uint32 const cityFaction = cityInfo.getFaction(); - - // mayor who is same aligned with his aligned city can use the "War Planner" title - if (!PvpData::isNeutralFactionId(cityFaction) && (cityFaction == owner->getPvpFaction()) && (cityInfo.getLeaderId() == owner->getNetworkId())) - qualifyForWarPlannerTitle = true; - - std::string const & gcwDefenderRegion = cityInfo.getGcwDefenderRegion(); - if (!gcwDefenderRegion.empty()) - { - cityGcwDefenderRegion = gcwDefenderRegion; - - int const timeJoinedGcwDefenderRegion = cityInfo.getTimeJoinedGcwDefenderRegion(); - timeQualifyForBonus = static_cast(::time(NULL)) - (ConfigServerGame::getGcwDaysRequiredForGcwRegionDefenderBonus() * 86400); - if (!PvpData::isNeutralFactionId(cityFaction) && (cityFaction == owner->getPvpFaction()) && (timeJoinedGcwDefenderRegion < timeQualifyForBonus)) - { - cityGcwDefenderRegionHasBonus = true; - - int regionPercentileScore = 0; - if (PvpData::isImperialFactionId(cityFaction)) - regionPercentileScore = ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); - else if (PvpData::isRebelFactionId(cityFaction)) - regionPercentileScore = 100 - ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); - - // title is available once the region is 70% controlled - if (regionPercentileScore >= 70) - cityGcwDefenderRegionHasTitle = true; - } - } - } - - std::string guildGcwDefenderRegion; - bool guildGcwDefenderRegionHasBonus = false;; - bool guildGcwDefenderRegionHasTitle = false;; - - int const guildId = owner->getGuildId(); - if (guildId > 0) - { - GuildInfo const * const gi = GuildInterface::getGuildInfo(guildId); - if (gi) - { - uint32 const guildFaction = GuildInterface::getGuildCurrentFaction(*gi); - - // guild leader who is same aligned with his aligned guild that meets the - // minimum guild member count requirement can use the "War Planner" title - if (!PvpData::isNeutralFactionId(guildFaction) && (guildFaction == owner->getPvpFaction()) && (gi->m_leaderId == owner->getNetworkId()) && (gi->getCountMembersOnly() >= ConfigServerGame::getGcwGuildMinMembersForGcwRegionDefender())) - qualifyForWarPlannerTitle = true; - - std::string const & gcwDefenderRegion = GuildInterface::getGuildCurrentGcwDefenderRegion(*gi); - if (!gcwDefenderRegion.empty()) - { - guildGcwDefenderRegion = gcwDefenderRegion; - - int const timeJoinedGcwDefenderRegion = GuildInterface::getTimeJoinedGuildCurrentGcwDefenderRegion(*gi); - if (timeQualifyForBonus < 0) - timeQualifyForBonus = static_cast(::time(NULL)) - (ConfigServerGame::getGcwDaysRequiredForGcwRegionDefenderBonus() * 86400); - - if (!PvpData::isNeutralFactionId(guildFaction) && (guildFaction == owner->getPvpFaction()) && (timeJoinedGcwDefenderRegion < timeQualifyForBonus)) - { - guildGcwDefenderRegionHasBonus = true; - - int regionPercentileScore = 0; - if (PvpData::isImperialFactionId(guildFaction)) - regionPercentileScore = ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); - else if (PvpData::isRebelFactionId(guildFaction)) - regionPercentileScore = 100 - ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); - - // title is available once the region is 70% controlled - if (regionPercentileScore >= 70) - guildGcwDefenderRegionHasTitle = true; - } - } - } - } - - m_cityGcwDefenderRegion.set(std::make_pair(cityGcwDefenderRegion, std::make_pair(cityGcwDefenderRegionHasBonus, cityGcwDefenderRegionHasTitle))); - m_guildGcwDefenderRegion.set(std::make_pair(guildGcwDefenderRegion, std::make_pair(guildGcwDefenderRegionHasBonus, guildGcwDefenderRegionHasTitle))); - - // clear title if not qualified - { - std::string const & currentTitle = getTitle(); - if (currentTitle == "city_gcw_region_defender") - { - if (cityGcwDefenderRegion.empty() || !cityGcwDefenderRegionHasTitle) - setTitle(std::string()); - } - else if (currentTitle == "guild_gcw_region_defender") - { - if (guildGcwDefenderRegion.empty() || !guildGcwDefenderRegionHasTitle) - setTitle(std::string()); - } - } - - // grant/clear "War Planner" title - { - std::string const & currentTitle = getTitle(); - if (qualifyForWarPlannerTitle) - { - if (PvpData::isImperialFactionId(owner->getPvpFaction())) - { - modifyCollectionSlotValue("imperial_gcw_war_planner", 1ll); - modifyCollectionSlotValue("rebel_gcw_war_planner", -1ll); - - if (currentTitle == "rebel_gcw_war_planner") - setTitle("imperial_gcw_war_planner"); - } - else if (PvpData::isRebelFactionId(owner->getPvpFaction())) - { - modifyCollectionSlotValue("imperial_gcw_war_planner", -1ll); - modifyCollectionSlotValue("rebel_gcw_war_planner", 1ll); - - if (currentTitle == "imperial_gcw_war_planner") - setTitle("rebel_gcw_war_planner"); - } - else - { - modifyCollectionSlotValue("imperial_gcw_war_planner", -1ll); - modifyCollectionSlotValue("rebel_gcw_war_planner", -1ll); - - if ((currentTitle == "imperial_gcw_war_planner") || (currentTitle == "rebel_gcw_war_planner")) - setTitle(std::string()); - } - } - else - { - modifyCollectionSlotValue("imperial_gcw_war_planner", -1ll); - modifyCollectionSlotValue("rebel_gcw_war_planner", -1ll); - - if ((currentTitle == "imperial_gcw_war_planner") || (currentTitle == "rebel_gcw_war_planner")) - setTitle(std::string()); - } - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::squelch(NetworkId const & squelchedById, std::string const & squelchedByName, int squelchDurationSeconds) -{ - if (isAuthoritative()) - { - m_squelchedById = squelchedById; - m_squelchedByName = squelchedByName; - - // persist squelch info - setObjVarItem(OBJVAR_SQUELCH_ID, squelchedById); - setObjVarItem(OBJVAR_SQUELCH_NAME, squelchedByName); - - if (squelchDurationSeconds < 0) - { - m_squelchExpireTime = -1; - - // persist squelch info - setObjVarItem(OBJVAR_SQUELCH_EXPIRE, -1); - } - else - { - m_squelchExpireTime = static_cast(::time(NULL)) + squelchDurationSeconds; - - // persist squelch info - setObjVarItem(OBJVAR_SQUELCH_EXPIRE, static_cast(ServerClock::getInstance().getGameTimeSeconds()) + squelchDurationSeconds); - } - - // update chat server - CreatureObject * const owner = getCreatureObject(); - if (owner) - { - GenericValueTypeMessage > setUnsquelchTime("SetUnsquelchTime", std::make_pair(owner->getNetworkId(), static_cast(m_squelchExpireTime.get()))); - Chat::sendToChatServer(setUnsquelchTime); - } - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_squelch, new MessageQueueGenericValueType > >(std::make_pair(squelchedByName, std::make_pair(squelchedById, squelchDurationSeconds)))); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::unsquelch() -{ - if (isAuthoritative()) - { - m_squelchedById = NetworkId::cms_invalid; - m_squelchedByName = std::string(); - m_squelchExpireTime = 0; - - // persist squelch info - removeObjVarItem(OBJVAR_SQUELCH_ID); - removeObjVarItem(OBJVAR_SQUELCH_NAME); - removeObjVarItem(OBJVAR_SQUELCH_EXPIRE); - - // update chat server - CreatureObject * const owner = getCreatureObject(); - if (owner) - { - GenericValueTypeMessage > setUnsquelchTime("SetUnsquelchTime", std::make_pair(owner->getNetworkId(), 0)); - Chat::sendToChatServer(setUnsquelchTime); - } - } - else - { - CreatureObject * const owner = getCreatureObject(); - if (owner) - owner->sendControllerMessageToAuthServer(CM_unsquelch, NULL); - } -} - -// ---------------------------------------------------------------------- -// returns 0 if not currently squelched; returns < 0 if indefinitely squelched -int PlayerObject::getSecondsUntilUnsquelched() -{ - // not squelched - if (!m_squelchedById.get().isValid()) - return 0; - - // squelched, but need to check to see if the squelch period has already expired - if (m_squelchExpireTime.get() < 0) // squelched indefinitely - return -1; - - int32 const timeNow = static_cast(::time(NULL)); - if (timeNow < m_squelchExpireTime.get()) // still in squelch period - return (m_squelchExpireTime.get() - timeNow); - - // squelch has expired - if (isAuthoritative()) - { - m_squelchedById = NetworkId::cms_invalid; - m_squelchedByName = std::string(); - m_squelchExpireTime = 0; - - // persist squelch info - removeObjVarItem(OBJVAR_SQUELCH_ID); - removeObjVarItem(OBJVAR_SQUELCH_NAME); - removeObjVarItem(OBJVAR_SQUELCH_EXPIRE); - } - return 0; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyShowBackpack(bool b) -{ - if(m_showBackpack.get() != b) - m_showBackpack = b; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::modifyShowHelmet(bool b) -{ - if(m_showHelmet.get () != b) - m_showHelmet = b; -} - -void PlayerObject::setEnvironmentFlags(EnvironmentInfo const & flags) -{ - m_environmentFlags = flags; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::toggleOutOfCharacter() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_outOfCharacter); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - -// ---------------------------------------------------------------------- - -void PlayerObject::toggleLookingForWork() -{ - if (isAuthoritative()) - { - MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); - - matchMakingId.toggleBit(MatchMakingId::B_lookingForWork); - - setMatchMakingCharacterProfileId(matchMakingId); - } -} - - -// ---------------------------------------------------------------------- - -void PlayerObject::setAccountNumLotsOverLimitSpam() -{ - if (!isAuthoritative()) - return; - - // if over the lot limit, spam warning; otherwise, if no - // longer over the lot limit, remove lot over limit restriction - CreatureObject * const owner = getCreatureObject(); - if (!owner) - return; - - if (m_accountNumLots.get() > owner->getMaxNumberOfLots()) - { - if (owner->getObjVars().hasItem("lotOverlimit")) - { - m_accountNumLotsOverLimitSpam = m_accountNumLots.get() - owner->getMaxNumberOfLots(); - - int const timeNow = static_cast(::time(NULL)); - int violationTime = 0; - if (!owner->getObjVars().getItem("lotOverlimit.violation_time", violationTime)) - { - violationTime = timeNow; - IGNORE_RETURN(owner->setObjVarItem("lotOverlimit.violation_time", violationTime)); - } - - if (owner->getClient()) - { - // spam once every 5 minutes for 24 hours after the violation, then once every minute after that - bool shouldSpam = true; - if ((violationTime + 86400) >= timeNow) - { - int timeLastSpam = 0; - if (owner->getObjVars().getItem("lotOverlimit.last_spam_time", timeLastSpam) && ((timeLastSpam + 300) >= timeNow)) - shouldSpam = false; - - if (shouldSpam) - IGNORE_RETURN(owner->setObjVarItem("lotOverlimit.last_spam_time", timeNow)); - } - else - { - // over 24 hours after violation, spam every minute (i.e. each time this messageTo fires) - owner->removeObjVarItem("lotOverlimit.last_spam_time"); - } - - if (shouldSpam) - { - Chat::sendSystemMessage(*owner, Unicode::narrowToWide("!!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!!"), Unicode::emptyString); - Chat::sendSystemMessage(*owner, Unicode::narrowToWide(FormattedString<256>().sprintf("YOU ARE %d LOTS OVER THE LOT LIMIT!!!", m_accountNumLotsOverLimitSpam.get())), Unicode::emptyString); - - std::string lotOverlimitStructureName; - std::string lotOverlimitStructureLocation; - IGNORE_RETURN(owner->getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); - IGNORE_RETURN(owner->getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); - Chat::sendSystemMessage(*owner, Unicode::narrowToWide(FormattedString<256>().sprintf("THE %s STRUCTURE LOCATED AT %s CAUSED YOU TO EXCEED THE LOT LIMIT!!!", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); - - Chat::sendSystemMessage(*owner, Unicode::narrowToWide("!!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!!"), Unicode::emptyString); - } - } - } - else - { - // over the limit, but we shouldn't spam - m_accountNumLotsOverLimitSpam = 0; - } - } - else - { - m_accountNumLotsOverLimitSpam = 0; - owner->removeObjVarItem("lotOverlimit"); - } -} - -// ---------------------------------------------------------------------- - -bool PlayerObject::canAccessGalacticReserve(real x, real z) -{ - // must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve - std::string const & sceneId = ServerWorld::getSceneId(); - if ((sceneId != "tatooine") && (sceneId != "naboo") && (sceneId != "corellia")) - return false; - - std::vector result; - RegionMaster::getRegionsAtPoint(sceneId, x, z, result); - if (result.empty()) - return false; - - static Unicode::String const regionMosEisley = Unicode::narrowToWide("@tatooine_region_names:mos_eisley"); - static Unicode::String const regionTheed = Unicode::narrowToWide("@naboo_region_names:theed"); - static Unicode::String const regionCoronet = Unicode::narrowToWide("@corellia_region_names:coronet"); - static uint32 const hashMosEisley = Crc::calculate(regionMosEisley.c_str(), regionMosEisley.length()*2); - static uint32 const hashTheed = Crc::calculate(regionTheed.c_str(), regionTheed.length()*2); - static uint32 const hashCoronet = Crc::calculate(regionCoronet.c_str(), regionCoronet.length()*2); - - for(std::vector::iterator it = result.begin(); it != result.end(); ++it) - { - if (((sceneId == "tatooine") && ((*it)->getNameCrc() == hashMosEisley)) || - ((sceneId == "naboo") && ((*it)->getNameCrc() == hashTheed)) || - ((sceneId == "corellia") && ((*it)->getNameCrc() == hashCoronet))) - { - return true; - } - } - - return false; -} - -// ---------------------------------------------------------------------- - -void PlayerObject::depositToGalacticReserve(bool ignoreCooldownAndLocationCheck) -{ - if (!isAuthoritative()) - return; - - CreatureObject * const co = getCreatureObject(); - if (!co) - return; - - Client const * const c = co->getClient(); - if (c && c->isFreeTrialAccount()) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide("Trial account cannot access the Galactic Reserve."), Unicode::emptyString); - return; - } - - bool const isGod = (c && c->isGod()); - - // check for cooldown - if (!isGod && !ignoreCooldownAndLocationCheck) - { - int cooldown; - if (co->getObjVars().getItem("galactic_reserve_cooldown", cooldown)) - { - int const timeNow = static_cast(ServerClock::getInstance().getGameTimeSeconds()); - if (cooldown > timeNow) - { - if (c) - Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %s before you can access the Galactic Reserve again.", CalendarTime::convertSecondsToMS(static_cast(cooldown - timeNow)).c_str())), Unicode::emptyString); - - return; - } - } - } - - // must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve - if (!ignoreCooldownAndLocationCheck) - { - Vector const positionW = co->getPosition_w(); - if (!canAccessGalacticReserve(positionW.x, positionW.z)) - { - if (c) - Chat::sendSystemMessage(*co, Unicode::narrowToWide("You must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve."), Unicode::emptyString); - - return; - } - } - - if (static_cast(m_galacticReserveDeposit.get()) >= ConfigServerGame::getMaxGalacticReserveDepositBillion()) - { - if (c) - Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("You already have the maximum %d billion credits in the Galactic Reserve.", ConfigServerGame::getMaxGalacticReserveDepositBillion())), Unicode::emptyString); - - return; - } - - // transfer as much cash as necessary into bank to get 1 billion in bank - int amountToTransferToBank = 1000000000 - co->getBankBalance(); - if (amountToTransferToBank > co->getCashBalance()) - { - if (c) - Chat::sendSystemMessage(*co, Unicode::narrowToWide("You do not currently have 1 billion credits to deposit to the Galactic Reserve."), Unicode::emptyString); - - return; - } - - if (amountToTransferToBank > 0) - { - co->depositCashToBank(amountToTransferToBank); - } - - // final sanity check to make sure there's 1 billion in the bank - if (co->getBankBalance() < 1000000000) - { - if (c) - Chat::sendSystemMessage(*co, Unicode::narrowToWide("You do not currently have 1 billion credits to deposit to the Galactic Reserve."), Unicode::emptyString); - - return; - } - - // do the transfer - if (!co->transferBankCreditsTo("galactic_reserve", 1000000000)) - { - if (c) - Chat::sendSystemMessage(*co, Unicode::narrowToWide("Failed to transfer 1 billion credits to the Galactic Reserve."), Unicode::emptyString); - - return; - } - - // update reserve balance - m_galacticReserveDeposit = m_galacticReserveDeposit.get() + 1; - co->setObjVarItem("galactic_reserve", static_cast(m_galacticReserveDeposit.get())); - - // set cooldown (15 minutes) - if (!ignoreCooldownAndLocationCheck) - { - co->setObjVarItem("galactic_reserve_cooldown", static_cast(ServerClock::getInstance().getGameTimeSeconds() + (15 * 60))); - } - - // display confirmation message - if (c) - Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("1 billion credits have been deposited to the Galactic Reserve. Your new Galactic Reserve balance is %d billion credits.", m_galacticReserveDeposit.get())), Unicode::emptyString); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::withdrawFromGalacticReserve() -{ - if (!isAuthoritative()) - return; - - CreatureObject * const co = getCreatureObject(); - if (!co) - return; - - Client const * const c = co->getClient(); - if (!c) - return; - - if (c->isFreeTrialAccount()) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide("Trial account cannot access the Galactic Reserve."), Unicode::emptyString); - return; - } - - // check for cooldown - if (!c->isGod()) - { - int cooldown; - if (co->getObjVars().getItem("galactic_reserve_cooldown", cooldown)) - { - int const timeNow = static_cast(ServerClock::getInstance().getGameTimeSeconds()); - if (cooldown > timeNow) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %s before you can access the Galactic Reserve again.", CalendarTime::convertSecondsToMS(static_cast(cooldown - timeNow)).c_str())), Unicode::emptyString); - return; - } - } - } - - // must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve - Vector const positionW = co->getPosition_w(); - if (!canAccessGalacticReserve(positionW.x, positionW.z)) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide("You must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve."), Unicode::emptyString); - return; - } - - if (m_galacticReserveDeposit.get() <= 0) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide("You do not have any deposit in the Galactic Reserve to withdraw."), Unicode::emptyString); - return; - } - - // move all the bank to cash to make room to receive the 1 billion into the bank - if (co->getBankBalance() > 0) - { - if ((co->getCashBalance() + co->getBankBalance()) > ConfigServerGame::getMaxMoney()) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide("Withdrawing 1 billion credits from the Galactic Reserve would cause your cash/bank balance to exceed the maximum balance limit."), Unicode::emptyString); - return; - } - - co->withdrawCashFromBank(co->getBankBalance()); - } - - // final sanity check to make sure the bank is empty to receive the 1 billion - if (co->getBankBalance() > 0) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide("Withdrawing 1 billion credits from the Galactic Reserve would cause your cash/bank balance to exceed the maximum balance limit."), Unicode::emptyString); - return; - } - - // do the transfer - if (!co->transferBankCreditsFrom("galactic_reserve", 1000000000)) - { - Chat::sendSystemMessage(*co, Unicode::narrowToWide("Failed to withdraw 1 billion credits from the Galactic Reserve."), Unicode::emptyString); - return; - } - - // update reserve balance - m_galacticReserveDeposit = m_galacticReserveDeposit.get() - 1; - if (m_galacticReserveDeposit.get() > 0) - co->setObjVarItem("galactic_reserve", static_cast(m_galacticReserveDeposit.get())); - else - co->removeObjVarItem("galactic_reserve"); - - // set cooldown (15 minutes) - co->setObjVarItem("galactic_reserve_cooldown", static_cast(ServerClock::getInstance().getGameTimeSeconds() + (15 * 60))); - - // display confirmation message - Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("1 billion credits have been withdrawn from the Galactic Reserve. Your new Galactic Reserve balance is %d billion credits.", m_galacticReserveDeposit.get())), Unicode::emptyString); -} - -// ---------------------------------------------------------------------- - -void PlayerObject::depersistGalacticReserveDeposit() -{ - if (!isAuthoritative()) - return; - - m_galacticReserveDeposit = 0; - - CreatureObject const * const co = getCreatureObject(); - if (!co) - return; - - // depersist galactic reserve - int temp; - if (co->getObjVars().getItem("galactic_reserve", temp)) - m_galacticReserveDeposit = static_cast(temp); -} - -// ---------------------------------------------------------------------- - -void PlayerObjectNamespace::checkAndSetCharacterAgeTitle(PlayerObject & player, bool thoroughCheck) -{ - static std::vector s_vectorCharacterAgeTitle; - if (s_vectorCharacterAgeTitle.empty()) - { - // we'll exit this loop as soon as we don't find the "next" character age title collection slot - for (int i = 1; i <= 1000000; ++i) - { - CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(FormattedString<128>().sprintf("character_age_%dyr", i)); - if (!collectionSlot) - break; - - FATAL((collectionSlot->collection.name != std::string("character_age_collection")), ("collection slot %s must be in collection character_age_collection", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.name != std::string("character_age_page")), ("collection slot %s must be in collection page character_age_page", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.book.name != std::string("character_age_book")), ("collection slot %s must be in collection book character_age_book", collectionSlot->name.c_str())); - - s_vectorCharacterAgeTitle.push_back(collectionSlot); - } - } - - int const ageInYears = ((player.getBornDate() > 0) ? (player.getAgeInDays() / 365) : 0); - - if (!thoroughCheck) - { - // just do quickie check to see if the player has turned a new year older - if (ageInYears <= static_cast(s_vectorCharacterAgeTitle.size())) - { - if (ageInYears >= 1) - { - if (!player.hasCompletedCollectionSlot(*s_vectorCharacterAgeTitle[ageInYears - 1])) - { - // this will force a check/set/unset of the proper character age slot for the player - thoroughCheck = true; - } - } - } - else - { - // we need to add additional character age collection slots - - // this will make sure to unset all previous character age slots the player may have - thoroughCheck = true; - } - } - - // go through all possible character age titles and verify that the appropriate one is set and the others are unset - if (thoroughCheck) - { - for (int i = 0, size = s_vectorCharacterAgeTitle.size(); i < size; ++i) - { - if ((i + 1) == ageInYears) - { - player.modifyCollectionSlotValue(s_vectorCharacterAgeTitle[i]->name, 1ll); - } - else - { - player.modifyCollectionSlotValue(s_vectorCharacterAgeTitle[i]->name, -1ll); - } - } - } -} - -// ---------------------------------------------------------------------- - -void PlayerObjectNamespace::checkAndSetAccountAgeTitle(PlayerObject & player) -{ - static std::vector s_vectorAccountAgeTitle; - if (s_vectorAccountAgeTitle.empty()) - { - // we'll exit this loop as soon as we don't find the "next" account age title collection slot - for (int i = 1; i <= 1000000; ++i) - { - CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(FormattedString<128>().sprintf("account_age_%dyr", i)); - if (!collectionSlot) - break; - - FATAL((collectionSlot->collection.name != std::string("account_age_collection")), ("collection slot %s must be in collection account_age_collection", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.name != std::string("account_age_page")), ("collection slot %s must be in collection page account_age_page", collectionSlot->name.c_str())); - FATAL((collectionSlot->collection.page.book.name != std::string("account_age_book")), ("collection slot %s must be in collection book account_age_book", collectionSlot->name.c_str())); - - s_vectorAccountAgeTitle.push_back(collectionSlot); - } - } - - CreatureObject const * const co = player.getCreatureObject(); - if (!co) - return; - - Client const * const c = co->getClient(); - if (!c) - return; - - if (c->isUsingAdminLogin()) - return; - - unsigned int const ageInYears = c->getEntitlementEntitledTime() / 365u; - - // go through all possible account age titles and verify that the appropriate one is set and the others are unset - for (size_t i = 0, size = s_vectorAccountAgeTitle.size(); i < size; ++i) - { - if ((i + 1) == ageInYears) - { - player.modifyCollectionSlotValue(s_vectorAccountAgeTitle[i]->name, 1ll); - } - else - { - player.modifyCollectionSlotValue(s_vectorAccountAgeTitle[i]->name, -1ll); - } - } -} - -// ---------------------------------------------------------------------- - -void PlayerObjectNamespace::grantGcwFactionalPresenceScore(std::string const & gcwCategory, PlayerObject const & po, CreatureObject const & co) -{ - // base_points = level * (level_% / 100) - // bonus_% = GCW_rank * bonus_%_per_rank - // - // if (in a same faction player city) - // { - // bonus_% += player_city_bonus_% - // bonus_% += (player_city_rank_bonus_% * city_rank) - // bonus_% += (player_city_age_bonus_% * city_age_in_years) - // } - // - // final_points = base_points + (base_points * (bonus_% / 100)) - int level = co.getLevel(); - int bonus = 100 + (po.getCurrentGcwRank() * ConfigServerGame::getGcwFactionalPresenceGcwRankBonusPct()); - int mountedPct = 100; - - // for ground, give bonus if in same faction player city - // - // for space, give bonus if the player's citizenship city is on the - // corresponding ground planet and is the same faction as the player - CityInfo const * ci = NULL; - if (!ServerWorld::isSpaceScene()) - { - Vector const creaturePosition = co.findPosition_w(); - int const cityId = CityInterface::getCityAtLocation(ServerWorld::getSceneId(), static_cast(creaturePosition.x), static_cast(creaturePosition.z), 0); - if (cityId > 0) - ci = &(CityInterface::getCityInfo(cityId)); - - // for ground, there may be a reduction for being on a vehicle/mount - if (co.getMountedCreature()) - mountedPct = std::min(std::max(ConfigServerGame::getGcwFactionalPresenceMountedPct(), 1), 100); // clamp to 1 - 100 - } - else - { - // for space, the "level" for a pilot (i.e. character is - // sitting in the pilot chair) is based on the pilot skill - // - // Pilots with one of the following skills should be considered Level 90 - // pilot_rebel_navy_master - // pilot_imperial_navy_master - // pilot_neutral_master - // - // Pilots with one of the following skills should be considered Level 69 - // pilot_rebel_navy_droid_03 - // pilot_imperial_navy_droid_03 - // pilot_neutral_droid_03 - // - // Pilots with one of the following skills should be considered Level 45 - // pilot_rebel_navy_droid_02 - // pilot_imperial_navy_droid_02 - // pilot_neutral_droid_02 - // - // Pilots with one of the following skills should be considered Level 21 - // pilot_rebel_navy_droid_01 - // pilot_imperial_navy_droid_01 - // pilot_neutral_droid_01 - // - // Else they should be consider level 1 - ServerObject const * const container = safe_cast(ContainerInterface::getContainedByObject(co)); - if (container && !container->asCellObject()) - { - static std::list > sPilotSkillToLevel; - if (sPilotSkillToLevel.empty()) - { - const SkillObject * skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_master"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 90)); - - skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_master"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 90)); - - skill = SkillManager::getInstance().getSkill("pilot_neutral_master"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 90)); - - skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_droid_03"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 69)); - - skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_droid_03"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 69)); - - skill = SkillManager::getInstance().getSkill("pilot_neutral_droid_03"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 69)); - - skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_droid_02"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 45)); - - skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_droid_02"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 45)); - - skill = SkillManager::getInstance().getSkill("pilot_neutral_droid_02"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 45)); - - skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_droid_01"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 21)); - - skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_droid_01"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 21)); - - skill = SkillManager::getInstance().getSkill("pilot_neutral_droid_01"); - if (skill) - sPilotSkillToLevel.push_back(std::make_pair(skill, 21)); - } - - level = 1; - CreatureObject::SkillList const & creatureSkill = co.getSkillList(); - for (std::list >::const_iterator iter = sPilotSkillToLevel.begin(); iter != sPilotSkillToLevel.end(); ++iter) - { - if (creatureSkill.count(iter->first) >= 1) - { - level = iter->second; - break; - } - } - } - - std::vector const & cityIds = CityInterface::getCitizenOfCityId(co.getNetworkId()); - if (!cityIds.empty()) - { - ci = &(CityInterface::getCityInfo(cityIds.front())); - - // player city on Rori will be associated with space_naboo - // player city on Talus will be associated with space_corellia - std::string const & playerCityPlanet = ci->getPlanet(); - std::string playerCitySpaceZone; - if (playerCityPlanet == std::string("rori")) - playerCitySpaceZone = std::string("space_naboo"); - else if (playerCityPlanet == std::string("talus")) - playerCitySpaceZone = std::string("space_corellia"); - else - playerCitySpaceZone = std::string("space_") + playerCityPlanet; - - if (playerCitySpaceZone != ServerWorld::getSceneId()) - ci = NULL; - } - } - - if (ci) - { - if (!PvpData::isNeutralFactionId(ci->getFaction()) && (ci->getFaction() == co.getPvpFaction())) - { - bonus += ConfigServerGame::getGcwFactionalPresenceAlignedCityBonusPct(); - - int cityRank = 5; - if (ci->getRadius() < 200) - cityRank = 1; - else if (ci->getRadius() < 300) - cityRank = 2; - else if (ci->getRadius() < 400) - cityRank = 3; - else if (ci->getRadius() < 450) - cityRank = 4; - - bonus += (cityRank * ConfigServerGame::getGcwFactionalPresenceAlignedCityRankBonusPct()); - - if (ci->getCreationTime() > 0) - bonus += std::max(0, (static_cast(::time(NULL)) - std::max(1041408000, ci->getCreationTime())) / 31536000 * ConfigServerGame::getGcwFactionalPresenceAlignedCityAgeBonusPct()); - } - } - - int const points = std::max(1, level * ConfigServerGame::getGcwFactionalPresenceLevelPct() * std::min(1000, bonus) * mountedPct / 1000000); - - if (PvpData::isImperialFactionId(co.getPvpFaction())) - ServerUniverse::getInstance().adjustGcwImperialScore(std::string("FactionalPresence"), const_cast(&co), gcwCategory, points); - else if (PvpData::isRebelFactionId(co.getPvpFaction())) - ServerUniverse::getInstance().adjustGcwRebelScore(std::string("FactionalPresence"), const_cast(&co), gcwCategory, points); -} - -// ====================================================================== +// ====================================================================== +// +// PlayerObject.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/PlayerObject.h" + +#include "LocalizationManager.h" +#include "serverGame/BiographyManager.h" +#include "serverGame/Chat.h" +#include "serverGame/CitizenInfo.h" +#include "serverGame/CityInfo.h" +#include "serverGame/CityInterface.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/DestroyMessageManager.h" +#include "serverGame/FactoryObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/GroupObject.h" +#include "serverGame/GroupWaypointBuilder.h" +#include "serverGame/GuildInfo.h" +#include "serverGame/GuildInterface.h" +#include "serverGame/GuildMemberInfo.h" +#include "sharedGame/GuildRankDataTable.h" +#include "serverGame/ManufactureSchematicObject.h" +#include "serverGame/MessageToQueue.h" +#include "serverGame/NameManager.h" +#include "serverGame/ObjectIdManager.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PgcRatingInfo.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/ProsePackageManagerServer.h" +#include "serverGame/RegionMaster.h" +#include "serverGame/ResourceContainerObject.h" +#include "serverGame/ResourceTypeObject.h" +#include "serverGame/ServerController.h" +#include "serverGame/ServerPlayerObjectTemplate.h" +#include "serverGame/ServerResourceClassObject.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/TangibleObject.h" +#include "serverNetworkMessages/LoginUpgradeAccountMessage.h" +#include "serverNetworkMessages/MessageToPayload.h" +#include "serverScript/ConfigServerScript.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptDictionary.h" +#include "serverScript/ScriptParameters.h" +#include "serverUtility/ConfigServerUtility.h" +#include "serverUtility/ServerClock.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/Os.h" +#include "sharedGame/CitizenRankDataTable.h" +#include "sharedGame/CityData.h" +#include "sharedGame/DraftSchematicGroupManager.h" +#include "sharedGame/GameLanguageManager.h" +#include "sharedGame/LfgDataTable.h" +#include "sharedGame/OutOfBandPackager.h" +#include "sharedGame/ProsePackage.h" +#include "sharedGame/PvpData.h" +#include "sharedGame/Quest.h" +#include "sharedGame/QuestManager.h" +#include "sharedGame/QuestTask.h" +#include "sharedGame/SharedObjectTemplate.h" +#include "sharedGame/TextIterator.h" +#include "sharedGame/TextManager.h" +#include "sharedLog/Log.h" +#include "sharedNetworkMessages/ChatAvatarId.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/MessageQueueDraftSchematics.h" +#include "sharedNetworkMessages/MessageQueueDraftSlots.h" +#include "sharedNetworkMessages/MessageQueueDraftSlotsQueryResponse.h" +#include "sharedNetworkMessages/MessageQueueGenericValueType.h" +#include "sharedNetworkMessages/PlayMusicMessage.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedObject/VolumeContainer.h" +#include "sharedSkillSystem/SkillManager.h" +#include "sharedSkillSystem/SkillObject.h" +#include "sharedUtility/Location.h" +#include "sharedUtility/LocationArchive.h" +#include "UnicodeUtils.h" + +#include +#include + +const SharedObjectTemplate * PlayerObject::m_defaultSharedTemplate = NULL; +bool PlayerObject::m_allowEmptySlot = false; + + +//----------------------------------------------------------------------- +PlayerObject::ChatLogEntry::ChatLogEntry() + : m_index(0) + , m_time(0) +// , m_serverProcessId(0) +{ +} + +// ====================================================================== + +namespace PlayerObjectNamespace +{ + // slot that holds the datapad + const ConstCharCrcLowerString DATAPAD_SLOT_NAME("datapad"); + + // objvars for crafting + const std::string OBJVAR_CRAFTING_STATION("crafting.station"); + const std::string OBJVAR_PRIVATE_STATION("crafting.private"); + const std::string OBJVAR_CRAFTING_PROTOTYPE_TIME("crafting.prototypeTime"); + const std::string OBJVAR_CRAFTING_PROTOTYPE_START_TIME("crafting.prototypeStartTime"); + const std::string OBJVAR_CRAFTING_PROTOTYPE_OBJECT("crafting.prototypeObject"); + const std::string OBJVAR_CRAFTING_PROTOTYPE_CRAFTER("crafting.prototypeCrafter"); + const std::string OBJVAR_CRAFTING_FAKE_PROTOTYPE("crafting.isFakePrototype"); + const std::string OBJVAR_CRAFTING_COMPONENT_CAN_BE_DAMAGED("crafting.damaged_ok"); + const std::string OBJVAR_FORCE_CRITICAL_ASSEMBLY("crafting.force_critical_assembly"); + const std::string OBJVAR_FORCE_CRITICAL_EXPERIMENT("crafting.force_critical_experiment"); + const std::string OBJVAR_FORCE_CRITICAL_SUCCESS("crafting.force_critical_success"); + const std::string OBJVAR_IN_CRAFTING_SESSION("crafting.inCraftingSession"); + + // objvars for chat spam info + const std::string OBJVAR_CHAT_SPAM_TIME_END_INTERVAL("chatSpam.timeEndInterval"); + const std::string OBJVAR_CHAT_SPAM_SPATIAL("chatSpam.spatial"); + const std::string OBJVAR_CHAT_SPAM_NON_SPATIAL("chatSpam.nonSpatial"); + + // objvars for privileged title + const std::string OBJVAR_PRIVILEGED_TITLE("privilegedTitle"); + + // objvars for squelch info + const std::string OBJVAR_SQUELCH_ID("squelch.id"); + const std::string OBJVAR_SQUELCH_NAME("squelch.name"); + const std::string OBJVAR_SQUELCH_EXPIRE("squelch.expire"); + + // skill data granted independently from skills + const std::string OBJVAR_NOT_SKILL_SCHEMATICS("_notskill.schematics"); + + const std::string OBJVAR_EXPERIENCE_MULTIPLIER("xp_multiplier"); + const std::string OBJVAR_GAME_FACTION_RANKINGS("gcw"); + + const std::string OBJVAR_DELETED_QUEST_COUNT("quests.numQuestsDeleted"); + + const StringId COMPONENT_LOST_MSG("system_msg", "lost_component"); + + const int MAX_KILL_METER = 50; + + //---------------------------------------------------------------------- + + std::set s_allPlayerObjects; + + //---------------------------------------------------------------------- + + bool isNestedInContainer (const NetworkId & itemId, const NetworkId & containerId) + { + NetworkId theItemId = itemId; + for (;;) + { + if (theItemId == containerId) + return true; + + const Object * const item = NetworkIdManager::getObjectById (theItemId); + if (!item) + break; + + const Object * const parent = ContainerInterface::getContainedByObject (*item); + if (!parent) + break; + + theItemId = parent->getNetworkId (); + } + + return false; + } + + void refScript(CreatureObject & owner, const std::string & scriptName) + { + GameScriptObject * script = owner.getScriptObject(); + if(script) + { + if(! script->hasScript(scriptName)) + { + script->attachScript(scriptName, false); + } + + int scriptRefCount = 0; + const DynamicVariableList & objvars = owner.getObjVars(); + + const std::string itemName = "quest.script." + scriptName; + if (objvars.getItem(itemName, scriptRefCount)) + { + scriptRefCount++; + } + else + { + scriptRefCount = 1; + } + + owner.setObjVarItem(itemName, scriptRefCount); + } + } + + void derefScript(CreatureObject & owner, const std::string & scriptName) + { + int scriptRefCount = 0; + const DynamicVariableList & objvars = owner.getObjVars(); + + const std::string itemName = "quest.script." + scriptName; + if (objvars.getItem(itemName, scriptRefCount)) + { + scriptRefCount--; + if(scriptRefCount < 0) + { + scriptRefCount = 0; + } + } + else + { + scriptRefCount = 0; + } + + if(scriptRefCount > 0) + { + owner.setObjVarItem(itemName, scriptRefCount); + } + else + { + owner.removeObjVarItem(itemName); + GameScriptObject * script = owner.getScriptObject(); + if(script) + { + if(script->hasScript(scriptName)) + { + script->detachScript(scriptName); + } + } + } + } + + //---------------------------------------------------------------------- + + void checkAndSetCharacterAgeTitle(PlayerObject & player, bool thoroughCheck); + void checkAndSetAccountAgeTitle(PlayerObject & player); + + //---------------------------------------------------------------------- + +// size_t s_waypointLimit = 10; + size_t s_questLimit = 1000; + + //---------------------------------------------------------------------- + + // Class to help us sort quest data by age + class QuestDataToSort + { + public: + QuestDataToSort() : + m_key(0) + {} + + QuestDataToSort( uint32 key, PlayerQuestData const& questData ) : + m_key(key), + m_questData(questData) + {} + + bool operator<(QuestDataToSort const & rhs) const + { + return (m_questData.getRelativeAgeIndex() < rhs.m_questData.getRelativeAgeIndex()); + } + + uint32 GetPlayerQuestDataKey() const { return m_key; } + PlayerQuestData const& GetPlayerQuestData() const { return m_questData; } + + private: + uint32 m_key; + PlayerQuestData m_questData; + }; + + typedef std::list SortableQuestList; + typedef std::vector< std::pair > TaskChanceVector; + + void grantGcwFactionalPresenceScore(std::string const & gcwCategory, PlayerObject const & po, CreatureObject const & co); +}; + +using namespace PlayerObjectNamespace; + +// ====================================================================== + +PlayerObject::PlayerObject(const ServerPlayerObjectTemplate* newTemplate) : + IntangibleObject(newTemplate), + m_callback(new MessageDispatch::Callback), + m_stationId(0), + m_houseId(CachedNetworkId(NetworkId::cms_invalid)), + m_accountNumLots(0), + m_accountNumLotsOverLimitSpam(0), + m_accountMaxLotsAdjustment(0), + m_accountIsOutcast(false), + m_accountCheaterLevel(0.0f), + m_draftSchematics(), + m_experiencePoints(), + m_expModified(0), + m_maxForcePower(0), + m_forcePower(0), + m_forceRegenRate(0), + m_forceRegenValue(0), + m_craftingLevel(0), + m_experimentPoints(8), + m_craftingStage(static_cast(Crafting::CS_none)), + m_craftingTool(), + m_craftingStation(), + m_craftingComponentBioLink(), + m_useableDraftSchematics(), + m_draftSchematic(NULL), + m_matchMakingPersonalProfileId(), + m_matchMakingCharacterProfileId(), + m_friendList(), + m_ignoreList(), + m_skillTitle(), + m_spokenLanguage(GameLanguageManager::getBasicLanguageId()), + m_waypoints(), + m_groupWaypoints(), + m_bornDate(0), + m_playedTime(0), + m_playedTimeAccum(0), + m_sessionStartPlayTime(0), + m_sessionLastActiveTime(0), + m_sessionActivePlayTimeDuration(0), + m_food(0), + m_maxFood(100), + m_drink(0), + m_maxDrink(100), + m_meds(0), + m_maxMeds(100), + m_privledgedTitle(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)), + m_completedQuests(), + m_activeQuests(), + m_currentQuest(0), + m_theaterDatatable(), + m_theaterPosition(), + m_theaterScene(), + m_theaterScript(), + m_theaterNumObjects(), + m_theaterRadius(), + m_theaterCreator(), + m_theaterName(), + m_theaterId(), + m_theaterLocationType(IntangibleObject::TLT_getGoodLocation), + m_roleIconChoice(0), + m_aggroImmuneDuration(0), + m_aggroImmuneStartTime(0), + m_chatLog(new ChatLog), + m_chatLogPurgeTime(0), + m_isUnsticking(false), + m_pendingRequestQuestCrc(0), + m_pendingRequestQuestGiver(NetworkId::cms_invalid), + m_skillTemplate(), + m_workingSkill(), + m_isFromLogin(true), + m_currentGcwPoints(0), + m_currentGcwRating(-1), + m_currentPvpKills(0), + m_lifetimeGcwPoints(0), + m_maxGcwImperialRating(-1), + m_maxGcwRebelRating(-1), + m_lifetimePvpKills(0), + m_nextGcwRatingCalcTime(0), + m_currentGcwRank(0), + m_currentGcwRankProgress(0.0f), + m_maxGcwImperialRank(0), + m_maxGcwRebelRank(0), + m_gcwRatingActualCalcTime(0), + m_playerHateList(), + m_sessionActivity(0), + m_killMeter(0), + m_killMeterRemainder(0.0f), + m_petId(NetworkId::cms_invalid), + m_petCommandList(0), + m_petToggledCommands(0), + m_collections(), + m_collections2(), + m_chatSpamSpatialNumCharacters(0), + m_chatSpamNonSpatialNumCharacters(0), + m_chatSpamTimeEndInterval(0), + m_chatSpamNextTimeToSyncWithChatServer(0), + m_chatSpamNextTimeToNotifyPlayerWhenLimited(0), + m_citizenshipCity(), + m_citizenshipType(static_cast(CityDataCitizenType::NotACitizen)), + m_currentGcwRegion(), + m_cityGcwDefenderRegion(std::make_pair(std::string(), std::make_pair(false, false))), + m_guildGcwDefenderRegion(std::make_pair(std::string(), std::make_pair(false, false))), + m_squelchedById(NetworkId::cms_invalid), + m_squelchedByName(), + m_squelchExpireTime(0), + m_showBackpack(true), + m_showHelmet(true), + m_environmentFlags(0), + m_defaultAttackOverride(), + m_guildRank(), + m_citizenRank(), + m_pickupDropAllItemsOperationId(0), + m_pickupDropAllItemsCellId(NetworkId::cms_invalid), + m_pickupAllItemsAllowInventoryOverload(false), + m_pickupDropAllItemsNumItemsSoFar(0), + m_pickupDropAllItemsProcessedItemsSoFar(), + m_restoreDecorationOperationId(0), + m_restoreDecorationPobId(NetworkId::cms_invalid), + m_restoreDecorationObjectBeingRestored(NetworkId::cms_invalid), + m_restoreDecorationTotalCount(0), + m_restoreDecorationAttemptedCount(0), + m_restoreDecorationSuccessCount(0), + m_restoreDecorationLayoutList(), + m_galacticReserveDeposit(0), + m_pgcRatingCount(0), + m_pgcRatingTotal(0), + m_pgcLastRatingTime(0) +{ + m_allCollections[0] = &m_collections; + m_allCollections[1] = &m_collections2; + + addMembersToPackages(); + m_waypoints.setOnInsert(this, &PlayerObject::onWaypointCreated); + m_waypoints.setOnSet(this, &PlayerObject::onWaypointSet); + m_waypoints.setOnErase(this, &PlayerObject::onWaypointRemoved); + IGNORE_RETURN(s_allPlayerObjects.insert(this)); +} + +//----------------------------------------------------------------------- + +PlayerObject::~PlayerObject() +{ + delete m_callback; + delete m_chatLog; + IGNORE_RETURN(s_allPlayerObjects.erase(this)); +} + +//----------------------------------------------------------------------- + +/** + * Returns a shared template if none was given for this object. + * + * @return the shared template + */ +const SharedObjectTemplate * PlayerObject::getDefaultSharedTemplate() const +{ +static const ConstCharCrcLowerString templateName("object/player/base/shared_player_default.iff"); + + if (m_defaultSharedTemplate == NULL) + { + m_defaultSharedTemplate = safe_cast( + ObjectTemplateList::fetch(templateName)); + WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create " + "default shared object template %s", templateName.getString())); + if (m_defaultSharedTemplate != NULL) + ExitChain::add (removeDefaultTemplate, "PlayerObject::removeDefaultTemplate"); + } + return m_defaultSharedTemplate; +} // PlayerObject::getDefaultSharedTemplate + +//----------------------------------------------------------------------- + +/** + * Cleans up the default shared template. + */ +void PlayerObject::removeDefaultTemplate() +{ + if (m_defaultSharedTemplate != NULL) + { + m_defaultSharedTemplate->releaseReference(); + m_defaultSharedTemplate = NULL; + } +} // PlayerObject::removeDefaultTemplate + +// ---------------------------------------------------------------------- + +void PlayerObject::setStationId(StationId account) +{ + DEBUG_FATAL(!isAuthoritative(),("PlayerObject %s wasn't authoritative in setStationId.\n",getNetworkId().getValueString().c_str())); + m_stationId=account; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setCheaterLevel(float level) +{ + m_accountCheaterLevel = level; +} + +//----------------------------------------------------------------------- + +/** + * Returns the current "birth" date. The birth date is defined as the number + * of days since Jan 1st, 2001 (Jan 1st, 2001 = 0) + */ +int PlayerObject::getCurrentBornDate() +{ + // get the base date of Jan 1st, 2001 + struct tm baseTimeData; + baseTimeData.tm_hour = 0; + baseTimeData.tm_isdst = 0; + baseTimeData.tm_mday = 1; + baseTimeData.tm_min = 0; + baseTimeData.tm_mon = 0; + baseTimeData.tm_sec = 0; + baseTimeData.tm_wday = 0; + baseTimeData.tm_yday = 0; + baseTimeData.tm_year = 101; + time_t baseTime = mktime(&baseTimeData); + + // get the current time and compute the birth date + time_t currentTime = time(NULL); + time_t delta = (currentTime - baseTime) / (60 * 60 * 24); + delta += ((currentTime - baseTime) % (60 * 60 * 24) != 0 ? 1 : 0); + return int(delta); +} // PlayerObject::getCurrentBornDate + +//----------------------------------------------------------------------- + +/** + * Sets the "birth" date of the player to the current date. The birth date is + * defined as the number of days since Jan 1st, 2001 (Jan 1st, 2001 = 0) + */ +void PlayerObject::setBornDate() +{ + if (m_bornDate.get() != 0) + return; + + if (isAuthoritative()) + { + m_bornDate = (int)getCurrentBornDate(); + } + else + { + WARNING(true, ("PlayerObject::setBornDate called on non-authoritative player")); + } +} // PlayerObject::setBornDate + +//----------------------------------------------------------------------- + +/** +* Adjust the "birth" date of the player by the specified number of days +* +* @param adjustment the number of days (can be negative) to adjust the "birth" date by +*/ +void PlayerObject::adjustBornDate(int adjustment) +{ + if (m_bornDate.get() == 0) + return; + + if (isAuthoritative()) + { + const int newBornDate = m_bornDate.get() + adjustment; + if ((newBornDate <= 0) || (newBornDate > getCurrentBornDate())) + return; + + m_bornDate = newBornDate; + } + else + { + WARNING(true, ("PlayerObject::adjustBornDate called on non-authoritative player")); + } +} // PlayerObject::adjustBornDate + +//----------------------------------------------------------------------- + +/** + * Changes the count of the amount of time this player has been online. Note we only + * update the time every 30 secs. + * + * @param time since last call to this function + */ +void PlayerObject::alterPlayedTime(float time) +{ +static const float TIME_LIMIT = 30.0f; + + if (isAuthoritative()) + { + m_playedTimeAccum += time; + if (m_playedTimeAccum >= TIME_LIMIT) + { + m_playedTime = m_playedTime.get() + static_cast(TIME_LIMIT); + m_playedTimeAccum -= TIME_LIMIT; + } + } + else + { + WARNING(true, ("PlayerObject::alterPlayedTime called on non-authoritative player")); + } +} // updatePlayedTime + +//----------------------------------------------------------------------- + +CreatureObject *PlayerObject::getCreatureObject() +{ + Object * const owner = ContainerInterface::getContainedByObject(*this); + if (owner) + { + ServerObject * const serverOwner = owner->asServerObject(); + if (serverOwner) + return serverOwner->asCreatureObject(); + } + return 0; +} + +//----------------------------------------------------------------------- + +CreatureObject const * PlayerObject::getCreatureObject() const +{ + Object const * const owner = ContainerInterface::getContainedByObject(*this); + if (owner) + { + ServerObject const * const serverOwner = owner->asServerObject(); + if (serverOwner) + return serverOwner->asCreatureObject(); + } + return 0; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::virtualOnSetAuthority() +{ + IntangibleObject::virtualOnSetAuthority(); + + if (isCrafting()) + { + const TangibleObject * tool = safe_cast(getCraftingTool().getObject()); + if (tool != NULL) + { + const ManufactureSchematicObject * manfSchematic = tool->getCraftingManufactureSchematic(); + if (manfSchematic != NULL) + { + m_draftSchematic = DraftSchematicObject::getSchematic( + manfSchematic->getDraftSchematic()); + if (m_draftSchematic.getPointer() == NULL) + { + WARNING(true, ("PlayerObject::virtualOnSetAuthority object " + "%s is flagged as crafting, but has bad manf schematic %lu", + getNetworkId().getValueString().c_str(), + manfSchematic->getDraftSchematic())); + } + } + else + { + WARNING(true, ("PlayerObject::virtualOnSetAuthority object " + "%s is flagged as crafting, but has no manf schematic", + getNetworkId().getValueString().c_str())); + } + } + else + { + WARNING(true, ("PlayerObject::virtualOnSetAuthority object " + "%s is flagged as crafting, but has no crafting tool", + getNetworkId().getValueString().c_str())); + } + } + + GroupWaypointBuilder::updateGroupWaypoints(*this, true); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::virtualOnLogout() +{ + IntangibleObject::virtualOnLogout(); + + // stop crafting + if (isCrafting()) + stopCrafting(false); + + // destroy any theater associated with us + if (m_theaterId.get() != NetworkId::cms_invalid) + { + MessageToQueue::getInstance().sendMessageToC(m_theaterId.get(), + "C++DestroySelf", "", 0, false); + m_theaterId = NetworkId::cms_invalid; + } + + // persist chat statistics + setObjVarItem(OBJVAR_CHAT_SPAM_TIME_END_INTERVAL, m_chatSpamTimeEndInterval.get()); + setObjVarItem(OBJVAR_CHAT_SPAM_SPATIAL, m_chatSpamSpatialNumCharacters.get()); + setObjVarItem(OBJVAR_CHAT_SPAM_NON_SPATIAL, m_chatSpamNonSpatialNumCharacters.get()); + + // persist privileged title + if (m_privledgedTitle.get() != static_cast(PlayerDataPriviledgedTitle::NormalPlayer)) + setObjVarItem(OBJVAR_PRIVILEGED_TITLE, static_cast(m_privledgedTitle.get())); + else + removeObjVarItem(OBJVAR_PRIVILEGED_TITLE); + + // persist squelch info + int const secondsUntilUnsquelched = getSecondsUntilUnsquelched(); + if (secondsUntilUnsquelched != 0) + { + setObjVarItem(OBJVAR_SQUELCH_ID, m_squelchedById.get()); + setObjVarItem(OBJVAR_SQUELCH_NAME, m_squelchedByName.get()); + if (secondsUntilUnsquelched < 0) + setObjVarItem(OBJVAR_SQUELCH_EXPIRE, -1); + else + setObjVarItem(OBJVAR_SQUELCH_EXPIRE, static_cast(ServerClock::getInstance().getGameTimeSeconds()) + secondsUntilUnsquelched); + } + else + { + removeObjVarItem(OBJVAR_SQUELCH_ID); + removeObjVarItem(OBJVAR_SQUELCH_NAME); + removeObjVarItem(OBJVAR_SQUELCH_EXPIRE); + } +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getExperiencePoints(const std::string & experienceType) const +{ + int result = 0; + std::map::const_iterator f = m_experiencePoints.find(experienceType); + if(f != m_experiencePoints.end()) + { + result = (*f).second; + } + return result; +} + +// ---------------------------------------------------------------------- + +const std::map & PlayerObject::getExperiencePoints() const +{ + return m_experiencePoints.getMap(); +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getExperienceLimit(const std::string & experienceType) const +{ + uint32 limit = static_cast(-1); + CreatureObject const * const owner = getCreatureObject(); + + if(owner) + { + // find out the xp limit based on the player's skills + const CreatureObject::SkillList & skills = owner->getSkillList(); + for (CreatureObject::SkillList::const_iterator iter = skills.begin(); + iter != skills.end(); ++iter) + { + if((*iter)) + { + const SkillObject::ExperiencePair * xpInfo = (*iter)->getPrerequisiteExperience(); + if (xpInfo != NULL && experienceType == xpInfo->first && xpInfo->second.second > 0) + { + if (limit == static_cast(-1) || + limit < static_cast(xpInfo->second.second)) + { + limit = xpInfo->second.second; + } + } + } + } + if (limit == static_cast(-1)) + { + // use the default limit + limit = SkillManager::getInstance().getDefaultXpLimit(experienceType); + WARNING(limit == static_cast(-1), ("No default xp limit defined " + "for xp type %s for player object %s", experienceType.c_str(), getNetworkId().getValueString().c_str())); + } + } + + WARNING(limit == static_cast(-1), ("No xp limit defined " + "for xp type %s for player object %s", experienceType.c_str(), getNetworkId().getValueString().c_str())); + + return limit; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::grantExperiencePoints(const std::string & experienceType, int amount) +{ + CreatureObject * const owner = getCreatureObject(); + NOT_NULL(owner); + + int amountGranted = amount; + + if(isAuthoritative()) + { + if (amount > 0) + { + int multiplier = 1; + + if (!getObjVars().getItem(OBJVAR_EXPERIENCE_MULTIPLIER, multiplier)) + multiplier = ConfigServerGame::getXpMultiplier(); + + amount *= multiplier; + + // adjust the xp based on what faction is doing best + // NOTE: HACK HACK HACK! + const PlanetObject * tatooine = ServerUniverse::getInstance().getTatooinePlanet(); + if (tatooine == NULL) + tatooine = ServerUniverse::getInstance().getPlanetByName("Tatooine"); + if (tatooine == NULL) + { + WARNING(true, ("Can't find planet tatooine from ServerUniverse")); + } + else + { + std::string factionName; + int factionPoints = 0; + bool tie = false; + const DynamicVariableList::NestedList factions(tatooine->getObjVars(), + OBJVAR_GAME_FACTION_RANKINGS); + for (DynamicVariableList::NestedList::const_iterator i(factions.begin()); + i != factions.end(); ++i) + { + int points = 0; + if (i.getValue(points)) + { + if (points > factionPoints) + { + tie = false; + factionPoints = points; + factionName = i.getName(); + } + else if (points == factionPoints) + tie = true; + } + else + { + WARNING(true, ("GCW faction %s value not stored as int", + i.getName().c_str())); + } + } + if (!tie && factionPoints > 0) + { + uint32 factionCrc = Crc::calculate(factionName.c_str()); + if (factionCrc == owner->getPvpFaction()) + { + amount += static_cast(amount * ConfigServerGame::getGcwXpBonus()); + } + } + } + + } + + // find out the xp limit based on the player's skills + int const limit = getExperienceLimit(experienceType); + + // get the current xp + int const current = getExperiencePoints(experienceType); + + // calculate the new xp + int total = current + amount; + + // cap the total xp, if necessary + if ((total > limit) && (limit >= 0)) + total = limit; + + if (ConfigServerScript::getLogBalance() && (total != current)) + { + // log the grant + unsigned long time = ServerClock::getInstance().getGameTimeSeconds(); + LOG("GameBalance", ("balancelog:%d:XP;%lu;%s;%s;%d;%d;%d;%d", + static_cast(GameServer::getInstance().getProcessId()), time, + owner->getNetworkId().getValueString().c_str(), experienceType.c_str(), + amount, current, total, (m_expModified.get()+1))); + } + + // calculate the actual xp granted + amountGranted = total - current; + + // only update the XP if it actually changed + if (total != current) + { + m_experiencePoints.set(experienceType, total); + m_expModified.set(m_expModified.get() + 1); + } + } + else + { + owner->sendControllerMessageToAuthServer(CM_grantExperiencePoints, new MessageQueueGenericValueType >(std::make_pair(experienceType, amount))); + } + + return amountGranted; +} + +//----------------------------------------------------------------------- + +bool PlayerObject::grantSchematicGroup(const std::string & groupNameWithModifier, bool fromSkill) +{ + if (groupNameWithModifier.size() <= 1 || (groupNameWithModifier[0] != '+' && groupNameWithModifier[0] != '-')) + return true; + + if (isAuthoritative()) + { + const std::string & groupName = groupNameWithModifier.substr (1); + static DraftSchematicGroupManager::SchematicVector drafts; + drafts.clear (); + if (!DraftSchematicGroupManager::getSchematicsForGroup (groupName, drafts)) + { + WARNING (true, ("Invalid schematic group [%s]", groupName.c_str ())); + return false; + } + + const bool addGroup = (groupNameWithModifier[0] == '+'); + + for (DraftSchematicGroupManager::SchematicVector::const_iterator it = drafts.begin (); it != drafts.end (); ++it) + { + const std::pair & schematic = *it; + if (addGroup) + grantSchematic(schematic.first, fromSkill); + else + revokeSchematic(schematic.first, fromSkill); + } + } + else + { + WARNING_STRICT_FATAL(true, ("Did not assign schematic group to proxy object %s", getNetworkId().getValueString().c_str())); + } + return true; +} + +//----------------------------------------------------------------------- + +bool PlayerObject::grantSchematic(uint32 schematicCrc, bool fromSkill) +{ + if (isAuthoritative()) + { + // if we are crafting, end the crafting session + if (isCrafting()) + stopCrafting(false); + + const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic( + schematicCrc); + if (schematic != NULL) + { + // add the schematic to the player's draft schematic list + Archive::AutoDeltaMap, int>::const_iterator found = m_draftSchematics.find(schematic->getCombinedCrc()); + if (found == m_draftSchematics.end()) + { + m_draftSchematics.set(schematic->getCombinedCrc(), 1); + CreatureObject * owner = dynamic_cast(ContainerInterface::getContainedByObject(*this)); + NOT_NULL(owner); + if (!fromSkill) + { + // save schematic as objvar + char buffer[256]; + sprintf(buffer, "%s.%lu", OBJVAR_NOT_SKILL_SCHEMATICS.c_str(), + schematicCrc); + owner->setObjVarItem(buffer, 1); + } + + // tell scripts the schematic was given + NOT_NULL(owner->getScriptObject()); + ScriptParams params; + params.addParam(static_cast(schematic->getCombinedCrc().first)); + params.addParam(fromSkill); + IGNORE_RETURN(owner->getScriptObject()->trigAllScripts( + Scripting::TRIG_GRANT_SCHEMATIC, params)); + } + else if (fromSkill) + { + m_draftSchematics.set(schematic->getCombinedCrc(), (*found).second + 1); + } + } + } + else + { + WARNING_STRICT_FATAL(true, ("Did not assign schematic to proxy object %s", getNetworkId().getValueString().c_str())); + } + return true; +} + +//----------------------------------------------------------------------- + +bool PlayerObject::revokeSchematic(uint32 schematicCrc, bool fromSkill) +{ + if (isAuthoritative()) + { + // if we are crafting, end the crafting session + if (isCrafting()) + stopCrafting(false); + + const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic(schematicCrc); + if (schematic != NULL) + { + // remove the schematic from the player's draft schematic list + Archive::AutoDeltaMap, int>::const_iterator found = m_draftSchematics.find(schematic->getCombinedCrc()); + if ((*found).second > 1 && fromSkill) + { + m_draftSchematics.set(schematic->getCombinedCrc(), (*found).second - 1); + } + else + { + WARNING((*found).second > 1, ("PlayerObject::revokeSchematic revoking schematic %s that has a ref count of %d from player %s, due to it being revoked outside the skill system", + schematic->getObjectTemplateName(), (*found).second, getAccountDescription().c_str())); + m_draftSchematics.erase(found); + CreatureObject * owner = dynamic_cast(ContainerInterface::getContainedByObject(*this)); + NOT_NULL(owner); + if (!fromSkill) + { + // remove schematic from objvars + char buffer[256]; + sprintf(buffer, "%s.%lu", OBJVAR_NOT_SKILL_SCHEMATICS.c_str(), + schematicCrc); + owner->removeObjVarItem(buffer); + } + + // tell scripts the schematic was removed + NOT_NULL(owner->getScriptObject()); + ScriptParams params; + params.addParam(static_cast(schematic->getCombinedCrc().first)); + params.addParam(fromSkill); + IGNORE_RETURN(owner->getScriptObject()->trigAllScripts( + Scripting::TRIG_REVOKE_SCHEMATIC, params)); + } + } + } + else + { + WARNING_STRICT_FATAL(true, ("Did not remove schematic from proxy object %s", getNetworkId().getValueString().c_str())); + } + return true; +} + +//----------------------------------------------------------------------- + +bool PlayerObject::hasSchematic(uint32 schematicCrc) +{ + const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic(schematicCrc); + if (schematic != NULL) + { + std::map,int>::const_iterator found = m_draftSchematics.find(schematic->getCombinedCrc()); + if (found != m_draftSchematics.end()) + return true; + } + return false; +} + + +// ====================================================================== +// ====================================================================== +// +// Crafting functions +// +// ====================================================================== +// ====================================================================== + +/** + * Sets the player's crafting tool. + * + * @param tool the crafting tool + */ +void PlayerObject::setCraftingTool(const TangibleObject & tool) +{ + m_craftingTool = CachedNetworkId(tool); +} // PlayerObject::setCraftingTool + +//----------------------------------------------------------------------- + +/** + * Sets the player's crafting station. + * + * @param station the crafting station + */ +void PlayerObject::setCraftingStation(const TangibleObject * station) +{ + if (station != NULL) + { + // verify the crafting station is valid + if (station->getObjVars().hasItem(OBJVAR_CRAFTING_STATION)) + { + m_craftingStation = CachedNetworkId(*station); + + // if we are private, make sure we have an ingredient hopper + int privateStation = 0; + station->getObjVars().getItem(OBJVAR_PRIVATE_STATION, privateStation); + if (privateStation == 1 && getCraftingLevel() == 3 && station->getIngredientHopper() == NULL) + { + CreatureObject * const owner = getCreatureObject(); + NOT_NULL(owner); + + WARNING(true, ("Player %s crafting near private station %s that " + "has no ingredient hopper! The crafting session level will " + "be reduced to 2", + owner->getNetworkId().getValueString().c_str(), + station->getNetworkId().getValueString().c_str())); + setCraftingLevel(2); + } + return; + } + } + m_craftingStation = CachedNetworkId::cms_cachedInvalid; +} // PlayerObject::setCraftingStation + +//----------------------------------------------------------------------- + +/** + * Called when the player wants to start crafting. + * + * @param toolId the crafting tool the player wants to use + * + * @return true if the session was started, false if not + */ +bool PlayerObject::requestCraftingSession(const NetworkId & toolId) +{ + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return false; + + const std::string myId = getNetworkId().getValueString(); + const char * const myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + const std::string toolIdStdString = toolId.getValueString(); + const char * const toolIdString = toolIdStdString.c_str(); + UNREF(toolIdString); // needed for release mode + + if (getCraftingTool() != NetworkId::cms_invalid) + { + if (m_craftingStage.get() == Crafting::CS_none || + m_craftingStage.get() == Crafting::CS_selectDraftSchematic) + { + stopCrafting(false); + } + else + { + DEBUG_WARNING(true, ("Player %s requesting crafting session with tool " + "%s while crafting with tool %s", myIdString, toolIdString, + getCraftingTool().getValueString().c_str())); + return false; + } + } + + TangibleObject * const tool = dynamic_cast(CachedNetworkId(toolId).getObject()); + if (tool == NULL) + { + DEBUG_WARNING(true, ("Player %s requesting crafting session with invalid " + "object %s", myIdString, toolIdString)); + return false; + } + + // If the tool is a crafting station, try to find a compatible crafting tool to launch. + if (tool->isCraftingStation()) + { + int const toolType = tool->getCraftingType(); + + ServerObject const * const inventory = owner->getInventory(); + if (inventory) + { + VolumeContainer const * const inventoryContainer = ContainerInterface::getVolumeContainer(*inventory); + if (inventoryContainer) + { + std::vector objList; + for (ContainerConstIterator iter(inventoryContainer->begin()); iter != inventoryContainer->end(); ++iter) + { + CachedNetworkId const & objId = (*iter); + TangibleObject * const obj = safe_cast(objId.getObject()); + if ((obj != NULL) && obj->isCraftingTool() && (toolType & obj->getCraftingType())) + { + return requestCraftingSession(objId) ; + } + } + } + } + } + else + { + return tool->startCraftingSession(*owner); + } + + return false; +} // PlayerObject::requestCraftingSession + +//----------------------------------------------------------------------- + +/** + * Sends a list of draft schematic names that a player may craft with to the + * player. + * + * @param schematicNames draft schematic template names the player can use + */ +void PlayerObject::sendUseableDraftSchematics(std::vector & schematicNames) +{ + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return; + + // keep around the names since we are just going to get an index back from + // the client; the calling function will free up the old names + m_useableDraftSchematics.swap(schematicNames); + + MessageQueueDraftSchematics * message = new MessageQueueDraftSchematics(getCraftingTool(), getCraftingStation()); + + // get the name of each schematic and put it in the network message + std::vector::iterator iter; + for (iter = m_useableDraftSchematics.begin(); iter != m_useableDraftSchematics.end();) + { + if (*iter != 0) + { + const DraftSchematicObject * const schematic = DraftSchematicObject::getSchematic(*iter); + if (schematic != NULL) + { + message->addSchematic(schematic->getCombinedCrc(), + static_cast(schematic->getCategory())); + ++iter; + } + else + { + const ConstCharCrcString & name = ObjectTemplateList::lookUp(*iter); + if (!name.isEmpty()) + { + WARNING(true, ("PlayerObject::sendUseableDraftSchematics bad draft " + "schematic name %s", name.getString())); + } + else + { + WARNING(true, ("PlayerObject::sendUseableDraftSchematics bad draft " + "schematic crc %u", *iter)); + } + iter = m_useableDraftSchematics.erase(iter); + } + } + else + iter = m_useableDraftSchematics.erase(iter); + } + + // send the names to the player + (safe_cast(owner->getController()))->appendMessage( + static_cast(CM_draftSchematicsMessage), 0.0f, message, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + + m_craftingStage = static_cast(Crafting::CS_selectDraftSchematic); +} // PlayerObject::sendUseableDraftSchematics + +//---------------------------------------------------------------------- + +/** + * Sends the player info about a draft schematic's slots, filtered by the + * player's skills. + * + * @param draftSchematicCrc the crc of the schematic to send + * @param message message to be sent to the player if we are getting slots for an object we are crafting + * @param queryMessage message to be sent to the player if we are getting slots for an arbitrary object + * + * @return true on success, false if draftSchematicName is not a valid schematic + */ +bool PlayerObject::requestDraftSlots(uint32 draftSchematicCrc, MessageQueueDraftSlots * message, MessageQueueDraftSlotsQueryResponse * queryMessage) +{ + ManufactureSchematicObject * manfSchematic = NULL; + MessageQueueDraftSlots::Slot slotInfo; + MessageQueueDraftSlots::Option optionInfo; + + if ((message == NULL && queryMessage == NULL) || + (message != NULL && queryMessage != NULL)) + { + return false; + } + + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return false; + + const ConstCharCrcString & schematicName = ObjectTemplateList::lookUp(draftSchematicCrc); + UNREF(schematicName); + + const DraftSchematicObject * const draftSchematic = DraftSchematicObject::getSchematic(draftSchematicCrc); + if (draftSchematic == NULL) + { + DEBUG_WARNING(true, ("Player %s requested invalid draft schematic %s", owner->getNetworkId().getValueString().c_str(), schematicName.getString())); + return false; + } + + if (message != NULL) + { + m_draftSchematic = draftSchematic; + + TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); + NOT_NULL(tool); + if (tool == NULL) + return false; + + tool->clearCraftingManufactureSchematic(); + tool->clearCraftingPrototype(); + + // make a temporary manufacturing schematic based on the draft scematic + manfSchematic = ServerWorld::createNewManufacturingSchematic(CachedNetworkId( + *owner), *tool, tool->getCraftingManufactureSchematicSlotId(), false); + if (manfSchematic == NULL) + { + DEBUG_WARNING(true, ("Error creating manufacturing schematic!")); + return false; + } + message->setManfSchemId(manfSchematic->getNetworkId ()); + tool->setCraftingManufactureSchematic(*manfSchematic); + + // flag that the schematic is being used in a crafting session + manfSchematic->setObjVarItem(OBJVAR_IN_CRAFTING_SESSION, 1); + + // reset the experiment points + m_experimentPoints = -1; + + // create a test prototype so the client will know what object is + // being made + ServerObject * prototype = manfSchematic->manufactureObject(owner->getNetworkId(), + *tool, tool->getCraftingPrototypeSlotId(), true); + if (prototype == NULL) + { + DEBUG_WARNING(true, ("Error creating temp prototype!")); + return false; + } + tool->setCraftingPrototype(*prototype); + message->setPrototypeId(prototype->getNetworkId()); + message->setVolume(draftSchematic->getVolume()); + message->setCanManufacture(draftSchematic->getItemsPerContainer() > 0); + + DEBUG_LOG("crafting", ("PlayerObject::requestDraftSlots, created schematic " + "%s, prototype %s for player %s", + manfSchematic->getNetworkId().getValueString().c_str(), + prototype->getNetworkId().getValueString().c_str(), + getAccountDescription().c_str())); + } + + if (queryMessage != NULL) + { + queryMessage->setComplexity(static_cast(draftSchematic->getComplexity())); + queryMessage->setVolume(draftSchematic->getVolume()); + queryMessage->setCanManufacture(draftSchematic->getItemsPerContainer() > 0); + } + + // get info about each slot in the schematic + Crafting::IngredientSlot manfSlot; + ServerDraftSchematicObjectTemplate::IngredientSlot slot; + const int slotCount = draftSchematic->getSlotsCount(); + for (int i = 0; i < slotCount; ++i) + { + if (!draftSchematic->getSlot(slot, i)) + { + DEBUG_WARNING(true, ("draft schematic slot %d for schematic %s not found!",i, schematicName.getString())); + continue; + } + if (!slot.optional || slot.optionalSkillCommand.empty() || + owner->hasCommand(slot.optionalSkillCommand)) + { + if (manfSchematic != NULL) + { + // create the slot + IGNORE_RETURN(manfSchematic->getSlot(slot.name, manfSlot)); + // set the manufacturing slot->draft slot map + manfSchematic->setSlotIndex(slot.name, i); + } + + slotInfo.name = slot.name; + slotInfo.optional = slot.optional; + bool componentSlot = false; + const int optionsCount = static_cast(slot.options.size()); + for (int j = 0; j < optionsCount; ++j) + { + const ServerIntangibleObjectTemplate::Ingredient & option = slot.options[static_cast(j)]; + + if (option.skillCommand.empty() || owner->hasCommand(option.skillCommand)) + { + const ServerIntangibleObjectTemplate::SimpleIngredient & simple = option.ingredients[0]; + + switch (option.ingredientType) + { + case Crafting::IT_template: + case Crafting::IT_templateGeneric: + { + // get the default object name from the shared template + const ObjectTemplate *const ingredientTemplate = ObjectTemplateList::fetch(simple.ingredient); + if (ingredientTemplate == NULL) + { + DEBUG_WARNING(true, ("draft schematic component ingredient %s not found!", simple.ingredient.c_str())); + continue; + } + const SharedObjectTemplate * const sharedTemplate = safe_cast(ObjectTemplateList::fetch((safe_cast(ingredientTemplate))->getSharedTemplate())); + if (sharedTemplate == NULL) + { + DEBUG_WARNING(true, ("draft schematic component ingredient %s shared template not found!", simple.ingredient.c_str())); + continue; + } + optionInfo.ingredient = Unicode::narrowToWide(sharedTemplate->DataResource::getName()); + sharedTemplate->releaseReference(); + ingredientTemplate->releaseReference(); + } + break; + case Crafting::IT_schematic: + case Crafting::IT_schematicGeneric: + { + // get the default object name from the shared template of the crafted object + const ObjectTemplate * const ingredientTemplate = ObjectTemplateList::fetch(simple.ingredient); + if (ingredientTemplate == NULL) + { + DEBUG_WARNING(true, ("draft schematic schematic ingredient %s not found!", simple.ingredient.c_str())); + continue; + } + const ServerObjectTemplate * const craftedTemplate = safe_cast(ingredientTemplate)->getCraftedObjectTemplate(); + if (craftedTemplate == NULL) + { + DEBUG_WARNING(true, ("draft schematic schematic ingredient %s not found!", simple.ingredient.c_str())); + continue; + } + const SharedObjectTemplate * const sharedTemplate = safe_cast(ObjectTemplateList::fetch((safe_cast(craftedTemplate))->getSharedTemplate())); + if (sharedTemplate == NULL) + { + DEBUG_WARNING(true, ("draft schematic component ingredient %s shared template not found!", simple.ingredient.c_str())); + continue; + } + optionInfo.ingredient = Unicode::narrowToWide(sharedTemplate->DataResource::getName()); + sharedTemplate->releaseReference(); + craftedTemplate->releaseReference(); + ingredientTemplate->releaseReference(); + } + break; + default: + optionInfo.ingredient = Unicode::narrowToWide(simple.ingredient); + break; + } + optionInfo.name = simple.name; + optionInfo.type = static_cast(static_cast(option.ingredientType)); + optionInfo.amountNeeded = simple.count; + slotInfo.options.push_back(optionInfo); + if (static_cast(option.ingredientType) == static_cast(Crafting::IT_template) || + static_cast(option.ingredientType) == static_cast(Crafting::IT_templateGeneric) || + static_cast(option.ingredientType) == static_cast(Crafting::IT_item) || + static_cast(option.ingredientType) == static_cast(Crafting::IT_schematic) || + static_cast(option.ingredientType) == static_cast(Crafting::IT_schematicGeneric)) + { + componentSlot = true; + } + } // if (hasCommand(option.skillCommand)) + } // for (int j = 0; j < optionsCount; ++j) + if (componentSlot) + slotInfo.hardpoint = slot.appearance; + if (message != NULL) + message->addSlot(slotInfo); + else + queryMessage->addSlot(slotInfo); + slotInfo.options.clear(); + } // if (hasCommand(slot.skillCommand)) + } // for (int i = 0; i < slotCount; ++i) + + // send the slot info to the player + if (message != NULL) + { + (safe_cast(owner->getController()))->appendMessage( + static_cast(CM_draftSlotsMessage), 0.0f, message, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + else + { + (safe_cast(owner->getController()))->appendMessage( + static_cast(CM_draftSlotsQueryResponse), 0.0f, queryMessage, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + return true; +} // PlayerObject::requestDraftSlots + +//---------------------------------------------------------------------- + +/** + * Called when a player has selected a draft schematic to use in a crafting + * tool. We send the player info about the slots that need to be filled + * in the schematic, filtered by his skills. + * + * @param index index into the available schematics the player can use. The + * index will be clipped if it is out of range. + */ +void PlayerObject::selectDraftSchematic(int index) +{ + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return; + + const std::string myId = getNetworkId().getValueString(); + const char * const myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // check the crafting tool + if (getCraftingTool() == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Player %s trying to select draft schematic with " + "no crafting tool!", myIdString)); + } + else if (m_craftingStage.get() != static_cast(Crafting::CS_selectDraftSchematic)) + { + DEBUG_WARNING(true, ("Player %s trying to select draft schematic in wrong " + "crafting stage %d!", myIdString, static_cast(m_craftingStage.get()))); + } + else + { + // check the available draft schematics + if (m_useableDraftSchematics.empty ()) + { + DEBUG_WARNING(true, ("Player %s selected a draft schematic to craft " + "when none are available!", myIdString)); + } + else + { + if (index < 0) + index = 0; + else if (index >= static_cast(m_useableDraftSchematics.size())) + index = static_cast(m_useableDraftSchematics.size()) - 1; + + MessageQueueDraftSlots * message = new MessageQueueDraftSlots( + getCraftingTool(), NetworkId::cms_invalid); + if (requestDraftSlots(m_useableDraftSchematics[static_cast(index)], message, NULL)) + { + m_craftingStage = static_cast(Crafting::CS_assembly); + m_craftingComponentBioLink = NetworkId::cms_invalid; + } + else + delete message; + } + } +} // PlayerObject::selectDraftSchematic + +//---------------------------------------------------------------------- + +/** + * Tries to fill the current manufacturing schematic with an ingredient in the player's + * inventory or the crafting station's input hopper. + * + * @param slotIndex index of the slot to fill + * @param slotOptionIndex index of the slot option to use + * @param ingredientId id of the ingredient to use + * + * @return CE_success on success, error code if the ingredient wasn't added + */ +Crafting::CraftingError PlayerObject::fillSlot(int slotIndex, int slotOptionIndex, const NetworkId & ingredientId) +{ + std::string myId = getNetworkId().getValueString(); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return Crafting::CE_noOwner; + + // check the draft schematic + if (m_draftSchematic.getPointer() == NULL) + { + WARNING(true, ("Player %s trying to fill slot with no draft schematic!", myIdString)); + return Crafting::CE_noDraftSchematic; + } + + if (m_draftSchematic->getGameObjectType() == SharedObjectTemplate::GOT_data_draft_schematic_read_only) + { + return Crafting::CE_readOnlyDraftSchematic; + } + + if (getCraftingStage() != Crafting::CS_assembly) + { + WARNING(true, ("Player %s trying to fill slot when not in assembly stage! " + "Stage = %d, schematic = %s, ingredient = %s, slot = %d", myIdString, + getCraftingStage(), m_draftSchematic->getTemplateName(), + ingredientId.getValueString().c_str(), slotIndex)); + return Crafting::CE_notAssemblyStage; + } + + // check the crafting tool + if (getCraftingTool() == NetworkId::cms_invalid) + { + WARNING(true, ("Player %s trying to fill slot with no crafting tool!", myIdString)); + return Crafting::CE_noCraftingTool; + } + + TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); + if (tool == NULL) + { + WARNING(true, ("Player %s trying to fill slot with crafting tool %s, but tool is NULL!", myIdString, getCraftingTool().getValueString().c_str())); + return Crafting::CE_noCraftingTool; + } + + // get the crafting station (if any) + TangibleObject * const station = dynamic_cast(getCraftingStation().getObject()); + + // check the manufacturing schematic + ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); + if (manfSchematic == NULL) + { + WARNING(true, ("Player %s trying to fill slot with no manufacturing schematic!", myIdString)); + return Crafting::CE_noManfSchematic; + } + + // verify the slot index + if (slotIndex < 0 || slotIndex >= manfSchematic->getSlotsCount()) + { + WARNING(true, ("Player %s trying to fill invalid slot %d",myIdString, slotIndex)); + return Crafting::CE_invalidSlot; + } + + // get the manufacturing schematic object + Crafting::IngredientSlot manfSlot; + if (!manfSchematic->getSlot(slotIndex, manfSlot, false)) + { + WARNING(true, ("Got invalid slot %d result for manf schematic %s, but we were told it was ok! What's going on?", slotIndex, manfSchematic->getNetworkId().getValueString().c_str())); + return Crafting::CE_invalidSlot; + } + + // get the draft schematic slot + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + if (!m_draftSchematic->getSlot(draftSlot, manfSlot.draftSlotIndex)) + { + return Crafting::CE_invalidSlot; + } + + // get the draft schematic option, convert the passed-in option index to the + // unfiltered index + int i, j; + const ServerIntangibleObjectTemplate::Ingredient * slotOption = NULL; + const int optionsCount = static_cast(draftSlot.options.size()); + for (i = 0, j = 0; i < optionsCount; ++i) + { + const ServerIntangibleObjectTemplate::Ingredient & tempOption = draftSlot.options[static_cast(i)]; + if (tempOption.skillCommand.empty() || owner->hasCommand(tempOption.skillCommand)) + { + if (j == slotOptionIndex) + { + slotOption = &tempOption; + break; + } + else + ++j; + } + } + if (i == optionsCount) + { + WARNING(true, ("Player %s selected invalid slot option %d for slot %d", myIdString, slotOptionIndex, slotIndex)); + return Crafting::CE_invalidSlotOption; + } + slotOptionIndex = i; + + if (slotOption->ingredients.size() != 1) + { + WARNING(true, ("Ingredient %d for draft schematic %s, slot %s, has ingredient count != 1", + slotOptionIndex, m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str())); + return Crafting::CE_invalidIngredientSize; + } + const ServerIntangibleObjectTemplate::SimpleIngredient & slotIngredient = slotOption->ingredients[0]; + + // see if the slot is already filled - also get how many ingredients are + // needed and how many we already have + int neededIngredientCount = slotIngredient.count; + int currentIngredientCount = 0; + if (manfSlot.ingredientType != Crafting::IT_none) + { + // the slot has something in it, see if it is full or not + for (Crafting::Ingredients::const_iterator iter = + manfSlot.ingredients.begin(); iter != manfSlot.ingredients.end(); ++iter) + { + currentIngredientCount += (*iter)->count; + } + if (currentIngredientCount >= neededIngredientCount) + { + DEBUG_WARNING(currentIngredientCount == neededIngredientCount, ( + "Player %s trying to fill filled slot %d", myIdString, slotIndex)); + WARNING_STRICT_FATAL(currentIngredientCount > neededIngredientCount, + ("HEY! Player %s trying to fill OVER filled slot %d (required = " + "%d, current = %d)", myIdString, slotIndex, neededIngredientCount, + currentIngredientCount)); + return Crafting::CE_slotFull; + } + } + int numIngredientsToAdd = neededIngredientCount - currentIngredientCount; + + TangibleObject * const ingredient = dynamic_cast(NetworkIdManager::getObjectById(ingredientId)); + if (ingredient == NULL) + { + WARNING(true, ("No object for ingredient id %s", ingredientId.getValueString().c_str())); + return Crafting::CE_invalidIngredient; + } + + // check if the ingredient is bio-linked + NetworkId bioLinkId(ingredient->getBioLink()); + if (bioLinkId != NetworkId::cms_invalid) + { + if (m_craftingComponentBioLink.get() == NetworkId::cms_invalid) + { + // this component defines the bio-link for the object + m_craftingComponentBioLink = bioLinkId; + } + else + { + return Crafting::CE_invalidBioLink; + } + } + else + m_craftingComponentBioLink = NetworkId::cms_invalid; + + // see if the ingredient is in the player's inventory + if (!owner->isIngredientInInventory(*ingredient)) + { + // if we are crafting level 3, also check the crafting station's hopper + if (getCraftingLevel() != 3 || (station != NULL && + !station->isIngredientInHopper(ingredientId))) + { + DEBUG_WARNING(true, ("Player %s chose invalid ingredient %s", myIdString, ingredientId.getValueString().c_str())); + return Crafting::CE_ingredientNotInInventory; + } + + } + + // see if the ingredient is a resource or component + ResourceContainerObject * const crate = dynamic_cast(ingredient); + if (crate != NULL) + { + // get the resource type name and class name + ResourceTypeObject const * const resource = crate->getResourceType(); + NetworkId const resourceId = resource ? resource->getNetworkId() : NetworkId::cms_invalid; + + bool slotOk = false; + + if (resource) + { + // make sure the selected slot is the right type + if (currentIngredientCount == 0) + { + if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_resourceType) + { + const std::string typeName(resource->getResourceName()); + if (typeName == slotIngredient.ingredient) + slotOk = true; + } + else if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_resourceClass) + { + ResourceClassObject const * resourceClass = &(resource->getParentClass()); + while (resourceClass != NULL) + { + const std::string className (resourceClass->getResourceClassName()); + if (className == slotIngredient.ingredient) + { + slotOk = true; + break; + } + resourceClass = resourceClass->getParent(); + } + } + } + else + { + // the resource type must be the exact one currently in the slot + if (resource->getNetworkId() == manfSlot.ingredients.front()->ingredient) + slotOk = true; + } + } + + if (slotOk) + { + // if we need more resources than we have, just empty the crate + if (crate->getQuantity() < numIngredientsToAdd) + numIngredientsToAdd = crate->getQuantity(); + + // we can put the resource in the manufacturing schematic + std::vector > sources; + if (crate->removeResource(resourceId, numIngredientsToAdd, &sources)) + { + if (currentIngredientCount == 0) + { + manfSchematic->setSlotOption(manfSlot.name, slotOptionIndex); + manfSchematic->modifySlotComplexity(manfSlot.name, slotOption->complexity); + manfSchematic->setSlotType(manfSlot.name, static_cast(slotOption->ingredientType)); + } + int count = sources.size(); + for (int i = 0; i < count; ++i) + { + manfSchematic->addSlotResource(manfSlot.name, resourceId, sources[i].second, sources[i].first); + manfSchematic->addIngredient(resourceId, sources[i].second, sources[i].first); + } + } + else + { + return Crafting::CE_cantRemoveResource; + } + } + else + { + DEBUG_WARNING(true, ("Invalid resource ingredient for draft schematic %s, slot %s, option %d", + m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), slotOptionIndex)); + return Crafting::CE_wrongResource; + } + } + else + { + if (manfSchematic->hasIngredient (ingredient->getNetworkId ())) + { + DEBUG_WARNING(true, ("Attempt to add ingredient multiple times.")); + return Crafting::CE_invalidIngredient; + } + + // see if the ingredient is a stacked loot item + // @todo: stacked loot should work the same as FactoryObject objects + if (ingredient->getScriptObject()->hasScript("object.onewayunstack")) + { + return Crafting::CE_stackedLoot; + } + + // test if the component is a factory + FactoryObject * factory = dynamic_cast(ingredient); + + // if this is an old-style factory, we can't use it directly in crafting + if (factory != NULL && !factory->getLoadContents()) + factory = NULL; + + // make sure the component isn't damaged + if (factory == NULL && ingredient->getDamageTaken() != 0 && + !ingredient->getObjVars().hasItem(OBJVAR_CRAFTING_COMPONENT_CAN_BE_DAMAGED)) + { + DEBUG_WARNING(true, ("Tried to use damaged component %s for draft schematic %s, slot %s, option %d", + ingredientId.getValueString().c_str(), + m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), + slotOptionIndex)); + return Crafting::CE_damagedComponent; + } + + // make sure the ingredient is crafted, if required + if ((slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematic || + slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematicGeneric) && + !ingredient->isCrafted()) + { + DEBUG_WARNING(true, ("Invalid component ingredient for draft schematic %s, slot %s, option %d", + m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), slotOptionIndex)); + return Crafting::CE_wrongComponent; + } + + // find the matching ingredient for the draft slot + bool slotOk = false; + if (currentIngredientCount == 0) + { + if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_item) + { + std::string tempName(Unicode::wideToNarrow(ingredient->getObjectName())); + if (tempName == slotIngredient.ingredient) + { + slotOk = true; + } + } + // for slots that require multiple non-generic components, make + // sure the component being added is crafted + else if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_templateGeneric || + ((slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_template || + slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematic || + slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_schematicGeneric) && + ingredient->isCrafted())) + { + std::string requiredIngredientName(slotIngredient.ingredient); + + // check the ingredient template name for every template in it's + // heirarchy + const ObjectTemplate * testTemplate = NULL; + if (slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_template || + slotOption->ingredientType == ServerIntangibleObjectTemplate::IT_templateGeneric) + { + if (factory == NULL) + testTemplate = ingredient->getObjectTemplate(); + else + testTemplate = factory->getContainedObjectTemplate(); + } + else + { + const DraftSchematicObject * itemSchematic = NULL; + if (factory == NULL) + itemSchematic = DraftSchematicObject::getSchematic(ingredient->getSourceDraftSchematic()); + else + itemSchematic = DraftSchematicObject::getSchematic(factory->getDraftSchematic()); + if (itemSchematic != NULL) + testTemplate = itemSchematic->getObjectTemplate(); + } + + while (testTemplate != NULL) + { + const std::string ingredientName(testTemplate->getName()); + if (ingredientName == requiredIngredientName) + { + slotOk = true; + break; + } + else + { + // travel down the ingredient template heirarchy + testTemplate = testTemplate->getBaseTemplate(); + } + } + } + } + else + { + // the ingredient must either be from the same template, or from the + // same manufacturing schematic as the ingredient currently in the slot; + // this is a configureable setting + const Crafting::ComponentIngredient * testComponent = dynamic_cast< + const Crafting::ComponentIngredient *>(manfSlot.ingredients.front().get()); + if (testComponent != NULL) + { + if (ConfigServerGame::getCraftingComponentStrict() && + (slotOption->ingredientType != ServerIntangibleObjectTemplate::IT_templateGeneric && + slotOption->ingredientType != ServerIntangibleObjectTemplate::IT_schematicGeneric)) + { + // component from same manf schematic + if (ingredient->getCraftedId() == testComponent->ingredient) + slotOk = true; + } + else + { + // component from same template + if (factory == NULL) + { + if (ingredient->getObjectTemplateName() != NULL && + ingredient->getObjectTemplateName() == testComponent->templateName) + { + slotOk = true; + } + } + else if (factory->getContainedTemplateName() != NULL && + factory->getContainedTemplateName() == testComponent->templateName) + { + slotOk = true; + } + } + } + } + if (slotOk) + { + if (factory == NULL || factory->getCount() <= numIngredientsToAdd) + { + // adding normal component or a complete factory object + if (manfSchematic->addIngredient(*ingredient)) + { + if (manfSlot.ingredientType == Crafting::IT_none) + { + manfSchematic->setSlotType(manfSlot.name, static_cast(slotOption->ingredientType)); + manfSchematic->setSlotOption(manfSlot.name, slotOptionIndex); + manfSchematic->modifySlotComplexity(manfSlot.name, slotOption->complexity); + } + if (factory == NULL) + { + manfSchematic->addSlotComponent(manfSlot.name, *ingredient, + slotOption->ingredientType); + } + else + { + int count = factory->getCount(); + for (i = 0; i < count; ++i) + { + manfSchematic->addSlotComponent(manfSlot.name, + *factory, slotOption->ingredientType); + } + } + } + else + return Crafting::CE_cantTransferComponent; + } + else + { + // adding component(s) from a factory + if (!factory->inCraftingSession()) + { + if (!factory->startCraftingSession(*manfSchematic)) + return Crafting::CE_cantTransferComponent; + } + if (!factory->removeCraftingReferences(numIngredientsToAdd)) + { + return Crafting::CE_cantTransferComponent; + } + if (manfSlot.ingredientType == Crafting::IT_none) + { + manfSchematic->setSlotType(manfSlot.name, static_cast(slotOption->ingredientType)); + manfSchematic->setSlotOption(manfSlot.name, slotOptionIndex); + manfSchematic->modifySlotComplexity(manfSlot.name, slotOption->complexity); + } + for (i = 0; i < numIngredientsToAdd; ++i) + { + manfSchematic->addSlotComponent(manfSlot.name, *factory, + slotOption->ingredientType); + } + } + } + else + { + DEBUG_WARNING(true, ("Invalid component ingredient for draft schematic %s, slot %s, option %d", + m_draftSchematic->getTemplateName(), draftSlot.name.getText().c_str(), slotOptionIndex)); + return Crafting::CE_wrongComponent; + } + } + + manfSchematic->computeComplexity(); + manfSchematic->signalClientChange(); + return Crafting::CE_success; +} // PlayerObject::fillSlot + +//---------------------------------------------------------------------- + +/** + * Removes the ingredients in a schematic slot and returns them to the crafting + * tool's ingredient hopper. + * + * @param slotIndex schematic slot to empty + * @param targetContainerId the container the player wants to unload the slot into. + * If NetworkId::cms_invalid, then unload the slot into + * the same container it was loaded from. + * + * @return CE_success on success, error code if the ingredient wasn't removed + */ +Crafting::CraftingError PlayerObject::emptySlot(int slotIndex, const NetworkId & targetContainerId) +{ + const std::string & myId = getNetworkId().getValueString(); + const char * const myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return Crafting::CE_noOwner; + + if (getCraftingStage() != Crafting::CS_assembly && !m_allowEmptySlot) + { + WARNING(true, ("Player %s trying to empty slot when not in assembly stage!", myIdString)); + return Crafting::CE_notAssemblyStage; + } + + // check the draft schematic + if (m_draftSchematic.getPointer() == NULL) + { + WARNING(true, ("Player %s trying to empty slot with no draft schematic!", myIdString)); + return Crafting::CE_noDraftSchematic; + } + + // check the crafting tool + if (getCraftingTool() == NetworkId::cms_invalid) + { + WARNING(true, ("Player %s trying to empty slot with no crafting tool!", myIdString)); + return Crafting::CE_noCraftingTool; + } + TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); + if (tool == NULL) + { + WARNING(true, ("Player %s trying to empty slot with crafting tool %s, but tool is NULL!", myIdString, getCraftingTool().getValueString().c_str())); + return Crafting::CE_noCraftingTool; + } + + // get the crafting station (if any) + TangibleObject * station = dynamic_cast(getCraftingStation().getObject()); + if (station != NULL && getCraftingLevel() == 3 && station->getIngredientHopper() == NULL) + { + WARNING_STRICT_FATAL(true, ("Player %s trying to empty crafting slot near " + "a crafting station %s that has no ingredient hopper!", + owner->getNetworkId().getValueString().c_str(), + station->getNetworkId().getValueString().c_str())); + return Crafting::CE_badTargetHopper; + } + + ServerObject * const inventory = owner->getInventory(); + if (inventory == NULL) + { + WARNING (true, ("Player %s has no inventory.", myIdString)); + return Crafting::CE_noInventory; + } + + //-- if the player specified a target container, try to use that + ServerObject * targetContainer = 0; + if (targetContainerId.isValid ()) + { + if (!isNestedInContainer (targetContainerId, inventory->getNetworkId())) + { + // check worn containers, such as backpacks, but only check one level down so we don't catch the datapad + bool containerIsWorn = false; + Object const * const possibleContainer = NetworkIdManager::getObjectById (targetContainerId); + if (possibleContainer) + { + containerIsWorn = owner->isItemEquipped (*possibleContainer); + } + + // if we are crafting level 3, also check the crafting station's hopper + if (!containerIsWorn && + (getCraftingLevel() != 3 || (station != NULL && + !isNestedInContainer (targetContainerId, station->getIngredientHopper()->getNetworkId())))) + { + WARNING (true, ("Player %s attempted to empty slot into invalid container [%s].", myIdString, targetContainerId.getValueString().c_str())); + return Crafting::CE_badTargetHopper; + } + } + + targetContainer = safe_cast(NetworkIdManager::getObjectById (targetContainerId)); + + if (targetContainer == NULL) + { + WARNING (true, ("Player %s attempted to empty slot into non-existant container [%s].", myIdString, targetContainerId.getValueString ().c_str ())); + return Crafting::CE_badTargetContainer; + } + } + //-- otherwise use the container that the ingredient came from in the first place + else + { + //@todo: this needs to find the target container from which the slot was originally populated + targetContainer = inventory; + } + + // check the manufacturing schematic + ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); + if (manfSchematic == NULL) + { + WARNING(true, ("Player %s trying to empty slot with no manufacturing schematic!", myIdString)); + return Crafting::CE_noManfSchematic; + } + + if (manfSchematic->mustDestroyIngredients() && + getCraftingStage() != Crafting::CS_assembly) + { + WARNING(true, ("Player %s trying to empty slot when not in assembly stage!", myIdString)); + return Crafting::CE_notAssemblyStage; + } + + // verify the slot index + if (slotIndex < 0 || slotIndex >= manfSchematic->getSlotsCount()) + { + WARNING(true, ("Player %s trying to empty invalid slot %d", myIdString, slotIndex)); + return Crafting::CE_invalidSlot; + } + + // get the manufacturing schematic object + Crafting::IngredientSlot manfSlot; + if (!manfSchematic->getSlot(slotIndex, manfSlot, true)) + { + return Crafting::CE_invalidSlot; + } + Crafting::IngredientType ingredientType = manfSlot.ingredientType; + if (ingredientType == Crafting::IT_none || manfSlot.ingredients.empty()) + { + DEBUG_WARNING(true, ("Player %s trying to empty already empty slot %d", myIdString, slotIndex)); + return Crafting::CE_emptySlot; + } + + // get the draft schematic slot + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + if (!m_draftSchematic->getSlot(draftSlot, manfSlot.draftSlotIndex)) + { + return Crafting::CE_invalidSlot; + } + + if (ingredientType == Crafting::IT_item || ingredientType == Crafting::IT_template || + ingredientType == Crafting::IT_templateGeneric || ingredientType == Crafting::IT_schematic || + ingredientType == Crafting::IT_schematicGeneric) + { + // ingredient is a component + Crafting::Ingredients::const_iterator iter; + for (iter = manfSlot.ingredients.begin(); iter != manfSlot.ingredients.end(); + ++iter) + { + const Crafting::ComponentIngredient * const componentInfo = dynamic_cast((*iter).get()); + NOT_NULL(componentInfo); + TangibleObject * const component = manfSchematic->getComponent(*componentInfo); + if (component != NULL) + { + // move the component from the schematic to the player + if (!manfSchematic->removeIngredient(*component, *targetContainer)) + { + Unicode::String oob; + { + ProsePackage pp; + ProsePackageManagerServer::createSimpleProsePackage (*component, COMPONENT_LOST_MSG, pp); + OutOfBandPackager::pack(pp, -1, oob); + } + Chat::sendSystemMessage(*owner, Unicode::emptyString, oob); + } + // if this component is bio-linked, clear our link data + NetworkId bioLinkId(component->getBioLink()); + if (bioLinkId != NetworkId::cms_invalid && bioLinkId == m_craftingComponentBioLink.get()) + { + m_craftingComponentBioLink = NetworkId::cms_invalid; + } + } + } + } + else + { + // ingredient is a resource + VolumeContainer * const targetVolumeContainer = ContainerInterface::getVolumeContainer(*targetContainer); + if (targetVolumeContainer == NULL) + { + DEBUG_WARNING(true, ("PlayerObject::emptySlot: targetContainer %s does not have a volume container", + targetContainer->getNetworkId().getValueString().c_str())); + return Crafting::CE_badTargetContainer; + } + Crafting::Ingredients::const_iterator iter; + for (iter = manfSlot.ingredients.begin(); iter != manfSlot.ingredients.end(); + ++iter) + { + Crafting::SimpleIngredient * resource = const_cast((*iter).get()); + const NetworkId resourceId(resource->ingredient); + if (resourceId != NetworkId::cms_invalid) + { + // find a resource crate in the targetContainer containing the resourceId + ContainerIterator iter2; + for (iter2 = targetVolumeContainer->begin(); iter2 != targetVolumeContainer->end(); + ++iter2) + { + if (*iter2 != NetworkId::cms_invalid) + { + ResourceContainerObject * crate = dynamic_cast< + ResourceContainerObject *>(NetworkIdManager::getObjectById((*iter2))); + if (crate != NULL && crate->getResourceTypeId() == resourceId) + { + int emptySpace = crate->getMaxQuantity() - crate->getQuantity(); + if (emptySpace > 0) + { + if (emptySpace >= resource->count) + { + // we can put all of the resource in the crate + IGNORE_RETURN(manfSchematic->removeIngredient( + resourceId, resource->count, *crate)); + break; + } + else + { + // fill up the crate an keep looking + IGNORE_RETURN(manfSchematic->removeIngredient( + resourceId, emptySpace, *crate)); + resource->count -= emptySpace; + } + } + } + } + } + if (iter2 == targetVolumeContainer->end()) + { + // create a new crate(s) in the target container + std::string crateTemplateName; + ResourceTypeObject const * const resourceType = ServerUniverse::getInstance().getResourceTypeById(resourceId); + resourceType->getCrateTemplate(crateTemplateName); + while (resource->count > 0) + { + ServerObject * crateObject = ServerWorld::createNewObject( + crateTemplateName, *targetContainer, true); + if (crateObject == NULL) + { + // @todo: inform the player + DEBUG_WARNING(true, ("PlayerObject::emptySlot tried to " + "create a new resource crate %s in container %s but " + "failed!", crateTemplateName.c_str(), + targetContainerId.getValueString().c_str())); + return Crafting::CE_cantCreateResourceCrate; + } + ResourceContainerObject * crate = safe_cast< + ResourceContainerObject *>(crateObject); + if (crate->getMaxQuantity() >= resource->count) + { + IGNORE_RETURN(manfSchematic->removeIngredient(resourceId, + resource->count, *crate)); + resource->count = 0; + } + else + { + IGNORE_RETURN(manfSchematic->removeIngredient(resourceId, + crate->getMaxQuantity(), *crate)); + resource->count -= crate->getMaxQuantity(); + } + } + } + } + } + } + + // empty the slot + manfSchematic->clearSlot(draftSlot.name); + + manfSchematic->computeComplexity(); + manfSchematic->signalClientChange(); + + return Crafting::CE_success; +} // PlayerObject::emptySlot + +//---------------------------------------------------------------------- + +/** + * Goes from the current stage in a crafting session to the next one. + * + * @return error code + */ +int PlayerObject::goToNextCraftingStage () +{ + int result = Crafting::CR_failure; + + switch (m_craftingStage.get()) + { + case Crafting::CS_assembly: + result = startCraftingExperiment(); + break; + case Crafting::CS_experiment: + m_craftingStage = static_cast(Crafting::CS_customize); + result = Crafting::CR_success; + break; + case Crafting::CS_customize: + m_craftingStage = static_cast(Crafting::CS_finish); + result = Crafting::CR_success; + break; + case Crafting::CS_none: + case Crafting::CS_selectDraftSchematic: + case Crafting::CS_finish: + default: + break; + } + return result; +} // PlayerObject::goToNextCraftingStage + +//---------------------------------------------------------------------- + +/** + * Moves a crafting session to the experimentation phase. This only occurs if + * all non-optional slots of the draft schematic have been filled. The ingredients + * used in the schematic will be destroyed unless the draft schematic is flagged + * as non-destroying. + * + * @return returns the success state of the assembly on success, -error code on fail + */ +int PlayerObject::startCraftingExperiment () +{ + int i; + + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return -Crafting::CE_noOwner; + + std::string myId = getNetworkId().getValueString(); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + if (m_draftSchematic.getPointer() == NULL) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with invalid schematic.", myIdString)); + return -Crafting::CE_noDraftSchematic; + } + if (getCraftingTool() == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with invalid crafting tool.", myIdString)); + return -Crafting::CE_noCraftingTool; + } + + if (m_draftSchematic->getGameObjectType() == SharedObjectTemplate::GOT_data_draft_schematic_read_only) + { + return -Crafting::CE_readOnlyDraftSchematic; + } + + TangibleObject * tool = safe_cast(getCraftingTool().getObject()); + NOT_NULL(tool); + + if (!tool) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with null crafting tool [%s].", myIdString, getCraftingTool().getValueString().c_str())); + return -Crafting::CE_noCraftingTool; + } + + // check the manufacturing schematic + ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); + if (manfSchematic == NULL) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with invalid manufacture schematic.", myIdString)); + return -Crafting::CE_noManfSchematic; + } + + // make sure all the manufacturing schematic slots are filled + Crafting::IngredientSlot slot; + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + int count = manfSchematic->getSlotsCount(); + for (i = 0; i < count; ++i) + { + if (!manfSchematic->getSlot(i, slot, false)) + { + return -Crafting::CE_invalidSlot; + } + + // get the draft schematic slot + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + if (!m_draftSchematic->getSlot(draftSlot, slot.draftSlotIndex)) + return -Crafting::CE_invalidSlot; + + Crafting::IngredientType type = slot.ingredientType; + if (type == Crafting::IT_none) + { + if (!draftSlot.optional) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with empty slot #%d.", myIdString, i)); + return -Crafting::CE_emptySlotAssembly; + } + } + else + { + int currentIngredientCount = 0; + for (Crafting::Ingredients::const_iterator iter = + slot.ingredients.begin(); iter != slot.ingredients.end(); ++iter) + { + currentIngredientCount += (*iter)->count; + } + if (currentIngredientCount != draftSlot.options[static_cast(slot.draftSlotOption)].ingredients[0].count) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation with partially full slot #%d.", myIdString, i)); + return -Crafting::CE_partialSlotAssembly; + } + } + } + + // remove unused optional slots from the schematic + for (i = 0; i < count;) + { + if (!manfSchematic->getSlot(i, slot, false)) + { + continue; + } + + // get the draft schematic slot + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + IGNORE_RETURN(m_draftSchematic->getSlot(draftSlot, slot.draftSlotIndex)); + + if (slot.ingredientType == Crafting::IT_none && draftSlot.optional) + { + manfSchematic->removeSlot(slot.name); + --count; + } + else + ++i; + } + + ServerObject * prototype = tool->getCraftingPrototype(); + if (prototype == NULL) + { + DEBUG_WARNING(true, ("PlayerObject::startCraftingExperiment crafting " + "tool %s has no prototype object!", + tool->getNetworkId().getValueString().c_str())); + return -Crafting::CE_noPrototype; + } + + // bio-link the prototype + if (m_craftingComponentBioLink.get() != NetworkId::cms_invalid) + safe_cast(prototype)->setBioLink(m_craftingComponentBioLink.get()); + else + safe_cast(prototype)->clearBioLink(); + + // if the tool we are using has the special crit success objvar, store that + // info on the schematic + int forceCritSuccess = 0; + if (tool->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_ASSEMBLY, forceCritSuccess)) + { + if (forceCritSuccess > 0) + manfSchematic->setObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS, forceCritSuccess); + } + + // call the trigger OnManufacturingSchematicCreation + int successState = static_cast(Crafting::CR_internalFailure); + m_experimentPoints = 0; + ScriptParams params; + params.addParam(owner->getNetworkId()); + params.addParam(prototype->getNetworkId()); + params.addParam(*manfSchematic); + params.addParam(successState); + params.addParam(m_experimentPoints.get()); + IGNORE_RETURN(manfSchematic->getScriptObject()->trigAllScripts( + Scripting::TRIG_MANUFACTURING_SCHEMATIC_CREATION, params)); + successState = params.getIntParam(3); + m_experimentPoints = params.getIntParam(4); + + if (successState == static_cast(Crafting::CR_internalFailure)) + { + // either the script crashed or we didn't even make it to the script + WARNING(true, ("PlayerObject::startCraftingExperiment failed calling OnManufacturingSchematicCreation on schematic %s (%s). Prepare for no owner for player!", + manfSchematic->getNetworkId().getValueString().c_str(), + m_draftSchematic->getObjectTemplateName())); + return successState; + } + + if (forceCritSuccess > 0) + { + // if the forced crit success count has changed, update the tool + int newForceCritSuccess = 0; + if (manfSchematic->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_SUCCESS, newForceCritSuccess)) + { + if (newForceCritSuccess != forceCritSuccess) + { + if (newForceCritSuccess > 0) + tool->setObjVarItem(OBJVAR_FORCE_CRITICAL_ASSEMBLY, newForceCritSuccess); + else + tool->removeObjVarItem(OBJVAR_FORCE_CRITICAL_ASSEMBLY); + } + } + manfSchematic->removeObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS); + } + + // important: we need to set the crafting stage here so restartCrafting + // will destroy the ingredients if we crit failed + m_craftingStage = static_cast(Crafting::CS_experiment); + + if (successState == static_cast(Crafting::CR_criticalFailure)) + { + // destroy the ingredients, restart the session at the assembly stage + IGNORE_RETURN(restartCrafting()); + m_craftingStage = static_cast(Crafting::CS_assembly); + } + else if (successState != static_cast(Crafting::CR_internalFailure) && + (getCraftingLevel() <= 1 || ((m_draftSchematic->getItemsPerContainer() == 0 || + m_craftingComponentBioLink.get() != NetworkId::cms_invalid) && + m_draftSchematic->getExperimentalAttributesCount() == 0))) + { + // if we are not near a station, we cannot experiment + m_craftingStage = static_cast(Crafting::CS_customize); + } + // if we crit failed but don't want to destroy the object, change the success + // back to crit fail to the ui will show the right thing + if (successState == static_cast(Crafting::CR_criticalFailureNoDestroy)) + { + successState = static_cast(Crafting::CR_criticalFailure); + m_craftingStage = static_cast(Crafting::CS_assembly); + } + + return successState; +} // PlayerObject::startCraftingExperiment + +//---------------------------------------------------------------------- + +/** + * Tries to experiment on a schematic attribute. + * + * @param experiments list of attributes and points assigned to them + * @param totalPoints total experimentation points used + * + * @return error code + */ +Crafting::CraftingResult PlayerObject::experiment(const std::vector & experiments, int totalPoints, int corelevel) +{ + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return Crafting::CR_internalFailure; + + std::string myId = getNetworkId().getValueString(); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // verify we are experimenting + if (m_craftingStage.get() != static_cast(Crafting::CS_experiment)) + { + DEBUG_WARNING(true, ("Player %s tried to experiment when not in " + "experimentation phase", myIdString)); + return Crafting::CR_internalFailure; + } + + // verify the points allocated + if (totalPoints < 1 || totalPoints > m_experimentPoints.get()) + { + DEBUG_WARNING(true, ("Player %s sent invalid number of experiment points " + "= %d (%d)", myIdString, totalPoints, m_experimentPoints.get() )); + return Crafting::CR_internalFailure; + } + + // verify the tool + if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation " + "with invalid schematic or crafting tool.", myIdString)); + return Crafting::CR_internalFailure; + } + TangibleObject * tool = safe_cast(getCraftingTool().getObject()); + NOT_NULL(tool); + if (!tool) + return Crafting::CR_internalFailure; + + // check the manufacturing schematic + ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); + if (manfSchematic == NULL) + { + DEBUG_WARNING(true, ("Player %s tried to experiment with invalid " + "manufacture schematic.", myIdString)); + return Crafting::CR_internalFailure; + } + const std::vector & attribNames = manfSchematic->getExperimentAttributeNames(); + + // check the test prototype + ServerObject * prototype = tool->getCraftingPrototype(); + if (prototype == NULL) + { + DEBUG_WARNING(true, ("Player %s tried to experiment with invalid test " + "prototype.", myIdString)); + return Crafting::CR_internalFailure; + } + + std::vector scriptAttributes; + std::vector scriptPoints; + + std::vector::const_iterator iter; + for (iter = experiments.begin(); iter != experiments.end(); ++iter) + { + int attributeIndex = (*iter).attributeIndex; + int points = (*iter).experimentPoints; + + // verify points + if (points <= 0) + { + DEBUG_WARNING(true, ("Player %s sent invalid experiment point count %d", + myIdString, points)); + return Crafting::CR_internalFailure; + } + + // verify attribute index + if (attributeIndex < 0 || attributeIndex >= static_cast(attribNames.size())) + { + DEBUG_WARNING(true, ("Player %s sent invalid attribute index %d", + myIdString, attributeIndex)); + return Crafting::CR_internalFailure; + } + + // set the experiment data for the index + scriptAttributes.push_back(&attribNames[static_cast(attributeIndex)]); + scriptPoints.push_back(points); + } + + m_experimentPoints = m_experimentPoints.get() - totalPoints; + + // if the tool we are using has the special crit success objvar, store that + // info on the schematic + int forceCritSuccess = 0; + if (tool->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_EXPERIMENT, forceCritSuccess)) + { + if (forceCritSuccess > 0) + manfSchematic->setObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS, forceCritSuccess); + } + + Crafting::CraftingResult experimentResult = Crafting::CR_failure; + ScriptParams params; + params.addParam(owner->getNetworkId()); + params.addParam(prototype->getNetworkId()); + params.addParam(scriptAttributes); + params.addParam(scriptPoints); + params.addParam(totalPoints); + params.addParam(static_cast(experimentResult)); + params.addParam(corelevel); + IGNORE_RETURN(manfSchematic->getScriptObject()->trigAllScripts(Scripting::TRIG_CRAFTING_EXPERIMENT, params)); + experimentResult = static_cast(params.getIntParam(5)); + + if (forceCritSuccess > 0) + { + // if the forced crit success count has changed, update the tool + int newForceCritSuccess = 0; + if (manfSchematic->getObjVars().getItem(OBJVAR_FORCE_CRITICAL_SUCCESS, newForceCritSuccess)) + { + if (newForceCritSuccess != forceCritSuccess) + { + if (newForceCritSuccess > 0) + tool->setObjVarItem(OBJVAR_FORCE_CRITICAL_EXPERIMENT, newForceCritSuccess); + else + tool->removeObjVarItem(OBJVAR_FORCE_CRITICAL_EXPERIMENT); + } + } + manfSchematic->removeObjVarItem(OBJVAR_FORCE_CRITICAL_SUCCESS); + } + + return experimentResult; +} // PlayerObject::experiment + +//---------------------------------------------------------------------- + +/** + * Sets a customization property value for the current manufacturing schematic. + * + * @param property index of the customization property + * @param value value the property + * + * @return true if the property was set, false if not + */ +bool PlayerObject::customize(int property, int value) const +{ + std::string myId = getNetworkId().getValueString(); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + if (m_craftingStage.get() != static_cast(Crafting::CS_customize)) + { + DEBUG_WARNING(true, ("Player %s tried to customize when not in " + "customization phase", myIdString)); + return false; + } + + if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Player %s tried to customize with invalid " + "schematic or crafting tool.", myIdString)); + return false; + } + + TangibleObject * tool = safe_cast(getCraftingTool().getObject()); + NOT_NULL(tool); + if (!tool) + return false; + ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); + NOT_NULL(manfSchematic); + ServerObject * prototype = tool->getCraftingPrototype(); + NOT_NULL(prototype); + + return manfSchematic->setCustomization(property, value, *prototype); +} // PlayerObject::customize + +//---------------------------------------------------------------------- + +/** + * Sets the customization data for a crafter's current manufacturing schematic. + * + * @param name the name of the object being crafted + * @param appearanceIndex index of the appearance of the object + * @param customizations customization information + * @param itemCount if making a manf schematic, the number of items the + * schematic can make + * + * @return error code + */ +int PlayerObject::setCustomizationData(const Unicode::String & name, + int appearanceIndex, const std::vector & customizations, + int itemCount) const +{ + // Strip any color codes from the text + + TextIterator textIterator(name); + Unicode::String strippedText(textIterator.getPrintableText()); + + std::string myId = getNetworkId().getValueString(); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + if (m_craftingStage.get() != static_cast(Crafting::CS_customize)) + { + DEBUG_WARNING(true, ("Player %s tried to customize when not in " + "customization phase", myIdString)); + return Crafting::CE_notCustomizeStage; + } + + if (m_draftSchematic.getPointer() == NULL) + { + DEBUG_WARNING(true, ("Player %s tried to customize with invalid schematic.", myIdString)); + return Crafting::CE_noDraftSchematic; + } + if (getCraftingTool() == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Player %s tried to customize with invalid crafting tool.", myIdString)); + return Crafting::CE_noCraftingTool; + } + + // make sure the object name is ok + if (!strippedText.empty() && (strippedText.size() >= 127 || !TextManager::isAppropriateText(strippedText))) + { + return Crafting::CE_invalidCraftedName; + } + + TangibleObject * tool = safe_cast(getCraftingTool().getObject()); + NOT_NULL(tool); + if (!tool) + { + LOG("Crafting", ("We should have FATALd in debug, but we didn't...no tool for player %s tool %s", myIdString, getCraftingTool().getValueString().c_str())); + return Crafting::CE_noCraftingTool; + } + + ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); + NOT_NULL(manfSchematic); + if (!manfSchematic) + { + LOG("Crafting", ("We should have FATALd in debug, but we didn't...no manfschem for player %s", myIdString)); + return Crafting::CE_noDraftSchematic; + } + TangibleObject * prototype = safe_cast(tool->getCraftingPrototype()); + NOT_NULL(prototype); + + if (!prototype) + { + LOG("Crafting", ("We should have FATALd in debug, but we didn't...no prototype for player %s", myIdString)); + return Crafting::CE_noCraftingTool; + } + + if (!strippedText.empty()) + { + prototype->setObjectName(strippedText); + manfSchematic->setObjectName(strippedText); + } + + manfSchematic->setCustomAppearance(appearanceIndex); + manfSchematic->setCount(std::min (1000, itemCount)); + prototype->setCustomAppearance(manfSchematic->getCustomAppearance()); + + std::vector::const_iterator iter; + for (iter = customizations.begin(); iter != customizations.end(); ++iter) + { + IGNORE_RETURN(manfSchematic->setCustomization((*iter).property, (*iter).value, *prototype)); + } + return Crafting::CE_success; +} // PlayerObject::setCustomizationData + +//---------------------------------------------------------------------- + +/** + * Creates a prototype object from the current manufacturing schematic. + * + * @param keepPrototype flag that this is a real prototype; if this is false + * we don't persist the prototype or give it to the player. + * + * @return true on success, false on fail + */ +bool PlayerObject::createPrototype(bool keepPrototype) +{ + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return false; + + std::string myId = getNetworkId().getValueString(); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // @todo: need to filter the name + + // verify we are in the final crafting phase + if (m_craftingStage.get() != static_cast(Crafting::CS_finish)) + { + DEBUG_WARNING(true, ("Player %s tried to create prototype when not in " + "final phase", myIdString)); + return false; + } + + if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Player %s tried to create prototype with invalid " + "schematic or crafting tool.", myIdString)); + return false; + } + + TangibleObject * tool = safe_cast(getCraftingTool().getObject()); + if (!tool) + { + WARNING_STRICT_FATAL(true, ("Could not find tool during create prototype phase.")); + return false; + } + TangibleObject * prototype = safe_cast(tool->getCraftingPrototype()); + if (!prototype) + { + WARNING_STRICT_FATAL(true, ("Could not find prototype during create prototype phase.")); + return false; + } + + ManufactureSchematicObject * const manfSchematic = tool->getCraftingManufactureSchematic(); + if (manfSchematic == NULL) + { + WARNING_STRICT_FATAL(true, ("No manf schematic in crafting tool %s", + tool->getNetworkId().getValueString().c_str())); + return false; + } + + // double-check the schematic data + Crafting::IngredientSlot sourceSlot; + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + int numSlots = manfSchematic->getSlotsCount(); + for (int i = 0; i < numSlots; ++i) + { + if (!manfSchematic->getSlot(i, sourceSlot, true)) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " + "%s has invalid manf schematic: cannot get slot info for slot %d", + owner->getNetworkId().getValueString().c_str(), i)); + return false; + } + if (!m_draftSchematic->getSlot(draftSlot, sourceSlot.name)) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " + "%s has invalid manf schematic: cannot get draft info for slot %s", + owner->getNetworkId().getValueString().c_str(), + sourceSlot.name.getCanonicalRepresentation().c_str())); + return false; + } + if (sourceSlot.ingredientType == Crafting::IT_invalid || + sourceSlot.ingredientType == Crafting::IT_none) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " + "%s has invalid manf schematic: slot %d has invalid ingredient " + "type %d", owner->getNetworkId().getValueString().c_str(), i, + static_cast(sourceSlot.ingredientType))); + return false; + } + if (sourceSlot.draftSlotOption < 0 || + sourceSlot.draftSlotOption >= static_cast(draftSlot.options.size())) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " + "%s has invalid manf schematic: slot %d has invalid slot option %d", + owner->getNetworkId().getValueString().c_str(), i, + sourceSlot.draftSlotOption)); + return false; + } + if (sourceSlot.draftSlotIndex < 0) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createPrototype player " + "%s has invalid manf schematic: slot %d has invalid slot index %d", + owner->getNetworkId().getValueString().c_str(), i, + sourceSlot.draftSlotIndex)); + return false; + } + } + + // call the trigger OnManufactureObject on the manf schematic to allow the + // script to initialize the prototype + ScriptParams params; + params.addParam(owner->getNetworkId()); + params.addParam(prototype->getNetworkId()); + params.addParam(*manfSchematic); + params.addParam(true); + params.addParam(keepPrototype); + if (manfSchematic->getScriptObject()->trigAllScripts( + Scripting::TRIG_MANUFACTURE_OBJECT, params) == SCRIPT_OVERRIDE) + { + return false; + } + + if (!tool->addObjectToOutputSlot(*prototype, owner)) + return false; + + if (!manfSchematic->setObjectComponents(prototype, false)) + { + return false; + } + + // tell the client to delete the prototype - we will recreate it when it is + // finished being "built"; this is so that the client can be updated with + // the prototype's appearance, which may change during the crafting process + ObserveTracker::onCraftingPrototypeCreated(*owner, *prototype); + + if (keepPrototype) + { + // save the prototype to the database + prototype->persist(); + + ScriptParams craftparams; + craftparams.addParam(prototype->getNetworkId()); + craftparams.addParam(*manfSchematic); + + GameScriptObject * scriptObject = owner->getScriptObject(); + if(scriptObject) + { + scriptObject->trigAllScripts(Scripting::TRIG_CRAFTED_PROTOTYPE, craftparams); + } + } + else + { + prototype->setObjVarItem(OBJVAR_CRAFTING_FAKE_PROTOTYPE, 1); + } + + // remove the manufacturing schematic + tool->clearCraftingManufactureSchematic(); + m_experimentPoints = -1; + m_craftingStage = static_cast(Crafting::CS_none); + + // lock the tool for the time needed to create the prototype + float prototypeTime = m_draftSchematic->getPrototypeTime() * prototype->getComplexity(); + if (prototypeTime < 1.0f) + prototypeTime = 1.0f; + + // send a message to ourself that will unlock the prototype + params.clear(); + params.addParam(owner->getNetworkId(), "crafter"); + params.addParam(prototype->getNetworkId(), "prototype"); + ScriptDictionaryPtr dictionary; + getScriptObject()->makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + + if (owner->getObjVars().hasItem("crafting_qa")) + { + Client * client = owner->getClient(); + + if (client != NULL && client->isGod()) + { + Chat::sendSystemMessage(*owner, Unicode::narrowToWide("Crafting time changed due to god mode and crafting_qa objvar."), Unicode::emptyString); + prototypeTime = 1; + } + } + +// MessageToQueue::getInstance().sendMessageToJava(tool->getNetworkId(), "prototypeDone", dictionary->getSerializedData(), prototypeTime, true); + MessageToQueue::getInstance().sendMessageToJava(tool->getNetworkId(), "prototypeDone", dictionary->getSerializedData(), static_cast(prototypeTime), false); + + tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_TIME, prototypeTime); + tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_START_TIME, static_cast(ServerClock::getInstance().getGameTimeSeconds())); + tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_OBJECT, prototype->getNetworkId()); + tool->setObjVarItem(OBJVAR_CRAFTING_PROTOTYPE_CRAFTER, owner->getNetworkId()); + + // message the object to update it's counter for the amount of time left + // before the prototype is done +// MessageToQueue::getInstance().sendMessageToC(tool->getNetworkId(), "C++updateCounter", "", 1.0f, true); + MessageToQueue::getInstance().sendMessageToC(tool->getNetworkId(), "C++updateCounter", "", 1, false); + } + else + { +// DEBUG_WARNING(true, ("Could not make script dictionary for prototype delay")); + WARNING(true, ("PlayerObject::createPrototype for player %s could not " + "make script dictionary for prototype delay", + owner->getNetworkId().getValueString().c_str())); + } + + LOG("CustomerService", ("Crafting:%s has crafted a prototype item %s", +// PlayerObject::getAccountDescription(owner->getNetworkId()).c_str(), ServerObject::getLogDescription(prototype).c_str())); + PlayerObject::getAccountDescription(owner->getNetworkId()).c_str(), + ServerObject::getLogDescription(prototype).c_str())); + + return true; +} // PlayerObject::createPrototype + +//---------------------------------------------------------------------- + +/** + * Moves the manufacturing schematic from it's temporary container to the output + * hopper of the crafting tool. + * + * @return true on success, false on fail + */ +bool PlayerObject::createManufacturingSchematic() +{ + static SlotId datapadSlotId = SlotIdManager::findSlotId(DATAPAD_SLOT_NAME); + + // if we are not near a station, we cannot make a manf schematic + if (getCraftingLevel() <= 1) + return false; + + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return false; + + // @todo: need to filter the name + + // verify we are in the final crafting phase + if (m_craftingStage.get() != static_cast(Crafting::CS_finish)) + { + WARNING(true, ("Player %s tried to create manf schematic when not in final phase", getNetworkId().getValueString().c_str ())); + return false; + } + + if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) + { + WARNING(true, ("Player %s tried to create manf schematic with invalid schematic or crafting tool.", getNetworkId().getValueString().c_str ())); + return false; + } + if (m_draftSchematic->getItemsPerContainer() == 0) + { + WARNING(true, ("Player %s tried to create manf schematic with schematic " + "%s that disallows manufacturing.", getAccountDescription().c_str(), + m_draftSchematic->getObjectTemplateName())); + return false; + } + + TangibleObject * const tool = safe_cast(getCraftingTool().getObject()); + if (tool == NULL) + { + WARNING_STRICT_FATAL(true, ("Could not find crafting tool during create manf schematic phase.")); + return false; + } + ManufactureSchematicObject * const manfSchematic = tool->removeCraftingManufactureSchematic(); + if (manfSchematic == NULL) + { + WARNING_STRICT_FATAL(true, ("Could not find manf schematic during create manf schematic phase.")); + return false; + } + TangibleObject * const prototype = safe_cast(tool->getCraftingPrototype()); + if (prototype == NULL) + { + WARNING_STRICT_FATAL(true, ("Could not find prototype during create manf schematic phase.")); + return false; + } + + // no manufacturing a bio-linked item + if (m_craftingComponentBioLink.get() != NetworkId::cms_invalid) + { + WARNING(true, ("Player %s tried to create manf schematic while using a " + "bio-linked component %s.", getAccountDescription().c_str(), + m_craftingComponentBioLink.get().getValueString().c_str())); + return false; + } + + // double-check the schematic data + Crafting::IngredientSlot sourceSlot; + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + int numSlots = manfSchematic->getSlotsCount(); + for (int i = 0; i < numSlots; ++i) + { + if (!manfSchematic->getSlot(i, sourceSlot, true)) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " + "%s has invalid manf schematic: cannot get slot info for slot %d", + getAccountDescription().c_str(), i)); + return false; + } + if (!m_draftSchematic->getSlot(draftSlot, sourceSlot.name)) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " + "%s has invalid manf schematic: cannot get draft info for slot %s", + getAccountDescription().c_str(), + sourceSlot.name.getCanonicalRepresentation().c_str())); + return false; + } + if (sourceSlot.ingredientType == Crafting::IT_invalid || + sourceSlot.ingredientType == Crafting::IT_none) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " + "%s has invalid manf schematic: slot %d has invalid ingredient " + "type %d", getAccountDescription().c_str(), i, + static_cast(sourceSlot.ingredientType))); + return false; + } + if (sourceSlot.draftSlotOption < 0 || + sourceSlot.draftSlotOption >= static_cast(draftSlot.options.size())) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " + "%s has invalid manf schematic: slot %d has invalid slot option %d", + getAccountDescription().c_str(), i, + sourceSlot.draftSlotOption)); + return false; + } + if (sourceSlot.draftSlotIndex < 0) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::createManufacturingSchematic player " + "%s has invalid manf schematic: slot %d has invalid slot index %d", + getAccountDescription().c_str(), i, + sourceSlot.draftSlotIndex)); + return false; + } + } + + // call the trigger OnFinalizeSchematic on the manf schematic to allow the + // script to initialize it + ScriptParams params; + params.addParam(owner->getNetworkId()); + params.addParam(prototype->getNetworkId()); + params.addParam(*manfSchematic); + if (manfSchematic->getScriptObject()->trigAllScripts(Scripting::TRIG_FINALIZE_SCHEMATIC, params) == SCRIPT_OVERRIDE) + { + return false; + } + + manfSchematic->clearSlotSources(); + manfSchematic->storeObjectAttributes (*prototype); + manfSchematic->removeObjVarItem(OBJVAR_IN_CRAFTING_SESSION); + manfSchematic->persist(); + + ServerObject * const datapad = owner->getDatapad (); + if (datapad == NULL) + { + DEBUG_WARNING(true, ("Can't find datapad for player %s", getAccountDescription().c_str())); + return false; + } + + Container::ContainerErrorCode tmp = Container::CEC_Success; + if (!ContainerInterface::transferItemToVolumeContainer(*datapad, *manfSchematic, NULL, tmp)) + { + return false; + } + + tool->clearCraftingPrototype(); + m_experimentPoints = -1; + m_craftingStage = static_cast(Crafting::CS_none); + + LOG("CustomerService", ("Crafting:%s has crafted a manufacturing schematic %s", + getAccountDescription().c_str(), ServerObject::getLogDescription(manfSchematic).c_str())); + + return true; +} // PlayerObject::createManufacturingSchematic + +//---------------------------------------------------------------------- + +/** + * Restarts the crafting session with the same draft schematic as this one. + * + * @return true on success, false on fail + */ +bool PlayerObject::restartCrafting () +{ + CreatureObject * const owner = getCreatureObject(); + if (owner == NULL) + return false; + + std::string myId = getNetworkId().getValueString(); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are crafting + if (m_craftingStage.get() == static_cast(Crafting::CS_none)) + { + DEBUG_WARNING(true, ("Player %s tried to restart crafting when not crafting", + myIdString)); + return false; + } + if (m_craftingStage.get() == static_cast(Crafting::CS_finish)) + { + DEBUG_WARNING(true, ("Player %s tried to restart crafting when crafting over", + myIdString)); + return false; + } + + // verify the tool + if (m_draftSchematic.getPointer() == NULL || getCraftingTool() == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Player %s tried to start crafting experimentation " + "with invalid schematic or crafting tool.", myIdString)); + return false; + } + TangibleObject * tool = safe_cast(getCraftingTool().getObject()); + NOT_NULL(tool); + if (!tool) + return false; + + // reset the manf schematic + ManufactureSchematicObject * manfSchematic = tool->getCraftingManufactureSchematic(); + if (manfSchematic == NULL) + { + DEBUG_WARNING(true, ("Player %s has no manufacturing schematic!", myIdString)); + return false; + } + + // if we are at the assembly stage of crafting, or the draft schematic says + // not to destroy the ingredients, put the ingredients in the schematic back + // in the player's inventory or station hopper + if (!manfSchematic->mustDestroyIngredients() || + m_craftingStage.get() == static_cast(Crafting::CS_assembly)) + { + setAllowEmptySlot(true); + int count = manfSchematic->getSlotsCount(); + // note this loop is odd because when we clear a slot it may + // actually be removed if it was optional + for (int i = 0; i < count;) + { + if (emptySlot(i, NetworkId::cms_invalid)) + { + if (count == manfSchematic->getSlotsCount()) + ++i; + else + count = manfSchematic->getSlotsCount(); + } + else + ++i; + } + setAllowEmptySlot(false); + } + else + { + manfSchematic->destroyAllIngredients(); + } + + // reset the manf schematic data + manfSchematic->reset(); + m_craftingComponentBioLink = NetworkId::cms_invalid; + + m_craftingStage = static_cast(Crafting::CS_assembly); + return true; +} // PlayerObject::restartCrafting + +//---------------------------------------------------------------------- + +/** + * Ends a crafting session. + * + * @param normalExit flag that we are exiting due to normal circumstances + */ +void PlayerObject::stopCrafting (bool normalExit) +{ + CreatureObject * const owner = getCreatureObject(); + + if (getCraftingTool().getObject() != NULL) + { + TangibleObject * tool = dynamic_cast(getCraftingTool().getObject()); + if (tool != NULL) + { + IGNORE_RETURN(tool->stopCraftingSession()); + } + + // tell scripts that the session has ended + ScriptParams params; + if (owner != NULL) + params.addParam(owner->getNetworkId()); + else + params.addParam(getNetworkId()); + if (getCurrentDraftSchematic() != NULL) + params.addParam(getCurrentDraftSchematic()->getTemplateName()); + else + params.addParam(""); + params.addParam(static_cast(m_craftingStage.get())); + params.addParam(normalExit); + IGNORE_RETURN(tool->getScriptObject()->trigAllScripts( + Scripting::TRIG_CRAFTING_DONE, params)); + } + + m_craftingStage = static_cast(Crafting::CS_none); + m_useableDraftSchematics.clear(); + m_craftingTool = CachedNetworkId::cms_cachedInvalid; + m_craftingComponentBioLink = NetworkId::cms_invalid; + + // tell the player crafting has ended + if (owner != NULL && owner->getController() != NULL) + { + (safe_cast(owner->getController()))->appendMessage( + static_cast(CM_craftingSessionEnded), 0.0f, + new MessageQueueGenericValueType(normalExit), + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } +} // PlayerObject::stopCrafting + +// ---------------------------------------------------------------------- + +void PlayerObject::getAttributes(stdvector >::fwd &data) const +{ + IntangibleObject::getAttributes(data); +} + +/** + * Sets the player's friend list + * + * @param friendList - The new player's friend list + */ +void PlayerObject::setFriendList(const StringVector &friendList) +{ + //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - Old Friend List\n")); + //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - %d\n", m_friendList.size())); + //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - New Friend List\n")); + //DEBUG_REPORT_LOG(true, ("PlayerObject::setFriendList() - %d\n", friendList.size())); + + if (isAuthoritative()) + { + // construct lowercase, sorted friend list + size_t const size = friendList.size(); + StringVector friendListLowercaseSorted(size); + for (size_t index = 0; index < size; ++index) + { + friendListLowercaseSorted[index] = Unicode::toLower(friendList[index]); + } + + if (!friendListLowercaseSorted.empty()) + { + std::sort(friendListLowercaseSorted.begin(), friendListLowercaseSorted.end()); + } + + LOG("ChatFriendIgnoreList", ("Friend=%d, %s", friendListLowercaseSorted.size(), getAccountDescription().c_str())); + m_friendList.set(friendListLowercaseSorted); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::requestFriendList() const +{ + CreatureObject const *owner = safe_cast(ContainerInterface::getContainedByObject(*this)); + + if (owner != NULL) + { + ChatAvatarId chatAvatarId(Chat::constructChatAvatarId(*owner)); + + DEBUG_WARNING(chatAvatarId.name.empty(), ("Chat avatar id name is empty")); + + Chat::getFriendsList(chatAvatarId.getFullName()); + } +} + +/** + * Determines whether the specified name is a friend of this player + * + * @param name - The name of the friend + */ +bool PlayerObject::isFriend(const std::string &name) const +{ + std::string firstName; + size_t pos = 0; + IGNORE_RETURN(Unicode::getFirstToken(name, 0, pos, firstName)); + + return std::binary_search(m_friendList.begin(), m_friendList.end(), Unicode::toLower(firstName)); +} + +/** + * Sets the player's list of people to ignore + * + * @param ignoreList - The new player's list of people to ignore + */ +void PlayerObject::setIgnoreList(const StringVector &ignoreList) +{ + //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - Old Ignore List\n")); + //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - %d\n", m_ignoreList.size())); + //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - New Ignore List\n")); + //DEBUG_REPORT_LOG(true, ("PlayerObject::setIgnoreList() - %d\n", ignoreList.size())); + + if (isAuthoritative ()) + { + // construct lowercase, sorted ignore list + size_t const size = ignoreList.size(); + StringVector ignoreListLowercaseSorted(size); + for (size_t index = 0; index < size; ++index) + { + ignoreListLowercaseSorted[index] = Unicode::toLower(ignoreList[index]); + } + + if (!ignoreListLowercaseSorted.empty()) + { + std::sort(ignoreListLowercaseSorted.begin(), ignoreListLowercaseSorted.end()); + } + + LOG("ChatFriendIgnoreList", ("Ignore=%d, %s", ignoreListLowercaseSorted.size(), getAccountDescription().c_str())); + m_ignoreList.set(ignoreListLowercaseSorted); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::requestIgnoreList() const +{ + CreatureObject const *owner = safe_cast(ContainerInterface::getContainedByObject(*this)); + + if (owner != NULL) + { + ChatAvatarId chatAvatarId(Chat::constructChatAvatarId(*owner)); + + DEBUG_WARNING(chatAvatarId.name.empty(), ("Chat avatar id name is empty")); + + Chat::getIgnoreList(chatAvatarId.getFullName()); + } +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::isIgnoring(const std::string &name) const +{ + std::string firstName; + size_t pos = 0; + IGNORE_RETURN(Unicode::getFirstToken(name, 0, pos, firstName)); + + return std::binary_search(m_ignoreList.begin(), m_ignoreList.end(), Unicode::toLower(firstName)); +} + +/** + * Sets a player's personal matchmaking id + * + * @param matchMakingId - The new match making id which describes their personality + */ +void PlayerObject::setMatchMakingPersonalProfileId(MatchMakingId const &id) +{ + if (isAuthoritative ()) + { + //DEBUG_REPORT_LOG(true, ("PlayerObject::setMatchMakingPersonalProfileId() %s %s\n", m_matchMakingPersonalProfileId.get().getDebugIntString().c_str(), id.getDebugIntString().c_str())); + + m_matchMakingPersonalProfileId = id; + } +} + +// ---------------------------------------------------------------------- + +MatchMakingId const &PlayerObject::getMatchMakingPersonalProfileId() const +{ + return m_matchMakingPersonalProfileId.get(); +} + +/** + * Sets a player's character matchmaking id + * + * @param matchMakingId - The new match making id which describes their character + */ +void PlayerObject::setMatchMakingCharacterProfileId(MatchMakingId const &id) +{ + if (isAuthoritative()) + { + m_matchMakingCharacterProfileId = id; + + //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_anonymous) ? "Yes" : "No")); + //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_helper) ? "Yes" : "No")); + //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_rolePlay) ? "Yes" : "No")); + //DEBUG_REPORT_LOG(true, ("MatchMakingCharacterProfileId: %s\n", m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_lookingForGroup) ? "Yes" : "No")); + + CreatureObject const * const owner = getCreatureObject(); + if (owner) + { + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(owner->getNetworkId()); + if (iterFind != connectedCharacterLfgData.end()) + { + bool const anonymous = id.isBitSet(MatchMakingId::B_anonymous); + if (iterFind->second.anonymous != anonymous) + ServerUniverse::setConnectedCharacterAnonymousData(owner->getNetworkId(), anonymous); + + bool const searchableByCtsSourceGalaxy = id.isBitSet(MatchMakingId::B_searchableByCtsSourceGalaxy); + if (iterFind->second.searchableByCtsSourceGalaxy != searchableByCtsSourceGalaxy) + ServerUniverse::setConnectedCharacterSearchableByCtsSourceGalaxyData(owner->getNetworkId(), searchableByCtsSourceGalaxy); + + bool const displayLocationInSearchResults = id.isBitSet(MatchMakingId::B_displayLocationInSearchResults); + if (iterFind->second.displayLocationInSearchResults != displayLocationInSearchResults) + ServerUniverse::setConnectedCharacterDisplayLocationInSearchResultsData(owner->getNetworkId(), displayLocationInSearchResults); + + BitArray characterInterests = iterFind->second.characterInterests; + + if (id.isBitSet(MatchMakingId::B_lookingForGroup)) + LfgDataTable::setBit("lfg", characterInterests); + else + LfgDataTable::clearBit("lfg", characterInterests); + + if (id.isBitSet(MatchMakingId::B_helper)) + LfgDataTable::setBit("helper", characterInterests); + else + LfgDataTable::clearBit("helper", characterInterests); + + if (id.isBitSet(MatchMakingId::B_rolePlay)) + LfgDataTable::setBit("rp", characterInterests); + else + LfgDataTable::clearBit("rp", characterInterests); + + if (id.isBitSet(MatchMakingId::B_lookingForWork)) + LfgDataTable::setBit("lfw", characterInterests); + else + LfgDataTable::clearBit("lfw", characterInterests); + + if (iterFind->second.characterInterests != characterInterests) + ServerUniverse::setConnectedCharacterInterestsData(owner->getNetworkId(), characterInterests); + } + } + } +} + +MatchMakingId const &PlayerObject::getMatchMakingCharacterProfileId() const +{ + return m_matchMakingCharacterProfileId.get(); +} + +/** +* Toggles the player's SearchableByCtsSourceGalaxy status. +*/ +void PlayerObject::toggleSearchableByCtsSourceGalaxy() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_searchableByCtsSourceGalaxy); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +/** +* Toggles the player's DisplayLocationInSearchResults status. +*/ +void PlayerObject::toggleDisplayLocationInSearchResults() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_displayLocationInSearchResults); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +/** + * Toggles the player's anonymous status. + */ +void PlayerObject::toggleAnonymous() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_anonymous); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +/** + * Toggles the player's helper status. + */ +void PlayerObject::toggleHelper() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_helper); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +/** + * Toggles the player's roleplay status. + */ +void PlayerObject::toggleRolePlay() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_rolePlay); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +// ---------------------------------------------------------------------- +bool PlayerObject::isLookingForGroup() const +{ + return m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_lookingForGroup); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setLookingForGroup(bool const lookingForGroup) +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.resetBit(MatchMakingId::B_lookingForGroup); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +/** + * Toggles the player's looking for group status. + */ +void PlayerObject::toggleLookingForGroup() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_lookingForGroup); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +/** + * Returns the player's away from keyboard status. + */ +bool PlayerObject::isAwayFromKeyBoard() const +{ + return m_matchMakingCharacterProfileId.get().isBitSet(MatchMakingId::B_awayFromKeyBoard); +} + +/** + * Toggles the player's away from keyboard status. + */ +void PlayerObject::toggleAwayFromKeyBoard() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_awayFromKeyBoard); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +/** + * Toggles the player's display of their faction rank. + */ +void PlayerObject::toggleDisplayingFactionRank() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_displayingFactionRank); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + + +// ---------------------------------------------------------------------- + +void PlayerObject::setLinkDead(bool const linkDead) +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + if (linkDead) + { + matchMakingId.setBit(MatchMakingId::B_linkDead); + } + else + { + matchMakingId.resetBit(MatchMakingId::B_linkDead); + } + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::getLinkDead() const +{ + MatchMakingId const matchMakingId(m_matchMakingCharacterProfileId.get()); + return matchMakingId.isBitSet(MatchMakingId::B_linkDead); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::adjustLotCount(int adjustment) +{ + CreatureObject * const owner = getCreatureObject(); + if (!owner) + return false; + + if (isAuthoritative()) + { + if (adjustment > 0 && + (m_accountNumLots.get() + adjustment) > (ConfigServerGame::getMaxLotsPerAccount() + m_accountMaxLotsAdjustment.get())) + { + DEBUG_REPORT_LOG(true,("Account %lu is not allowed to use any more lots. (Already has %i, limit is %i, tried to use %i more.)\n", + m_stationId.get(), m_accountNumLots.get(), ConfigServerGame::getMaxLotsPerAccount() + m_accountMaxLotsAdjustment.get(), adjustment)); + return false; + } + else + { + m_accountNumLots = m_accountNumLots.get() + adjustment; + // make sure the number of used lot doesn't go below 0, because + // it means we would be giving the player extra lots + if (m_accountNumLots.get() < 0) + m_accountNumLots = 0; + + // if no longer over the lot limit, remove lot over limit restriction + if (m_accountNumLots.get() <= owner->getMaxNumberOfLots()) + { + m_accountNumLotsOverLimitSpam = 0; + owner->removeObjVarItem("lotOverlimit"); + } + + return true; + } + } + else + { + owner->sendControllerMessageToAuthServer(CM_adjustLotCount, new MessageQueueGenericValueType(adjustment)); + return true; + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setTitle(std::string const &title) +{ + if (isAuthoritative()) + { + // Make sure the skill title requested is valid + if (title == "city_gcw_region_defender") + { + std::pair > const & cityGcwDefenderRegionInfo = getCityGcwDefenderRegionInfo(); + if (!cityGcwDefenderRegionInfo.first.empty() && cityGcwDefenderRegionInfo.second.second) + { + if (title != m_skillTitle.get()) + m_skillTitle = title; + } + } + else if (title == "guild_gcw_region_defender") + { + std::pair > const & guildGcwDefenderRegionInfo = getGuildGcwDefenderRegionInfo(); + if (!guildGcwDefenderRegionInfo.first.empty() && guildGcwDefenderRegionInfo.second.second) + { + if (title != m_skillTitle.get()) + m_skillTitle = title; + } + } + else if (title.empty() || (title == "citizenship") || (SkillManager::getInstance().getSkill(title) != NULL) || (CollectionsDataTable::isASlotTitle(title) != NULL) || (CollectionsDataTable::isACollectionTitle(title) != NULL) || (CollectionsDataTable::isAPageTitle(title) != NULL) || (GuildRankDataTable::isARankTitle(title) != NULL) || (CitizenRankDataTable::isARankTitle(title) != NULL)) + { + if (title != m_skillTitle.get()) + m_skillTitle = title; + } + else + { + WARNING(true, ("The player is trying to set a title that does not exist in the SkillManager or the CollectionsDataTable or the GuildRankDataTable or the CitizenRankDataTable: [%s]", title.c_str())); + } + } +} + +// ---------------------------------------------------------------------- + +std::string const &PlayerObject::getTitle() const +{ + return m_skillTitle.get(); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setSpokenLanguage(int const languageId) +{ + if (isAuthoritative() && GameLanguageManager::isLanguageValid(languageId)) + { + m_spokenLanguage = languageId; + } +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getSpokenLanguage() const +{ + return m_spokenLanguage.get(); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::isIgnoring(NetworkId const &target, NetworkId const &source) +{ + std::string const &sourceName = NameManager::getInstance().getPlayerName(source); + if (!sourceName.empty()) + { + Object const * const o = NetworkIdManager::getObjectById(target); + + if (o) + { + ServerObject const * const so = o->asServerObject(); + if (so) + { + CreatureObject const * const co = so->asCreatureObject(); + if (co) + { + PlayerObject const * const targetPlayerObject = PlayerCreatureController::getPlayerObject(co); + if (targetPlayerObject) + return targetPlayerObject->isIgnoring(sourceName); + } + } + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setMaxForcePower(int value) +{ + if (isAuthoritative()) + { + if (value < 0) + value = 0; + m_maxForcePower = value; + if (m_forcePower.get() > value) + m_forcePower = value; + } + else + { + sendControllerMessageToAuthServer(CM_setMaxForcePower, + new MessageQueueGenericValueType(value)); + } +} + +//---------------------------------------------------------------------- + +void PlayerObject::setForcePower(int value) +{ + if (isAuthoritative()) + { + if (value < 0) + value = 0; + else if (value > m_maxForcePower.get()) + value = m_maxForcePower.get(); + m_forcePower = value; + } + else + { + sendControllerMessageToAuthServer(CM_setForcePower, + new MessageQueueGenericValueType(value)); + } +} + +//---------------------------------------------------------------------- + +void PlayerObject::setForcePowerRegenRate(float value) +{ + if ((isJedi() == 0) && (getMaxForcePower() == 0)) + return; + + if (isAuthoritative()) + { + if (value < ConfigServerGame::getMinForcePowerRegenRate()) + value = ConfigServerGame::getMinForcePowerRegenRate(); + + m_forceRegenRate = value; + } + else + { + sendControllerMessageToAuthServer(CM_setForceRegenRate, + new MessageQueueGenericValueType(value)); + } +} + +//---------------------------------------------------------------------- + +void PlayerObject::regenerateForcePower(float time) +{ + int forcePower = getForcePower(); + if (forcePower < getMaxForcePower()) + { + setForcePower(forcePower + getForcePowerRegen(time)); + } +} + +//---------------------------------------------------------------------- + +/** + * Returns the amount of force power regenerated for a given timeslice. + * + * @param time amount of time that has passed + * + * @return the amount of force power regenerated + */ +int PlayerObject::getForcePowerRegen(float time) +{ + // make sure we are force sensitive + if ((isJedi() == 0) && (getMaxForcePower() == 0)) + return 0; + + if (time <= 0) + { + WARNING(true, ("PlayerObject::getForcePowerRegen called for player %s " + "with time %f <= 0", getAccountDescription().c_str(), time)); + return 0; + } + + // double-check the regen rate + float minRate = ConfigServerGame::getMinForcePowerRegenRate(); + if (minRate <= 0) + { + WARNING_STRICT_FATAL(true, ("PlayerObject::getForcePowerRegen: min regen " + "rate = %f", minRate)); + minRate = 0.1f; + } + float rate = getForcePowerRegenRate(); + if (rate < minRate) + { + WARNING(true, ("PlayerObject::getForcePowerRegen called for player %s " + "with regen rate %f < min rate %f", getAccountDescription().c_str(), + rate, minRate)); + setForcePowerRegenRate(minRate); + rate = minRate; + } + + float regenValue = 0; + + // compute the amount of regen power accumulated; if it is over the threshold, + // we regenerate + float newValue = m_forceRegenValue.get() + rate * time; + if (newValue > ConfigServerGame::getRegenThreshold()) + { + regenValue = static_cast(floor(newValue)); + newValue -= regenValue; + + } + m_forceRegenValue = newValue; + + return static_cast(regenValue); +} // PlayerObject::getForcePowerRegen + +//---------------------------------------------------------------------- + +/** + * Grant a Jedi slot to this account. (Calling this function more than + * once will not create multiple Jedi slots.) + * NOTE: Not guaranteed to succeed, because it depends on a connection to + * a LoginServer, which is not guaranteed to be up. Call this function + * again if you don't get addJediToAccountAck() in a reasonable amount of time. + */ +void PlayerObject::addJediToAccount() const +{ + const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (owner) + { + LOG("CustomerService", ("Jedi: Requesting extra character slot for player %s", getAccountDescription().c_str())); + LoginUpgradeAccountMessage const luam(LoginUpgradeAccountMessage::UT_addJedi,m_stationId.get(),owner->getNetworkId(),getNetworkId(),"C++JediAdded","",false); + GameServer::getInstance().sendToCentralServer(luam); + } +} + +// ---------------------------------------------------------------------- + +/** + * Acknowledgement to addJediToAccount(). Until this function is called, + * it is not guaranteed that the account is enabled for Jedi. + */ +void PlayerObject::addJediToAccountAck() const +{ + CreatureObject * owner = const_cast(safe_cast< + const CreatureObject *>(ContainerInterface::getContainedByObject(*this))); + if (owner) + { + LOG("CustomerService", ("Jedi: Got extra character slot ack for player %s", getAccountDescription().c_str())); + owner->addJediToAccountAck(); + } +} + +// ---------------------------------------------------------------------- + +/** + * Flags that this character is spectral in the account database. Not + * guaranteed -- repeat the call if makeSpectralOnAccountAck() is not called. + */ +void PlayerObject::makeSpectralOnAccount() const +{ + const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (owner) + { + LoginUpgradeAccountMessage const luam(LoginUpgradeAccountMessage::UT_setSpectral,m_stationId.get(),owner->getNetworkId(), getNetworkId(),"C++SpectralSet","",false); + GameServer::getInstance().sendToCentralServer(luam); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::makeSpectralOnAccountAck() const +{ + const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (owner) + { + Chat::sendSystemMessage(*owner,Unicode::narrowToWide("Character marked as spectral in the login database."),Unicode::String()); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::handleCMessageTo(const MessageToPayload &message) +{ + if (message.getMethod() == "C++JediAdded") + { + addJediToAccountAck(); + } + else if (message.getMethod() == "C++SpectralSet") + { + makeSpectralOnAccountAck(); + } + else if (message.getMethod() == "C++ClearTheater") + { + clearTheater(); + } + else if (message.getMethod() == "C++TheaterDestroyed") + { + const std::vector & data = message.getPackedDataVector(); + std::string theaterIdString(data.begin(), data.end()); + if (theaterIdString == m_theaterId.get().getValueString()) + m_theaterId = NetworkId::cms_invalid; + } + else if (message.getMethod() == "C++RecalculateGcwRating") + { + m_gcwRatingActualCalcTime = 0; + handleRecalculateGcwRating(); + } + else if (message.getMethod() == "C++updateConnectedCharacterLfgData") + { + CreatureObject * const owner = getCreatureObject(); + if (m_sessionStartPlayTime.get() != 0) + { + if (owner) + { + // check for changes to the player's GCW Region information, and update if necessary; must be + // called first as it updates information that is used later by other stuff in this function + updateGcwRegionInfo(); + + { + LfgCharacterData lfgCharacterData; + owner->getLfgCharacterData(lfgCharacterData); + + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFindLfg = connectedCharacterLfgData.find(owner->getNetworkId()); + if ((iterFindLfg == connectedCharacterLfgData.end()) || (iterFindLfg->second != lfgCharacterData)) + ServerUniverse::setConnectedCharacterLfgData(owner->getNetworkId(), lfgCharacterData); + + // grant GCW factional presence score + if (!lfgCharacterData.locationFactionalPresenceGcwRegion.empty()) + grantGcwFactionalPresenceScore(lfgCharacterData.locationFactionalPresenceGcwRegion, *this, *owner); + } + + { + BiographyManager::requestBiography(owner->getNetworkId(), NULL); + } + + bool needsTitleCheck = false; + + // if the character is a guild member (or just sponsored), make sure the guild member + // profession and level matches the actual profession and level of the character + + // also check to see if the guild member rank has changed, and if so, update the guild member rank information + { + int guildId = owner->getGuildId(); + bool const isGuildMember = (guildId != 0); + + // if character is not a guild member, see if character has been sponsored for guild membership + if (guildId == 0) + { + guildId = GuildInterface::getGuildIdForSponsored(owner->getNetworkId()); + + // no longer a guild member, so make sure guild rank is empty + if (!m_guildRank.get().empty()) + { + setGuildRank(BitArray()); + + // force a title check to make sure the character isn't + // using a guild rank title he is no longer entitled to + needsTitleCheck = true; + } + } + + if (guildId > 0) + { + GuildMemberInfo const * const guildMemberInfo = GuildInterface::getGuildMemberInfo(guildId, owner->getNetworkId()); + if (guildMemberInfo) + { + std::string const & professionSkillTemplate = getSkillTemplate(); + bool const professionSkillTemplateDiffers = (!professionSkillTemplate.empty() && (guildMemberInfo->m_professionSkillTemplate != professionSkillTemplate)); + + int const level = owner->getLevel(); + bool const levelDifers = ((level > 0) && (guildMemberInfo->m_level != level)); + + if (professionSkillTemplateDiffers || levelDifers) + { + GuildInterface::setGuildMemberProfessionInfo(guildId, owner->getNetworkId(), (professionSkillTemplateDiffers ? professionSkillTemplate : guildMemberInfo->m_professionSkillTemplate), (levelDifers ? level : guildMemberInfo->m_level)); + } + + // check to see if guild rank has changed + if (isGuildMember && (m_guildRank.get() != guildMemberInfo->m_rank)) + { + setGuildRank(guildMemberInfo->m_rank); + + // force a title check to make sure the character isn't + // using a guild rank title he is no longer entitled to + needsTitleCheck = true; + } + } + } + } + + // if the character is a citizen, make sure the citizen profession and + // level matches the actual profession and level of the character + + // also check to see if the citizen rank has changed, and if so, update the citizen rank information + { + std::vector const & cityIds = CityInterface::getCitizenOfCityId(owner->getNetworkId()); + CitizenInfo const * const citizenInfo = (!cityIds.empty() ? CityInterface::getCitizenInfo(cityIds.front(), owner->getNetworkId()) : NULL); + if (!citizenInfo) + { + // not a citizen, so make sure the citizen rank is empty + if (!m_citizenRank.get().empty()) + { + setCitizenRank(BitArray()); + + // force a title check to make sure the character isn't + // using a citizen rank title he is no longer entitled to + needsTitleCheck = true; + } + } + else + { + std::string const & professionSkillTemplate = getSkillTemplate(); + bool const professionSkillTemplateDiffers = (!professionSkillTemplate.empty() && (citizenInfo->m_citizenProfessionSkillTemplate != professionSkillTemplate)); + + int const level = owner->getLevel(); + bool const levelDifers = ((level > 0) && (citizenInfo->m_citizenLevel != level)); + + if (professionSkillTemplateDiffers || levelDifers) + { + CityInterface::setCitizenProfessionInfo(cityIds.front(), owner->getNetworkId(), (professionSkillTemplateDiffers ? professionSkillTemplate : citizenInfo->m_citizenProfessionSkillTemplate), (levelDifers ? level : citizenInfo->m_citizenLevel)); + } + + // check to see if citizen rank has changed + if (m_citizenRank.get() != citizenInfo->m_citizenRank) + { + setCitizenRank(citizenInfo->m_citizenRank); + + // force a title check to make sure the character isn't + // using a citizen rank title he is no longer entitled to + needsTitleCheck = true; + } + } + } + + // if necessary, force a title check to make sure the character isn't + // using a guild or citizen rank title he is no longer entitled to + if (needsTitleCheck) + { + MessageToQueue::getInstance().sendMessageToC(owner->getNetworkId(), + "C++CheckCharacterTitle", "", 5, false); + } + + // check for changes to the player's citizenship information, and update if necessary + updateCitizenshipInfo(); + + // check for changes to the player's GCW Region Defender information, and update if necessary + updateGcwDefenderRegionInfo(); + + // check for update to the player's PGC rating information + PgcRatingInfo const * const pgcRatingInfo = CityInterface::getPgcRating(owner->getNetworkId()); + if (pgcRatingInfo) + { + if (m_pgcRatingCount.get() != pgcRatingInfo->m_ratingCount) + { + m_pgcRatingCount.set(pgcRatingInfo->m_ratingCount); + } + + if (m_pgcRatingTotal.get() != pgcRatingInfo->m_ratingTotal) + { + m_pgcRatingTotal.set(pgcRatingInfo->m_ratingTotal); + } + + if (m_pgcLastRatingTime.get() != pgcRatingInfo->m_lastRatingTime) + { + m_pgcLastRatingTime.set(pgcRatingInfo->m_lastRatingTime); + } + } + } + + // check/set the character's proper "character age" title + checkAndSetCharacterAgeTitle(*this, false); + } + + // check to see if the character needs to get (delay) flagged as enabled/disabled for guild war + // + // check to see if the guild member's guild war pvp status has changed, and if so, set the + // delay time to start counting down to when the guild war pvp status will get changed + if (owner) + { + if (owner->getTimeToUpdateGuildWarPvpStatus()) + { + if (ServerClock::getInstance().getGameTimeSeconds() > owner->getTimeToUpdateGuildWarPvpStatus()) + owner->setGuildWarEnabled(GuildInterface::getGuildMemberGuildWarEnabled(owner->getGuildId(), owner->getNetworkId())); + } + else if (owner->getGuildId()) + { + // see if guild war pvp status has changed, and if yes, start countdown timer to change the status + if (GuildInterface::getGuildMemberGuildWarEnabled(owner->getGuildId(), owner->getNetworkId()) != owner->getGuildWarEnabled()) + owner->setTimeToUpdateGuildWarPvpStatus(ServerClock::getInstance().getGameTimeSeconds() + static_cast(ConfigServerGame::getPvpGuildWarExemptionExclusiveDelaySeconds())); + } + else if (owner->getGuildWarEnabled()) + { + // not in a guild, so should be guild war pvp disabled + owner->setGuildWarEnabled(false); + } + } + + // check for over lot limit condition + setAccountNumLotsOverLimitSpam(); + } + else if (message.getMethod() == "C++RequestChatFriendsList") + { + requestFriendList(); + } + else if (message.getMethod() == "C++RequestChatIgnoreList") + { + requestIgnoreList(); + } + else + { + IntangibleObject::handleCMessageTo(message); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::endBaselines() +{ + IntangibleObject::endBaselines(); + + const CreatureObject * owner = safe_cast(ContainerInterface::getContainedByObject(*this)); + + if (owner != NULL) + { + SharedCreatureObjectTemplate::Species const species = owner->getSpecies(); + setSpokenLanguage(GameLanguageManager::getStartingLanguage(species)); + +// if (owner->isAuthoritative() && ServerUniverse::getInstance().getXpManager() != NULL) +// { +// // get any xp we earned while offline +// ServerUniverse::getInstance().getXpManager()->requestXp(*this); +// } + } + + // check for empty force values from the db + if (m_maxForcePower.get() < 0) + m_maxForcePower = 0; + if (m_forcePower.get() < 0) + m_forcePower = 0; + if (m_forceRegenRate.get() < 0) + m_forceRegenRate = 0; + + if (isAuthoritative()) + { + GroupWaypointBuilder::updateGroupWaypoints(*this, true); + + // calculate rank values when loaded for the first time from DB + Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); + m_currentGcwRank = pvpRankInfo.rank; + + if (pvpRankInfo.rank > 0) + { + m_currentGcwRankProgress = static_cast(std::min(static_cast(m_currentGcwRating.get()), pvpRankInfo.maxRating) - pvpRankInfo.minRating) * 100.0f / static_cast(pvpRankInfo.maxRating - pvpRankInfo.minRating + 1); + } + else + { + m_currentGcwRankProgress = 0.0f; + } + + m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; + m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; + + // depersist chat statistics + int temp; + DynamicVariableList const & objVars = getObjVars(); + if (objVars.getItem(OBJVAR_CHAT_SPAM_TIME_END_INTERVAL, temp)) + { + m_chatSpamTimeEndInterval = temp; + + if (objVars.getItem(OBJVAR_CHAT_SPAM_SPATIAL, temp)) + m_chatSpamSpatialNumCharacters = temp; + else + m_chatSpamSpatialNumCharacters = 0; + + if (objVars.getItem(OBJVAR_CHAT_SPAM_NON_SPATIAL, temp)) + m_chatSpamNonSpatialNumCharacters = temp; + else + m_chatSpamNonSpatialNumCharacters = 0; + + m_chatSpamNextTimeToSyncWithChatServer = 0; + } + else + { + m_chatSpamTimeEndInterval = static_cast(::time(NULL)) + (ConfigServerGame::getChatSpamLimiterIntervalMinutes() * 60); + m_chatSpamSpatialNumCharacters = 0; + m_chatSpamNonSpatialNumCharacters = 0; + m_chatSpamNextTimeToSyncWithChatServer = 0; + } + + // depersist privileged title + if (objVars.getItem(OBJVAR_PRIVILEGED_TITLE, temp)) + m_privledgedTitle.set(static_cast(temp)); + else + m_privledgedTitle.set(static_cast(PlayerDataPriviledgedTitle::NormalPlayer)); + + // depersist squelch info + m_squelchedById = NetworkId::cms_invalid; + m_squelchedByName = std::string(); + m_squelchExpireTime = 0; + + NetworkId tempNetworkId; + std::string tempString; + if ((objVars.getItem(OBJVAR_SQUELCH_ID, tempNetworkId)) && (objVars.getItem(OBJVAR_SQUELCH_NAME, tempString)) && (objVars.getItem(OBJVAR_SQUELCH_EXPIRE, temp))) + { + if (tempNetworkId.isValid()) + { + if (temp < 0) + { + m_squelchedById = tempNetworkId; + m_squelchedByName = tempString; + m_squelchExpireTime = -1; + } + else if (temp > 0) + { + int const gameTimeNow = static_cast(ServerClock::getInstance().getGameTimeSeconds()); + if (gameTimeNow < temp) + { + m_squelchedById = tempNetworkId; + m_squelchedByName = tempString; + m_squelchExpireTime = static_cast(::time(NULL)) + (temp - gameTimeNow); + } + } + } + } + + // remove expired GCW contribution + { + DynamicVariableList::NestedList const gcwContribution(getObjVars(), "gcwContributionTracking"); + if (!gcwContribution.empty()) + { + int const timeExpired = static_cast(::time(NULL)) - (60 * 60 * 24 * 30); // 30 days + std::list gcwContributionToRemove; + int timeLastContributed; + for (DynamicVariableList::NestedList::const_iterator i = gcwContribution.begin(); i != gcwContribution.end(); ++i) + { + if (!Pvp::getGcwScoreCategory(i.getName()) || !i.getValue(timeLastContributed) || (timeLastContributed < timeExpired)) + gcwContributionToRemove.push_back(std::string("gcwContributionTracking.") + i.getName()); + } + + if (!gcwContributionToRemove.empty()) + { + for (std::list::const_iterator iterRemove = gcwContributionToRemove.begin(); iterRemove != gcwContributionToRemove.end(); ++iterRemove) + removeObjVarItem(*iterRemove); + } + } + } + + // check/set the character's proper "character age" title (age may/will changed while the character was logged out) + checkAndSetCharacterAgeTitle(*this, true); + + // start timer to periodically update logged in character global data + MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++updateConnectedCharacterLfgData", std::string(), 60); + } +} + +//----------------------------------------------------------------------- + +void PlayerObject::onLoadedFromDatabase() +{ + IntangibleObject::onLoadedFromDatabase(); + + // clear any deprecated quests + { + static std::vector deprecatedQuests; + for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) + { + if (!QuestManager::getQuest(i->first)) + deprecatedQuests.push_back(i->first); + } + + for (std::vector::const_iterator oldQuest=deprecatedQuests.begin(); oldQuest!=deprecatedQuests.end(); ++oldQuest) + questClearQuest(*oldQuest); + + deprecatedQuests.clear(); + } + CreatureObject * const owner = getCreatureObject(); + if(owner && owner->isInitialized()) + { + owner->fixupPersistentBuffsAfterLoading(); + owner->fixupLevelXpAfterLoading(); + } +} + +//----------------------------------------------------------------------- + +Waypoint const PlayerObject::createWaypoint(const Location & location, bool ignoreLimits) +{ + float const maxSaneCoordinate = 100000; + Vector const & where = location.getCoordinates(); + if ((where.x < -maxSaneCoordinate) || + (where.x > maxSaneCoordinate) || + (where.y < -maxSaneCoordinate) || + (where.y > maxSaneCoordinate) || + (where.z < -maxSaneCoordinate) || + (where.z > maxSaneCoordinate)) + { + WARNING(true,("INSANE_WAYPOINT_COORDINATES: PlayerObject %s attempted to create a waypoint with coordinates that were way out of range", getNetworkId().getValueString().c_str())); + return Waypoint(); + } + + if (ignoreLimits || m_waypoints.size() < static_cast(ConfigServerGame::getMaxWaypointsPerCharacter())) + { + Waypoint waypoint(ObjectIdManager::getNewObjectId()); + waypoint.setLocation(location); + m_waypoints.set(waypoint.getNetworkId(), waypoint); + Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(waypoint.getNetworkId()); + if(f != m_waypoints.end()) + { + Waypoint & w = const_cast(f->second); + m_callback->connect(w.getChangeNotification(), *this, &PlayerObject::onWaypointChanged); + + // call TRIG_WAYPOINT_CREATED + CreatureObject * const owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + ScriptParams params; + params.addParam(w.getNetworkId()); + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_WAYPOINT_CREATED, params)); + } + } + + // set a reasonable default color (the caller can change it) + if (strncmp("space_",location.getSceneId(),6)==0) + w.setColor(Waypoint::Space); + else + w.setColor(Waypoint::Blue); + + return w; + } + } + + return Waypoint(); +} + +//----------------------------------------------------------------------- + +Waypoint const PlayerObject::createOrUpdateReusableWaypoint(const Location & location, const std::string & objvarTrackingName, const Unicode::String & waypointNameIfCreated, int waypointColorIfCreated /*= -1*/) +{ + const std::string objvarName = std::string("reuseableWp.") + objvarTrackingName; + const DynamicVariableList & objvars = getObjVars(); + NetworkId waypointId; + bool newWpCreated = false; + if (!objvars.hasItem(objvarName) || (objvars.getType(objvarName) != DynamicVariable::NETWORK_ID)) + { + // create a new waypoint + Waypoint waypoint(createWaypoint(location, true)); + newWpCreated = true; + waypointId = waypoint.getNetworkId(); + setObjVarItem(objvarName, waypointId); + } + else + { + objvars.getItem(objvarName, waypointId); + + // find the existing waypoint in the datapad + std::vector waypointsInDatapad; + getWaypointsInDatapad(waypointsInDatapad); + if(std::find(waypointsInDatapad.begin(), waypointsInDatapad.end(), waypointId) == waypointsInDatapad.end()) + { + // original waypoint has been destroyed, create a new one + Waypoint waypoint(createWaypoint(location, true)); + newWpCreated = true; + waypointId = waypoint.getNetworkId(); + setObjVarItem(objvarName, waypointId); + } + } + + if (waypointId != NetworkId::cms_invalid) + { + Waypoint waypoint = Waypoint::getWaypointById(waypointId); + waypoint.setActive(true); + waypoint.setLocation(location); + + if (newWpCreated) + { + if (!waypointNameIfCreated.empty()) + waypoint.setName(waypointNameIfCreated); + + if ((waypointColorIfCreated >= 0) && (waypointColorIfCreated < static_cast(Waypoint::NumColors))) + waypoint.setColor(static_cast(waypointColorIfCreated)); + } + + return waypoint; + } + + return Waypoint(); +} + +//----------------------------------------------------------------------- + +void PlayerObject::destroyWaypoint(const NetworkId & id) +{ + // call TRIG_WAYPOINT_DESTROYED + Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(id); + if(f != m_waypoints.end()) + { + Waypoint & w = const_cast(f->second); + CreatureObject * const owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + ScriptParams params; + params.addParam(w.getNetworkId()); + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_WAYPOINT_DESTROYED, params)); + } + } + } + m_waypoints.erase(id); +} + +//----------------------------------------------------------------------- + +void PlayerObject::onWaypointChanged(const Waypoint & waypointData) +{ + Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(waypointData.getNetworkId()); + if(f != m_waypoints.end()) + { + if(isAuthoritative()) + m_waypoints.set(waypointData.getNetworkId(), waypointData); + } +} + +//----------------------------------------------------------------------- + +void PlayerObject::onWaypointCreated(const NetworkId &, const Waypoint & w) +{ + m_callback->connect(const_cast(w).getChangeNotification(), *this, &PlayerObject::onWaypointChanged); + GroupWaypointBuilder::updateGroupWaypoints(*this, true); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::onWaypointSet(NetworkId const &, Waypoint const &, Waypoint const &) +{ + GroupWaypointBuilder::updateGroupWaypoints(*this, true); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::onWaypointRemoved(NetworkId const &, Waypoint const &) +{ + GroupWaypointBuilder::updateGroupWaypoints(*this, true); +} + +//----------------------------------------------------------------------- + +Waypoint & PlayerObject::getWaypoint(const NetworkId & id) +{ + Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(id); + if(f != m_waypoints.end()) + { + return const_cast(f->second); + } + + static const Waypoint empty; + static Waypoint notFound; + notFound = empty; + return notFound; +} + +//----------------------------------------------------------------------- + +void PlayerObject::getWaypointsInDatapad(std::vector & target) +{ + Archive::AutoDeltaMap::const_iterator i; + for(i = m_waypoints.begin(); i != m_waypoints.end(); ++i) + { + target.push_back(i->second.getNetworkId()); + } +} + +//----------------------------------------------------------------------- + +void PlayerObject::getWaypointAttributes(const NetworkId & waypointId, ServerObject::AttributeVector & data) +{ + CreatureObject * const owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + Archive::AutoDeltaMap::const_iterator f = m_waypoints.find(waypointId); + if(f != m_waypoints.end()) + { + if (script->hasTrigger (Scripting::TRIG_WAYPOINT_ON_GET_ATTRIBUTES)) + { + static const int MAX_ATTRIBS = 20; + + // allow scripts to add attribute data to the vector + static std::vector names (MAX_ATTRIBS, static_cast(0)); + static std::vector attribs (MAX_ATTRIBS, static_cast(0)); + + //-- clear the vectors + names.clear (); + attribs.clear (); + names.resize (MAX_ATTRIBS, static_cast(0)); + attribs.resize (MAX_ATTRIBS, static_cast(0)); + + ScriptParams params; + params.addParam (waypointId); + params.addParam (owner->getNetworkId()); + params.addParam (names); + params.addParam (attribs); + + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_WAYPOINT_ON_GET_ATTRIBUTES, params)); + + const std::vector & newNames = params.getStringArrayParam (2); + const std::vector & newAttribs = params.getUnicodeArrayParam (3); + + // copy the returned strings to data + for (int i = 0; i < MAX_ATTRIBS; ++i) + { + const char * const newName = newNames [i]; + const Unicode::String * const newAttrib = newAttribs [i]; + + if (newName && *newName && newAttrib && !newAttrib->empty ()) + { + data.push_back (std::make_pair (std::string (newName), *newAttrib)); + } + else + break; + } + } + + } + } + } +} + +//----------------------------------------------------------------------- + +std::string PlayerObject::getAccountDescription(const NetworkId & creatureId) +{ + std::string result = getAccountDescription(safe_cast(NetworkIdManager::getObjectById(creatureId))); + if (result.empty() || result == "UNKNOWN") + result = creatureId.getValueString(); + return result; +} + +//----------------------------------------------------------------------- + +std::string PlayerObject::getAccountDescription(const ServerObject * creature) +{ + std::string desc = ""; + if (creature) + { + const PlayerObject * player = PlayerCreatureController::getPlayerObject(creature->asCreatureObject()); + if (creature->asCreatureObject() && player) + { + return player->getAccountDescription(); + } + else if (creature->asCreatureObject()) + { + desc += "Non-Player "; + desc += Unicode::wideToNarrow(creature->getObjectName()); + desc += "("; + desc += creature->getNetworkId().getValueString(); + desc += ") "; + desc += creature->getObjectTemplateName(); + } + else + desc = creature->getNetworkId().getValueString(); + } + else + { + desc = "UNKNOWN"; + } + return desc; +} + +//----------------------------------------------------------------------- + +std::string PlayerObject::getAccountDescription() const +{ + const ServerObject * owner = safe_cast( + ContainerInterface::getContainedByObject(*this)); + if (owner == NULL) + return "UNKNOWN"; + + bool isGod = false; + bool isSecure = false; + Client * client = NULL; + if (owner && owner->getClient()) + { + client = owner->getClient(); + if (client->isGod()) + isGod = true; + if (client->isGodValidated()) + isSecure = true; + } + + std::string desc; + desc += "Player "; + desc += Unicode::wideToNarrow(owner->getObjectName()); + desc += "("; + desc += owner->getNetworkId().getValueString(); + desc += ") StationId("; + char stationIdBuf[32] = {"\0"}; + snprintf(stationIdBuf, sizeof(stationIdBuf), "%lu", m_stationId.get()); + stationIdBuf[sizeof(stationIdBuf) - 1] = 0; + desc += stationIdBuf; + if (isGod) + desc += " isGod"; + else if (isSecure) + desc += " isSecure"; + + if (client && client->isFreeTrialAccount()) + { + desc += " isFreeTrial"; + } + + desc += ")"; + + return desc; +} + +//----------------------------------------------------------------------- + +void PlayerObject::logChat(int const logIndex) +{ + if (m_chatLog != NULL) + { + time_t const logTime = Os::getRealSystemTime(); + + ChatLogEntry chatLogEntry; + + chatLogEntry.m_index = logIndex; + chatLogEntry.m_time = logTime; + + m_chatLog->push_back(chatLogEntry); + + cleanChatLog(); + } +} + +//----------------------------------------------------------------------- + +PlayerObject::ChatLog const &PlayerObject::getChatLog() const +{ + NOT_NULL(m_chatLog); + + return *m_chatLog; +} + +//----------------------------------------------------------------------- + +void PlayerObject::checkStomach() +{ + int temp = 0; + + const CreatureObject * const creature = getCreatureObject(); + + if(creature) + { + const DynamicVariableList & objvars = creature->getObjVars(); + + if (objvars.getItem("stomach.food", temp)) + { + m_food = temp; + } + if (objvars.getItem("stomach.drink",temp)) + { + m_drink = temp; + } + if (objvars.getItem("stomach.medicine",temp)) + { + m_meds = temp; + } + } +} + +//----------------------------------------------------------------------- + +void PlayerObject::cleanChatLog() +{ + // See if we need to purge any old messages + + time_t currentTime; + time(¤tTime); + + if (m_chatLogPurgeTime != currentTime) + { + m_chatLogPurgeTime = currentTime; + + // See if anything needs to be purged from the front of the logs + + time_t const chatLogTime = ConfigServerUtility::getChatLogMinutes() * 60; + int chatLogCount = static_cast(m_chatLog->size()); + + ChatLog::iterator iterChatLog = m_chatLog->begin(); + while (!m_chatLog->empty()) + { + const time_t messageTime = iterChatLog->m_time; + + if (messageTime < (currentTime - chatLogTime) || (chatLogCount > ConfigServerUtility::getPlayerMaxChatLogLines())) + { + iterChatLog = m_chatLog->erase(iterChatLog); + --chatLogCount; + } + else + { + break; + } + } + } +} + +//---------------------------------------------------------------------- + +bool PlayerObject::isJedi() const +{ + return false; +} + +//------------------------------------------------------------------------------------------ + +bool PlayerObject::getIsUnsticking() const +{ + return m_isUnsticking; +} + +//------------------------------------------------------------------------------------------ + +void PlayerObject::setIsUnsticking(bool value) +{ + m_isUnsticking = value; +} + +// ======================================================================================== +//---------------------------------------------------------------------- + +void PlayerObject::findFriend(const std::string & friendName) +{ + // ask the name manager for the network id of the friend + std::string normalizedName = NameManager::normalizeName(friendName); + NetworkId target = NameManager::getInstance().getPlayerId(normalizedName); + const CreatureObject * creatureObject = getCreatureObject(); + if(target != NetworkId::cms_invalid) + { + if(creatureObject) + { + std::string myName = Unicode::wideToNarrow(creatureObject->getAssignedObjectFirstName()); + + // shortcut: if the player is on this server, don't send a + // messageTo + CreatureObject * friendObject = safe_cast(NetworkIdManager::getObjectById(target)); + if(friendObject && friendObject->isAuthoritative() && PlayerCreatureController::getPlayerObject(friendObject)) + { + // extract the PlayerObject from the CreatureObject + PlayerObject * friendPlayer = PlayerCreatureController::getPlayerObject(friendObject); + if(friendPlayer) + { + // go ahead and invoke replyLocationToFriend on the + // local PlayerObject. + friendPlayer->replyLocationToFriend(myName, creatureObject->getNetworkId()); + } + } + else + { + // the player is not on this server, send a message to C for the + // friend's network ID. + Archive::ByteStream payload; + Archive::put(payload, creatureObject->getNetworkId()); + Archive::put(payload, myName); + + //@todo: This should really use sprintf to pack the data into a string, rather than reintrepreting a byte stream as a string + + MessageToQueue::getInstance().sendMessageToC(target, "FindFriend", std::string(reinterpret_cast(payload.getBuffer()), payload.getSize()), 0, false); + } + } + } + else + { + StringId noName("ui_cmnty", "friend_location_failed_noname"); + Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); + } +} + +//---------------------------------------------------------------------- + +void PlayerObject::replyLocationToFriend(const std::string & friendName, const NetworkId & friendNetworkId) +{ + // Do not send location information to players who are not + // on this player's friend list (e.g. the Bounty hunter trying + // to find a Jedi) + if(isFriend(friendName)) + { + // the requesting player is our friend, send the location + CreatureObject * creatureObject = getCreatureObject(); + if(creatureObject) + { + Vector coordinates = creatureObject->findPosition_w(); + std::string scene = ServerWorld::getSceneId(); + Location location(coordinates, NetworkId::cms_invalid, Location::getCrcBySceneName(scene)); + // If the requestor is on this server, invoke the response + // directly, otherwise send a message to the remote + // creature object with the data. + CreatureObject * friendCreatureObject = safe_cast(NetworkIdManager::getObjectById(friendNetworkId)); + if(friendCreatureObject && friendCreatureObject->isAuthoritative()) + { + // retrieve the PlayerObject associated with the + // character and give it the coordinates + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(friendCreatureObject); + if(playerObject) + { + playerObject->receiveLocationToFriend(creatureObject->getNetworkId(), location); + } + else + { + // send an error to the requesting player + failLocationToFriend(friendNetworkId); + } + } + else + { + // the character is not on this server, send the response + // to the requestor's network Id + Archive::ByteStream response; + Archive::put(response, location); + Archive::put(response, creatureObject->getNetworkId()); + MessageToQueue::getInstance().sendMessageToC(friendNetworkId, "LocationToFriend", std::string(reinterpret_cast(response.getBuffer()), response.getSize()), 0, false); + + } + } + else + { + // send an error to the requesting player + failLocationToFriend(friendNetworkId); + } + } + else + { + // send a failure to the requestor, let them know that + // both players must be on the friends list + failLocationToFriend(friendNetworkId); + } +} + +//---------------------------------------------------------------------- + +void PlayerObject::receiveLocationToFriend(const NetworkId & friendId, const Location & friendLocation) +{ + // receiving a response to the findFriend request + CreatureObject * creatureObject = getCreatureObject(); + if(creatureObject) + { + const DynamicVariableList & objvars = creatureObject->getObjVars(); + NetworkId friendWaypointId; + bool newWpCreated = false; + if(! objvars.hasItem("friend_waypoint_id")) + { + // create a new "friend" waypoint + Waypoint friendWaypoint(createWaypoint(friendLocation, true)); + newWpCreated = true; + friendWaypointId = friendWaypoint.getNetworkId(); + creatureObject->setObjVarItem("friend_waypoint_id", friendWaypointId); + } + else + { + objvars.getItem("friend_waypoint_id", friendWaypointId); + // find the existing waypoint in the datapad + std::vector waypointsInDatapad; + getWaypointsInDatapad(waypointsInDatapad); + if(std::find(waypointsInDatapad.begin(), waypointsInDatapad.end(), friendWaypointId) == waypointsInDatapad.end()) + { + // original waypoint has been destroyed, create a new one + Waypoint newWaypoint(createWaypoint(friendLocation, true)); + newWpCreated = true; + friendWaypointId = newWaypoint.getNetworkId(); + creatureObject->setObjVarItem("friend_waypoint_id", friendWaypointId); + } + } + + std::string friendName = NameManager::getInstance().getPlayerName(friendId); + if(friendWaypointId != NetworkId::cms_invalid) + { + Waypoint friendWaypoint = Waypoint::getWaypointById(friendWaypointId); + friendWaypoint.setActive(true); + friendWaypoint.setLocation(friendLocation); + friendWaypoint.setName(Unicode::narrowToWide(NameManager::getInstance().getPlayerName(friendId))); + + // findFriend waypoint is purple by default + if (newWpCreated) + friendWaypoint.setColor(Waypoint::Purple); + + Unicode::String oob; + ProsePackage pp; + if(! friendName.empty()) + { + if (newWpCreated) + { + pp.actor.str = Unicode::narrowToWide(friendName); + pp.stringId = StringId("ui_cmnty", "friend_location_create_new_wp"); + OutOfBandPackager::pack(pp, -1, oob); + Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); + } + else + { + pp.actor.str = Unicode::narrowToWide(friendName); + pp.stringId = StringId("ui_cmnty", "friend_location"); + OutOfBandPackager::pack(pp, -1, oob); + Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); + } + } + else + { + StringId noName("ui_cmnty", "friend_location_failed_noname"); + Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); + } + } + else + { + if( !friendName.empty()) + { + ProsePackage pp; + pp.actor.str = Unicode::narrowToWide(friendName); + pp.stringId = StringId("ui_cmnty", "friend_location_failed"); + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); + } + else + { + StringId noName("ui_cmnty", "friend_location_failed_noname"); + Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); + } + } + } +} + +//---------------------------------------------------------------------- + +void PlayerObject::failLocationToFriend(const NetworkId & friendId) +{ + CreatureObject * requestor = safe_cast(NetworkIdManager::getObjectById(friendId)); + if(requestor && requestor->isAuthoritative()) + { + PlayerObject * player = PlayerCreatureController::getPlayerObject(requestor); + if(player) + { + player->receiveFailLocationToFriend(getCreatureObject()->getNetworkId()); + } + } + else + { + Archive::ByteStream response; + Archive::put(response, getCreatureObject()->getNetworkId()); + MessageToQueue::getInstance().sendMessageToC(friendId, "FailLocationToFriend", std::string(reinterpret_cast(response.getBuffer()), response.getSize()), 0, false); + } +} + +//---------------------------------------------------------------------- + +void PlayerObject::receiveFailLocationToFriend(const NetworkId & friendId) +{ + CreatureObject * creatureObject = getCreatureObject(); + if(creatureObject) + { + std::string friendName = NameManager::getInstance().getPlayerName(friendId); + if(! friendName.empty()) + { + ProsePackage pp; + pp.actor.str = Unicode::narrowToWide(friendName); + pp.stringId = StringId("ui_cmnty", "friend_location_failed"); + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + Chat::sendSystemMessage(*creatureObject, Unicode::emptyString, oob); + } + else + { + StringId noName("ui_cmnty", "friend_location_failed_noname"); + Chat::sendSystemMessage(*creatureObject, noName, Unicode::emptyString); + } + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setPriviledgedTitle(int8 priviledgedTitle) +{ + if (isAuthoritative()) + { + if (m_privledgedTitle.get() != priviledgedTitle) + { + // if becoming a warden, send system message and warden introduction mail + if (priviledgedTitle == static_cast(PlayerDataPriviledgedTitle::Warden)) + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + { + static const Unicode::String mailSubject = Unicode::narrowToWide("@" + StringId("warden", "warden_introduction_subject").getCanonicalRepresentation()); + + ProsePackage pp; + pp.stringId = StringId("warden", "warden_introduction_body"); + + Unicode::String oob; + OutOfBandPackager::pack(pp, -1, oob); + + Chat::sendPersistentMessage("system", Unicode::wideToNarrow(owner->getAssignedObjectName()), mailSubject, Unicode::emptyString, oob); + + Chat::sendSystemMessage(*owner, StringId("warden", "grant_warden"), Unicode::emptyString); + } + } + // if warden being revoked, send system message + else if (m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::Warden)) + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + Chat::sendSystemMessage(*owner, StringId("warden", "revoke_warden"), Unicode::emptyString); + } + + m_privledgedTitle.set(priviledgedTitle); + + // persist privileged title + if (priviledgedTitle != static_cast(PlayerDataPriviledgedTitle::NormalPlayer)) + setObjVarItem(OBJVAR_PRIVILEGED_TITLE, static_cast(priviledgedTitle)); + else + removeObjVarItem(OBJVAR_PRIVILEGED_TITLE); + } + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_setPriviledgedTitle, new MessageQueueGenericValueType(static_cast(priviledgedTitle))); + } +} + +//------------------------------------------------------------------------------------------ + +void PlayerObject::activateQuest(int questId) +{ + BitArray b = m_activeQuests.get(); + b.setBit(questId); + m_activeQuests.set(b); + ScriptParams params; + params.addParam(questId); + CreatureObject * creatureObject = getCreatureObject(); + if(creatureObject) + { + GameScriptObject * gameScriptObject = creatureObject->getScriptObject(); + if(gameScriptObject) + { + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_QUEST_ACTIVATED, params)); + } + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::deactivateQuest(int questId) +{ + BitArray b = m_activeQuests.get(); + b.clearBit(questId); + m_activeQuests.set(b); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::completeQuest(int questId) +{ + BitArray b = m_activeQuests.get(); + b.clearBit(questId); + m_activeQuests.set(b); + b = m_completedQuests.get(); + b.setBit(questId); + m_completedQuests.set(b); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::isQuestActive(int questId) const +{ + return m_activeQuests.get().testBit(questId); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::isQuestComplete(int questId) const +{ + return m_completedQuests.get().testBit(questId); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::clearCompletedQuest(int questId) +{ + BitArray b = m_completedQuests.get(); + b.clearBit(questId); + m_completedQuests.set(b); +} + +// ---------------------------------------------------------------------- + +/** + * Checks if the theater assigned to this player should be spawned. NOTE: if we + * spawn the theater, our theater data will be cleared. + * + * @param pos our position + * @param scene our scene + * @param speed our speed + * @param updateRadius distance when we start receiving objects + */ +void PlayerObject::checkTheater(const Vector & pos, const std::string & scene, + float speed, float updateRadius) +{ + if (!isAuthoritative()) + return; + + if (!hasTheater()) + return; + + if (m_theaterScene.get() != scene) + return; + + // we want to spawn the theater so that all the objects will have been created + // by the time the theater comes into view + float timeToCreate = (m_theaterNumObjects.get() / IntangibleObject::getObjectsCreatedPerFrame()) * 0.25f; + float creationDistance = m_theaterRadius.get() + updateRadius * 1.5f + speed * timeToCreate; + float distance = pos.magnitudeBetweenSquared(m_theaterPosition.get()); + if (distance < creationDistance * creationDistance) + { + DEBUG_LOG("Theater", ("PlayerObject spawning theater at a distance of " + "%f(%f, %f, %f, %f)\n", static_cast(sqrt(distance)), creationDistance, + speed, updateRadius, timeToCreate)); + IntangibleObject * theater = IntangibleObject::spawnTheater(m_theaterDatatable.get(), + m_theaterPosition.get(), m_theaterScript.get(), + static_cast(m_theaterLocationType.get())); + if (theater != NULL) + { + const CreatureObject * owner = getCreatureObject(); + if (owner != NULL) + theater->setPlayer(*owner); + theater->setTheaterCreator(m_theaterCreator.get()); + if (!theater->setTheaterName(m_theaterName.get())) + { + WARNING(true, ("PlayerObject::checkTheater could not create " + "theater with name %s", m_theaterName.get().c_str())); + theater->permanentlyDestroy(DeleteReasons::SetupFailed); + theater = NULL; + } + } + if (theater == NULL) + { + CreatureObject * creatureObject = getCreatureObject(); + if (creatureObject) + { + GameScriptObject * gameScriptObject = creatureObject->getScriptObject(); + if (gameScriptObject) + { + ScriptParams params; + params.addParam(m_theaterDatatable.get().c_str()); + params.addParam(m_theaterName.get().c_str()); + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_PLAYER_THEATER_FAIL, params)); + } + } + } + else + m_theaterId = theater->getNetworkId(); + + // there seems to be a problem if an objvar gets set and cleared in the + // same frame, so we message ourselves to clean up next frame + clearTheater(); + //m_theaterDatatable = ""; + //MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++ClearTheater", std::string(), 0.1f, true); + } +} // PlayerObject::checkTheater + +// ---------------------------------------------------------------------- + +/** + * Sets the data for a theater that will be created when this player gets near + * it. NOTE: we do not store the data if the player already has a theater. + * + * @param datatable the datatable where the theater info is stored + * @param position the general location of the theater (the actual location + * is determined by getGoodLocation() when the theater is spawned) + * @param scene the planet/scene where the theater is + * @param script the script to be attached to the theater object + * @param creator who's creating the theater + * @param name the theater's name + * @param locationType how to create the theater + * + * @return true on success, false on fail + */ +bool PlayerObject::setTheater(const std::string & datatable, const Vector & position, + const std::string & scene, const std::string & script, const NetworkId & creator, + const std::string & name, IntangibleObject::TheaterLocationType locationType) +{ + if (!isAuthoritative()) + { + WARNING(true, ("PlayerObject::setTheater called on unauthoritative player")); + return false; + } + + if (hasTheater()) + { + WARNING(true, ("PlayerObject::setTheater called on player with theater")); + return false; + } + + m_theaterNumObjects = IntangibleObject::getNumObjects(datatable); + if (m_theaterNumObjects.get() == 0) + { + WARNING(true, ("PlayerObject::setTheater called with invalid datatable %s", + datatable.c_str())); + return false; + } + + if (ServerUniverse::getInstance().getPlanetByName(scene) == NULL) + { + WARNING(true, ("PlayerObject::setTheater called with invalid scene %s", + scene.c_str())); + return false; + } + + m_theaterDatatable = datatable; + m_theaterPosition = position; + m_theaterScene = scene; + m_theaterScript = script; + m_theaterCreator = creator; + m_theaterName = name; + m_theaterLocationType = static_cast(locationType); + + // note that we set the radius to 3 times the radius returned since that is + // the area that the theater could be created in + m_theaterRadius = IntangibleObject::getRadius(datatable) * 3.0f; + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Clears the player's theater data. + */ +void PlayerObject::clearTheater() +{ + if (!isAuthoritative()) + return; + + m_theaterDatatable = ""; + m_theaterPosition = Vector(0,0,0); + m_theaterScene = ""; + m_theaterScript = ""; + m_theaterRadius = 0; + m_theaterCreator = NetworkId::cms_invalid; + m_theaterName = ""; + m_theaterLocationType = IntangibleObject::TLT_getGoodLocation; +} + +// ---------------------------------------------------------------------- + +/** + * Checks if the player has theater data. + */ +bool PlayerObject::hasTheater() const +{ + return !m_theaterDatatable.get().empty(); +} + +// ---------------------------------------------------------------------- + +PlayerObject *PlayerObject::asPlayerObject() +{ + return this; +} + +// ---------------------------------------------------------------------- + +PlayerObject const *PlayerObject::asPlayerObject() const +{ + return this; +} + +// ====================================================================== +// Quest System functions +// ====================================================================== + +PlayerObject::QuestResult PlayerObject::questCanActivateQuest(uint32 const questCrc) const +{ + Quest const * const quest=QuestManager::getQuest(questCrc); + if (!quest) + return QR_noSuchQuest; + + if (questHasActiveQuest(questCrc)) + return QR_alreadyActive; + + if (!quest->isRepeatable() && questHasCompletedQuest(questCrc)) + return QR_alreadyComplete; + + { + std::vector const & prerequisites = quest->getPrerequisiteQuests(); + for (std::vector::const_iterator i=prerequisites.begin(); i!=prerequisites.end(); ++i) + { + if (!questHasCompletedQuest(*i)) + return QR_failedPrerequisites; + } + } + + { + std::vector const & exclusion = quest->getExclusionQuests(); + for (std::vector::const_iterator i=exclusion.begin(); i!=exclusion.end(); ++i) + { + if (questHasCompletedQuest(*i) || questHasActiveQuest(*i)) + return QR_failedExclusion; + } + } + + return QR_success; +} + +// ---------------------------------------------------------------------- + + +PlayerObject::QuestResult PlayerObject::questActivateQuest(uint32 const questCrc, NetworkId const & questGiver) +{ + QuestResult canActivateResult = questCanActivateQuest(questCrc); + if (canActivateResult != QR_success) + return canActivateResult; + + questCheckQuestLimits(); + + PlayerQuestData playerQuestData(questGiver); + m_quests.set(questCrc, playerQuestData); + setCurrentQuest(questCrc); + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + ScriptParams params; + params.addParam(static_cast(questCrc)); + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_QUEST_ACTIVATED, params)); + } + } + + questActivateQuestTask(questCrc, 0); + + return QR_success; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::questCheckQuestLimits() +{ + if (m_quests.size() > s_questLimit) + { + // Randomly remove some quests to get the number back down to the limit + // Most of the quests in the list should be completed, so try + // to prefer completed quests when picking ones to delete + // + // The hope is that game mechanisms will keep the number of quests + // within the limits, and this code won't have to be used. + + CreatureObject * const owner = NON_NULL(getCreatureObject()); + + size_t numberToDelete = m_quests.size() - s_questLimit; + int previousNumberDeleted; + if (!owner->getObjVars().getItem(OBJVAR_DELETED_QUEST_COUNT, previousNumberDeleted)) + previousNumberDeleted=0; + IGNORE_RETURN(owner->setObjVarItem(OBJVAR_DELETED_QUEST_COUNT, previousNumberDeleted + static_cast(numberToDelete))); + + // We need to sort the quests to delete by age + SortableQuestList possibleQuestsToDelete; + + // First find all the completed quests than can be deleted + for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) + { + PlayerQuestData const& questData = i->second; + if (questData.isCompleted()) + { + possibleQuestsToDelete.push_back(QuestDataToSort(i->first, questData)); + } + } + + // Sort the possible quests by age + possibleQuestsToDelete.sort(); + + // Determine whether we found enough quests to delete + if (possibleQuestsToDelete.size() < numberToDelete) + { + SortableQuestList additionalPossibleQuestsToDelete; + + // Our failure case has hit a failure case! There aren't enough completed quests to stay within the limit. + for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end() && possibleQuestsToDelete.size() < numberToDelete; ++i) + { + PlayerQuestData const& questData = i->second; + if (!questData.isCompleted()) + { + additionalPossibleQuestsToDelete.push_back(QuestDataToSort(i->first, questData)); + } + } + + // Sort the additional quests by age + additionalPossibleQuestsToDelete.sort(); + + // Add the additional quests to the end of the possibilities list + possibleQuestsToDelete.splice(possibleQuestsToDelete.end(), + additionalPossibleQuestsToDelete, + additionalPossibleQuestsToDelete.begin(), + additionalPossibleQuestsToDelete.end()); + } + + while (numberToDelete > 0) + { + DEBUG_FATAL(possibleQuestsToDelete.empty(),("Programmer bug: there is an error in the questCheckQuestLimits logic such that possibleQuestsToDelete was unexpectedly empty")); + + // Remove the "oldest" quest from the beginning of the list + QuestDataToSort const& questDataToSort = possibleQuestsToDelete.front(); + uint32 const playerQuestDataKey = questDataToSort.GetPlayerQuestDataKey(); + questClearQuest(playerQuestDataKey); + possibleQuestsToDelete.pop_front(); + --numberToDelete; + + LOG("CustomerService",("Removed quest %lu from player %s because there were too many quests in the journal", playerQuestDataKey, NON_NULL(getCreatureObject())->getNetworkId().getValueString().c_str())); + } + } +} + +// ---------------------------------------------------------------------- + +PlayerObject::QuestResult PlayerObject::questCompleteQuest(uint32 const questCrc) +{ + Quest const * const quest = QuestManager::getQuest(questCrc); + if (!quest) + return QR_noSuchQuest; + + if(!questHasActiveQuest(questCrc)) + return QR_questNotActive; + + if(questHasCompletedQuest(questCrc)) + return QR_alreadyComplete; + + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + if (questData==m_quests.end()) + return QR_questNotActive; + + //clear any leftover tasks for this quest + int taskId = 0; + for(; taskId < quest->getNumberOfTasks(); ++taskId) + { + if(questHasActiveQuestTask(questCrc, taskId)) + questClearQuestTask(questCrc, taskId); + } + + PlayerQuestData newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators + setPlayerQuestDataComplete(questCrc, newQuestData); + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + ScriptParams params; + params.addParam(static_cast(questCrc)); + GameScriptObject * const scriptObject = owner->getScriptObject(); + if(scriptObject) + { + scriptObject->trigAllScripts(Scripting::TRIG_QUEST_COMPLETED, params); + } + } + + CreatureObject * const playerCreature = getCreatureObject(); + //see if this quest needs to go through our acceptance/completion UI flow + if(QuestManager::isQuestAcceptable(quest->getName().getString())) + { + //-- Request the recipient's client to have the emitter object render the text. + Controller * const controller = playerCreature->getController(); + if(controller) + { + setPendingRequestQuestInformation(questCrc, NetworkId::cms_invalid); + MessageQueueGenericValueType * const msg = new MessageQueueGenericValueType(static_cast(questCrc)); + controller->appendMessage(static_cast(CM_requestCompleteQuest), 0.0f, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } + else + { + questGrantQuestReward(static_cast(questCrc), ""); + } + + return QR_success; +} + +// ---------------------------------------------------------------------- + +PlayerObject::QuestResult PlayerObject::questGrantQuestReward(uint32 const questCrc, std::string const & selectedReward) +{ + Quest const * const quest=QuestManager::getQuest(questCrc); + if (!quest) + return QR_noSuchQuest; + + if(!questHasCompletedQuest(questCrc)) + return QR_questNotCompleted; + + PlayerQuestDataMap::const_iterator questData = m_quests.find(questCrc); + + PlayerQuestData newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators + + if(newQuestData.hasReceivedReward()) + { + return QR_alreadyReceivedReward; + } + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + ScriptParams params; + params.addParam(static_cast(questCrc)); + if(quest->isAnExclusiveStaticLootReward(selectedReward)) + params.addParam(selectedReward.c_str()); + else + params.addParam(""); + GameScriptObject * const scriptObject = owner->getScriptObject(); + if(scriptObject) + { + if(scriptObject->trigAllScripts(Scripting::TRIG_QUEST_GRANT_REWARD, params) == SCRIPT_CONTINUE) + { + newQuestData.setHasReceivedReward(true); + setPlayerQuestDataComplete(questCrc, newQuestData); + } + } + } + + return QR_success; +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::questPlayerCanClaimRewardFor(uint32 const questCrc) +{ + PlayerQuestDataMap::const_iterator const questData = m_quests.find(questCrc); + + PlayerQuestData const newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators + + return (questHasCompletedQuest(questCrc) && !newQuestData.hasReceivedReward()); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::questClearQuest(uint32 const questCrc) +{ + Quest const * const quest=QuestManager::getQuest(questCrc); + if(quest) + { + //clear any leftover tasks for this quest + int taskId = 0; + for(; taskId < quest->getNumberOfTasks(); ++taskId) + { + if(questHasActiveQuestTask(questCrc, taskId)) + questClearQuestTask(questCrc, taskId); + } + } + + m_quests.erase(questCrc); + + //-- if the cleared quest is the current quest, pick a new one + if (questCrc == getCurrentQuest()) + { + pickNewCurrentQuest(); + } + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + ScriptParams params; + params.addParam(static_cast(questCrc)); + GameScriptObject * const scriptObject = owner->getScriptObject(); + if(scriptObject) + { + scriptObject->trigAllScripts(Scripting::TRIG_QUEST_CLEARED, params); + } + } +} + +// ---------------------------------------------------------------------- + +PlayerObject::QuestResult PlayerObject::questCanActivateQuestTask(uint32 const questCrc, int const taskId) const +{ + Quest const * const quest = QuestManager::getQuest(questCrc); + if (!quest) + return QR_noSuchQuest; + QuestTask const * const questTask = quest->getTask(taskId); + if (!questTask) + return QR_noSuchTask; + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + if (questData==m_quests.end()) + return QR_questNotActive; + if (questData->second.isTaskActive(taskId)) + return QR_alreadyActive; + if (!questTask->isRepeatable() && questData->second.isTaskCompleted(taskId)) + return QR_alreadyComplete; + + // check for prerequisites/exclusions + { + std::vector const & prerequisites = questTask->getPrerequisiteTasks(); + for(std::vector::const_iterator i = prerequisites.begin(); i!= prerequisites.end(); ++i) + { + if (!questData->second.isTaskCompleted(*i)) + return QR_failedPrerequisites; + } + } + { + std::vector const & exclustion = questTask->getExclusionTasks(); + for(std::vector::const_iterator i = exclustion.begin(); i!= exclustion.end(); ++i) + { + if (questData->second.isTaskCompleted(*i) || questData->second.isTaskActive(*i)) + return QR_failedExclusion; + } + } + + return QR_success; +} + +// ---------------------------------------------------------------------- + +PlayerObject::QuestResult PlayerObject::questActivateQuestTask(uint32 const questCrc, int const taskId) +{ + QuestResult canActivateResult = questCanActivateQuestTask(questCrc, taskId); + if (canActivateResult != QR_success) + return canActivateResult; + + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + DEBUG_FATAL(questData==m_quests.end(),("Programmer bug: questCanActivateQuestTask(%lu, %i) returned success, but the quest was not in m_quests", questCrc, taskId)); + + PlayerQuestData newQuestData(questData->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators + newQuestData.activateTask(taskId); + m_quests.set(questCrc, newQuestData); + + const Quest * const quest = QuestManager::getQuest(questCrc); + if(quest) + { + const QuestTask * const task = quest->getTask(taskId); + if(task) + { + ScriptParams params; + params.addParam(static_cast(questCrc)); + params.addParam(static_cast(taskId)); + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + const std::string & attachScript = task->getAttachScript(); + if(!attachScript.empty()) + { + refScript(*owner, attachScript); + { + IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_ACTIVATED, params)); + } + } + + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_ACTIVATED, params)); + } + } + + CreatureObject * const co = getCreatureObject(); + if(co) + { + if(!task->getMusicOnActivate().empty()) + { + Client * const c = co->getClient(); + if (c) + { + PlayMusicMessage const msg(task->getMusicOnActivate(), NetworkId::cms_invalid, 0, false); + c->send(msg, true); + } + } + } + } + } + + return QR_success; +} + +// ---------------------------------------------------------------------- + +PlayerObject::QuestResult PlayerObject::questCompleteQuestTask(uint32 const questCrc, int const taskId) +{ + Quest const * const quest = QuestManager::getQuest(questCrc); + if (!quest) + return QR_noSuchQuest; // Quest has been removed from the data table, apparently + QuestTask const * const questTask = quest->getTask(taskId); + if (!questTask) + return QR_noSuchTask; + + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + if (questData==m_quests.end()) + return QR_questNotActive; + if (!questData->second.isTaskActive(taskId)) + return QR_taskNotActive; + + PlayerQuestData newQuestData(questData->second); + newQuestData.completeTask(taskId); + m_quests.set(questCrc, newQuestData); + + ScriptParams params; + params.addParam(static_cast(questCrc)); + params.addParam(static_cast(taskId)); + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + const std::string & attachScript = questTask->getAttachScript(); + if(!attachScript.empty()) + { + IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_COMPLETED, params)); + derefScript(*owner, attachScript); + } + + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_COMPLETED, params)); + } + } + + if (questTask->questCompletesOnTaskCompletion()) + { + questCompleteQuest(questCrc); + return QR_success; + } + else if (questTask->questClearsOnTaskCompletion()) + { + questClearQuest(questCrc); + return QR_success; + } + + TaskChanceVector tasksWithChanceToActivate; + int totalChance = 0; + + QuestTask::TaskIdList const & nextTasks = questTask->getTasksOnComplete(); + for (QuestTask::TaskIdList::const_iterator i=nextTasks.begin(); i != nextTasks.end(); ++i) + { + QuestTask const * const taskOnComplete = quest->getTask(*i); + if (taskOnComplete) + { + int const chanceToActivate = taskOnComplete->getChanceToActivate(); + if (chanceToActivate <= 0) + IGNORE_RETURN(questActivateQuestTask(questCrc, *i)); // activate all that are possible, ignore the ones that aren't + else + { + tasksWithChanceToActivate.push_back(std::make_pair(*i, chanceToActivate)); + totalChance += chanceToActivate; + } + } + } + + if (totalChance) + { + int const winningChance = Random::random(totalChance - 1); + int previousChance = 0; + + TaskChanceVector::const_iterator currentTaskChance = tasksWithChanceToActivate.begin(); + + for (;currentTaskChance != tasksWithChanceToActivate.end(); ++currentTaskChance) + { + int const currentChance = previousChance + currentTaskChance->second; + + if (winningChance >= previousChance && winningChance < currentChance) + { + IGNORE_RETURN(questActivateQuestTask(questCrc, currentTaskChance->first)); + break; + } + + previousChance = currentChance; + } + } + + //closeout quest if they're done with all the tasks, if the quest is marked to allow this + //The "space quests" written using breinhart's quest backend will NOT use this, the "ground quests" will + bool questIsComplete = true; + for(int it = 0; it < quest->getNumberOfTasks(); ++it) + { + bool const completedTask = questHasCompletedQuestTask(questCrc, it); + if(!completedTask) + { + questIsComplete = false; + break; + } + } + if(questIsComplete && quest->getCompleteQuestWhenTasksComplete()) + { + questCompleteQuest(questCrc); + } + return QR_success; +} + +// ---------------------------------------------------------------------- + +PlayerObject::QuestResult PlayerObject::questFailQuestTask(uint32 const questCrc, int const taskId) +{ + Quest const * const quest = QuestManager::getQuest(questCrc); + if (!quest) + return QR_noSuchQuest; // Quest has been removed from the data table, apparently + QuestTask const * const questTask = quest->getTask(taskId); + if (!questTask) + return QR_noSuchTask; + + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + if (questData==m_quests.end()) + return QR_questNotActive; + if (!questData->second.isTaskActive(taskId)) + return QR_taskNotActive; + + PlayerQuestData newQuestData(questData->second); + newQuestData.clearTask(taskId); + m_quests.set(questCrc, newQuestData); + + ScriptParams params; + params.addParam(static_cast(questCrc)); + params.addParam(static_cast(taskId)); + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + const std::string & attachScript = questTask->getAttachScript(); + if(!attachScript.empty()) + { + IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_FAILED, params)); + derefScript(*owner, attachScript); + } + + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_FAILED, params)); + } + } + + if (questTask->questCompletesOnTaskFailure()) + { + questCompleteQuest(questCrc); + return QR_success; + } + else if (questTask->questClearsOnTaskFailure()) + { + questClearQuest(questCrc); + return QR_success; + } + + QuestTask::TaskIdList const & nextTasks = questTask->getTasksOnFail(); + for (QuestTask::TaskIdList::const_iterator i=nextTasks.begin(); i != nextTasks.end(); ++i) + { + IGNORE_RETURN(questActivateQuestTask(questCrc, *i)); // activate all that are possible, ignore the ones that aren't + } + + return QR_success; +} + +// ---------------------------------------------------------------------- + +PlayerObject::QuestResult PlayerObject::questClearQuestTask(uint32 const questCrc, int const taskId) +{ + Quest const * const quest = QuestManager::getQuest(questCrc); + if (!quest) + return QR_noSuchQuest; // Quest has been removed from the data table, apparently + QuestTask const * const questTask = quest->getTask(taskId); + if (!questTask) + return QR_noSuchTask; + + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + if (questData==m_quests.end()) + return QR_questNotActive; + if (!questData->second.isTaskActive(taskId)) + return QR_taskNotActive; + + PlayerQuestData newQuestData(questData->second); + newQuestData.clearTask(taskId); + m_quests.set(questCrc, newQuestData); + + ScriptParams params; + params.addParam(static_cast(questCrc)); + params.addParam(static_cast(taskId)); + + CreatureObject * owner = getCreatureObject(); + if(owner) + { + GameScriptObject * script = owner->getScriptObject(); + if(script) + { + const std::string & attachScript = questTask->getAttachScript(); + if(!attachScript.empty()) + { + IGNORE_RETURN(script->trigOneScript(attachScript, Scripting::TRIG_TASK_CLEARED, params)); + derefScript(*owner, attachScript); + } + + IGNORE_RETURN(script->trigAllScripts(Scripting::TRIG_SOME_TASK_CLEARED, params)); + } + } + + return QR_success; +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::questHasActiveQuest(uint32 const questCrc) const +{ + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + return (questData!=m_quests.end() && !questData->second.isCompleted()); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::questHasCompletedQuest(uint32 const questCrc) const +{ + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + return (questData!=m_quests.end() && questData->second.isCompleted()); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::questHasActiveQuestTask(uint32 const questCrc, int const taskId) const +{ + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + if (questData==m_quests.end()) + return false; + + return (questData->second.isTaskActive(taskId)); + +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::questHasCompletedQuestTask(uint32 const questCrc, int const taskId) const +{ + PlayerQuestDataMap::const_iterator questData=m_quests.find(questCrc); + if (questData==m_quests.end()) + return false; + + return (questData->second.isTaskCompleted(taskId)); +} + +// ---------------------------------------------------------------------- + +uint32 PlayerObject::questGetQuestStatus(uint32 const questCrc) const +{ + PlayerQuestDataMap::const_iterator questData = m_quests.find(questCrc); + + if (questData == m_quests.end()) + return 0; + + return (questData->second.getActiveTasks() << 16) | (questData->second.getCompletedTasks() & 0xFFFF); +} + +// ---------------------------------------------------------------------- + +std::set const &PlayerObject::getAllPlayerObjects() // static +{ + return s_allPlayerObjects; +} + +// ---------------------------------------------------------------------- + +PlayerObject::WaypointMap const &PlayerObject::getWaypoints() const +{ + return m_waypoints.getMap(); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const +{ + if(name == "quests") + { + Archive::AutoDeltaMap(m_quests).pack(target); + } + else if(name == "completedQuests") + { + m_completedQuests.pack(target); + } + else if(name == "activeQuests") + { + m_activeQuests.pack(target); + } + else if(name == "currentQuest") + { + m_currentQuest.pack(target); + } + else if(name == "bornDate") + { + m_bornDate.pack(target); + } + else if(name == "playedTime") + { + m_playedTime.pack(target); + } + else if(name == "food") + { + m_food.pack(target); + } + else if(name == "maxFood") + { + m_maxFood.pack(target); + } + else if(name == "drink") + { + m_drink.pack(target); + } + else if(name == "maxDrink") + { + m_maxDrink.pack(target); + } + else if(name == "meds") + { + m_meds.pack(target); + } + else if(name == "maxMeds") + { + m_maxMeds.pack(target); + } + else if(name == "privledgedTitle") + { + m_privledgedTitle.pack(target); + } + else if(name == "matchMakingPersonalProfileId") + { + m_matchMakingPersonalProfileId.pack(target); + } + else if(name == "matchMakingCharacterProfileId") + { + m_matchMakingCharacterProfileId.pack(target); + } + else if(name == "workingSkill") + { + m_workingSkill.pack(target); + } + else if(name == "skillTemplate") + { + m_skillTemplate.pack(target); + } + else if(name == "collections") + { + m_collections.pack(target); + } + else if(name == "collections2") + { + m_collections2.pack(target); + } + else + { + IntangibleObject::getByteStreamFromAutoVariable(name, target); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source) +{ + Archive::ReadIterator ri(source); + if(name == "quests") + { + typedef Archive::AutoDeltaMap::Command Commands; + std::vector quests; + + m_quests.clear(); + Archive::AutoDeltaMap(m_quests).unpack(ri, quests); + + for (std::vector::const_iterator questIter = quests.begin(); questIter != quests.end(); ++questIter) + { + m_quests.set(questIter->key, questIter->value); + } + } + else if(name == "completedQuests") + { + m_completedQuests.unpackDelta(ri); + } + else if(name == "activeQuests") + { + m_activeQuests.unpackDelta(ri); + } + else if(name == "currentQuest") + { + m_currentQuest.unpackDelta(ri); + } + else if(name == "bornDate") + { + m_bornDate.unpackDelta(ri); + } + else if(name == "playedTime") + { + m_playedTime.unpackDelta(ri); + } + else if(name == "food") + { + m_food.unpackDelta(ri); + } + else if(name == "maxFood") + { + m_maxFood.unpackDelta(ri); + } + else if(name == "drink") + { + m_drink.unpackDelta(ri); + } + else if(name == "maxDrink") + { + m_maxDrink.unpackDelta(ri); + } + else if(name == "meds") + { + m_meds.unpackDelta(ri); + } + else if(name == "maxMeds") + { + m_maxMeds.unpackDelta(ri); + } + else if(name == "privledgedTitle") + { + m_privledgedTitle.unpackDelta(ri); + } + else if(name == "matchMakingPersonalProfileId") + { + m_matchMakingPersonalProfileId.unpackDelta(ri); + } + else if(name == "matchMakingCharacterProfileId") + { + m_matchMakingCharacterProfileId.unpackDelta(ri); + } + else if(name == "workingSkill") + { + m_workingSkill.unpackDelta(ri); + } + else if(name == "skillTemplate") + { + m_skillTemplate.unpackDelta(ri); + } + else if(name == "collections") + { + m_collections.unpackDelta(ri); + } + else if(name == "collections2") + { + m_collections2.unpackDelta(ri); + } + else + { + IntangibleObject::setAutoVariableFromByteStream(name, source); + } + addObjectToConcludeList(); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setGroupWaypoints(WaypointMap const &groupWaypoints) +{ + DEBUG_FATAL(!isAuthoritative(), ("PlayerObject::setGroupWaypoints: called on non-authoritative object %s", getDebugInformation().c_str())); + if (isAuthoritative()) + { + //-- Anything in the new set, we need to set (the AutoDeltaMap will throw out anything unchanged) + { + for (WaypointMap::const_iterator i = groupWaypoints.begin(); i != groupWaypoints.end(); ++i) + m_groupWaypoints.set((*i).first, (*i).second); + } + + //-- Anything that is not in the original set, we need to remove + { + for (WaypointMap::const_iterator i = m_groupWaypoints.begin(); i != m_groupWaypoints.end(); ++i) + if (groupWaypoints.find((*i).first) == groupWaypoints.end()) + m_groupWaypoints.erase((*i).first); + } + } +} + +// ---------------------------------------------------------------------- + +uint32 PlayerObject::getPlayedTime() const +{ + return static_cast(m_playedTime.get() + m_playedTimeAccum); +} + +// ---------------------------------------------------------------------- + +float PlayerObject::getPlayedTimeAccumOnly() const +{ + return m_playedTimeAccum; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setPlayedTimeAccumOnly(float playedTimeAccum) +{ + m_playedTimeAccum = playedTimeAccum; +} + +// ---------------------------------------------------------------------- + +unsigned long PlayerObject::getSessionPlayTimeDuration() const +{ + time_t const sessionStartPlayTime = static_cast(m_sessionStartPlayTime.get()); + if (sessionStartPlayTime > 0) + { + time_t const now = ::time(NULL); + if (now > sessionStartPlayTime) + return static_cast(now - sessionStartPlayTime); + } + + return 0; +} + +// ---------------------------------------------------------------------- + +unsigned long PlayerObject::getSessionActivePlayTimeDuration() const +{ + unsigned long activePlayTimeDuration = m_sessionActivePlayTimeDuration.get(); + + time_t const sessionLastActiveTime = static_cast(m_sessionLastActiveTime.get()); + if (sessionLastActiveTime > 0) + { + time_t const now = ::time(NULL); + if (now > sessionLastActiveTime) + activePlayTimeDuration += static_cast(now - sessionLastActiveTime); + } + + return activePlayTimeDuration; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setSessionPlayTimeInfo(int32 sessionStartPlayTime, int32 sessionLastActiveTime, unsigned long sessionActivePlayTimeDuration) +{ + // shouldn't be calling this on a non-auth object + if (!isAuthoritative()) + return; + + int32 const previousSessionStartPlayTime = m_sessionStartPlayTime.get(); + int32 const previousSessionLastActiveTime = m_sessionLastActiveTime.get(); + + m_sessionStartPlayTime = sessionStartPlayTime; + m_sessionLastActiveTime = sessionLastActiveTime; + m_sessionActivePlayTimeDuration = sessionActivePlayTimeDuration; + + // just connected + if ((previousSessionStartPlayTime == 0) && (sessionStartPlayTime != 0)) + { + CreatureObject const * const owner = getCreatureObject(); + if (owner) + { + LfgCharacterData lfgCharacterData; + owner->getLfgCharacterData(lfgCharacterData); + + ServerUniverse::setConnectedCharacterLfgData(owner->getNetworkId(), lfgCharacterData); + + BiographyManager::requestBiography(owner->getNetworkId(), NULL); + + // check/set "account age" title + checkAndSetAccountAgeTitle(*this); + } + } + // just disconnected + else if ((sessionStartPlayTime == 0) && (previousSessionStartPlayTime != 0)) + { + CreatureObject const * const owner = getCreatureObject(); + if (owner) + { + ServerUniverse::removeConnectedCharacterData(owner->getNetworkId()); + } + } + else if (sessionStartPlayTime != 0) + { + // just went active/inactive + if (((previousSessionLastActiveTime == 0) && (sessionLastActiveTime != 0)) || + ((sessionLastActiveTime == 0) && (previousSessionLastActiveTime != 0))) + { + CreatureObject const * const owner = getCreatureObject(); + if (owner) + { + LfgCharacterData lfgCharacterData; + owner->getLfgCharacterData(lfgCharacterData); + + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFindLfg = connectedCharacterLfgData.find(owner->getNetworkId()); + if ((iterFindLfg == connectedCharacterLfgData.end()) || (iterFindLfg->second != lfgCharacterData)) + ServerUniverse::setConnectedCharacterLfgData(owner->getNetworkId(), lfgCharacterData); + } + } + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setRoleIconChoice(int roleIconChoice) +{ + m_roleIconChoice = roleIconChoice; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getRoleIconChoice() const +{ + return m_roleIconChoice.get(); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setAggroImmuneDuration(int const time) +{ + m_aggroImmuneDuration = static_cast(time); + m_aggroImmuneStartTime = Os::getRealSystemTime(); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::isAggroImmune() const +{ + time_t const elapsedTime = Os::getRealSystemTime() - m_aggroImmuneStartTime.get(); + + return (elapsedTime < m_aggroImmuneDuration.get()); +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getAgeInDays() const +{ + return int(getCurrentBornDate() - getBornDate()); +} + +// ---------------------------------------------------------------------- + +std::string const & PlayerObject::getSkillTemplate() const +{ + return m_skillTemplate.get(); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::setSkillTemplate(std::string const & templateName, bool const clientRequest) +{ + std::string const previousTemplateName(m_skillTemplate.get()); + + // we need to pass an empty string to script to do cleanup, but we don't want to actually change the player's skill + if (!templateName.empty()) + m_skillTemplate.set(templateName); + + CreatureObject * const owner = getCreatureObject(); + if(owner) + { + GameScriptObject * const script = owner->getScriptObject(); + if(script) + { + ScriptParams params; + + params.addParam(templateName.c_str()); + params.addParam(clientRequest); + + if (script->trigAllScripts(Scripting::TRIG_SKILL_TEMPLATE_CHANGED, params) == SCRIPT_DEFAULT) + { + m_skillTemplate.set(previousTemplateName); + LOG("ScriptInvestigation", ("Scripts blocked setSkillTemplate( %s ) on Player( %s ). Reverting to %s.", templateName.c_str(), getAccountDescription().c_str(), previousTemplateName.c_str())); + } + } + + if (previousTemplateName != m_skillTemplate.get()) + { + uint8 const newProfession = static_cast(LfgCharacterData::convertSkillTemplateToProfession(m_skillTemplate.get())); + + GroupObject * const group = owner->getGroup(); + if (group) + { + uint8 const currentProfessionForGroup = group->getMemberProfession(owner->getNetworkId()); + + if (newProfession != currentProfessionForGroup) + group->setMemberProfession(owner->getNetworkId(), newProfession); + } + + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(owner->getNetworkId()); + if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.profession != static_cast(newProfession))) + ServerUniverse::setConnectedCharacterProfessionData(owner->getNetworkId(), static_cast(newProfession)); + } + } + + return (templateName != previousTemplateName); +} + +// ---------------------------------------------------------------------- + +std::string const & PlayerObject::getWorkingSkill() const +{ + return m_workingSkill.get(); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::setWorkingSkill(std::string const & skillName, bool const clientRequest) +{ + std::string const previousWorkingSkill(m_workingSkill.get()); + + m_workingSkill.set(skillName); + + CreatureObject * const owner = getCreatureObject(); + if(owner) + { + GameScriptObject * const script = owner->getScriptObject(); + if(script) + { + ScriptParams params; + + params.addParam(skillName.c_str()); + params.addParam(clientRequest); + + if (script->trigAllScripts(Scripting::TRIG_WORKING_SKILL_CHANGED, params) == SCRIPT_DEFAULT) + { + m_workingSkill.set(previousWorkingSkill); + LOG("ScriptInvestigation", ("Scripts blocked setWorkingSkill( %s ) on Player( %s ). Reverting to %s.", skillName.c_str(), getAccountDescription().c_str(), previousWorkingSkill.c_str())); + } + } + } + + + return (previousWorkingSkill != skillName); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setPendingRequestQuestInformation(uint32 questCrc, NetworkId const & questGiver) +{ + m_pendingRequestQuestCrc = questCrc; + m_pendingRequestQuestGiver = questGiver; +} + +// ---------------------------------------------------------------------- + +uint32 PlayerObject::getPendingRequestQuestCrc() const +{ + return m_pendingRequestQuestCrc; +} + +// ---------------------------------------------------------------------- + +NetworkId const & PlayerObject::getPendingRequestQuestGiver() const +{ + return m_pendingRequestQuestGiver; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getNumberOfActiveQuests() const +{ + int counter = 0; + for (PlayerQuestDataMap::const_iterator i = m_quests.begin(); i != m_quests.end(); ++i) + { + PlayerQuestData const questData(i->second); // unfortunately have to copy the quest data, because AutoDeltaPackedMap does not have non-const iterators + if(!questData.isCompleted()) + { + ++counter; + } + } + return counter; +} + +// ---------------------------------------------------------------------- + +std::vector PlayerObject::questGetAllActiveQuestIds() const +{ + std::vector result; + for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) + { + if(!i->second.isCompleted()) + { + result.push_back(i->first); + } + } + return result; +} + +// ---------------------------------------------------------------------- + +std::vector PlayerObject::questGetAllCompletedQuestIds() const +{ + std::vector result; + for (PlayerQuestDataMap::const_iterator i=m_quests.begin(); i!=m_quests.end(); ++i) + { + if(i->second.isCompleted()) + { + result.push_back(i->first); + } + } + return result; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setPlayerQuestDataComplete(uint32 questCrc, PlayerQuestData & playerQuestData) +{ + playerQuestData.complete(); + m_quests.set(questCrc, playerQuestData); + + //-- if the completed quest is the current quest, pick a new one + if (questCrc == getCurrentQuest()) + { + pickNewCurrentQuest(); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::pickNewCurrentQuest() +{ + uint32 lastRelativeAgeIndex = 0; + uint32 lastQuestCrc = 0; + + for (PlayerQuestDataMap::const_iterator i = m_quests.begin(); i != m_quests.end(); ++i) + { + PlayerQuestData const & questData = i->second; + uint32 const questCrc = i->first; + + if (!questData.isCompleted() && questData.getRelativeAgeIndex() >= lastRelativeAgeIndex) + { + lastQuestCrc = questCrc; + lastRelativeAgeIndex = questData.getRelativeAgeIndex(); + } + } + + setCurrentQuest(lastQuestCrc); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyCurrentGcwPoints(int const count, bool modifyLifetimeValue) +{ + CreatureObject * const owner = getCreatureObject(); + if (!owner) + return; + + if (isAuthoritative()) + { + if (PvpData::isImperialFactionId(owner->getPvpFaction()) || PvpData::isRebelFactionId(owner->getPvpFaction())) + { + static int32 const max = std::numeric_limits::max(); + + // m_currentGcwPoints should always be >= 0 + int32 const currentValue = std::max(static_cast(0), m_currentGcwPoints.get()); + + // limit count so it doesn't cause overflow + int32 const adjustedCount = std::min(static_cast(count), max - currentValue); + + int32 temp = 0; + if (adjustedCount != 0) + { + temp = m_currentGcwPoints.get(); + m_currentGcwPoints = std::max(static_cast(0), currentValue + adjustedCount); + } + + if (modifyLifetimeValue && (count > 0)) + modifyLifetimeGcwPoints(count); + + if (adjustedCount != 0) + { + char buffer[256]; + sprintf(buffer, INT64_FORMAT_SPECIFIER, m_lifetimeGcwPoints.get()); + + LOG("CustomerService", ("PvP_Ranking:%s|adjust point=%d|current=%ld|new=%ld|lifetime=%s", + getAccountDescription().c_str(), + count, + temp, + m_currentGcwPoints.get(), + buffer)); + } + } + else + { + // non-factional characters is always at 0 + if (m_currentGcwPoints.get() != 0) + { + LOG("CustomerService", ("PvP_Ranking:%s|adjust point=%d|setting current points (%ld) to 0 because not factional", + getAccountDescription().c_str(), + count, + m_currentGcwPoints.get())); + + m_currentGcwPoints = 0; + } + } + + // make sure that m_nextGcwRatingCalcTime is set so that the + // rating will be recalculated at the next recalculation interval + setNextGcwRatingCalcTime(false); + } + else + { + owner->sendControllerMessageToAuthServer(CM_modifyCurrentGcwPoints, new MessageQueueGenericValueType >(std::make_pair(count, (modifyLifetimeValue ? 1 : 0)))); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyCurrentGcwRating(int const count, bool modifyMaxValue) +{ + CreatureObject * const owner = getCreatureObject(); + if (!owner) + return; + + if (isAuthoritative()) + { + if (PvpData::isImperialFactionId(owner->getPvpFaction()) || PvpData::isRebelFactionId(owner->getPvpFaction())) + { + static int32 const max = std::numeric_limits::max(); + + // m_currentGcwRating should always be >= 0 + int32 const currentValue = std::max(static_cast(Pvp::getMinRatingForRank()), m_currentGcwRating.get()); + + // limit count so it doesn't cause overflow + int32 const adjustedCount = std::min(static_cast(count), max - currentValue); + + if (adjustedCount != 0) + { + int32 const temp = m_currentGcwRating.get(); + + m_currentGcwRating = std::min(std::max(static_cast(Pvp::getMinRatingForRank()), currentValue + adjustedCount), static_cast(Pvp::getMaxRatingForRank())); + + // calculate new rank + Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); + int const oldRank = m_currentGcwRank.get(); + m_currentGcwRank = pvpRankInfo.rank; + + if (pvpRankInfo.rank > 0) + { + m_currentGcwRankProgress = static_cast(std::min(static_cast(m_currentGcwRating.get()), pvpRankInfo.maxRating) - pvpRankInfo.minRating) * 100.0f / static_cast(pvpRankInfo.maxRating - pvpRankInfo.minRating + 1); + } + else + { + m_currentGcwRankProgress = 0.0f; + } + + if (modifyMaxValue) + { + if (PvpData::isImperialFactionId(owner->getPvpFaction()) && (m_currentGcwRating.get() > m_maxGcwImperialRating.get())) + { + m_maxGcwImperialRating = m_currentGcwRating; + m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; + } + else if (PvpData::isRebelFactionId(owner->getPvpFaction()) && (m_currentGcwRating.get() > m_maxGcwRebelRating.get())) + { + m_maxGcwRebelRating = m_currentGcwRating; + m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; + } + } + + LOG("CustomerService", ("PvP_Ranking:%s|adjust rating=%d|current=%ld|new=%ld|max imp=%ld|max reb=%ld", + getAccountDescription().c_str(), + count, + temp, + m_currentGcwRating.get(), + m_maxGcwImperialRating.get(), + m_maxGcwRebelRating.get())); + + // notify script if rank changed + if (oldRank != m_currentGcwRank.get()) + { + GameScriptObject * const script = owner->getScriptObject(); + + if (script != 0) + { + ScriptParams params; + params.addParam(oldRank); + params.addParam(m_currentGcwRank.get()); + script->trigAllScripts(Scripting::TRIG_PVP_RANKING_CHANGED, params); + } + } + } + } + else + { + // non-factional characters is always at -1 + if (m_currentGcwRating.get() != -1) + { + LOG("CustomerService", ("PvP_Ranking:%s|adjust rating=%d|setting current rating (%ld) to -1 because not factional", + getAccountDescription().c_str(), + count, + m_currentGcwRating.get())); + + m_currentGcwRating = -1; + } + + int const oldRank = m_currentGcwRank.get(); + m_currentGcwRank = 0; + m_currentGcwRankProgress = 0.0f; + + // notify script if rank changed + if (oldRank != m_currentGcwRank.get()) + { + GameScriptObject * const script = owner->getScriptObject(); + + if (script != 0) + { + ScriptParams params; + params.addParam(oldRank); + params.addParam(m_currentGcwRank.get()); + script->trigAllScripts(Scripting::TRIG_PVP_RANKING_CHANGED, params); + } + } + } + + // make sure that m_nextGcwRatingCalcTime is set so that the + // rating will be recalculated at the next recalculation interval + setNextGcwRatingCalcTime(false); + } + else + { + owner->sendControllerMessageToAuthServer(CM_modifyCurrentGcwRating, new MessageQueueGenericValueType >(std::make_pair(count, (modifyMaxValue ? 1 : 0)))); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyCurrentPvpKills(int const count, bool modifyLifetimeValue) +{ + CreatureObject * const owner = getCreatureObject(); + if (!owner) + return; + + if (isAuthoritative()) + { + if (PvpData::isImperialFactionId(owner->getPvpFaction()) || PvpData::isRebelFactionId(owner->getPvpFaction())) + { + static int32 const max = std::numeric_limits::max(); + + // m_currentPvpKills should always be >= 0 + int32 const currentValue = std::max(static_cast(0), m_currentPvpKills.get()); + + // limit count so it doesn't cause overflow + int32 const adjustedCount = std::min(static_cast(count), max - currentValue); + + int32 temp = 0; + if (adjustedCount != 0) + { + temp = m_currentPvpKills.get(); + m_currentPvpKills = std::max(static_cast(0), currentValue + adjustedCount); + } + + if (modifyLifetimeValue && (count > 0)) + modifyLifetimePvpKills(count); + + if (adjustedCount != 0) + { + LOG("CustomerService", ("PvP_Ranking:%s|adjust pvp kill=%d|current=%ld|new=%ld|lifetime=%ld", + getAccountDescription().c_str(), + count, + temp, + m_currentPvpKills.get(), + m_lifetimePvpKills.get())); + } + } + else + { + // non-factional characters is always at 0 + if (m_currentPvpKills.get() != 0) + { + LOG("CustomerService", ("PvP_Ranking:%s|adjust pvp kill=%d|setting current pvp kill (%ld) to 0 because not factional", + getAccountDescription().c_str(), + count, + m_currentPvpKills.get())); + + m_currentPvpKills = 0; + } + } + + // make sure that m_nextGcwRatingCalcTime is set so that the + // rating will be recalculated at the next recalculation interval + setNextGcwRatingCalcTime(false); + } + else + { + owner->sendControllerMessageToAuthServer(CM_modifyCurrentPvpKills, new MessageQueueGenericValueType >(std::make_pair(count, (modifyLifetimeValue ? 1 : 0)))); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyLifetimeGcwPoints(int const count) +{ + if (isAuthoritative()) + { + static int64 const max = std::numeric_limits::max(); + + // m_lifetimeGcwPoints should always be >= 0 + int64 const currentValue = std::max(static_cast(0), m_lifetimeGcwPoints.get()); + + // limit count so it doesn't cause overflow + int64 const adjustedCount = std::min(static_cast(count), max - currentValue); + + if (adjustedCount != 0) + m_lifetimeGcwPoints = std::max(static_cast(0), currentValue + adjustedCount); + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_modifyLifetimeGcwPoints, new MessageQueueGenericValueType(count)); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyMaxGcwImperialRating(int const count) +{ + if (isAuthoritative()) + { + static int32 const min = std::numeric_limits::min() + 1; + static int32 const max = std::numeric_limits::max() - 1; + + // m_maxGcwImperialRating should always be >= -1 + int32 currentValue = std::max(static_cast(-1), m_maxGcwImperialRating.get()); + currentValue = std::min(currentValue, max); + + // limit count so it doesn't cause underflow or overflow + int32 adjustedCount = std::max(static_cast(count), min); + adjustedCount = std::min(adjustedCount, max - currentValue); + + if (adjustedCount != 0) + { + m_maxGcwImperialRating = std::min(std::max(static_cast(-1), currentValue + adjustedCount), static_cast(Pvp::getMaxRatingForRank())); + m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; + } + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_modifyMaxGcwImperialRating, new MessageQueueGenericValueType(count)); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyMaxGcwRebelRating(int const count) +{ + if (isAuthoritative()) + { + static int32 const min = std::numeric_limits::min() + 1; + static int32 const max = std::numeric_limits::max() - 1; + + // m_maxGcwRebelRating should always be >= -1 + int32 currentValue = std::max(static_cast(-1), m_maxGcwRebelRating.get()); + currentValue = std::min(currentValue, max); + + // limit count so it doesn't cause underflow or overflow + int32 adjustedCount = std::max(static_cast(count), min); + adjustedCount = std::min(adjustedCount, max - currentValue); + + if (adjustedCount != 0) + { + m_maxGcwRebelRating = std::min(std::max(static_cast(-1), currentValue + adjustedCount), static_cast(Pvp::getMaxRatingForRank())); + m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; + } + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_modifyMaxGcwRebelRating, new MessageQueueGenericValueType(count)); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyLifetimePvpKills(int const count) +{ + if (isAuthoritative()) + { + static int32 const max = std::numeric_limits::max(); + + // m_lifetimePvpKills should always be >= 0 + int32 const currentValue = std::max(static_cast(0), m_lifetimePvpKills.get()); + + // limit count so it doesn't cause overflow + int32 const adjustedCount = std::min(static_cast(count), max - currentValue); + + if (adjustedCount != 0) + m_lifetimePvpKills = std::max(static_cast(0), currentValue + adjustedCount); + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_modifyLifetimePvpKills, new MessageQueueGenericValueType(count)); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyNextGcwRatingCalcTime(int const weekCount) +{ + if (isAuthoritative()) + { + // don't need to do anything if the player doesn't need rating recalculated + if (!needsGcwRatingRecalculated()) + return; + + static int32 const max = std::numeric_limits::max(); + int32 const now = static_cast(::time(NULL)); + + // m_nextGcwRatingCalcTime should always be >= 0 + int32 const currentValue = std::max(static_cast(0), m_nextGcwRatingCalcTime.get()); + + // limit weekCount to -1000 to 1000 with 0 meaning "now" + int32 adjustedWeekCount = std::max(static_cast(-1000), static_cast(weekCount)); + adjustedWeekCount = std::min(static_cast(1000), adjustedWeekCount); + + // if necessary, cancel the currently pending messageTo for rating recalculation + if (m_nextGcwRatingCalcTime.get() > 0) + { + cancelMessageTo("C++RecalculateGcwRating"); + m_gcwRatingActualCalcTime = 0; + } + + if (adjustedWeekCount != 0) + { + int32 adjustedSeconds = 60 * 60 * 24 * 7 * adjustedWeekCount; + + // limit adjustedSeconds so it doesn't cause overflow + adjustedSeconds = std::min(adjustedSeconds, max - currentValue); + + // don't allow the recalc time to be too far in the past + if (adjustedSeconds != 0) + m_nextGcwRatingCalcTime = std::max(static_cast(CalendarTimeNamespace::g_CalendarTimeEarliestTime), currentValue + adjustedSeconds); + } + else // 0 means "now" + { + m_nextGcwRatingCalcTime = now; + } + + // if necessary, send messageTo to trigger rating recalculation + if (m_nextGcwRatingCalcTime.get() > 0) + { + // randomly spread out the recalculation so they don't all + // happen at exactly the same time and lag out the server, + // unless the recalculation time has passed in which case + // we want to do the recalculation much more quickly + if (m_nextGcwRatingCalcTime.get() <= now) + sendRecalculateGcwRatingMessageTo(5); + else + sendRecalculateGcwRatingMessageTo(std::max(30, static_cast(m_nextGcwRatingCalcTime.get() - now)) + 5 + (rand() % 60)); + } + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_modifyNextGcwRatingCalcTime, new MessageQueueGenericValueType(weekCount)); + } +} + +// ---------------------------------------------------------------------- +void PlayerObject::ctsUseOnlySetGcwInfo(int32 currentGcwPoints, int32 currentGcwRating, int32 currentPvpKills, int64 lifetimeGcwPoints, int32 maxGcwImperialRating, int32 maxGcwRebelRating, int32 lifetimePvpKills, int32 nextGcwRatingCalcTime) +{ + // should only be called on authoritative object + if (!isAuthoritative()) + return; + + // can't do anything if we're not attached to the creature object + if (!getCreatureObject()) + return; + + int32 const oldCurrentGcwPoints = m_currentGcwPoints.get(); + int32 const oldCurrentGcwRating = m_currentGcwRating.get(); + int32 const oldCurrentPvpKills = m_currentPvpKills.get(); + int64 const oldLifetimeGcwPoints = m_lifetimeGcwPoints.get(); + int32 const oldMaxGcwImperialRating = m_maxGcwImperialRating.get(); + int32 const oldMaxGcwRebelRating = m_maxGcwRebelRating.get(); + int32 const oldLifetimePvpKills = m_lifetimePvpKills.get(); + int32 const oldNextGcwRatingCalcTime = m_nextGcwRatingCalcTime.get(); + + m_currentGcwPoints = std::max(static_cast(0), currentGcwPoints); + m_currentGcwRating = std::min(std::max(static_cast(-1), currentGcwRating), static_cast(Pvp::getMaxRatingForRank())); + m_currentPvpKills = std::max(static_cast(0), currentPvpKills); + m_lifetimeGcwPoints = std::max(static_cast(0), lifetimeGcwPoints); + m_maxGcwImperialRating = std::min(std::max(static_cast(-1), maxGcwImperialRating), static_cast(Pvp::getMaxRatingForRank())); + m_maxGcwRebelRating = std::min(std::max(static_cast(-1), maxGcwRebelRating), static_cast(Pvp::getMaxRatingForRank())); + m_lifetimePvpKills = std::max(static_cast(0), lifetimePvpKills); + + // don't allow the recalc time to be too far in the past + m_nextGcwRatingCalcTime = ((nextGcwRatingCalcTime == 0) ? 0 : std::max(static_cast(CalendarTimeNamespace::g_CalendarTimeEarliestTime), nextGcwRatingCalcTime)); + + Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); + m_currentGcwRank = pvpRankInfo.rank; + + if (pvpRankInfo.rank > 0) + { + m_currentGcwRankProgress = static_cast(std::min(static_cast(m_currentGcwRating.get()), pvpRankInfo.maxRating) - pvpRankInfo.minRating) * 100.0f / static_cast(pvpRankInfo.maxRating - pvpRankInfo.minRating + 1); + } + else + { + m_currentGcwRankProgress = 0.0f; + } + + m_maxGcwImperialRank = Pvp::getRankInfo(m_maxGcwImperialRating.get()).rank; + m_maxGcwRebelRank = Pvp::getRankInfo(m_maxGcwRebelRating.get()).rank; + + char buffer1[128]; + char buffer2[128]; + sprintf(buffer1, INT64_FORMAT_SPECIFIER, oldLifetimeGcwPoints); + sprintf(buffer2, INT64_FORMAT_SPECIFIER, m_lifetimeGcwPoints.get()); + + LOG("CustomerService", ("PvP_Ranking:%s|applying info from CTS|point:%ld -> %ld|rating:%ld -> %ld|pvp kill:%ld -> %ld|lifetime point:%s -> %s|max imp rating:%ld -> %ld|max reb rating:%ld -> %ld|lifetime pvp kill:%ld -> %ld|calc time:%ld -> %ld", + getAccountDescription().c_str(), + oldCurrentGcwPoints, m_currentGcwPoints.get(), + oldCurrentGcwRating, m_currentGcwRating.get(), + oldCurrentPvpKills, m_currentPvpKills.get(), + buffer1, buffer2, + oldMaxGcwImperialRating, m_maxGcwImperialRating.get(), + oldMaxGcwRebelRating, m_maxGcwRebelRating.get(), + oldLifetimePvpKills, m_lifetimePvpKills.get(), + oldNextGcwRatingCalcTime, m_nextGcwRatingCalcTime.get())); + + // if necessary, cancel the currently pending messageTo for rating recalculation + if (oldNextGcwRatingCalcTime > 0) + { + cancelMessageTo("C++RecalculateGcwRating"); + m_gcwRatingActualCalcTime = 0; + } + + // make sure that m_nextGcwRatingCalcTime is set so that the + // rating will be recalculated at the next recalculation interval + setNextGcwRatingCalcTime(true); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setNextGcwRatingCalcTime(bool const alwaysSendMessageToForRecalc) +{ + // should only be called on authoritative object + if (!isAuthoritative()) + return; + + bool needToSendMessageTo = alwaysSendMessageToForRecalc; + int32 const now = static_cast(::time(NULL)); + + // if the player needs a rating recalculation, + // make sure that m_nextGcwRatingCalcTime is set so that the + // rating will be recalculated at the next recalculation interval + if (needsGcwRatingRecalculated()) + { + if (m_nextGcwRatingCalcTime.get() <= 0) + { + time_t const nextCalcTime = CalendarTime::getNextGMTTimeOcurrence(static_cast(now), ConfigServerGame::getGcwRecalcTimeDayOfWeek(), ConfigServerGame::getGcwRecalcTimeHour(), ConfigServerGame::getGcwRecalcTimeMinute(), ConfigServerGame::getGcwRecalcTimeSecond()); + if (nextCalcTime > 0) + { + m_nextGcwRatingCalcTime = static_cast(nextCalcTime); + needToSendMessageTo = true; + } + } + } + else + { + // if necessary, cancel the currently pending messageTo for rating recalculation + if (m_nextGcwRatingCalcTime.get() > 0) + { + cancelMessageTo("C++RecalculateGcwRating"); + m_gcwRatingActualCalcTime = 0; + } + + m_nextGcwRatingCalcTime = 0; + } + + // send messageTo to trigger rating recalculation + if (needToSendMessageTo && (m_nextGcwRatingCalcTime.get() > 0)) + { + // randomly spread out the recalculation so they don't all + // happen at exactly the same time and lag out the server, + // unless the recalculation time has passed in which case + // we want to do the recalculation much more quickly + if (m_nextGcwRatingCalcTime.get() <= now) + sendRecalculateGcwRatingMessageTo(5); + else + sendRecalculateGcwRatingMessageTo(std::max(30, static_cast(m_nextGcwRatingCalcTime.get() - now)) + 5 + (rand() % 60)); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::handleRecalculateGcwRating() +{ + // should only be called on authoritative object + if (!isAuthoritative()) + return; + + // can't do anything if we're not attached to the creature object + if (!getCreatureObject()) + return; + + // is it time to recalculate? + int32 const now = static_cast(::time(NULL)); + if ((m_nextGcwRatingCalcTime.get() > 0) && (m_nextGcwRatingCalcTime.get() <= now)) + { + // is recalculation required? + if (needsGcwRatingRecalculated()) + { + int32 nextCalcInterval = m_nextGcwRatingCalcTime.get(); + int32 points = std::max(static_cast(0), m_currentGcwPoints.get()); + int32 currentRating = m_currentGcwRating.get(); + int32 previousRating; + int totalRatingAdjustment, totalEarnedRating, totalEarnedRatingAfterDecay, cappedRatingAdjustment; + bool moreRecalculationNeeded = false; + while (true) + { + // calculate rating adjustment for interval + totalRatingAdjustment = Pvp::calculateRatingAdjustment(static_cast(points), static_cast(currentRating), totalEarnedRating, totalEarnedRatingAfterDecay, cappedRatingAdjustment); + + // don't apply rating loss if we are in a "rating loss exclusion interval" + if ((totalRatingAdjustment < 0) && (Pvp::isInGcwRankDecayExclusionInterval(static_cast(nextCalcInterval)))) + { + // CS log + LOG("CustomerService", ("PvP_Ranking:%s|NOT APPLYING RATING LOSS|interval %ld (%s) (%s)|current rating=%ld|points=%ld|total earned rating=%ld|total earned rating after decay=%ld|capped rating adjustment=%ld|final rating adjustment=%ld", + getAccountDescription().c_str(), + nextCalcInterval, + CalendarTime::convertEpochToTimeStringGMT(static_cast(nextCalcInterval)).c_str(), + CalendarTime::convertEpochToTimeStringLocal(static_cast(nextCalcInterval)).c_str(), + currentRating, + points, + totalEarnedRating, + totalEarnedRatingAfterDecay, + cappedRatingAdjustment, + totalRatingAdjustment)); + } + else + { + // update rating + previousRating = currentRating; + currentRating += static_cast(totalRatingAdjustment); + + // make sure updated rating is in range of valid rating + currentRating = std::max(currentRating, static_cast(Pvp::getMinRatingForRank())); + currentRating = std::min(currentRating, static_cast(Pvp::getMaxRatingForRank())); + + // CS log + LOG("CustomerService", ("PvP_Ranking:%s|interval %ld (%s) (%s)|current rating=%ld|new rating=%ld|points=%ld|total earned rating=%ld|total earned rating after decay=%ld|capped rating adjustment=%ld|final rating adjustment=%ld", + getAccountDescription().c_str(), + nextCalcInterval, + CalendarTime::convertEpochToTimeStringGMT(static_cast(nextCalcInterval)).c_str(), + CalendarTime::convertEpochToTimeStringLocal(static_cast(nextCalcInterval)).c_str(), + previousRating, + currentRating, + points, + totalEarnedRating, + totalEarnedRatingAfterDecay, + cappedRatingAdjustment, + totalRatingAdjustment)); + } + + // point have all been converted + points = 0; + + // check to see if we need to do another calculation for the next interval + nextCalcInterval = static_cast(CalendarTime::getNextGMTTimeOcurrence(static_cast(nextCalcInterval)+1, ConfigServerGame::getGcwRecalcTimeDayOfWeek(), ConfigServerGame::getGcwRecalcTimeHour(), ConfigServerGame::getGcwRecalcTimeMinute(), ConfigServerGame::getGcwRecalcTimeSecond())); + if (nextCalcInterval <= 0) + break; + + if (nextCalcInterval > now) + break; + + Pvp::PvpRankInfo const & pvpNewRankInfo = Pvp::getRankInfo(currentRating); + if (pvpNewRankInfo.rank < 1) + break; + + if (pvpNewRankInfo.ratingDecayBalance <= 0) + break; + + // if rating increased, then exit loop so that the new rating + // can be updated so that the max rating can be saved, and rank + // increase notification gets sent; otherwise, the rating + // increase may get "lost" with subsequent decrease due to decay + // as this loop iterates; if further calculation is required for more + // intervals, then send another messageTo to trigger more calculations + if (currentRating > m_currentGcwRating.get()) + { + moreRecalculationNeeded = true; + break; + } + } + + // decrementing the value by a really large + // number will cause it to reset to 0 + static int const min = std::numeric_limits::min(); + + // apply new GCW values + if (m_currentGcwPoints.get() != 0) + modifyCurrentGcwPoints(min, false); + + if (m_currentPvpKills.get() != 0) + modifyCurrentPvpKills(min, false); + + if (currentRating != m_currentGcwRating.get()) + modifyCurrentGcwRating((currentRating - m_currentGcwRating.get()), true); + + // if more recalculations are needed, send + // messageTo to trigger more recalculations + if (moreRecalculationNeeded) + { + m_nextGcwRatingCalcTime = nextCalcInterval; + sendRecalculateGcwRatingMessageTo(5); + } + else + { + // make sure that m_nextGcwRatingCalcTime is set so that the + // rating will be recalculated at the next recalculation interval + m_nextGcwRatingCalcTime = 0; + setNextGcwRatingCalcTime(false); + } + } + else + { + m_nextGcwRatingCalcTime = 0; + } + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::sendRecalculateGcwRatingMessageTo(int delay) +{ + // cancel any pending messageTo + cancelMessageTo("C++RecalculateGcwRating"); + + // send new messageTo + int const adjustedDelay = std::max(5, delay); + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++RecalculateGcwRating", "", adjustedDelay, false); + m_gcwRatingActualCalcTime = static_cast(::time(NULL) + adjustedDelay); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::needsGcwRatingRecalculated() const +{ + Pvp::PvpRankInfo const & pvpRankInfo = Pvp::getRankInfo(m_currentGcwRating.get()); + return ((m_currentGcwPoints.get() > 0) || (m_currentPvpKills.get() > 0) || ((pvpRankInfo.rank > 0) && (pvpRankInfo.ratingDecayBalance > 0))); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::clearSessionActivity() +{ + if (isAuthoritative()) + { + m_sessionActivity = 0; + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_clearSessionActivity, 0); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::addSessionActivity(uint32 activity) +{ + if (isAuthoritative()) + { + m_sessionActivity = m_sessionActivity.get() | activity; + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_addSessionActivity, new MessageQueueGenericValueType(static_cast(activity))); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setPetId(NetworkId const & newId) +{ + m_petId.set(newId); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setPetCommandList(std::vector const &commands) +{ + m_petCommandList.set(commands); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::setPetToggledCommands(std::vector const &commands) +{ + m_petToggledCommands.set(commands); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::updateKillMeter(float deltaTime) +{ + if(!isAuthoritative()) + return; + + if(m_killMeter.get() == 0) + return; + float currentValue = m_killMeter.get() + m_killMeterRemainder; + float newValue = (currentValue) - (m_killMeter.get() / 150.0f) * deltaTime; + int32 newValueInt = static_cast(newValue); + m_killMeterRemainder = (newValue - newValueInt); + if(m_killMeterRemainder > 0.01f) + { + newValueInt += 1; + m_killMeterRemainder -= 1.0f; + } + if(newValueInt != m_killMeter.get()) + m_killMeter = newValueInt; + + return; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::incrementKillMeter(int amount) +{ + if(isAuthoritative()) + { + if(m_killMeter.get() + amount > MAX_KILL_METER) + { + m_killMeter = MAX_KILL_METER; + m_killMeterRemainder = 0.0f; + } + else + { + m_killMeter = m_killMeter.get() + amount; + } + } + else + { + CreatureObject *owner = getCreatureObject(); + owner->sendControllerMessageToAuthServer(CM_incrementKillMeter, new MessageQueueGenericValueType(amount)); + } +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::modifyCollectionSlotValue(std::string const & slotName, int64 delta) +{ + CreatureObject * const owner = getCreatureObject(); + if (!owner) + return false; + + if (isAuthoritative()) + { + CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); + if (!slotInfo) + { + DEBUG_WARNING(true, ("Trying to modify a collection slot for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); + return false; + } + + Archive::AutoDeltaVariable * const collections = m_allCollections[slotInfo->slotIdIndex]; + + // bit-type slot + if (!slotInfo->counterTypeSlot) + { + // set bit-type slot + if (delta > 0) + { + if (!collections->get().testBit(slotInfo->beginSlotId)) + { + // check prereqs first + if (!hasCompletedCollectionSlotPrereq(*slotInfo)) + return false; + + BitArray b = collections->get(); + b.setBit(slotInfo->beginSlotId); + collections->set(b); + + LOG("CustomerService", ("Collection:%s added collection %d (%s/%s/%s/%s)", + getAccountDescription().c_str(), + slotInfo->absoluteBeginSlotId, + slotInfo->collection.page.book.name.c_str(), + slotInfo->collection.page.name.c_str(), + slotInfo->collection.name.c_str(), + slotInfo->name.c_str())); + + // for "server first" tracking, we need to check if the collection + // is completed *BEFORE* triggering script, because script may clear + // a completed collection (for repeatable collections), so that + // when we come back from triggering script, the collection will not + // appear to be completed, even though it really was completed and + // "server first" should have been granted + bool grantServerFirst = false; + if (slotInfo->collection.trackServerFirst && (slotInfo->collection.serverFirstClaimTime <= 0)) + { + bool const isSecuredLogin = (owner->getClient() && owner->getClient()->isGodValidated()); + if (!ConfigServerGame::getDisableCollectionServerFirstGrantForSecuredLogin() || !isSecuredLogin) + { + if (hasCompletedCollection(slotInfo->collection.name)) + { + grantServerFirst = true; + } + } + } + + GameScriptObject * gameScriptObject = owner->getScriptObject(); + if (gameScriptObject && slotInfo->notifyScriptOnModify) + { + ScriptParams params; + params.addParam(slotInfo->collection.page.book.name.c_str()); // book + params.addParam(slotInfo->collection.page.name.c_str()); // page + params.addParam(slotInfo->collection.name.c_str()); // collection + params.addParam(slotInfo->name.c_str()); // slot + params.addParam(false); // is counter-type slot? + params.addParam(static_cast(0)); // previous slot value + params.addParam(static_cast(1)); // current slot value + params.addParam(static_cast(1)); // max slot value + params.addParam(true); // slot completed? + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SLOT_MODIFIED, params)); + } + + // grant "server first", if necessary + if (grantServerFirst) + { + PlanetObject * const planetObject = ServerUniverse::getInstance().getTatooinePlanet(); + if (planetObject) + { + planetObject->setCollectionServerFirst(slotInfo->collection, owner->getNetworkId(), owner->getAssignedObjectName(), getAccountDescription()); + } + } + } + } + // clear bit-type slot + else if (delta < 0) + { + if (collections->get().testBit(slotInfo->beginSlotId)) + { + BitArray b = collections->get(); + b.clearBit(slotInfo->beginSlotId); + collections->set(b); + + LOG("CustomerService", ("Collection:%s removed collection %d (%s/%s/%s/%s)", + getAccountDescription().c_str(), + slotInfo->absoluteBeginSlotId, + slotInfo->collection.page.book.name.c_str(), + slotInfo->collection.page.name.c_str(), + slotInfo->collection.name.c_str(), + slotInfo->name.c_str())); + + GameScriptObject * gameScriptObject = owner->getScriptObject(); + if (gameScriptObject && slotInfo->notifyScriptOnModify) + { + ScriptParams params; + params.addParam(slotInfo->collection.page.book.name.c_str()); // book + params.addParam(slotInfo->collection.page.name.c_str()); // page + params.addParam(slotInfo->collection.name.c_str()); // collection + params.addParam(slotInfo->name.c_str()); // slot + params.addParam(false); // is counter-type slot? + params.addParam(static_cast(1)); // previous slot value + params.addParam(static_cast(0)); // current slot value + params.addParam(static_cast(1)); // max slot value + params.addParam(false); // slot completed? + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SLOT_MODIFIED, params)); + } + } + } + } + // counter-type slot + else if (delta != 0) + { + // check prereqs first + if ((delta > 0) && !hasCompletedCollectionSlotPrereq(*slotInfo)) + return false; + + int64 const currentSlotValue = static_cast(collections->get().getValue(slotInfo->beginSlotId, slotInfo->endSlotId)); + int64 const newSlotValue = clamp(static_cast(0), (currentSlotValue + delta), ((slotInfo->maxSlotValue > 0) ? static_cast(slotInfo->maxSlotValue) : static_cast(slotInfo->maxValueForNumBits))); + + // did slot value changed? + if (currentSlotValue != newSlotValue) + { + BitArray b = collections->get(); + b.setValue(slotInfo->beginSlotId, slotInfo->endSlotId, static_cast(newSlotValue)); + collections->set(b); + + LOG("CustomerService", ("Collection:%s modified collection %d-%d (%s/%s/%s/%s) from %lu to %lu", + getAccountDescription().c_str(), + slotInfo->absoluteBeginSlotId, + slotInfo->absoluteEndSlotId, + slotInfo->collection.page.book.name.c_str(), + slotInfo->collection.page.name.c_str(), + slotInfo->collection.name.c_str(), + slotInfo->name.c_str(), + static_cast(currentSlotValue), + static_cast(newSlotValue))); + + bool const completedCollectionSlot = hasCompletedCollectionSlot(*slotInfo, static_cast(newSlotValue)); + + // for "server first" tracking, we need to check if the collection + // is completed *BEFORE* triggering script, because script may clear + // a completed collection (for repeatable collections), so that + // when we come back from triggering script, the collection will not + // appear to be completed, even though it really was completed and + // "server first" should have been granted + bool grantServerFirst = false; + if (completedCollectionSlot && slotInfo->collection.trackServerFirst && (slotInfo->collection.serverFirstClaimTime <= 0)) + { + bool const isSecuredLogin = (owner->getClient() && owner->getClient()->isGodValidated()); + if (!ConfigServerGame::getDisableCollectionServerFirstGrantForSecuredLogin() || !isSecuredLogin) + { + if (hasCompletedCollection(slotInfo->collection.name)) + { + grantServerFirst = true; + } + } + } + + GameScriptObject * gameScriptObject = owner->getScriptObject(); + if (gameScriptObject && slotInfo->notifyScriptOnModify) + { + ScriptParams params; + params.addParam(slotInfo->collection.page.book.name.c_str()); // book + params.addParam(slotInfo->collection.page.name.c_str()); // page + params.addParam(slotInfo->collection.name.c_str()); // collection + params.addParam(slotInfo->name.c_str()); // slot + params.addParam(true); // is counter-type slot? + params.addParam(static_cast(currentSlotValue)); // previous slot value + params.addParam(static_cast(newSlotValue)); // current slot value + params.addParam(static_cast(slotInfo->maxSlotValue)); // max slot value + params.addParam(completedCollectionSlot); // slot completed? + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_COLLECTION_SLOT_MODIFIED, params)); + } + + // grant "server first", if necessary + if (grantServerFirst) + { + PlanetObject * const planetObject = ServerUniverse::getInstance().getTatooinePlanet(); + if (planetObject) + { + planetObject->setCollectionServerFirst(slotInfo->collection, owner->getNetworkId(), owner->getAssignedObjectName(), getAccountDescription()); + } + } + } + } + } + else + { + owner->sendControllerMessageToAuthServer(CM_modifyCollectionSlotValue, new MessageQueueGenericValueType >(std::make_pair(slotName, delta))); + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::getCollectionSlotValue(std::string const & slotName, unsigned long & value) const +{ + value = 0; + + CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); + if (!slotInfo) + { + DEBUG_WARNING(true, ("Trying to get a collection slot value for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); + return false; + } + + return getCollectionSlotValue(*slotInfo, value); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::getCollectionSlotValue(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long & value) const +{ + // bit-type slot + if (!slotInfo.counterTypeSlot) + { + if (m_allCollections[slotInfo.slotIdIndex]->get().testBit(slotInfo.beginSlotId)) + value = 1; + else + value = 0; + } + else + { + value = m_allCollections[slotInfo.slotIdIndex]->get().getValue(slotInfo.beginSlotId, slotInfo.endSlotId); + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollectionSlotPrereq(std::string const & slotName, std::vector * collectionInfo /*= NULL*/) const +{ + CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); + if (!slotInfo) + { + DEBUG_WARNING(true, ("Checking for collection slot prereq completion for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); + return false; + } + + return hasCompletedCollectionSlotPrereq(*slotInfo, collectionInfo); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollectionSlotPrereq(CollectionsDataTable::CollectionInfoSlot const & slotInfo, std::vector * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + if (slotInfo.prereqsPtr.empty()) + return true; + + bool completed = true; + for (std::vector::const_iterator iterPrereqs = slotInfo.prereqsPtr.begin(); iterPrereqs != slotInfo.prereqsPtr.end(); ++iterPrereqs) + { + if (!hasCompletedCollectionSlot(**iterPrereqs)) + { + if (!collectionInfo) + return false; + + collectionInfo->push_back(*iterPrereqs); + completed = false; + } + } + + return completed; +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollectionSlot(std::string const & slotName) const +{ + CollectionsDataTable::CollectionInfoSlot const * slotInfo = CollectionsDataTable::getSlotByName(slotName); + if (!slotInfo) + { + DEBUG_WARNING(true, ("Checking for collection slot completion for (%s) using an invalid collection slot name (%s)", getAccountDescription().c_str(), slotName.c_str())); + return false; + } + + return hasCompletedCollectionSlot(*slotInfo); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo) const +{ + // bit-type slot + if (!slotInfo.counterTypeSlot) + return m_allCollections[slotInfo.slotIdIndex]->get().testBit(slotInfo.beginSlotId); + + // counter-type slot is only completed if a max slot value is + // specified and the current slot value equals the max slot value + return ((slotInfo.maxSlotValue > 0) && (m_allCollections[slotInfo.slotIdIndex]->get().getValue(slotInfo.beginSlotId, slotInfo.endSlotId) >= slotInfo.maxSlotValue)); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long slotValue) +{ + // bit-type slot + if (!slotInfo.counterTypeSlot) + return (slotValue > 0); + + // counter-type slot is only completed if a max slot value is + // specified and the current slot value equals the max slot value + return ((slotInfo.maxSlotValue > 0) && (slotValue >= slotInfo.maxSlotValue)); +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollection(std::string const & collectionName) const +{ + std::vector const & slots = CollectionsDataTable::getSlotsInCollection(collectionName); + + if (slots.empty()) + return false; + + for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) + { + if (!hasCompletedCollectionSlot(**iter)) + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollectionPage(std::string const & pageName) const +{ + std::vector const & collections = CollectionsDataTable::getCollectionsInPage(pageName); + + if (collections.empty()) + return false; + + for (std::vector::const_iterator iter = collections.begin(); iter != collections.end(); ++iter) + { + if (!hasCompletedCollection((*iter)->name)) + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::hasCompletedCollectionBook(std::string const & bookName) const +{ + std::vector const & pages = CollectionsDataTable::getPagesInBook(bookName); + + if (pages.empty()) + return false; + + for (std::vector::const_iterator iter = pages.begin(); iter != pages.end(); ++iter) + { + if (!hasCompletedCollectionPage((*iter)->name)) + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getCompletedCollectionSlotCountInCollection(std::string const & collectionName, stdvector::fwd * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + int count = 0; + std::vector const & slots = CollectionsDataTable::getSlotsInCollection(collectionName); + for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) + { + if (hasCompletedCollectionSlot(**iter)) + { + ++count; + + if (collectionInfo) + collectionInfo->push_back(*iter); + } + } + + return count; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getCompletedCollectionSlotCountInPage(std::string const & pageName, std::vector * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + int count = 0; + std::vector const & slots = CollectionsDataTable::getSlotsInPage(pageName); + for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) + { + if (hasCompletedCollectionSlot(**iter)) + { + ++count; + + if (collectionInfo) + collectionInfo->push_back(*iter); + } + } + + return count; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getCompletedCollectionCountInPage(std::string const & pageName, std::vector * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + int count = 0; + std::vector const & collections = CollectionsDataTable::getCollectionsInPage(pageName); + for (std::vector::const_iterator iter = collections.begin(); iter != collections.end(); ++iter) + { + if (hasCompletedCollection((*iter)->name)) + { + ++count; + + if (collectionInfo) + collectionInfo->push_back(*iter); + } + } + + return count; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getCompletedCollectionSlotCountInBook(std::string const & bookName, std::vector * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + int count = 0; + std::vector const & slots = CollectionsDataTable::getSlotsInBook(bookName); + for (std::vector::const_iterator iter = slots.begin(); iter != slots.end(); ++iter) + { + if (hasCompletedCollectionSlot(**iter)) + { + ++count; + + if (collectionInfo) + collectionInfo->push_back(*iter); + } + } + + return count; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getCompletedCollectionCountInBook(std::string const & bookName, std::vector * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + int count = 0; + std::vector const & collections = CollectionsDataTable::getCollectionsInBook(bookName); + for (std::vector::const_iterator iter = collections.begin(); iter != collections.end(); ++iter) + { + if (hasCompletedCollection((*iter)->name)) + { + ++count; + + if (collectionInfo) + collectionInfo->push_back(*iter); + } + } + + return count; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getCompletedCollectionPageCountInBook(std::string const & bookName, std::vector * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + int count = 0; + std::vector const & pages = CollectionsDataTable::getPagesInBook(bookName); + for (std::vector::const_iterator iter = pages.begin(); iter != pages.end(); ++iter) + { + if (hasCompletedCollectionPage((*iter)->name)) + { + ++count; + + if (collectionInfo) + collectionInfo->push_back(*iter); + } + } + + return count; +} + +// ---------------------------------------------------------------------- + +int PlayerObject::getCompletedCollectionBookCount(std::vector * collectionInfo /*= NULL*/) const +{ + if (collectionInfo) + collectionInfo->clear(); + + int count = 0; + std::vector const & books = CollectionsDataTable::getAllBooks(); + for (std::vector::const_iterator iter = books.begin(); iter != books.end(); ++iter) + { + if (hasCompletedCollectionBook((*iter)->name)) + { + ++count; + + if (collectionInfo) + collectionInfo->push_back(*iter); + } + } + + return count; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::migrateLegacyBadgesToCollection(std::vector const & badges) +{ + if (badges.empty()) + return; + + // get the list of all possible collection id for the old badges + static std::map badgeCollectionIds; + if (badgeCollectionIds.empty()) + { + std::vector const & badgeCollectionInfo = CollectionsDataTable::getSlotsInBook("badge_book"); + for (std::vector::const_iterator iter = badgeCollectionInfo.begin(); iter != badgeCollectionInfo.end(); ++iter) + { + if ((*iter)->slotIdIndex == 0) + { + badgeCollectionIds[(*iter)->absoluteBeginSlotId] = *iter; + } + } + } + + BitArray ba = m_collections.get(); + bool anyBadgeMigrated = false; + + char buffer[32]; + std::string badgesString; + CollectionsDataTable::CollectionInfoSlot const * slotInfo; + int badgeIndex = 0; + for (std::vector::const_iterator iter = badges.begin(); iter != badges.end(); ++iter) + { + // for CS logging + snprintf(buffer, sizeof(buffer)-1, "%d", *iter); + buffer[sizeof(buffer)-1] = '\0'; + if (!badgesString.empty()) + badgesString += ", "; + badgesString += buffer; + + for (int i = 0; i < 32; ++i) + { + if (((*iter & (1 << i)) != 0) && (badgeCollectionIds.count(badgeIndex) >= 1) && (!ba.testBit(badgeIndex))) + { + anyBadgeMigrated = true; + ba.setBit(badgeIndex); + + slotInfo = badgeCollectionIds[badgeIndex]; + if (slotInfo) + { + LOG("CustomerService", ("Collection:%s migrated badge to collection %d (%s/%s/%s/%s)", + getAccountDescription().c_str(), + badgeIndex, + slotInfo->collection.page.book.name.c_str(), + slotInfo->collection.page.name.c_str(), + slotInfo->collection.name.c_str(), + slotInfo->name.c_str())); + } + else + { + LOG("CustomerService", ("Collection:%s migrated badge to collection %d", + getAccountDescription().c_str(), + badgeIndex)); + } + } + + ++badgeIndex; + } + } + + if (anyBadgeMigrated) + m_collections.set(ba); + + // CS log the badge objvars so we have a record of badges that were migrated + if (!badgesString.empty()) + LOG("CustomerService", ("Collection:%s migrated legacy badges (%s) over to collection system", getAccountDescription().c_str(), badgesString.c_str())); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::updateChatSpamSpatialNumCharacters(NetworkId const & character, int spatialNumCharacters) +{ + if (!isAuthoritative()) + return; + + int const timeNow = static_cast(::time(NULL)); + bool syncChatServer = false; + + // new interval, reset + if (timeNow > m_chatSpamTimeEndInterval.get()) + { + m_chatSpamTimeEndInterval = timeNow + (ConfigServerGame::getChatSpamLimiterIntervalMinutes() * 60); + m_chatSpamSpatialNumCharacters = spatialNumCharacters; + m_chatSpamNonSpatialNumCharacters = 0; + syncChatServer = true; + } + // update spatial character count + else + { + m_chatSpamSpatialNumCharacters = m_chatSpamSpatialNumCharacters.get() + spatialNumCharacters; + } + + // sync chat character count with chat server + if ((syncChatServer) || (timeNow > m_chatSpamNextTimeToSyncWithChatServer.get())) + { + time_t timeUnsquelch = static_cast(getSecondsUntilUnsquelched()); + if (timeUnsquelch > 0) + timeUnsquelch += ::time(NULL); + + GenericValueTypeMessage, int>, std::pair > > chatStatistics("ChatStatisticsGS", std::make_pair(std::make_pair(std::make_pair(character, static_cast(timeUnsquelch)), m_chatSpamTimeEndInterval.get()), std::make_pair(m_chatSpamSpatialNumCharacters.get(), m_chatSpamNonSpatialNumCharacters.get()))); + Chat::sendToChatServer(chatStatistics); + m_chatSpamNextTimeToSyncWithChatServer = timeNow + ConfigServerGame::getChatStatisticsReportIntervalSeconds(); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::handleChatStatisticsFromChatServer(NetworkId const & character, int chatSpamTimeEndInterval, int spatialNumCharacters, int nonSpatialNumCharacters) +{ + if (!isAuthoritative()) + return; + + int const timeNow = static_cast(::time(NULL)); + bool syncChatServer = false; + + // new interval, reset + if (timeNow > m_chatSpamTimeEndInterval.get()) + { + m_chatSpamTimeEndInterval = timeNow + (ConfigServerGame::getChatSpamLimiterIntervalMinutes() * 60); + m_chatSpamSpatialNumCharacters = 0; + m_chatSpamNonSpatialNumCharacters = 0; + syncChatServer = true; + } + // chat server is in sync with us, update non-spatial + // character count with value from chat server + else if (chatSpamTimeEndInterval == m_chatSpamTimeEndInterval.get()) + { + m_chatSpamNonSpatialNumCharacters = nonSpatialNumCharacters; + } + // chat server is out of sync, ignore data, and resync with chat server + else + { + syncChatServer = true; + } + + // sync chat character count with chat server + if (syncChatServer || ((spatialNumCharacters != m_chatSpamSpatialNumCharacters.get()) && (timeNow > m_chatSpamNextTimeToSyncWithChatServer.get()))) + { + time_t timeUnsquelch = static_cast(getSecondsUntilUnsquelched()); + if (timeUnsquelch > 0) + timeUnsquelch += ::time(NULL); + + GenericValueTypeMessage, int>, std::pair > > chatStatistics("ChatStatisticsGS", std::make_pair(std::make_pair(std::make_pair(character, static_cast(timeUnsquelch)), m_chatSpamTimeEndInterval.get()), std::make_pair(m_chatSpamSpatialNumCharacters.get(), m_chatSpamNonSpatialNumCharacters.get()))); + Chat::sendToChatServer(chatStatistics); + m_chatSpamNextTimeToSyncWithChatServer = timeNow + ConfigServerGame::getChatStatisticsReportIntervalSeconds(); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::updateCitizenshipInfo() +{ + if (!isAuthoritative()) + return; + + CreatureObject const * const owner = getCreatureObject(); + if (!owner) + return; + + std::string cityName; + int8 citizenType = static_cast(CityDataCitizenType::NotACitizen); + + std::vector const & cityIds = CityInterface::getCitizenOfCityId(owner->getNetworkId()); + if (!cityIds.empty()) + { + int const cityId = cityIds.front(); + CityInfo const & cityInfo = CityInterface::getCityInfo(cityId); + cityName = cityInfo.getCityName(); + if (!cityName.empty()) + { + if (owner->getNetworkId() == cityInfo.getLeaderId()) + citizenType = static_cast(CityDataCitizenType::Mayor); + else if (CityInterface::isCityMilitia(cityId, owner->getNetworkId())) + citizenType = static_cast(CityDataCitizenType::Militia); + else + citizenType = static_cast(CityDataCitizenType::Citizen); + } + } + + if (m_citizenshipCity.get() != cityName) + m_citizenshipCity = cityName; + + if (m_citizenshipType.get() != citizenType) + m_citizenshipType = citizenType; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::updateGcwRegionInfo() +{ + if (!isAuthoritative()) + return; + + CreatureObject const * const owner = getCreatureObject(); + if (!owner) + return; + + std::string const & sceneId = ServerWorld::getSceneId(); + Vector const pos = owner->findPosition_w(); + std::string const * currentGcwRegion = &(Pvp::getGcwScoreCategoryRegion(sceneId, pos)); + if (currentGcwRegion->empty()) + { + // if not in a GCW contested region, use the default region + Pvp::GcwScoreCategory const * const defaultGcwRegion = Pvp::getGcwScoreDefaultCategoryForPlanet(sceneId); + if (defaultGcwRegion) + currentGcwRegion = &(defaultGcwRegion->categoryName); + } + + // set the GCW region the character is currently in + m_currentGcwRegion.set(*currentGcwRegion); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::updateGcwDefenderRegionInfo() +{ + if (!isAuthoritative()) + return; + + CreatureObject const * const owner = getCreatureObject(); + if (!owner) + return; + + int timeQualifyForBonus = -1; + bool qualifyForWarPlannerTitle = false; + + std::string cityGcwDefenderRegion; + bool cityGcwDefenderRegionHasBonus = false;; + bool cityGcwDefenderRegionHasTitle = false;; + + std::vector const & cityIds = CityInterface::getCitizenOfCityId(owner->getNetworkId()); + if (!cityIds.empty()) + { + CityInfo const & cityInfo = CityInterface::getCityInfo(cityIds.front()); + uint32 const cityFaction = cityInfo.getFaction(); + + // mayor who is same aligned with his aligned city can use the "War Planner" title + if (!PvpData::isNeutralFactionId(cityFaction) && (cityFaction == owner->getPvpFaction()) && (cityInfo.getLeaderId() == owner->getNetworkId())) + qualifyForWarPlannerTitle = true; + + std::string const & gcwDefenderRegion = cityInfo.getGcwDefenderRegion(); + if (!gcwDefenderRegion.empty()) + { + cityGcwDefenderRegion = gcwDefenderRegion; + + int const timeJoinedGcwDefenderRegion = cityInfo.getTimeJoinedGcwDefenderRegion(); + timeQualifyForBonus = static_cast(::time(NULL)) - (ConfigServerGame::getGcwDaysRequiredForGcwRegionDefenderBonus() * 86400); + if (!PvpData::isNeutralFactionId(cityFaction) && (cityFaction == owner->getPvpFaction()) && (timeJoinedGcwDefenderRegion < timeQualifyForBonus)) + { + cityGcwDefenderRegionHasBonus = true; + + int regionPercentileScore = 0; + if (PvpData::isImperialFactionId(cityFaction)) + regionPercentileScore = ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); + else if (PvpData::isRebelFactionId(cityFaction)) + regionPercentileScore = 100 - ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); + + // title is available once the region is 70% controlled + if (regionPercentileScore >= 70) + cityGcwDefenderRegionHasTitle = true; + } + } + } + + std::string guildGcwDefenderRegion; + bool guildGcwDefenderRegionHasBonus = false;; + bool guildGcwDefenderRegionHasTitle = false;; + + int const guildId = owner->getGuildId(); + if (guildId > 0) + { + GuildInfo const * const gi = GuildInterface::getGuildInfo(guildId); + if (gi) + { + uint32 const guildFaction = GuildInterface::getGuildCurrentFaction(*gi); + + // guild leader who is same aligned with his aligned guild that meets the + // minimum guild member count requirement can use the "War Planner" title + if (!PvpData::isNeutralFactionId(guildFaction) && (guildFaction == owner->getPvpFaction()) && (gi->m_leaderId == owner->getNetworkId()) && (gi->getCountMembersOnly() >= ConfigServerGame::getGcwGuildMinMembersForGcwRegionDefender())) + qualifyForWarPlannerTitle = true; + + std::string const & gcwDefenderRegion = GuildInterface::getGuildCurrentGcwDefenderRegion(*gi); + if (!gcwDefenderRegion.empty()) + { + guildGcwDefenderRegion = gcwDefenderRegion; + + int const timeJoinedGcwDefenderRegion = GuildInterface::getTimeJoinedGuildCurrentGcwDefenderRegion(*gi); + if (timeQualifyForBonus < 0) + timeQualifyForBonus = static_cast(::time(NULL)) - (ConfigServerGame::getGcwDaysRequiredForGcwRegionDefenderBonus() * 86400); + + if (!PvpData::isNeutralFactionId(guildFaction) && (guildFaction == owner->getPvpFaction()) && (timeJoinedGcwDefenderRegion < timeQualifyForBonus)) + { + guildGcwDefenderRegionHasBonus = true; + + int regionPercentileScore = 0; + if (PvpData::isImperialFactionId(guildFaction)) + regionPercentileScore = ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); + else if (PvpData::isRebelFactionId(guildFaction)) + regionPercentileScore = 100 - ServerUniverse::getInstance().getGcwImperialScorePercentile(gcwDefenderRegion); + + // title is available once the region is 70% controlled + if (regionPercentileScore >= 70) + guildGcwDefenderRegionHasTitle = true; + } + } + } + } + + m_cityGcwDefenderRegion.set(std::make_pair(cityGcwDefenderRegion, std::make_pair(cityGcwDefenderRegionHasBonus, cityGcwDefenderRegionHasTitle))); + m_guildGcwDefenderRegion.set(std::make_pair(guildGcwDefenderRegion, std::make_pair(guildGcwDefenderRegionHasBonus, guildGcwDefenderRegionHasTitle))); + + // clear title if not qualified + { + std::string const & currentTitle = getTitle(); + if (currentTitle == "city_gcw_region_defender") + { + if (cityGcwDefenderRegion.empty() || !cityGcwDefenderRegionHasTitle) + setTitle(std::string()); + } + else if (currentTitle == "guild_gcw_region_defender") + { + if (guildGcwDefenderRegion.empty() || !guildGcwDefenderRegionHasTitle) + setTitle(std::string()); + } + } + + // grant/clear "War Planner" title + { + std::string const & currentTitle = getTitle(); + if (qualifyForWarPlannerTitle) + { + if (PvpData::isImperialFactionId(owner->getPvpFaction())) + { + modifyCollectionSlotValue("imperial_gcw_war_planner", 1ll); + modifyCollectionSlotValue("rebel_gcw_war_planner", -1ll); + + if (currentTitle == "rebel_gcw_war_planner") + setTitle("imperial_gcw_war_planner"); + } + else if (PvpData::isRebelFactionId(owner->getPvpFaction())) + { + modifyCollectionSlotValue("imperial_gcw_war_planner", -1ll); + modifyCollectionSlotValue("rebel_gcw_war_planner", 1ll); + + if (currentTitle == "imperial_gcw_war_planner") + setTitle("rebel_gcw_war_planner"); + } + else + { + modifyCollectionSlotValue("imperial_gcw_war_planner", -1ll); + modifyCollectionSlotValue("rebel_gcw_war_planner", -1ll); + + if ((currentTitle == "imperial_gcw_war_planner") || (currentTitle == "rebel_gcw_war_planner")) + setTitle(std::string()); + } + } + else + { + modifyCollectionSlotValue("imperial_gcw_war_planner", -1ll); + modifyCollectionSlotValue("rebel_gcw_war_planner", -1ll); + + if ((currentTitle == "imperial_gcw_war_planner") || (currentTitle == "rebel_gcw_war_planner")) + setTitle(std::string()); + } + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::squelch(NetworkId const & squelchedById, std::string const & squelchedByName, int squelchDurationSeconds) +{ + if (isAuthoritative()) + { + m_squelchedById = squelchedById; + m_squelchedByName = squelchedByName; + + // persist squelch info + setObjVarItem(OBJVAR_SQUELCH_ID, squelchedById); + setObjVarItem(OBJVAR_SQUELCH_NAME, squelchedByName); + + if (squelchDurationSeconds < 0) + { + m_squelchExpireTime = -1; + + // persist squelch info + setObjVarItem(OBJVAR_SQUELCH_EXPIRE, -1); + } + else + { + m_squelchExpireTime = static_cast(::time(NULL)) + squelchDurationSeconds; + + // persist squelch info + setObjVarItem(OBJVAR_SQUELCH_EXPIRE, static_cast(ServerClock::getInstance().getGameTimeSeconds()) + squelchDurationSeconds); + } + + // update chat server + CreatureObject * const owner = getCreatureObject(); + if (owner) + { + GenericValueTypeMessage > setUnsquelchTime("SetUnsquelchTime", std::make_pair(owner->getNetworkId(), static_cast(m_squelchExpireTime.get()))); + Chat::sendToChatServer(setUnsquelchTime); + } + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_squelch, new MessageQueueGenericValueType > >(std::make_pair(squelchedByName, std::make_pair(squelchedById, squelchDurationSeconds)))); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::unsquelch() +{ + if (isAuthoritative()) + { + m_squelchedById = NetworkId::cms_invalid; + m_squelchedByName = std::string(); + m_squelchExpireTime = 0; + + // persist squelch info + removeObjVarItem(OBJVAR_SQUELCH_ID); + removeObjVarItem(OBJVAR_SQUELCH_NAME); + removeObjVarItem(OBJVAR_SQUELCH_EXPIRE); + + // update chat server + CreatureObject * const owner = getCreatureObject(); + if (owner) + { + GenericValueTypeMessage > setUnsquelchTime("SetUnsquelchTime", std::make_pair(owner->getNetworkId(), 0)); + Chat::sendToChatServer(setUnsquelchTime); + } + } + else + { + CreatureObject * const owner = getCreatureObject(); + if (owner) + owner->sendControllerMessageToAuthServer(CM_unsquelch, NULL); + } +} + +// ---------------------------------------------------------------------- +// returns 0 if not currently squelched; returns < 0 if indefinitely squelched +int PlayerObject::getSecondsUntilUnsquelched() +{ + // not squelched + if (!m_squelchedById.get().isValid()) + return 0; + + // squelched, but need to check to see if the squelch period has already expired + if (m_squelchExpireTime.get() < 0) // squelched indefinitely + return -1; + + int32 const timeNow = static_cast(::time(NULL)); + if (timeNow < m_squelchExpireTime.get()) // still in squelch period + return (m_squelchExpireTime.get() - timeNow); + + // squelch has expired + if (isAuthoritative()) + { + m_squelchedById = NetworkId::cms_invalid; + m_squelchedByName = std::string(); + m_squelchExpireTime = 0; + + // persist squelch info + removeObjVarItem(OBJVAR_SQUELCH_ID); + removeObjVarItem(OBJVAR_SQUELCH_NAME); + removeObjVarItem(OBJVAR_SQUELCH_EXPIRE); + } + return 0; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyShowBackpack(bool b) +{ + if(m_showBackpack.get() != b) + m_showBackpack = b; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::modifyShowHelmet(bool b) +{ + if(m_showHelmet.get () != b) + m_showHelmet = b; +} + +void PlayerObject::setEnvironmentFlags(EnvironmentInfo const & flags) +{ + m_environmentFlags = flags; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::toggleOutOfCharacter() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_outOfCharacter); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + +// ---------------------------------------------------------------------- + +void PlayerObject::toggleLookingForWork() +{ + if (isAuthoritative()) + { + MatchMakingId matchMakingId(m_matchMakingCharacterProfileId.get()); + + matchMakingId.toggleBit(MatchMakingId::B_lookingForWork); + + setMatchMakingCharacterProfileId(matchMakingId); + } +} + + +// ---------------------------------------------------------------------- + +void PlayerObject::setAccountNumLotsOverLimitSpam() +{ + if (!isAuthoritative()) + return; + + // if over the lot limit, spam warning; otherwise, if no + // longer over the lot limit, remove lot over limit restriction + CreatureObject * const owner = getCreatureObject(); + if (!owner) + return; + + if (m_accountNumLots.get() > owner->getMaxNumberOfLots()) + { + if (owner->getObjVars().hasItem("lotOverlimit")) + { + m_accountNumLotsOverLimitSpam = m_accountNumLots.get() - owner->getMaxNumberOfLots(); + + int const timeNow = static_cast(::time(NULL)); + int violationTime = 0; + if (!owner->getObjVars().getItem("lotOverlimit.violation_time", violationTime)) + { + violationTime = timeNow; + IGNORE_RETURN(owner->setObjVarItem("lotOverlimit.violation_time", violationTime)); + } + + if (owner->getClient()) + { + // spam once every 5 minutes for 24 hours after the violation, then once every minute after that + bool shouldSpam = true; + if ((violationTime + 86400) >= timeNow) + { + int timeLastSpam = 0; + if (owner->getObjVars().getItem("lotOverlimit.last_spam_time", timeLastSpam) && ((timeLastSpam + 300) >= timeNow)) + shouldSpam = false; + + if (shouldSpam) + IGNORE_RETURN(owner->setObjVarItem("lotOverlimit.last_spam_time", timeNow)); + } + else + { + // over 24 hours after violation, spam every minute (i.e. each time this messageTo fires) + owner->removeObjVarItem("lotOverlimit.last_spam_time"); + } + + if (shouldSpam) + { + Chat::sendSystemMessage(*owner, Unicode::narrowToWide("!!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!!"), Unicode::emptyString); + Chat::sendSystemMessage(*owner, Unicode::narrowToWide(FormattedString<256>().sprintf("YOU ARE %d LOTS OVER THE LOT LIMIT!!!", m_accountNumLotsOverLimitSpam.get())), Unicode::emptyString); + + std::string lotOverlimitStructureName; + std::string lotOverlimitStructureLocation; + IGNORE_RETURN(owner->getObjVars().getItem("lotOverlimit.structure_name", lotOverlimitStructureName)); + IGNORE_RETURN(owner->getObjVars().getItem("lotOverlimit.structure_location", lotOverlimitStructureLocation)); + Chat::sendSystemMessage(*owner, Unicode::narrowToWide(FormattedString<256>().sprintf("THE %s STRUCTURE LOCATED AT %s CAUSED YOU TO EXCEED THE LOT LIMIT!!!", lotOverlimitStructureName.c_str(), lotOverlimitStructureLocation.c_str())), Unicode::emptyString); + + Chat::sendSystemMessage(*owner, Unicode::narrowToWide("!!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!!"), Unicode::emptyString); + } + } + } + else + { + // over the limit, but we shouldn't spam + m_accountNumLotsOverLimitSpam = 0; + } + } + else + { + m_accountNumLotsOverLimitSpam = 0; + owner->removeObjVarItem("lotOverlimit"); + } +} + +// ---------------------------------------------------------------------- + +bool PlayerObject::canAccessGalacticReserve(real x, real z) +{ + // must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve + std::string const & sceneId = ServerWorld::getSceneId(); + if ((sceneId != "tatooine") && (sceneId != "naboo") && (sceneId != "corellia")) + return false; + + std::vector result; + RegionMaster::getRegionsAtPoint(sceneId, x, z, result); + if (result.empty()) + return false; + + static Unicode::String const regionMosEisley = Unicode::narrowToWide("@tatooine_region_names:mos_eisley"); + static Unicode::String const regionTheed = Unicode::narrowToWide("@naboo_region_names:theed"); + static Unicode::String const regionCoronet = Unicode::narrowToWide("@corellia_region_names:coronet"); + static uint32 const hashMosEisley = Crc::calculate(regionMosEisley.c_str(), regionMosEisley.length()*2); + static uint32 const hashTheed = Crc::calculate(regionTheed.c_str(), regionTheed.length()*2); + static uint32 const hashCoronet = Crc::calculate(regionCoronet.c_str(), regionCoronet.length()*2); + + for(std::vector::iterator it = result.begin(); it != result.end(); ++it) + { + if (((sceneId == "tatooine") && ((*it)->getNameCrc() == hashMosEisley)) || + ((sceneId == "naboo") && ((*it)->getNameCrc() == hashTheed)) || + ((sceneId == "corellia") && ((*it)->getNameCrc() == hashCoronet))) + { + return true; + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +void PlayerObject::depositToGalacticReserve(bool ignoreCooldownAndLocationCheck) +{ + if (!isAuthoritative()) + return; + + CreatureObject * const co = getCreatureObject(); + if (!co) + return; + + Client const * const c = co->getClient(); + if (c && c->isFreeTrialAccount()) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide("Trial account cannot access the Galactic Reserve."), Unicode::emptyString); + return; + } + + bool const isGod = (c && c->isGod()); + + // check for cooldown + if (!isGod && !ignoreCooldownAndLocationCheck) + { + int cooldown; + if (co->getObjVars().getItem("galactic_reserve_cooldown", cooldown)) + { + int const timeNow = static_cast(ServerClock::getInstance().getGameTimeSeconds()); + if (cooldown > timeNow) + { + if (c) + Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %s before you can access the Galactic Reserve again.", CalendarTime::convertSecondsToMS(static_cast(cooldown - timeNow)).c_str())), Unicode::emptyString); + + return; + } + } + } + + // must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve + if (!ignoreCooldownAndLocationCheck) + { + Vector const positionW = co->getPosition_w(); + if (!canAccessGalacticReserve(positionW.x, positionW.z)) + { + if (c) + Chat::sendSystemMessage(*co, Unicode::narrowToWide("You must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve."), Unicode::emptyString); + + return; + } + } + + if (static_cast(m_galacticReserveDeposit.get()) >= ConfigServerGame::getMaxGalacticReserveDepositBillion()) + { + if (c) + Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("You already have the maximum %d billion credits in the Galactic Reserve.", ConfigServerGame::getMaxGalacticReserveDepositBillion())), Unicode::emptyString); + + return; + } + + // transfer as much cash as necessary into bank to get 1 billion in bank + int amountToTransferToBank = 1000000000 - co->getBankBalance(); + if (amountToTransferToBank > co->getCashBalance()) + { + if (c) + Chat::sendSystemMessage(*co, Unicode::narrowToWide("You do not currently have 1 billion credits to deposit to the Galactic Reserve."), Unicode::emptyString); + + return; + } + + if (amountToTransferToBank > 0) + { + co->depositCashToBank(amountToTransferToBank); + } + + // final sanity check to make sure there's 1 billion in the bank + if (co->getBankBalance() < 1000000000) + { + if (c) + Chat::sendSystemMessage(*co, Unicode::narrowToWide("You do not currently have 1 billion credits to deposit to the Galactic Reserve."), Unicode::emptyString); + + return; + } + + // do the transfer + if (!co->transferBankCreditsTo("galactic_reserve", 1000000000)) + { + if (c) + Chat::sendSystemMessage(*co, Unicode::narrowToWide("Failed to transfer 1 billion credits to the Galactic Reserve."), Unicode::emptyString); + + return; + } + + // update reserve balance + m_galacticReserveDeposit = m_galacticReserveDeposit.get() + 1; + co->setObjVarItem("galactic_reserve", static_cast(m_galacticReserveDeposit.get())); + + // set cooldown (15 minutes) + if (!ignoreCooldownAndLocationCheck) + { + co->setObjVarItem("galactic_reserve_cooldown", static_cast(ServerClock::getInstance().getGameTimeSeconds() + (15 * 60))); + } + + // display confirmation message + if (c) + Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("1 billion credits have been deposited to the Galactic Reserve. Your new Galactic Reserve balance is %d billion credits.", m_galacticReserveDeposit.get())), Unicode::emptyString); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::withdrawFromGalacticReserve() +{ + if (!isAuthoritative()) + return; + + CreatureObject * const co = getCreatureObject(); + if (!co) + return; + + Client const * const c = co->getClient(); + if (!c) + return; + + if (c->isFreeTrialAccount()) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide("Trial account cannot access the Galactic Reserve."), Unicode::emptyString); + return; + } + + // check for cooldown + if (!c->isGod()) + { + int cooldown; + if (co->getObjVars().getItem("galactic_reserve_cooldown", cooldown)) + { + int const timeNow = static_cast(ServerClock::getInstance().getGameTimeSeconds()); + if (cooldown > timeNow) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("You must wait %s before you can access the Galactic Reserve again.", CalendarTime::convertSecondsToMS(static_cast(cooldown - timeNow)).c_str())), Unicode::emptyString); + return; + } + } + } + + // must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve + Vector const positionW = co->getPosition_w(); + if (!canAccessGalacticReserve(positionW.x, positionW.z)) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide("You must be at a bank terminal in Mos Eisley, Theed, or Coronet to access the Galactic Reserve."), Unicode::emptyString); + return; + } + + if (m_galacticReserveDeposit.get() <= 0) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide("You do not have any deposit in the Galactic Reserve to withdraw."), Unicode::emptyString); + return; + } + + // move all the bank to cash to make room to receive the 1 billion into the bank + if (co->getBankBalance() > 0) + { + if ((co->getCashBalance() + co->getBankBalance()) > ConfigServerGame::getMaxMoney()) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide("Withdrawing 1 billion credits from the Galactic Reserve would cause your cash/bank balance to exceed the maximum balance limit."), Unicode::emptyString); + return; + } + + co->withdrawCashFromBank(co->getBankBalance()); + } + + // final sanity check to make sure the bank is empty to receive the 1 billion + if (co->getBankBalance() > 0) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide("Withdrawing 1 billion credits from the Galactic Reserve would cause your cash/bank balance to exceed the maximum balance limit."), Unicode::emptyString); + return; + } + + // do the transfer + if (!co->transferBankCreditsFrom("galactic_reserve", 1000000000)) + { + Chat::sendSystemMessage(*co, Unicode::narrowToWide("Failed to withdraw 1 billion credits from the Galactic Reserve."), Unicode::emptyString); + return; + } + + // update reserve balance + m_galacticReserveDeposit = m_galacticReserveDeposit.get() - 1; + if (m_galacticReserveDeposit.get() > 0) + co->setObjVarItem("galactic_reserve", static_cast(m_galacticReserveDeposit.get())); + else + co->removeObjVarItem("galactic_reserve"); + + // set cooldown (15 minutes) + co->setObjVarItem("galactic_reserve_cooldown", static_cast(ServerClock::getInstance().getGameTimeSeconds() + (15 * 60))); + + // display confirmation message + Chat::sendSystemMessage(*co, Unicode::narrowToWide(FormattedString<1024>().sprintf("1 billion credits have been withdrawn from the Galactic Reserve. Your new Galactic Reserve balance is %d billion credits.", m_galacticReserveDeposit.get())), Unicode::emptyString); +} + +// ---------------------------------------------------------------------- + +void PlayerObject::depersistGalacticReserveDeposit() +{ + if (!isAuthoritative()) + return; + + m_galacticReserveDeposit = 0; + + CreatureObject const * const co = getCreatureObject(); + if (!co) + return; + + // depersist galactic reserve + int temp; + if (co->getObjVars().getItem("galactic_reserve", temp)) + m_galacticReserveDeposit = static_cast(temp); +} + +// ---------------------------------------------------------------------- + +void PlayerObjectNamespace::checkAndSetCharacterAgeTitle(PlayerObject & player, bool thoroughCheck) +{ + static std::vector s_vectorCharacterAgeTitle; + if (s_vectorCharacterAgeTitle.empty()) + { + // we'll exit this loop as soon as we don't find the "next" character age title collection slot + for (int i = 1; i <= 1000000; ++i) + { + CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(FormattedString<128>().sprintf("character_age_%dyr", i)); + if (!collectionSlot) + break; + + FATAL((collectionSlot->collection.name != std::string("character_age_collection")), ("collection slot %s must be in collection character_age_collection", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.name != std::string("character_age_page")), ("collection slot %s must be in collection page character_age_page", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.book.name != std::string("character_age_book")), ("collection slot %s must be in collection book character_age_book", collectionSlot->name.c_str())); + + s_vectorCharacterAgeTitle.push_back(collectionSlot); + } + } + + int const ageInYears = ((player.getBornDate() > 0) ? (player.getAgeInDays() / 365) : 0); + + if (!thoroughCheck) + { + // just do quickie check to see if the player has turned a new year older + if (ageInYears <= static_cast(s_vectorCharacterAgeTitle.size())) + { + if (ageInYears >= 1) + { + if (!player.hasCompletedCollectionSlot(*s_vectorCharacterAgeTitle[ageInYears - 1])) + { + // this will force a check/set/unset of the proper character age slot for the player + thoroughCheck = true; + } + } + } + else + { + // we need to add additional character age collection slots + + // this will make sure to unset all previous character age slots the player may have + thoroughCheck = true; + } + } + + // go through all possible character age titles and verify that the appropriate one is set and the others are unset + if (thoroughCheck) + { + for (int i = 0, size = s_vectorCharacterAgeTitle.size(); i < size; ++i) + { + if ((i + 1) == ageInYears) + { + player.modifyCollectionSlotValue(s_vectorCharacterAgeTitle[i]->name, 1ll); + } + else + { + player.modifyCollectionSlotValue(s_vectorCharacterAgeTitle[i]->name, -1ll); + } + } + } +} + +// ---------------------------------------------------------------------- + +void PlayerObjectNamespace::checkAndSetAccountAgeTitle(PlayerObject & player) +{ + static std::vector s_vectorAccountAgeTitle; + if (s_vectorAccountAgeTitle.empty()) + { + // we'll exit this loop as soon as we don't find the "next" account age title collection slot + for (int i = 1; i <= 1000000; ++i) + { + CollectionsDataTable::CollectionInfoSlot const * collectionSlot = CollectionsDataTable::getSlotByName(FormattedString<128>().sprintf("account_age_%dyr", i)); + if (!collectionSlot) + break; + + FATAL((collectionSlot->collection.name != std::string("account_age_collection")), ("collection slot %s must be in collection account_age_collection", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.name != std::string("account_age_page")), ("collection slot %s must be in collection page account_age_page", collectionSlot->name.c_str())); + FATAL((collectionSlot->collection.page.book.name != std::string("account_age_book")), ("collection slot %s must be in collection book account_age_book", collectionSlot->name.c_str())); + + s_vectorAccountAgeTitle.push_back(collectionSlot); + } + } + + CreatureObject const * const co = player.getCreatureObject(); + if (!co) + return; + + Client const * const c = co->getClient(); + if (!c) + return; + + if (c->isUsingAdminLogin()) + return; + + unsigned int const ageInYears = c->getEntitlementEntitledTime() / 365u; + + // go through all possible account age titles and verify that the appropriate one is set and the others are unset + for (size_t i = 0, size = s_vectorAccountAgeTitle.size(); i < size; ++i) + { + if ((i + 1) == ageInYears) + { + player.modifyCollectionSlotValue(s_vectorAccountAgeTitle[i]->name, 1ll); + } + else + { + player.modifyCollectionSlotValue(s_vectorAccountAgeTitle[i]->name, -1ll); + } + } +} + +// ---------------------------------------------------------------------- + +void PlayerObjectNamespace::grantGcwFactionalPresenceScore(std::string const & gcwCategory, PlayerObject const & po, CreatureObject const & co) +{ + // base_points = level * (level_% / 100) + // bonus_% = GCW_rank * bonus_%_per_rank + // + // if (in a same faction player city) + // { + // bonus_% += player_city_bonus_% + // bonus_% += (player_city_rank_bonus_% * city_rank) + // bonus_% += (player_city_age_bonus_% * city_age_in_years) + // } + // + // final_points = base_points + (base_points * (bonus_% / 100)) + int level = co.getLevel(); + int bonus = 100 + (po.getCurrentGcwRank() * ConfigServerGame::getGcwFactionalPresenceGcwRankBonusPct()); + int mountedPct = 100; + + // for ground, give bonus if in same faction player city + // + // for space, give bonus if the player's citizenship city is on the + // corresponding ground planet and is the same faction as the player + CityInfo const * ci = NULL; + if (!ServerWorld::isSpaceScene()) + { + Vector const creaturePosition = co.findPosition_w(); + int const cityId = CityInterface::getCityAtLocation(ServerWorld::getSceneId(), static_cast(creaturePosition.x), static_cast(creaturePosition.z), 0); + if (cityId > 0) + ci = &(CityInterface::getCityInfo(cityId)); + + // for ground, there may be a reduction for being on a vehicle/mount + if (co.getMountedCreature()) + mountedPct = std::min(std::max(ConfigServerGame::getGcwFactionalPresenceMountedPct(), 1), 100); // clamp to 1 - 100 + } + else + { + // for space, the "level" for a pilot (i.e. character is + // sitting in the pilot chair) is based on the pilot skill + // + // Pilots with one of the following skills should be considered Level 90 + // pilot_rebel_navy_master + // pilot_imperial_navy_master + // pilot_neutral_master + // + // Pilots with one of the following skills should be considered Level 69 + // pilot_rebel_navy_droid_03 + // pilot_imperial_navy_droid_03 + // pilot_neutral_droid_03 + // + // Pilots with one of the following skills should be considered Level 45 + // pilot_rebel_navy_droid_02 + // pilot_imperial_navy_droid_02 + // pilot_neutral_droid_02 + // + // Pilots with one of the following skills should be considered Level 21 + // pilot_rebel_navy_droid_01 + // pilot_imperial_navy_droid_01 + // pilot_neutral_droid_01 + // + // Else they should be consider level 1 + ServerObject const * const container = safe_cast(ContainerInterface::getContainedByObject(co)); + if (container && !container->asCellObject()) + { + static std::list > sPilotSkillToLevel; + if (sPilotSkillToLevel.empty()) + { + const SkillObject * skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_master"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 90)); + + skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_master"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 90)); + + skill = SkillManager::getInstance().getSkill("pilot_neutral_master"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 90)); + + skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_droid_03"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 69)); + + skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_droid_03"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 69)); + + skill = SkillManager::getInstance().getSkill("pilot_neutral_droid_03"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 69)); + + skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_droid_02"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 45)); + + skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_droid_02"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 45)); + + skill = SkillManager::getInstance().getSkill("pilot_neutral_droid_02"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 45)); + + skill = SkillManager::getInstance().getSkill("pilot_rebel_navy_droid_01"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 21)); + + skill = SkillManager::getInstance().getSkill("pilot_imperial_navy_droid_01"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 21)); + + skill = SkillManager::getInstance().getSkill("pilot_neutral_droid_01"); + if (skill) + sPilotSkillToLevel.push_back(std::make_pair(skill, 21)); + } + + level = 1; + CreatureObject::SkillList const & creatureSkill = co.getSkillList(); + for (std::list >::const_iterator iter = sPilotSkillToLevel.begin(); iter != sPilotSkillToLevel.end(); ++iter) + { + if (creatureSkill.count(iter->first) >= 1) + { + level = iter->second; + break; + } + } + } + + std::vector const & cityIds = CityInterface::getCitizenOfCityId(co.getNetworkId()); + if (!cityIds.empty()) + { + ci = &(CityInterface::getCityInfo(cityIds.front())); + + // player city on Rori will be associated with space_naboo + // player city on Talus will be associated with space_corellia + std::string const & playerCityPlanet = ci->getPlanet(); + std::string playerCitySpaceZone; + if (playerCityPlanet == std::string("rori")) + playerCitySpaceZone = std::string("space_naboo"); + else if (playerCityPlanet == std::string("talus")) + playerCitySpaceZone = std::string("space_corellia"); + else + playerCitySpaceZone = std::string("space_") + playerCityPlanet; + + if (playerCitySpaceZone != ServerWorld::getSceneId()) + ci = NULL; + } + } + + if (ci) + { + if (!PvpData::isNeutralFactionId(ci->getFaction()) && (ci->getFaction() == co.getPvpFaction())) + { + bonus += ConfigServerGame::getGcwFactionalPresenceAlignedCityBonusPct(); + + int cityRank = 5; + if (ci->getRadius() < 200) + cityRank = 1; + else if (ci->getRadius() < 300) + cityRank = 2; + else if (ci->getRadius() < 400) + cityRank = 3; + else if (ci->getRadius() < 450) + cityRank = 4; + + bonus += (cityRank * ConfigServerGame::getGcwFactionalPresenceAlignedCityRankBonusPct()); + + if (ci->getCreationTime() > 0) + bonus += std::max(0, (static_cast(::time(NULL)) - std::max(1041408000, ci->getCreationTime())) / 31536000 * ConfigServerGame::getGcwFactionalPresenceAlignedCityAgeBonusPct()); + } + } + + int const points = std::max(1, level * ConfigServerGame::getGcwFactionalPresenceLevelPct() * std::min(1000, bonus) * mountedPct / 1000000); + + if (PvpData::isImperialFactionId(co.getPvpFaction())) + ServerUniverse::getInstance().adjustGcwImperialScore(std::string("FactionalPresence"), const_cast(&co), gcwCategory, points); + else if (PvpData::isRebelFactionId(co.getPvpFaction())) + ServerUniverse::getInstance().adjustGcwRebelScore(std::string("FactionalPresence"), const_cast(&co), gcwCategory, points); +} + +// ====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/object/PlayerObject.h b/src/engine/server/library/serverGame/src/shared/object/PlayerObject.h index 7748b000d..2298e6bd3 100644 --- a/src/engine/server/library/serverGame/src/shared/object/PlayerObject.h +++ b/src/engine/server/library/serverGame/src/shared/object/PlayerObject.h @@ -1,1336 +1,1336 @@ -// ====================================================================== -// -// PlayerObject.h -// -// Copyright 2001 Sony Online Entertainment -// -// ====================================================================== - -#ifndef _PLAYER_OBJECT_H -#define _PLAYER_OBJECT_H - -// ====================================================================== - -#include "Archive/AutoDeltaMap.h" -#include "Archive/AutoDeltaPackedMap.h" -#include "serverGame/DraftSchematicObject.h" -#include "serverGame/IntangibleObject.h" -#include "serverGame/Region.h" -#include "sharedFoundation/BitArray.h" -#include "sharedFoundation/StationId.h" -#include "sharedFoundation/Watcher.h" -#include "sharedGame/CollectionsDataTable.h" -#include "sharedGame/CraftingData.h" -#include "sharedGame/MatchMakingId.h" -#include "sharedGame/PlayerData.h" -#include "sharedGame/PlayerQuestData.h" -#include "sharedGame/Waypoint.h" -#include "sharedMath/Quaternion.h" -#include "sharedNetworkMessages/MessageQueueCraftExperiment.h" -#include "sharedObject/CachedNetworkId.h" -#include "sharedSkillSystem/SkillObject.h" - -#include - -// ====================================================================== - -struct ChatAvatarId; -class MessageQueueDraftSlots; -class MessageQueueDraftSlotsQueryResponse; -class ServerPlayerObjectTemplate; -class TangibleObject; - -namespace MessageDispatch -{ - class Callback; -} - -// ====================================================================== - -/** - * Class to hold all the player and account-level data. A character should - * keep this object, even if the creature/vehicle/etc. they control changes. - */ -class PlayerObject : public IntangibleObject -{ -public: - - struct ChatLogEntry - { - ChatLogEntry(); - - int m_index; - time_t m_time; - }; - - typedef stdlist::fwd ChatLog; - typedef stdvector::fwd StringVector; - typedef stdmap::fwd ExperiencePointMap; - typedef stdmap::fwd WaypointMap; - typedef Archive::AutoDeltaPackedMap PlayerQuestDataMap; - - explicit PlayerObject(const ServerPlayerObjectTemplate* newTemplate); - virtual ~PlayerObject(); - - virtual PlayerObject *asPlayerObject(); - virtual PlayerObject const *asPlayerObject() const; - - static void removeDefaultTemplate(void); - static stdset::fwd const &getAllPlayerObjects(); - - void addMembersToPackages (); - Waypoint const createWaypoint (const Location & location, bool ignoreLimits); - Waypoint const createOrUpdateReusableWaypoint(const Location & location, const std::string & objvarTrackingName, const Unicode::String & waypointNameIfCreated, int waypointColorIfCreated = -1); - Waypoint & getWaypoint (const NetworkId & waypointId); - void getWaypointsInDatapad (std::vector & target); - void getWaypointAttributes (const NetworkId & waypointId, ServerObject::AttributeVector & data); - void destroyWaypoint (const NetworkId & waypoint); - WaypointMap const &getWaypoints () const; - void setGroupWaypoints (WaypointMap const &groupWaypointMap); - - virtual void getAttributes (stdvector >::fwd &data) const; - virtual void endBaselines(); - virtual void onLoadedFromDatabase(); - static std::string getAccountDescription(const ServerObject *); - static std::string getAccountDescription(const NetworkId &); - std::string getAccountDescription() const; - -public: - StationId getStationId() const; - float getCheaterLevel() const; - int getBornDate() const; - int getAgeInDays() const; - static int getCurrentBornDate(); - uint32 getPlayedTime() const; - float getPlayedTimeAccumOnly() const; - void setPlayedTimeAccumOnly(float playedTimeAccum); - - unsigned long getSessionPlayTimeDuration() const; - unsigned long getSessionActivePlayTimeDuration() const; - int32 getSessionStartPlayTime() const; - int32 getSessionLastActiveTime() const; - void setSessionPlayTimeInfo(int32 sessionStartPlayTime, int32 sessionLastActiveTime, unsigned long sessionActivePlayTimeDuration); - - void setStationId(StationId account); - void setCheaterLevel(float level); - void setBornDate(); - void adjustBornDate(int adjustment); - void alterPlayedTime(float time); - - void setMatchMakingPersonalProfileId(MatchMakingId const &id); - MatchMakingId const &getMatchMakingPersonalProfileId() const; - - void setMatchMakingCharacterProfileId(MatchMakingId const &id); - MatchMakingId const &getMatchMakingCharacterProfileId() const; - - void toggleSearchableByCtsSourceGalaxy(); - void toggleDisplayLocationInSearchResults(); - void toggleAnonymous(); - void toggleHelper(); - void toggleRolePlay(); - void toggleOutOfCharacter(); - void toggleLookingForWork(); - - - bool isAwayFromKeyBoard() const; - void toggleAwayFromKeyBoard(); - - void toggleDisplayingFactionRank(); - - bool isLookingForGroup() const; - void setLookingForGroup(bool const lookingForGroup); - void toggleLookingForGroup(); - - StringVector const & getSortedLowercaseFriendList() const; - void setFriendList(const StringVector &friendList); - bool isFriend(const std::string &name) const; - void requestFriendList() const; - void findFriend(const std::string & name); - void replyLocationToFriend(const std::string & friendName, const NetworkId & friendId); - void receiveLocationToFriend(const NetworkId & friendId, const Location & friendLocation); - void failLocationToFriend(const NetworkId & friendId); - void receiveFailLocationToFriend(const NetworkId & friendId); - - StringVector const & getSortedLowercaseIgnoreList() const; - void setIgnoreList(const StringVector &ignoreList); - bool isIgnoring(const std::string &name) const; - void requestIgnoreList() const; - - void setTitle(std::string const &title); - std::string const & getTitle() const; - - bool adjustLotCount(int adjustment); - - void setSpokenLanguage(int const languageId); - int getSpokenLanguage() const; - - void setLinkDead(bool const linkDead); - bool getLinkDead() const; - - static bool isIgnoring(NetworkId const &target, NetworkId const &source); - - int getMaxForcePower (void) const; - virtual void setMaxForcePower (int value); - int getForcePower (void) const; - void setForcePower (int value); - float getForcePowerRegenRate (void) const; - void setForcePowerRegenRate (float value); - void regenerateForcePower (float time); - - //@todo It is unfortunate that these jedi-related things are in the supposedly generic PlayerObject - virtual bool isJedi() const; - void addJediToAccount() const; - void addJediToAccountAck() const; - void makeSpectralOnAccount() const; - void makeSpectralOnAccountAck() const; - - void checkStomach(); - - virtual void handleCMessageTo(const MessageToPayload &message); - - void logChat(int const logIndex); - - ChatLog const &getChatLog() const; - void cleanChatLog(); - - void checkTheater(const Vector & pos, const std::string & scene, float speed, float updateRadius); - bool setTheater(const std::string & datatable, const Vector & position, const std::string & scene, const std::string & script, const NetworkId & creator, const std::string & name, IntangibleObject::TheaterLocationType locationType); - void clearTheater(); - bool hasTheater() const; - const NetworkId & getTheater() const; - -public: - - int getExperiencePoints(const std::string & experienceType) const; - const std::map & getExperiencePoints() const; - int getExperienceLimit(const std::string & experienceType) const; - int grantExperiencePoints(const std::string & experienceType, int amount); - void clearSchematics(); - bool grantSchematicGroup(const std::string & groupNameWithModifier, bool fromSkill); - bool grantSchematic(uint32 schematicCrc, bool fromSkill); - bool revokeSchematic(uint32 schematicCrc, bool fromSkill); - bool hasSchematic(uint32 schematicCrc); - - // crafting functions - bool isCrafting(void) const; - const stdmap,int>::fwd & getDraftSchematics () const; - const CachedNetworkId & getCraftingTool () const; - void setCraftingTool(const TangibleObject & tool); - const CachedNetworkId & getCraftingStation () const; - void setCraftingStation(const TangibleObject * station); - const DraftSchematicObject * getCurrentDraftSchematic () const; - bool requestCraftingSession(const NetworkId & toolId); - void sendUseableDraftSchematics(stdvector::fwd & schematicNames); - bool requestDraftSlots(uint32 draftSchematicCrc, MessageQueueDraftSlots * message, MessageQueueDraftSlotsQueryResponse * queryMessage); - void selectDraftSchematic(int index); - Crafting::CraftingError fillSlot(int slotIndex, int slotOptionIndex, const NetworkId & ingredientIndex); - Crafting::CraftingError emptySlot(int slotIndex, const NetworkId & targetContainer); - int goToNextCraftingStage (); - int startCraftingExperiment (); - Crafting::CraftingResult experiment(const stdvector::fwd & experiments, int totalPoints, int corelevel); - bool customize(int property, int value) const; - int setCustomizationData(const Unicode::String & name, int appearanceIndex, const std::vector & customizations, int itemCount) const; - bool createPrototype(bool keepPrototype); - bool createManufacturingSchematic(void); - bool restartCrafting (); - void stopCrafting (bool normalExit); - enum Crafting::CraftingStage getCraftingStage () const; - void setCraftingLevel(int level); - int getCraftingLevel() const; - void setAllowEmptySlot(bool allow); - - int getAccountNumLots() const; - void setAccountNumLotsOverLimitSpam(); - - CreatureObject * getCreatureObject(); - const CreatureObject * getCreatureObject() const; - - void setPriviledgedTitle(int8 priviledgedTitle); - - bool getIsUnsticking() const; - void setIsUnsticking(bool value); - - //-- old quest system - bool isQuestComplete(int questId) const; - bool isQuestActive(int questId) const; - void activateQuest(int questId); - void deactivateQuest(int questId); - void completeQuest(int questId); - void clearCompletedQuest(int questId); - - //--new quest system - enum QuestResult {QR_success, QR_alreadyActive, QR_noSuchQuest, QR_noSuchTask, QR_alreadyComplete, QR_failedPrerequisites, QR_failedExclusion, QR_questNotActive, QR_taskNotActive, QR_noSuchPlayer, QR_questNotCompleted, QR_alreadyReceivedReward}; - - QuestResult questCanActivateQuest(uint32 questCrc) const; - QuestResult questActivateQuest(uint32 questCrc, NetworkId const & questGiver); - QuestResult questCompleteQuest(uint32 questCrc); - QuestResult questGrantQuestReward(uint32 questCrc, std::string const & selectedReward); - void questClearQuest(uint32 questCrc); - QuestResult questCanActivateQuestTask(uint32 questCrc, int taskId) const; - QuestResult questActivateQuestTask(uint32 questCrc, int taskId); - QuestResult questCompleteQuestTask(uint32 questCrc, int taskId); - QuestResult questFailQuestTask(uint32 questCrc, int taskId); - QuestResult questClearQuestTask(uint32 questCrc, int taskId); - bool questHasActiveQuest(uint32 questCrc) const; - bool questHasCompletedQuest(uint32 questCrc) const; - bool questHasActiveQuestTask(uint32 questCrc, int taskId) const; - bool questHasCompletedQuestTask(uint32 questCrc, int taskId) const; - uint32 questGetQuestStatus(uint32 const questCrc) const; - stdvector::fwd questGetAllActiveQuestIds() const; - stdvector::fwd questGetAllCompletedQuestIds() const; - bool questPlayerCanClaimRewardFor(uint32 questCrc); - - uint32 getCurrentQuest() const; - void setCurrentQuest(uint32 questCrc); - - virtual void virtualOnLogout(); - virtual void getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const; - virtual void setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source); - - void setRoleIconChoice(int roleIconChoice); - int getRoleIconChoice() const; - void setAggroImmuneDuration(int const duration); - bool isAggroImmune() const; - - std::string const & getSkillTemplate() const; - bool setSkillTemplate(std::string const & templateName, bool clientRequest); - - std::string const & getWorkingSkill() const; - bool setWorkingSkill(std::string const & skillName, bool clientRequest); - - bool getIsFromLogin(void) const; - void setIsFromLogin(bool val); - - bool isNormalPlayer() const; - bool isCustomerServiceRepresentative() const; - bool isDeveloper() const; - bool isWarden() const; - - void setPendingRequestQuestInformation(uint32 questCrc, NetworkId const & questGiver); - uint32 getPendingRequestQuestCrc() const; - NetworkId const & getPendingRequestQuestGiver() const; - - int getNumberOfActiveQuests() const; - void setPlayerQuestDataComplete(uint32 questCrc, PlayerQuestData & playerQuestData); - void pickNewCurrentQuest(); - - int32 getCurrentGcwPoints() const; - int32 getCurrentGcwRating() const; - int32 getCurrentPvpKills() const; - int64 getLifetimeGcwPoints() const; - int32 getMaxGcwImperialRating() const; - int32 getMaxGcwRebelRating() const; - int32 getLifetimePvpKills() const; - int32 getNextGcwRatingCalcTime() const; - int getCurrentGcwRank() const; - float getCurrentGcwRankProgress() const; - int getMaxGcwImperialRank() const; - int getMaxGcwRebelRank() const; - int32 getGcwRatingActualCalcTime() const; - bool needsGcwRatingRecalculated() const; - - void modifyCurrentGcwPoints(int count, bool modifyLifetimeValue); - void modifyCurrentGcwRating(int count, bool modifyMaxValue); - void modifyCurrentPvpKills(int count, bool modifyLifetimeValue); - void modifyLifetimeGcwPoints(int count); - void modifyMaxGcwImperialRating(int count); - void modifyMaxGcwRebelRating(int count); - void modifyLifetimePvpKills(int count); - void modifyNextGcwRatingCalcTime(int weekCount); - void setNextGcwRatingCalcTime(bool alwaysSendMessageToForRecalc); - void ctsUseOnlySetGcwInfo(int32 currentGcwPoints, int32 currentGcwRating, int32 currentPvpKills, int64 lifetimeGcwPoints, int32 maxGcwImperialRating, int32 maxGcwRebelRating, int32 lifetimePvpKills, int32 nextGcwRatingCalcTime); - - void addToPlayerHateList(NetworkId const & id); - void removeFromPlayerHateList(NetworkId const & id); - void clearPlayerHateList(); - - uint32 getSessionActivity() const; - void clearSessionActivity(); - void addSessionActivity(uint32 activity); - int32 getKillMeter() const; - void incrementKillMeter(int amount); - void updateKillMeter(float deltaTime); - - NetworkId const &getPetId() const; - void setPetId(NetworkId const & newId); - void setPetCommandList(std::vector const &commands); - void setPetToggledCommands(std::vector const &commands); - - bool modifyCollectionSlotValue(std::string const & slotName, int64 delta); - - bool getCollectionSlotValue(std::string const & slotName, unsigned long & value) const; - bool getCollectionSlotValue(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long & value) const; - - bool hasCompletedCollectionSlotPrereq(std::string const & slotName, stdvector::fwd * collectionInfo = NULL) const; - bool hasCompletedCollectionSlotPrereq(CollectionsDataTable::CollectionInfoSlot const & slotInfo, stdvector::fwd * collectionInfo = NULL) const; - - bool hasCompletedCollectionSlot(std::string const & slotName) const; - bool hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo) const; - static bool hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long slotValue); - - bool hasCompletedCollection(std::string const & collectionName) const; - - bool hasCompletedCollectionPage(std::string const & pageName) const; - - bool hasCompletedCollectionBook(std::string const & bookName) const; - - int getCompletedCollectionSlotCountInCollection(std::string const & collectionName, stdvector::fwd * collectionInfo = NULL) const; - - int getCompletedCollectionSlotCountInPage(std::string const & pageName, stdvector::fwd * collectionInfo = NULL) const; - int getCompletedCollectionCountInPage(std::string const & pageName, stdvector::fwd * collectionInfo = NULL) const; - - int getCompletedCollectionSlotCountInBook(std::string const & bookName, stdvector::fwd * collectionInfo = NULL) const; - int getCompletedCollectionCountInBook(std::string const & bookName, stdvector::fwd * collectionInfo = NULL) const; - int getCompletedCollectionPageCountInBook(std::string const & bookName, stdvector::fwd * collectionInfo = NULL) const; - int getCompletedCollectionBookCount(stdvector::fwd * collectionInfo = NULL) const; - - void migrateLegacyBadgesToCollection(stdvector::fwd const & badges); - - // chat spam info - int getChatSpamSpatialNumCharacters() const; - void updateChatSpamSpatialNumCharacters(NetworkId const & character, int spatialNumCharacters); - - int getChatSpamNonSpatialNumCharacters() const; - void handleChatStatisticsFromChatServer(NetworkId const & character, int chatSpamTimeEndInterval, int spatialNumCharacters, int nonSpatialNumCharacters); - - int getChatSpamTimeEndInterval() const; - - time_t getChatSpamNextTimeToNotifyPlayerWhenLimited() const; - void setChatSpamNextTimeToNotifyPlayerWhenLimited(time_t chatSpamNextTimeToNotifyPlayerWhenLimited); - - // citizenship info - void updateCitizenshipInfo(); - - // GCW Region info - void updateGcwRegionInfo(); - std::string const & getCurrentGcwRegion() const; - - void updateGcwDefenderRegionInfo(); - std::pair > const & getCityGcwDefenderRegionInfo() const; - std::pair > const & getGuildGcwDefenderRegionInfo() const; - - // squelch info - void squelch(NetworkId const & squelchedById, std::string const & squelchedByName, int squelchDurationSeconds); - void unsquelch(); - NetworkId const & getSquelchedById() const; - int getSecondsUntilUnsquelched(); // returns 0 if not currently squelched; returns < 0 if indefinitely squelched - - void modifyShowBackpack(bool b); - void modifyShowHelmet(bool b); - - bool getShowBackpack() const; - bool getShowHelmet() const; - - void setGuildRank(BitArray const & guildRank); - BitArray const & getGuildRank() const; - - void setCitizenRank(BitArray const & citizenRank); - BitArray const & getCitizenRank() const; - - EnvironmentInfo getEnvironmentFlags() const; - void overrideDefaultAttack(std::string const & attack); - std::string const & getDefaultAttackOverride() const; - - void setEnvironmentFlags(EnvironmentInfo const & flags); - - // getter/setter for variables to track the status of the - // /pickupAllRoomItemsIntoInventory and - // /dropAllInventoryItemsIntoRoom commands - int getPickupDropAllItemsOperationId() const; - void setPickupDropAllItemsOperationId(int pickupDropAllItemsOperationId); - - NetworkId const & getPickupDropAllItemsCellId() const; - void setPickupDropAllItemsCellId(NetworkId const & pickupDropAllItemsCellId); - - bool getPickupAllItemsAllowInventoryOverload() const; - void setPickupAllItemsAllowInventoryOverload(bool pickupAllItemsAllowInventoryOverload); - - int getPickupDropAllItemsNumItemsSoFar() const; - void setPickupDropAllItemsNumItemsSoFar(int pickupDropAllItemsNumItemsSoFar); - - std::set & getPickupDropAllItemsProcessedItemsSoFar(); - - // getter/setter for variables to track the status of a restore decoration layout operation - int getRestoreDecorationOperationId() const; - void setRestoreDecorationOperationId(int restoreDecorationOperationId); - - NetworkId const & getRestoreDecorationPobId() const; - void setRestoreDecorationPobId(NetworkId const & restoreDecorationPobId); - - NetworkId const & getRestoreDecorationObjectBeingRestored() const; - void setRestoreDecorationObjectBeingRestored(NetworkId const & restoreDecorationObjectBeingRestored); - - int getRestoreDecorationTotalCount() const; - void setRestoreDecorationTotalCount(int restoreDecorationTotalCount); - - int getRestoreDecorationAttemptedCount() const; - void setRestoreDecorationAttemptedCount(int restoreDecorationAttemptedCount); - - int getRestoreDecorationSuccessCount() const; - void setRestoreDecorationSuccessCount(int restoreDecorationSuccessCount); - - std::list, std::pair > > & getRestoreDecorationLayoutList(); - - static bool canAccessGalacticReserve(real x, real z); - void depositToGalacticReserve(bool ignoreCooldownAndLocationCheck); - void withdrawFromGalacticReserve(); - void depersistGalacticReserveDeposit(); - int8 getGalacticReserveDeposit() const; - -protected: - - virtual const SharedObjectTemplate * getDefaultSharedTemplate(void) const; - virtual void virtualOnSetAuthority(); - -private: - int getForcePowerRegen(float time); - void onWaypointChanged(const Waypoint & newValue); - void onWaypointCreated(const NetworkId &, const Waypoint &); - void onWaypointSet(NetworkId const &, Waypoint const &, Waypoint const &); - void onWaypointRemoved(NetworkId const &, const Waypoint &); - - void questCheckQuestLimits(); - - void handleRecalculateGcwRating(); - void sendRecalculateGcwRatingMessageTo(int delay); - -private: - static const SharedObjectTemplate * m_defaultSharedTemplate; // template to use if no shared template is given - - MessageDispatch::Callback * m_callback; - - Archive::AutoDeltaVariable m_stationId; - - // ***DEPRECATED DO NOT USE*** - // see CreatureObject::getHouse() and CreatureObject::setHouse() for replacement - Archive::AutoDeltaVariable m_houseId; ///< The player's domicile - - Archive::AutoDeltaVariable m_accountNumLots; ///< Number of lots used by all the characters on this account (on this server cluster only) - Archive::AutoDeltaVariable m_accountNumLotsOverLimitSpam; /// controls whether the player should be spammed for exceeding the lot limit - Archive::AutoDeltaVariable m_accountMaxLotsAdjustment; ///< Extra lots available to this account (or possibly penalty lots taken away) - Archive::AutoDeltaVariable m_accountIsOutcast; ///< Is this account outcast? - Archive::AutoDeltaVariable m_accountCheaterLevel; ///< how suspected of cheating this person is, for use with movement validation - - PlayerObject(const PlayerObject &); - PlayerObject & operator = ( const PlayerObject & ); - - // player abilities - Archive::AutoDeltaMap, int> m_draftSchematics; // draft schematics the player may use - Archive::AutoDeltaMap m_experiencePoints; // xp name->amount map - Archive::AutoDeltaVariable m_expModified; // just a flag that we increment any time the creature is granted new xp - Archive::AutoDeltaVariable m_maxForcePower; ///< Maximum force power the player can have - Archive::AutoDeltaVariable m_forcePower; ///< Current force power the player has - Archive::AutoDeltaVariable m_forceRegenRate; ///< Rate at which the force power regenerates (units/sec) - Archive::AutoDeltaVariable m_forceRegenValue; ///< Amount of force power that's regenerated - - // crafting system data - Archive::AutoDeltaVariable m_craftingLevel; // crafting level of the current crafting session - Archive::AutoDeltaVariable m_experimentPoints; // experiment points available to the player - Archive::AutoDeltaVariable m_craftingStage; // what stage in the crafting process a player is in - Archive::AutoDeltaVariable m_craftingTool; // tool a player is crafting with - Archive::AutoDeltaVariable m_craftingStation; // station a player is crafting with - Archive::AutoDeltaVariable m_craftingComponentBioLink;// bio-link id of a component - stdvector::fwd m_useableDraftSchematics; // draft schematics a player may currently select from - ConstWatcher m_draftSchematic; // draft schematic the player is crafting with - static bool m_allowEmptySlot; // flag to allow emptySlot() to be called when not in the crafting assembly stage. - - Archive::AutoDeltaVariable m_matchMakingPersonalProfileId; // What the player defines their personality as - Archive::AutoDeltaVariable m_matchMakingCharacterProfileId; // What the player defines their character as - - // these 2 lists ***MUST BE LOWERCASE AND MUST BE KEPT SORTED FOR QUICK LOOKUP*** - Archive::AutoDeltaVector m_friendList; - Archive::AutoDeltaVector m_ignoreList; - - Archive::AutoDeltaVariable m_skillTitle; - Archive::AutoDeltaVariable m_spokenLanguage; - Archive::AutoDeltaMap m_waypoints; - Archive::AutoDeltaMap m_groupWaypoints; - Archive::AutoDeltaVariable m_bornDate; - Archive::AutoDeltaVariable m_playedTime; - float m_playedTimeAccum; - - // information to track player's play time during this particular session - // this information is kept and tracked in the connection server, but is - // cached here for use by the game server - Archive::AutoDeltaVariable m_sessionStartPlayTime; // time when the player started playing the character - Archive::AutoDeltaVariable m_sessionLastActiveTime; // the client will detect when the player is "active" or "inactive"; this keeps track of the last time that the client said the player was "active"; if 0, it means the client is currently "inactive" - Archive::AutoDeltaVariable m_sessionActivePlayTimeDuration; // total amount of play time player was active (i.e. at the mouse/keyboard/joystick) - - Archive::AutoDeltaVariable m_food; - Archive::AutoDeltaVariable m_maxFood; - Archive::AutoDeltaVariable m_drink; - Archive::AutoDeltaVariable m_maxDrink; - Archive::AutoDeltaVariable m_meds; - Archive::AutoDeltaVariable m_maxMeds; - - Archive::AutoDeltaVariable m_privledgedTitle; - Archive::AutoDeltaVariable m_completedQuests; - Archive::AutoDeltaVariable m_activeQuests; - Archive::AutoDeltaVariable m_currentQuest; - - Archive::AutoDeltaPackedMap m_quests; - - Archive::AutoDeltaVariable m_theaterDatatable; - Archive::AutoDeltaVariable m_theaterPosition; - Archive::AutoDeltaVariable m_theaterScene; - Archive::AutoDeltaVariable m_theaterScript; - Archive::AutoDeltaVariable m_theaterNumObjects; - Archive::AutoDeltaVariable m_theaterRadius; - Archive::AutoDeltaVariable m_theaterCreator; - Archive::AutoDeltaVariable m_theaterName; - Archive::AutoDeltaVariable m_theaterId; - Archive::AutoDeltaVariable m_theaterLocationType; - Archive::AutoDeltaVariable m_roleIconChoice; - Archive::AutoDeltaVariable m_aggroImmuneDuration; - Archive::AutoDeltaVariable m_aggroImmuneStartTime; - - ChatLog * const m_chatLog; - time_t m_chatLogPurgeTime; - bool m_isUnsticking; - - //when asking a player to accept or complete a quest, remember the quest that we asked them about - - //TODO sync to other servers as necessary? - uint32 m_pendingRequestQuestCrc; - NetworkId m_pendingRequestQuestGiver; - - Archive::AutoDeltaVariable m_skillTemplate; - Archive::AutoDeltaVariable m_workingSkill; - Archive::AutoDeltaVariable m_isFromLogin; ///< This defaults to true, and is set to false in CreatureObject::virtualOnSetClient, (used to distinguish when coming from login as opposed to from a scene warp) - - Archive::AutoDeltaVariable m_currentGcwPoints; - Archive::AutoDeltaVariable m_currentGcwRating; - Archive::AutoDeltaVariable m_currentPvpKills; - Archive::AutoDeltaVariable m_lifetimeGcwPoints; - Archive::AutoDeltaVariable m_maxGcwImperialRating; - Archive::AutoDeltaVariable m_maxGcwRebelRating; - Archive::AutoDeltaVariable m_lifetimePvpKills; - Archive::AutoDeltaVariable m_nextGcwRatingCalcTime; - Archive::AutoDeltaVariable m_currentGcwRank; - Archive::AutoDeltaVariable m_currentGcwRankProgress; - Archive::AutoDeltaVariable m_maxGcwImperialRank; - Archive::AutoDeltaVariable m_maxGcwRebelRank; - - // the Epoch when the next messageTo to cause GCW rating recalculation will occur - Archive::AutoDeltaVariable m_gcwRatingActualCalcTime; - - // copy of the player's hate list sent to the authoritative client - Archive::AutoDeltaSet m_playerHateList; - - // activity that the player has done during this session - Archive::AutoDeltaVariable m_sessionActivity; - // these two variables represent the commando kill meter - Archive::AutoDeltaVariable m_killMeter; - // this variable stores the fractional state of the meter but is not persisted nor synchronized across servers. - float m_killMeterRemainder; - - Archive::AutoDeltaVariable m_petId; - Archive::AutoDeltaVector m_petCommandList; - Archive::AutoDeltaVector m_petToggledCommands; // These are the commands on the - // pet toolbar that should display - // visually as being toggled on - - // both m_collections and m_collections2 form a "contiguous" collections bit array - // we only break them up into multiple members because of DB storage restrictions - Archive::AutoDeltaVariable m_collections; - Archive::AutoDeltaVariable m_collections2; - Archive::AutoDeltaVariable * m_allCollections[2]; - - // chat spam info - Archive::AutoDeltaVariable m_chatSpamSpatialNumCharacters; - Archive::AutoDeltaVariable m_chatSpamNonSpatialNumCharacters; - Archive::AutoDeltaVariable m_chatSpamTimeEndInterval; - Archive::AutoDeltaVariable m_chatSpamNextTimeToSyncWithChatServer; - time_t m_chatSpamNextTimeToNotifyPlayerWhenLimited; - - // citizenship info - Archive::AutoDeltaVariable m_citizenshipCity; - Archive::AutoDeltaVariable m_citizenshipType; // CityDataCitizenType - - // GCW Region info - Archive::AutoDeltaVariable m_currentGcwRegion; - // std::pair > - Archive::AutoDeltaVariable > > m_cityGcwDefenderRegion; - Archive::AutoDeltaVariable > > m_guildGcwDefenderRegion; - - // squelch info - Archive::AutoDeltaVariable m_squelchedById; // id of the toon who squelched this toon; is NetworkId::cms_invalid if this toon is not squelched - Archive::AutoDeltaVariable m_squelchedByName; // name of the toon who squelched this toon - Archive::AutoDeltaVariable m_squelchExpireTime; // the Epoch time when the toon will be unsquelched; is < 0 for indefinite squelch - - Archive::AutoDeltaVariable m_showBackpack; - Archive::AutoDeltaVariable m_showHelmet; - - Archive::AutoDeltaVariable m_environmentFlags; // Force Day, Night, whatever else. - // Default attack override - Archive::AutoDeltaVariable m_defaultAttackOverride; // This string will override the user's default attack - - Archive::AutoDeltaVariable m_guildRank; - Archive::AutoDeltaVariable m_citizenRank; - - // for use to track the status of the /pickupAllRoomItemsIntoInventory - // and /dropAllInventoryItemsIntoRoom commands, which occurs over a - // period of time; these are not proxied, as the only way the cell/structure - // in which the player is standing when the command is executed can - // change authority is during a game server crash recovery scenario - // (or a warp in the case of a POB ship), in which case we'll just cancel - // the currently executing /pickupAllRoomItemsIntoInventory - // or /dropAllInventoryItemsIntoRoom command, and the player do it again - int m_pickupDropAllItemsOperationId; - NetworkId m_pickupDropAllItemsCellId; - bool m_pickupAllItemsAllowInventoryOverload; - int m_pickupDropAllItemsNumItemsSoFar; - std::set m_pickupDropAllItemsProcessedItemsSoFar; - - // for use to track the status of a restore decoration layout operation, - // which occurs over a period of time; these are not proxied, as the only - // way the structure in which the player is standing when the command - // is executed can change authority is during a game server crash recovery - // scenario (or a warp in the case of a POB ship), in which case we'll just - // cancel the currently executing operation, and the player can do it again - int m_restoreDecorationOperationId; - NetworkId m_restoreDecorationPobId; - NetworkId m_restoreDecorationObjectBeingRestored; - int m_restoreDecorationTotalCount; - int m_restoreDecorationAttemptedCount; - int m_restoreDecorationSuccessCount; - std::list, std::pair > > m_restoreDecorationLayoutList; - - Archive::AutoDeltaVariable m_galacticReserveDeposit; - - Archive::AutoDeltaVariable m_pgcRatingCount; - Archive::AutoDeltaVariable m_pgcRatingTotal; - Archive::AutoDeltaVariable m_pgcLastRatingTime; -}; - -// ====================================================================== - -inline StationId PlayerObject::getStationId() const -{ - return m_stationId.get(); -} - -// ---------------------------------------------------------------------- - -inline float PlayerObject::getCheaterLevel() const -{ - return m_accountCheaterLevel.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getBornDate() const -{ - return m_bornDate.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getSessionStartPlayTime() const -{ - return m_sessionStartPlayTime.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getSessionLastActiveTime() const -{ - return m_sessionLastActiveTime.get(); -} - -// ---------------------------------------------------------------------- - -inline const stdmap,int>::fwd & PlayerObject::getDraftSchematics () const -{ - return m_draftSchematics.getMap(); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::clearSchematics() -{ - m_draftSchematics.clear(); -} - -// ---------------------------------------------------------------------- - -inline const CachedNetworkId & PlayerObject::getCraftingTool() const -{ - return m_craftingTool.get(); -} - -// ---------------------------------------------------------------------- - -inline const CachedNetworkId & PlayerObject::getCraftingStation() const -{ - return m_craftingStation.get(); -} - -// ---------------------------------------------------------------------- - -inline const DraftSchematicObject * PlayerObject::getCurrentDraftSchematic () const -{ - return m_draftSchematic.getPointer(); -} - -// ---------------------------------------------------------------------- - -inline enum Crafting::CraftingStage PlayerObject::getCraftingStage () const -{ - return static_cast(m_craftingStage.get()); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setCraftingLevel(int level) -{ - m_craftingLevel = level; -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getCraftingLevel() const -{ - return m_craftingLevel.get(); -} - -// ---------------------------------------------------------------------- - -inline bool PlayerObject::isCrafting(void) const -{ - return getCraftingStage() != Crafting::CS_none; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setAllowEmptySlot(bool allow) -{ - m_allowEmptySlot = allow; -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getAccountNumLots() const -{ - return m_accountNumLots.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getMaxForcePower(void) const -{ - return m_maxForcePower.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getForcePower(void) const -{ - return m_forcePower.get(); -} - -// ---------------------------------------------------------------------- - -inline float PlayerObject::getForcePowerRegenRate() const -{ - return m_forceRegenRate.get(); -} - -// ---------------------------------------------------------------------- - -inline const NetworkId & PlayerObject::getTheater() const -{ - return m_theaterId.get(); -} - -// ---------------------------------------------------------------------- - -inline bool PlayerObject::getIsFromLogin(void) const -{ - return m_isFromLogin.get(); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setIsFromLogin(bool val) -{ - m_isFromLogin = val; -} - -//---------------------------------------------------------------------- - -inline bool PlayerObject::isNormalPlayer() const -{ - return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::NormalPlayer); -} - -//---------------------------------------------------------------------- - -inline bool PlayerObject::isCustomerServiceRepresentative() const -{ - return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::CustomerServiceRepresentative); -} - -//---------------------------------------------------------------------- - -inline bool PlayerObject::isDeveloper() const -{ - return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::Developer); -} - -//---------------------------------------------------------------------- - -inline bool PlayerObject::isWarden() const -{ - return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::Warden); -} - -// ---------------------------------------------------------------------- - -inline uint32 PlayerObject::getCurrentQuest() const -{ - return m_currentQuest.get(); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setCurrentQuest(uint32 questCrc) -{ - m_currentQuest = questCrc; -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getCurrentGcwPoints() const -{ - return m_currentGcwPoints.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getKillMeter() const -{ - return m_killMeter.get(); -} - -inline NetworkId const & PlayerObject::getPetId() const -{ - return m_petId.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getCurrentGcwRating() const -{ - return m_currentGcwRating.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getCurrentPvpKills() const -{ - return m_currentPvpKills.get(); -} - -// ---------------------------------------------------------------------- - -inline int64 PlayerObject::getLifetimeGcwPoints() const -{ - return m_lifetimeGcwPoints.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getMaxGcwImperialRating() const -{ - return m_maxGcwImperialRating.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getMaxGcwRebelRating() const -{ - return m_maxGcwRebelRating.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getLifetimePvpKills() const -{ - return m_lifetimePvpKills.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getNextGcwRatingCalcTime() const -{ - return m_nextGcwRatingCalcTime.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getCurrentGcwRank() const -{ - return m_currentGcwRank.get(); -} - -// ---------------------------------------------------------------------- - -inline float PlayerObject::getCurrentGcwRankProgress() const -{ - return m_currentGcwRankProgress.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getMaxGcwImperialRank() const -{ - return m_maxGcwImperialRank.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getMaxGcwRebelRank() const -{ - return m_maxGcwRebelRank.get(); -} - -// ---------------------------------------------------------------------- - -inline int32 PlayerObject::getGcwRatingActualCalcTime() const -{ - return m_gcwRatingActualCalcTime.get(); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::addToPlayerHateList(NetworkId const & id) -{ - m_playerHateList.insert(id); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::removeFromPlayerHateList(NetworkId const & id) -{ - m_playerHateList.erase(id); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::clearPlayerHateList() -{ - m_playerHateList.clear(); -} - -// ---------------------------------------------------------------------- - -inline uint32 PlayerObject::getSessionActivity() const -{ - return m_sessionActivity.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getChatSpamSpatialNumCharacters() const -{ - return m_chatSpamSpatialNumCharacters.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getChatSpamNonSpatialNumCharacters() const -{ - return m_chatSpamNonSpatialNumCharacters.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getChatSpamTimeEndInterval() const -{ - return m_chatSpamTimeEndInterval.get(); -} - -// ---------------------------------------------------------------------- - -inline time_t PlayerObject::getChatSpamNextTimeToNotifyPlayerWhenLimited() const -{ - return m_chatSpamNextTimeToNotifyPlayerWhenLimited; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setChatSpamNextTimeToNotifyPlayerWhenLimited(time_t chatSpamNextTimeToNotifyPlayerWhenLimited) -{ - m_chatSpamNextTimeToNotifyPlayerWhenLimited = chatSpamNextTimeToNotifyPlayerWhenLimited; -} - -// ---------------------------------------------------------------------- - -inline NetworkId const & PlayerObject::getSquelchedById() const -{ - return m_squelchedById.get(); -} - -// ---------------------------------------------------------------------- - -inline bool PlayerObject::getShowHelmet() const -{ - return m_showHelmet.get(); -} - -// ---------------------------------------------------------------------- - -inline bool PlayerObject::getShowBackpack() const -{ - return m_showBackpack.get(); -} - -// ---------------------------------------------------------------------- - -inline PlayerObject::StringVector const & PlayerObject::getSortedLowercaseFriendList() const -{ - return m_friendList.get(); -} - -// ---------------------------------------------------------------------- - -inline PlayerObject::StringVector const & PlayerObject::getSortedLowercaseIgnoreList() const -{ - return m_ignoreList.get(); -} - -// ---------------------------------------------------------------------- - -inline EnvironmentInfo PlayerObject::getEnvironmentFlags() const -{ - return m_environmentFlags.get(); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::overrideDefaultAttack(std::string const & attack) -{ - m_defaultAttackOverride = attack; -} - -// ---------------------------------------------------------------------- - -inline std::string const & PlayerObject::getDefaultAttackOverride() const -{ - return m_defaultAttackOverride.get(); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setGuildRank(BitArray const & guildRank) -{ - m_guildRank.set(guildRank); -} - -// ---------------------------------------------------------------------- - -inline BitArray const & PlayerObject::getGuildRank() const -{ - return m_guildRank.get(); -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setCitizenRank(BitArray const & citizenRank) -{ - m_citizenRank.set(citizenRank); -} - -// ---------------------------------------------------------------------- - -inline BitArray const & PlayerObject::getCitizenRank() const -{ - return m_citizenRank.get(); -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getPickupDropAllItemsOperationId() const -{ - return m_pickupDropAllItemsOperationId; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setPickupDropAllItemsOperationId(int pickupDropAllItemsOperationId) -{ - m_pickupDropAllItemsOperationId = pickupDropAllItemsOperationId; -} - -// ---------------------------------------------------------------------- - -inline NetworkId const & PlayerObject::getPickupDropAllItemsCellId() const -{ - return m_pickupDropAllItemsCellId; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setPickupDropAllItemsCellId(NetworkId const & pickupDropAllItemsCellId) -{ - m_pickupDropAllItemsCellId = pickupDropAllItemsCellId; -} - -// ---------------------------------------------------------------------- - -inline bool PlayerObject::getPickupAllItemsAllowInventoryOverload() const -{ - return m_pickupAllItemsAllowInventoryOverload; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setPickupAllItemsAllowInventoryOverload(bool pickupAllItemsAllowInventoryOverload) -{ - m_pickupAllItemsAllowInventoryOverload = pickupAllItemsAllowInventoryOverload; -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getPickupDropAllItemsNumItemsSoFar() const -{ - return m_pickupDropAllItemsNumItemsSoFar; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setPickupDropAllItemsNumItemsSoFar(int pickupDropAllItemsNumItemsSoFar) -{ - m_pickupDropAllItemsNumItemsSoFar = pickupDropAllItemsNumItemsSoFar; -} - -// ---------------------------------------------------------------------- - -inline std::set & PlayerObject::getPickupDropAllItemsProcessedItemsSoFar() -{ - return m_pickupDropAllItemsProcessedItemsSoFar; -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getRestoreDecorationOperationId() const -{ - return m_restoreDecorationOperationId; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setRestoreDecorationOperationId(int restoreDecorationOperationId) -{ - m_restoreDecorationOperationId = restoreDecorationOperationId; -} - -// ---------------------------------------------------------------------- - -inline NetworkId const & PlayerObject::getRestoreDecorationPobId() const -{ - return m_restoreDecorationPobId; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setRestoreDecorationPobId(NetworkId const & restoreDecorationPobId) -{ - m_restoreDecorationPobId = restoreDecorationPobId; -} - -// ---------------------------------------------------------------------- - -inline NetworkId const & PlayerObject::getRestoreDecorationObjectBeingRestored() const -{ - return m_restoreDecorationObjectBeingRestored; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setRestoreDecorationObjectBeingRestored(NetworkId const & restoreDecorationObjectBeingRestored) -{ - m_restoreDecorationObjectBeingRestored = restoreDecorationObjectBeingRestored; -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getRestoreDecorationTotalCount() const -{ - return m_restoreDecorationTotalCount; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setRestoreDecorationTotalCount(int restoreDecorationTotalCount) -{ - m_restoreDecorationTotalCount = restoreDecorationTotalCount; -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getRestoreDecorationAttemptedCount() const -{ - return m_restoreDecorationAttemptedCount; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setRestoreDecorationAttemptedCount(int restoreDecorationAttemptedCount) -{ - m_restoreDecorationAttemptedCount = restoreDecorationAttemptedCount; -} - -// ---------------------------------------------------------------------- - -inline int PlayerObject::getRestoreDecorationSuccessCount() const -{ - return m_restoreDecorationSuccessCount; -} - -// ---------------------------------------------------------------------- - -inline void PlayerObject::setRestoreDecorationSuccessCount(int restoreDecorationSuccessCount) -{ - m_restoreDecorationSuccessCount = restoreDecorationSuccessCount; -} - -// ---------------------------------------------------------------------- - -inline std::list, std::pair > > & PlayerObject::getRestoreDecorationLayoutList() -{ - return m_restoreDecorationLayoutList; -} - -// ---------------------------------------------------------------------- - -inline int8 PlayerObject::getGalacticReserveDeposit() const -{ - return m_galacticReserveDeposit.get(); -} - -// ---------------------------------------------------------------------- - -inline std::string const & PlayerObject::getCurrentGcwRegion() const -{ - return m_currentGcwRegion.get(); -} - -// ---------------------------------------------------------------------- - -inline std::pair > const & PlayerObject::getCityGcwDefenderRegionInfo() const -{ - return m_cityGcwDefenderRegion.get(); -} - -// ---------------------------------------------------------------------- - -inline std::pair > const & PlayerObject::getGuildGcwDefenderRegionInfo() const -{ - return m_guildGcwDefenderRegion.get(); -} - -// ====================================================================== - -#endif // _PLAYER_OBJECT_H +// ====================================================================== +// +// PlayerObject.h +// +// Copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef _PLAYER_OBJECT_H +#define _PLAYER_OBJECT_H + +// ====================================================================== + +#include "Archive/AutoDeltaMap.h" +#include "Archive/AutoDeltaPackedMap.h" +#include "serverGame/DraftSchematicObject.h" +#include "serverGame/IntangibleObject.h" +#include "serverGame/Region.h" +#include "sharedFoundation/BitArray.h" +#include "sharedFoundation/StationId.h" +#include "sharedFoundation/Watcher.h" +#include "sharedGame/CollectionsDataTable.h" +#include "sharedGame/CraftingData.h" +#include "sharedGame/MatchMakingId.h" +#include "sharedGame/PlayerData.h" +#include "sharedGame/PlayerQuestData.h" +#include "sharedGame/Waypoint.h" +#include "sharedMath/Quaternion.h" +#include "sharedNetworkMessages/MessageQueueCraftExperiment.h" +#include "sharedObject/CachedNetworkId.h" +#include "sharedSkillSystem/SkillObject.h" + +#include + +// ====================================================================== + +struct ChatAvatarId; +class MessageQueueDraftSlots; +class MessageQueueDraftSlotsQueryResponse; +class ServerPlayerObjectTemplate; +class TangibleObject; + +namespace MessageDispatch +{ + class Callback; +} + +// ====================================================================== + +/** + * Class to hold all the player and account-level data. A character should + * keep this object, even if the creature/vehicle/etc. they control changes. + */ +class PlayerObject : public IntangibleObject +{ +public: + + struct ChatLogEntry + { + ChatLogEntry(); + + int m_index; + time_t m_time; + }; + + typedef stdlist::fwd ChatLog; + typedef stdvector::fwd StringVector; + typedef stdmap::fwd ExperiencePointMap; + typedef stdmap::fwd WaypointMap; + typedef Archive::AutoDeltaPackedMap PlayerQuestDataMap; + + explicit PlayerObject(const ServerPlayerObjectTemplate* newTemplate); + virtual ~PlayerObject(); + + virtual PlayerObject *asPlayerObject(); + virtual PlayerObject const *asPlayerObject() const; + + static void removeDefaultTemplate(void); + static stdset::fwd const &getAllPlayerObjects(); + + void addMembersToPackages (); + Waypoint const createWaypoint (const Location & location, bool ignoreLimits); + Waypoint const createOrUpdateReusableWaypoint(const Location & location, const std::string & objvarTrackingName, const Unicode::String & waypointNameIfCreated, int waypointColorIfCreated = -1); + Waypoint & getWaypoint (const NetworkId & waypointId); + void getWaypointsInDatapad (std::vector & target); + void getWaypointAttributes (const NetworkId & waypointId, ServerObject::AttributeVector & data); + void destroyWaypoint (const NetworkId & waypoint); + WaypointMap const &getWaypoints () const; + void setGroupWaypoints (WaypointMap const &groupWaypointMap); + + virtual void getAttributes (stdvector >::fwd &data) const; + virtual void endBaselines(); + virtual void onLoadedFromDatabase(); + static std::string getAccountDescription(const ServerObject *); + static std::string getAccountDescription(const NetworkId &); + std::string getAccountDescription() const; + +public: + StationId getStationId() const; + float getCheaterLevel() const; + int getBornDate() const; + int getAgeInDays() const; + static int getCurrentBornDate(); + uint32 getPlayedTime() const; + float getPlayedTimeAccumOnly() const; + void setPlayedTimeAccumOnly(float playedTimeAccum); + + unsigned long getSessionPlayTimeDuration() const; + unsigned long getSessionActivePlayTimeDuration() const; + int32 getSessionStartPlayTime() const; + int32 getSessionLastActiveTime() const; + void setSessionPlayTimeInfo(int32 sessionStartPlayTime, int32 sessionLastActiveTime, unsigned long sessionActivePlayTimeDuration); + + void setStationId(StationId account); + void setCheaterLevel(float level); + void setBornDate(); + void adjustBornDate(int adjustment); + void alterPlayedTime(float time); + + void setMatchMakingPersonalProfileId(MatchMakingId const &id); + MatchMakingId const &getMatchMakingPersonalProfileId() const; + + void setMatchMakingCharacterProfileId(MatchMakingId const &id); + MatchMakingId const &getMatchMakingCharacterProfileId() const; + + void toggleSearchableByCtsSourceGalaxy(); + void toggleDisplayLocationInSearchResults(); + void toggleAnonymous(); + void toggleHelper(); + void toggleRolePlay(); + void toggleOutOfCharacter(); + void toggleLookingForWork(); + + + bool isAwayFromKeyBoard() const; + void toggleAwayFromKeyBoard(); + + void toggleDisplayingFactionRank(); + + bool isLookingForGroup() const; + void setLookingForGroup(bool const lookingForGroup); + void toggleLookingForGroup(); + + StringVector const & getSortedLowercaseFriendList() const; + void setFriendList(const StringVector &friendList); + bool isFriend(const std::string &name) const; + void requestFriendList() const; + void findFriend(const std::string & name); + void replyLocationToFriend(const std::string & friendName, const NetworkId & friendId); + void receiveLocationToFriend(const NetworkId & friendId, const Location & friendLocation); + void failLocationToFriend(const NetworkId & friendId); + void receiveFailLocationToFriend(const NetworkId & friendId); + + StringVector const & getSortedLowercaseIgnoreList() const; + void setIgnoreList(const StringVector &ignoreList); + bool isIgnoring(const std::string &name) const; + void requestIgnoreList() const; + + void setTitle(std::string const &title); + std::string const & getTitle() const; + + bool adjustLotCount(int adjustment); + + void setSpokenLanguage(int const languageId); + int getSpokenLanguage() const; + + void setLinkDead(bool const linkDead); + bool getLinkDead() const; + + static bool isIgnoring(NetworkId const &target, NetworkId const &source); + + int getMaxForcePower (void) const; + virtual void setMaxForcePower (int value); + int getForcePower (void) const; + void setForcePower (int value); + float getForcePowerRegenRate (void) const; + void setForcePowerRegenRate (float value); + void regenerateForcePower (float time); + + //@todo It is unfortunate that these jedi-related things are in the supposedly generic PlayerObject + virtual bool isJedi() const; + void addJediToAccount() const; + void addJediToAccountAck() const; + void makeSpectralOnAccount() const; + void makeSpectralOnAccountAck() const; + + void checkStomach(); + + virtual void handleCMessageTo(const MessageToPayload &message); + + void logChat(int const logIndex); + + ChatLog const &getChatLog() const; + void cleanChatLog(); + + void checkTheater(const Vector & pos, const std::string & scene, float speed, float updateRadius); + bool setTheater(const std::string & datatable, const Vector & position, const std::string & scene, const std::string & script, const NetworkId & creator, const std::string & name, IntangibleObject::TheaterLocationType locationType); + void clearTheater(); + bool hasTheater() const; + const NetworkId & getTheater() const; + +public: + + int getExperiencePoints(const std::string & experienceType) const; + const std::map & getExperiencePoints() const; + int getExperienceLimit(const std::string & experienceType) const; + int grantExperiencePoints(const std::string & experienceType, int amount); + void clearSchematics(); + bool grantSchematicGroup(const std::string & groupNameWithModifier, bool fromSkill); + bool grantSchematic(uint32 schematicCrc, bool fromSkill); + bool revokeSchematic(uint32 schematicCrc, bool fromSkill); + bool hasSchematic(uint32 schematicCrc); + + // crafting functions + bool isCrafting(void) const; + const stdmap,int>::fwd & getDraftSchematics () const; + const CachedNetworkId & getCraftingTool () const; + void setCraftingTool(const TangibleObject & tool); + const CachedNetworkId & getCraftingStation () const; + void setCraftingStation(const TangibleObject * station); + const DraftSchematicObject * getCurrentDraftSchematic () const; + bool requestCraftingSession(const NetworkId & toolId); + void sendUseableDraftSchematics(stdvector::fwd & schematicNames); + bool requestDraftSlots(uint32 draftSchematicCrc, MessageQueueDraftSlots * message, MessageQueueDraftSlotsQueryResponse * queryMessage); + void selectDraftSchematic(int index); + Crafting::CraftingError fillSlot(int slotIndex, int slotOptionIndex, const NetworkId & ingredientIndex); + Crafting::CraftingError emptySlot(int slotIndex, const NetworkId & targetContainer); + int goToNextCraftingStage (); + int startCraftingExperiment (); + Crafting::CraftingResult experiment(const stdvector::fwd & experiments, int totalPoints, int corelevel); + bool customize(int property, int value) const; + int setCustomizationData(const Unicode::String & name, int appearanceIndex, const std::vector & customizations, int itemCount) const; + bool createPrototype(bool keepPrototype); + bool createManufacturingSchematic(void); + bool restartCrafting (); + void stopCrafting (bool normalExit); + enum Crafting::CraftingStage getCraftingStage () const; + void setCraftingLevel(int level); + int getCraftingLevel() const; + void setAllowEmptySlot(bool allow); + + int getAccountNumLots() const; + void setAccountNumLotsOverLimitSpam(); + + CreatureObject * getCreatureObject(); + const CreatureObject * getCreatureObject() const; + + void setPriviledgedTitle(int8 priviledgedTitle); + + bool getIsUnsticking() const; + void setIsUnsticking(bool value); + + //-- old quest system + bool isQuestComplete(int questId) const; + bool isQuestActive(int questId) const; + void activateQuest(int questId); + void deactivateQuest(int questId); + void completeQuest(int questId); + void clearCompletedQuest(int questId); + + //--new quest system + enum QuestResult {QR_success, QR_alreadyActive, QR_noSuchQuest, QR_noSuchTask, QR_alreadyComplete, QR_failedPrerequisites, QR_failedExclusion, QR_questNotActive, QR_taskNotActive, QR_noSuchPlayer, QR_questNotCompleted, QR_alreadyReceivedReward}; + + QuestResult questCanActivateQuest(uint32 questCrc) const; + QuestResult questActivateQuest(uint32 questCrc, NetworkId const & questGiver); + QuestResult questCompleteQuest(uint32 questCrc); + QuestResult questGrantQuestReward(uint32 questCrc, std::string const & selectedReward); + void questClearQuest(uint32 questCrc); + QuestResult questCanActivateQuestTask(uint32 questCrc, int taskId) const; + QuestResult questActivateQuestTask(uint32 questCrc, int taskId); + QuestResult questCompleteQuestTask(uint32 questCrc, int taskId); + QuestResult questFailQuestTask(uint32 questCrc, int taskId); + QuestResult questClearQuestTask(uint32 questCrc, int taskId); + bool questHasActiveQuest(uint32 questCrc) const; + bool questHasCompletedQuest(uint32 questCrc) const; + bool questHasActiveQuestTask(uint32 questCrc, int taskId) const; + bool questHasCompletedQuestTask(uint32 questCrc, int taskId) const; + uint32 questGetQuestStatus(uint32 const questCrc) const; + stdvector::fwd questGetAllActiveQuestIds() const; + stdvector::fwd questGetAllCompletedQuestIds() const; + bool questPlayerCanClaimRewardFor(uint32 questCrc); + + uint32 getCurrentQuest() const; + void setCurrentQuest(uint32 questCrc); + + virtual void virtualOnLogout(); + virtual void getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const; + virtual void setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source); + + void setRoleIconChoice(int roleIconChoice); + int getRoleIconChoice() const; + void setAggroImmuneDuration(int const duration); + bool isAggroImmune() const; + + std::string const & getSkillTemplate() const; + bool setSkillTemplate(std::string const & templateName, bool clientRequest); + + std::string const & getWorkingSkill() const; + bool setWorkingSkill(std::string const & skillName, bool clientRequest); + + bool getIsFromLogin(void) const; + void setIsFromLogin(bool val); + + bool isNormalPlayer() const; + bool isCustomerServiceRepresentative() const; + bool isDeveloper() const; + bool isWarden() const; + + void setPendingRequestQuestInformation(uint32 questCrc, NetworkId const & questGiver); + uint32 getPendingRequestQuestCrc() const; + NetworkId const & getPendingRequestQuestGiver() const; + + int getNumberOfActiveQuests() const; + void setPlayerQuestDataComplete(uint32 questCrc, PlayerQuestData & playerQuestData); + void pickNewCurrentQuest(); + + int32 getCurrentGcwPoints() const; + int32 getCurrentGcwRating() const; + int32 getCurrentPvpKills() const; + int64 getLifetimeGcwPoints() const; + int32 getMaxGcwImperialRating() const; + int32 getMaxGcwRebelRating() const; + int32 getLifetimePvpKills() const; + int32 getNextGcwRatingCalcTime() const; + int getCurrentGcwRank() const; + float getCurrentGcwRankProgress() const; + int getMaxGcwImperialRank() const; + int getMaxGcwRebelRank() const; + int32 getGcwRatingActualCalcTime() const; + bool needsGcwRatingRecalculated() const; + + void modifyCurrentGcwPoints(int count, bool modifyLifetimeValue); + void modifyCurrentGcwRating(int count, bool modifyMaxValue); + void modifyCurrentPvpKills(int count, bool modifyLifetimeValue); + void modifyLifetimeGcwPoints(int count); + void modifyMaxGcwImperialRating(int count); + void modifyMaxGcwRebelRating(int count); + void modifyLifetimePvpKills(int count); + void modifyNextGcwRatingCalcTime(int weekCount); + void setNextGcwRatingCalcTime(bool alwaysSendMessageToForRecalc); + void ctsUseOnlySetGcwInfo(int32 currentGcwPoints, int32 currentGcwRating, int32 currentPvpKills, int64 lifetimeGcwPoints, int32 maxGcwImperialRating, int32 maxGcwRebelRating, int32 lifetimePvpKills, int32 nextGcwRatingCalcTime); + + void addToPlayerHateList(NetworkId const & id); + void removeFromPlayerHateList(NetworkId const & id); + void clearPlayerHateList(); + + uint32 getSessionActivity() const; + void clearSessionActivity(); + void addSessionActivity(uint32 activity); + int32 getKillMeter() const; + void incrementKillMeter(int amount); + void updateKillMeter(float deltaTime); + + NetworkId const &getPetId() const; + void setPetId(NetworkId const & newId); + void setPetCommandList(std::vector const &commands); + void setPetToggledCommands(std::vector const &commands); + + bool modifyCollectionSlotValue(std::string const & slotName, int64 delta); + + bool getCollectionSlotValue(std::string const & slotName, unsigned long & value) const; + bool getCollectionSlotValue(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long & value) const; + + bool hasCompletedCollectionSlotPrereq(std::string const & slotName, stdvector::fwd * collectionInfo = NULL) const; + bool hasCompletedCollectionSlotPrereq(CollectionsDataTable::CollectionInfoSlot const & slotInfo, stdvector::fwd * collectionInfo = NULL) const; + + bool hasCompletedCollectionSlot(std::string const & slotName) const; + bool hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo) const; + static bool hasCompletedCollectionSlot(CollectionsDataTable::CollectionInfoSlot const & slotInfo, unsigned long slotValue); + + bool hasCompletedCollection(std::string const & collectionName) const; + + bool hasCompletedCollectionPage(std::string const & pageName) const; + + bool hasCompletedCollectionBook(std::string const & bookName) const; + + int getCompletedCollectionSlotCountInCollection(std::string const & collectionName, stdvector::fwd * collectionInfo = NULL) const; + + int getCompletedCollectionSlotCountInPage(std::string const & pageName, stdvector::fwd * collectionInfo = NULL) const; + int getCompletedCollectionCountInPage(std::string const & pageName, stdvector::fwd * collectionInfo = NULL) const; + + int getCompletedCollectionSlotCountInBook(std::string const & bookName, stdvector::fwd * collectionInfo = NULL) const; + int getCompletedCollectionCountInBook(std::string const & bookName, stdvector::fwd * collectionInfo = NULL) const; + int getCompletedCollectionPageCountInBook(std::string const & bookName, stdvector::fwd * collectionInfo = NULL) const; + int getCompletedCollectionBookCount(stdvector::fwd * collectionInfo = NULL) const; + + void migrateLegacyBadgesToCollection(stdvector::fwd const & badges); + + // chat spam info + int getChatSpamSpatialNumCharacters() const; + void updateChatSpamSpatialNumCharacters(NetworkId const & character, int spatialNumCharacters); + + int getChatSpamNonSpatialNumCharacters() const; + void handleChatStatisticsFromChatServer(NetworkId const & character, int chatSpamTimeEndInterval, int spatialNumCharacters, int nonSpatialNumCharacters); + + int getChatSpamTimeEndInterval() const; + + time_t getChatSpamNextTimeToNotifyPlayerWhenLimited() const; + void setChatSpamNextTimeToNotifyPlayerWhenLimited(time_t chatSpamNextTimeToNotifyPlayerWhenLimited); + + // citizenship info + void updateCitizenshipInfo(); + + // GCW Region info + void updateGcwRegionInfo(); + std::string const & getCurrentGcwRegion() const; + + void updateGcwDefenderRegionInfo(); + std::pair > const & getCityGcwDefenderRegionInfo() const; + std::pair > const & getGuildGcwDefenderRegionInfo() const; + + // squelch info + void squelch(NetworkId const & squelchedById, std::string const & squelchedByName, int squelchDurationSeconds); + void unsquelch(); + NetworkId const & getSquelchedById() const; + int getSecondsUntilUnsquelched(); // returns 0 if not currently squelched; returns < 0 if indefinitely squelched + + void modifyShowBackpack(bool b); + void modifyShowHelmet(bool b); + + bool getShowBackpack() const; + bool getShowHelmet() const; + + void setGuildRank(BitArray const & guildRank); + BitArray const & getGuildRank() const; + + void setCitizenRank(BitArray const & citizenRank); + BitArray const & getCitizenRank() const; + + EnvironmentInfo getEnvironmentFlags() const; + void overrideDefaultAttack(std::string const & attack); + std::string const & getDefaultAttackOverride() const; + + void setEnvironmentFlags(EnvironmentInfo const & flags); + + // getter/setter for variables to track the status of the + // /pickupAllRoomItemsIntoInventory and + // /dropAllInventoryItemsIntoRoom commands + int getPickupDropAllItemsOperationId() const; + void setPickupDropAllItemsOperationId(int pickupDropAllItemsOperationId); + + NetworkId const & getPickupDropAllItemsCellId() const; + void setPickupDropAllItemsCellId(NetworkId const & pickupDropAllItemsCellId); + + bool getPickupAllItemsAllowInventoryOverload() const; + void setPickupAllItemsAllowInventoryOverload(bool pickupAllItemsAllowInventoryOverload); + + int getPickupDropAllItemsNumItemsSoFar() const; + void setPickupDropAllItemsNumItemsSoFar(int pickupDropAllItemsNumItemsSoFar); + + std::set & getPickupDropAllItemsProcessedItemsSoFar(); + + // getter/setter for variables to track the status of a restore decoration layout operation + int getRestoreDecorationOperationId() const; + void setRestoreDecorationOperationId(int restoreDecorationOperationId); + + NetworkId const & getRestoreDecorationPobId() const; + void setRestoreDecorationPobId(NetworkId const & restoreDecorationPobId); + + NetworkId const & getRestoreDecorationObjectBeingRestored() const; + void setRestoreDecorationObjectBeingRestored(NetworkId const & restoreDecorationObjectBeingRestored); + + int getRestoreDecorationTotalCount() const; + void setRestoreDecorationTotalCount(int restoreDecorationTotalCount); + + int getRestoreDecorationAttemptedCount() const; + void setRestoreDecorationAttemptedCount(int restoreDecorationAttemptedCount); + + int getRestoreDecorationSuccessCount() const; + void setRestoreDecorationSuccessCount(int restoreDecorationSuccessCount); + + std::list, std::pair > > & getRestoreDecorationLayoutList(); + + static bool canAccessGalacticReserve(real x, real z); + void depositToGalacticReserve(bool ignoreCooldownAndLocationCheck); + void withdrawFromGalacticReserve(); + void depersistGalacticReserveDeposit(); + int8 getGalacticReserveDeposit() const; + +protected: + + virtual const SharedObjectTemplate * getDefaultSharedTemplate(void) const; + virtual void virtualOnSetAuthority(); + +private: + int getForcePowerRegen(float time); + void onWaypointChanged(const Waypoint & newValue); + void onWaypointCreated(const NetworkId &, const Waypoint &); + void onWaypointSet(NetworkId const &, Waypoint const &, Waypoint const &); + void onWaypointRemoved(NetworkId const &, const Waypoint &); + + void questCheckQuestLimits(); + + void handleRecalculateGcwRating(); + void sendRecalculateGcwRatingMessageTo(int delay); + +private: + static const SharedObjectTemplate * m_defaultSharedTemplate; // template to use if no shared template is given + + MessageDispatch::Callback * m_callback; + + Archive::AutoDeltaVariable m_stationId; + + // ***DEPRECATED DO NOT USE*** + // see CreatureObject::getHouse() and CreatureObject::setHouse() for replacement + Archive::AutoDeltaVariable m_houseId; ///< The player's domicile + + Archive::AutoDeltaVariable m_accountNumLots; ///< Number of lots used by all the characters on this account (on this server cluster only) + Archive::AutoDeltaVariable m_accountNumLotsOverLimitSpam; /// controls whether the player should be spammed for exceeding the lot limit + Archive::AutoDeltaVariable m_accountMaxLotsAdjustment; ///< Extra lots available to this account (or possibly penalty lots taken away) + Archive::AutoDeltaVariable m_accountIsOutcast; ///< Is this account outcast? + Archive::AutoDeltaVariable m_accountCheaterLevel; ///< how suspected of cheating this person is, for use with movement validation + + PlayerObject(const PlayerObject &); + PlayerObject & operator = ( const PlayerObject & ); + + // player abilities + Archive::AutoDeltaMap, int> m_draftSchematics; // draft schematics the player may use + Archive::AutoDeltaMap m_experiencePoints; // xp name->amount map + Archive::AutoDeltaVariable m_expModified; // just a flag that we increment any time the creature is granted new xp + Archive::AutoDeltaVariable m_maxForcePower; ///< Maximum force power the player can have + Archive::AutoDeltaVariable m_forcePower; ///< Current force power the player has + Archive::AutoDeltaVariable m_forceRegenRate; ///< Rate at which the force power regenerates (units/sec) + Archive::AutoDeltaVariable m_forceRegenValue; ///< Amount of force power that's regenerated + + // crafting system data + Archive::AutoDeltaVariable m_craftingLevel; // crafting level of the current crafting session + Archive::AutoDeltaVariable m_experimentPoints; // experiment points available to the player + Archive::AutoDeltaVariable m_craftingStage; // what stage in the crafting process a player is in + Archive::AutoDeltaVariable m_craftingTool; // tool a player is crafting with + Archive::AutoDeltaVariable m_craftingStation; // station a player is crafting with + Archive::AutoDeltaVariable m_craftingComponentBioLink;// bio-link id of a component + stdvector::fwd m_useableDraftSchematics; // draft schematics a player may currently select from + ConstWatcher m_draftSchematic; // draft schematic the player is crafting with + static bool m_allowEmptySlot; // flag to allow emptySlot() to be called when not in the crafting assembly stage. + + Archive::AutoDeltaVariable m_matchMakingPersonalProfileId; // What the player defines their personality as + Archive::AutoDeltaVariable m_matchMakingCharacterProfileId; // What the player defines their character as + + // these 2 lists ***MUST BE LOWERCASE AND MUST BE KEPT SORTED FOR QUICK LOOKUP*** + Archive::AutoDeltaVector m_friendList; + Archive::AutoDeltaVector m_ignoreList; + + Archive::AutoDeltaVariable m_skillTitle; + Archive::AutoDeltaVariable m_spokenLanguage; + Archive::AutoDeltaMap m_waypoints; + Archive::AutoDeltaMap m_groupWaypoints; + Archive::AutoDeltaVariable m_bornDate; + Archive::AutoDeltaVariable m_playedTime; + float m_playedTimeAccum; + + // information to track player's play time during this particular session + // this information is kept and tracked in the connection server, but is + // cached here for use by the game server + Archive::AutoDeltaVariable m_sessionStartPlayTime; // time when the player started playing the character + Archive::AutoDeltaVariable m_sessionLastActiveTime; // the client will detect when the player is "active" or "inactive"; this keeps track of the last time that the client said the player was "active"; if 0, it means the client is currently "inactive" + Archive::AutoDeltaVariable m_sessionActivePlayTimeDuration; // total amount of play time player was active (i.e. at the mouse/keyboard/joystick) + + Archive::AutoDeltaVariable m_food; + Archive::AutoDeltaVariable m_maxFood; + Archive::AutoDeltaVariable m_drink; + Archive::AutoDeltaVariable m_maxDrink; + Archive::AutoDeltaVariable m_meds; + Archive::AutoDeltaVariable m_maxMeds; + + Archive::AutoDeltaVariable m_privledgedTitle; + Archive::AutoDeltaVariable m_completedQuests; + Archive::AutoDeltaVariable m_activeQuests; + Archive::AutoDeltaVariable m_currentQuest; + + Archive::AutoDeltaPackedMap m_quests; + + Archive::AutoDeltaVariable m_theaterDatatable; + Archive::AutoDeltaVariable m_theaterPosition; + Archive::AutoDeltaVariable m_theaterScene; + Archive::AutoDeltaVariable m_theaterScript; + Archive::AutoDeltaVariable m_theaterNumObjects; + Archive::AutoDeltaVariable m_theaterRadius; + Archive::AutoDeltaVariable m_theaterCreator; + Archive::AutoDeltaVariable m_theaterName; + Archive::AutoDeltaVariable m_theaterId; + Archive::AutoDeltaVariable m_theaterLocationType; + Archive::AutoDeltaVariable m_roleIconChoice; + Archive::AutoDeltaVariable m_aggroImmuneDuration; + Archive::AutoDeltaVariable m_aggroImmuneStartTime; + + ChatLog * const m_chatLog; + time_t m_chatLogPurgeTime; + bool m_isUnsticking; + + //when asking a player to accept or complete a quest, remember the quest that we asked them about + + //TODO sync to other servers as necessary? + uint32 m_pendingRequestQuestCrc; + NetworkId m_pendingRequestQuestGiver; + + Archive::AutoDeltaVariable m_skillTemplate; + Archive::AutoDeltaVariable m_workingSkill; + Archive::AutoDeltaVariable m_isFromLogin; ///< This defaults to true, and is set to false in CreatureObject::virtualOnSetClient, (used to distinguish when coming from login as opposed to from a scene warp) + + Archive::AutoDeltaVariable m_currentGcwPoints; + Archive::AutoDeltaVariable m_currentGcwRating; + Archive::AutoDeltaVariable m_currentPvpKills; + Archive::AutoDeltaVariable m_lifetimeGcwPoints; + Archive::AutoDeltaVariable m_maxGcwImperialRating; + Archive::AutoDeltaVariable m_maxGcwRebelRating; + Archive::AutoDeltaVariable m_lifetimePvpKills; + Archive::AutoDeltaVariable m_nextGcwRatingCalcTime; + Archive::AutoDeltaVariable m_currentGcwRank; + Archive::AutoDeltaVariable m_currentGcwRankProgress; + Archive::AutoDeltaVariable m_maxGcwImperialRank; + Archive::AutoDeltaVariable m_maxGcwRebelRank; + + // the Epoch when the next messageTo to cause GCW rating recalculation will occur + Archive::AutoDeltaVariable m_gcwRatingActualCalcTime; + + // copy of the player's hate list sent to the authoritative client + Archive::AutoDeltaSet m_playerHateList; + + // activity that the player has done during this session + Archive::AutoDeltaVariable m_sessionActivity; + // these two variables represent the commando kill meter + Archive::AutoDeltaVariable m_killMeter; + // this variable stores the fractional state of the meter but is not persisted nor synchronized across servers. + float m_killMeterRemainder; + + Archive::AutoDeltaVariable m_petId; + Archive::AutoDeltaVector m_petCommandList; + Archive::AutoDeltaVector m_petToggledCommands; // These are the commands on the + // pet toolbar that should display + // visually as being toggled on + + // both m_collections and m_collections2 form a "contiguous" collections bit array + // we only break them up into multiple members because of DB storage restrictions + Archive::AutoDeltaVariable m_collections; + Archive::AutoDeltaVariable m_collections2; + Archive::AutoDeltaVariable * m_allCollections[2]; + + // chat spam info + Archive::AutoDeltaVariable m_chatSpamSpatialNumCharacters; + Archive::AutoDeltaVariable m_chatSpamNonSpatialNumCharacters; + Archive::AutoDeltaVariable m_chatSpamTimeEndInterval; + Archive::AutoDeltaVariable m_chatSpamNextTimeToSyncWithChatServer; + time_t m_chatSpamNextTimeToNotifyPlayerWhenLimited; + + // citizenship info + Archive::AutoDeltaVariable m_citizenshipCity; + Archive::AutoDeltaVariable m_citizenshipType; // CityDataCitizenType + + // GCW Region info + Archive::AutoDeltaVariable m_currentGcwRegion; + // std::pair > + Archive::AutoDeltaVariable > > m_cityGcwDefenderRegion; + Archive::AutoDeltaVariable > > m_guildGcwDefenderRegion; + + // squelch info + Archive::AutoDeltaVariable m_squelchedById; // id of the toon who squelched this toon; is NetworkId::cms_invalid if this toon is not squelched + Archive::AutoDeltaVariable m_squelchedByName; // name of the toon who squelched this toon + Archive::AutoDeltaVariable m_squelchExpireTime; // the Epoch time when the toon will be unsquelched; is < 0 for indefinite squelch + + Archive::AutoDeltaVariable m_showBackpack; + Archive::AutoDeltaVariable m_showHelmet; + + Archive::AutoDeltaVariable m_environmentFlags; // Force Day, Night, whatever else. + // Default attack override + Archive::AutoDeltaVariable m_defaultAttackOverride; // This string will override the user's default attack + + Archive::AutoDeltaVariable m_guildRank; + Archive::AutoDeltaVariable m_citizenRank; + + // for use to track the status of the /pickupAllRoomItemsIntoInventory + // and /dropAllInventoryItemsIntoRoom commands, which occurs over a + // period of time; these are not proxied, as the only way the cell/structure + // in which the player is standing when the command is executed can + // change authority is during a game server crash recovery scenario + // (or a warp in the case of a POB ship), in which case we'll just cancel + // the currently executing /pickupAllRoomItemsIntoInventory + // or /dropAllInventoryItemsIntoRoom command, and the player do it again + int m_pickupDropAllItemsOperationId; + NetworkId m_pickupDropAllItemsCellId; + bool m_pickupAllItemsAllowInventoryOverload; + int m_pickupDropAllItemsNumItemsSoFar; + std::set m_pickupDropAllItemsProcessedItemsSoFar; + + // for use to track the status of a restore decoration layout operation, + // which occurs over a period of time; these are not proxied, as the only + // way the structure in which the player is standing when the command + // is executed can change authority is during a game server crash recovery + // scenario (or a warp in the case of a POB ship), in which case we'll just + // cancel the currently executing operation, and the player can do it again + int m_restoreDecorationOperationId; + NetworkId m_restoreDecorationPobId; + NetworkId m_restoreDecorationObjectBeingRestored; + int m_restoreDecorationTotalCount; + int m_restoreDecorationAttemptedCount; + int m_restoreDecorationSuccessCount; + std::list, std::pair > > m_restoreDecorationLayoutList; + + Archive::AutoDeltaVariable m_galacticReserveDeposit; + + Archive::AutoDeltaVariable m_pgcRatingCount; + Archive::AutoDeltaVariable m_pgcRatingTotal; + Archive::AutoDeltaVariable m_pgcLastRatingTime; +}; + +// ====================================================================== + +inline StationId PlayerObject::getStationId() const +{ + return m_stationId.get(); +} + +// ---------------------------------------------------------------------- + +inline float PlayerObject::getCheaterLevel() const +{ + return m_accountCheaterLevel.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getBornDate() const +{ + return m_bornDate.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getSessionStartPlayTime() const +{ + return m_sessionStartPlayTime.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getSessionLastActiveTime() const +{ + return m_sessionLastActiveTime.get(); +} + +// ---------------------------------------------------------------------- + +inline const stdmap,int>::fwd & PlayerObject::getDraftSchematics () const +{ + return m_draftSchematics.getMap(); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::clearSchematics() +{ + m_draftSchematics.clear(); +} + +// ---------------------------------------------------------------------- + +inline const CachedNetworkId & PlayerObject::getCraftingTool() const +{ + return m_craftingTool.get(); +} + +// ---------------------------------------------------------------------- + +inline const CachedNetworkId & PlayerObject::getCraftingStation() const +{ + return m_craftingStation.get(); +} + +// ---------------------------------------------------------------------- + +inline const DraftSchematicObject * PlayerObject::getCurrentDraftSchematic () const +{ + return m_draftSchematic.getPointer(); +} + +// ---------------------------------------------------------------------- + +inline enum Crafting::CraftingStage PlayerObject::getCraftingStage () const +{ + return static_cast(m_craftingStage.get()); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setCraftingLevel(int level) +{ + m_craftingLevel = level; +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getCraftingLevel() const +{ + return m_craftingLevel.get(); +} + +// ---------------------------------------------------------------------- + +inline bool PlayerObject::isCrafting(void) const +{ + return getCraftingStage() != Crafting::CS_none; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setAllowEmptySlot(bool allow) +{ + m_allowEmptySlot = allow; +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getAccountNumLots() const +{ + return m_accountNumLots.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getMaxForcePower(void) const +{ + return m_maxForcePower.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getForcePower(void) const +{ + return m_forcePower.get(); +} + +// ---------------------------------------------------------------------- + +inline float PlayerObject::getForcePowerRegenRate() const +{ + return m_forceRegenRate.get(); +} + +// ---------------------------------------------------------------------- + +inline const NetworkId & PlayerObject::getTheater() const +{ + return m_theaterId.get(); +} + +// ---------------------------------------------------------------------- + +inline bool PlayerObject::getIsFromLogin(void) const +{ + return m_isFromLogin.get(); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setIsFromLogin(bool val) +{ + m_isFromLogin = val; +} + +//---------------------------------------------------------------------- + +inline bool PlayerObject::isNormalPlayer() const +{ + return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::NormalPlayer); +} + +//---------------------------------------------------------------------- + +inline bool PlayerObject::isCustomerServiceRepresentative() const +{ + return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::CustomerServiceRepresentative); +} + +//---------------------------------------------------------------------- + +inline bool PlayerObject::isDeveloper() const +{ + return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::Developer); +} + +//---------------------------------------------------------------------- + +inline bool PlayerObject::isWarden() const +{ + return m_privledgedTitle.get() == static_cast(PlayerDataPriviledgedTitle::Warden); +} + +// ---------------------------------------------------------------------- + +inline uint32 PlayerObject::getCurrentQuest() const +{ + return m_currentQuest.get(); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setCurrentQuest(uint32 questCrc) +{ + m_currentQuest = questCrc; +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getCurrentGcwPoints() const +{ + return m_currentGcwPoints.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getKillMeter() const +{ + return m_killMeter.get(); +} + +inline NetworkId const & PlayerObject::getPetId() const +{ + return m_petId.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getCurrentGcwRating() const +{ + return m_currentGcwRating.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getCurrentPvpKills() const +{ + return m_currentPvpKills.get(); +} + +// ---------------------------------------------------------------------- + +inline int64 PlayerObject::getLifetimeGcwPoints() const +{ + return m_lifetimeGcwPoints.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getMaxGcwImperialRating() const +{ + return m_maxGcwImperialRating.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getMaxGcwRebelRating() const +{ + return m_maxGcwRebelRating.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getLifetimePvpKills() const +{ + return m_lifetimePvpKills.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getNextGcwRatingCalcTime() const +{ + return m_nextGcwRatingCalcTime.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getCurrentGcwRank() const +{ + return m_currentGcwRank.get(); +} + +// ---------------------------------------------------------------------- + +inline float PlayerObject::getCurrentGcwRankProgress() const +{ + return m_currentGcwRankProgress.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getMaxGcwImperialRank() const +{ + return m_maxGcwImperialRank.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getMaxGcwRebelRank() const +{ + return m_maxGcwRebelRank.get(); +} + +// ---------------------------------------------------------------------- + +inline int32 PlayerObject::getGcwRatingActualCalcTime() const +{ + return m_gcwRatingActualCalcTime.get(); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::addToPlayerHateList(NetworkId const & id) +{ + m_playerHateList.insert(id); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::removeFromPlayerHateList(NetworkId const & id) +{ + m_playerHateList.erase(id); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::clearPlayerHateList() +{ + m_playerHateList.clear(); +} + +// ---------------------------------------------------------------------- + +inline uint32 PlayerObject::getSessionActivity() const +{ + return m_sessionActivity.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getChatSpamSpatialNumCharacters() const +{ + return m_chatSpamSpatialNumCharacters.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getChatSpamNonSpatialNumCharacters() const +{ + return m_chatSpamNonSpatialNumCharacters.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getChatSpamTimeEndInterval() const +{ + return m_chatSpamTimeEndInterval.get(); +} + +// ---------------------------------------------------------------------- + +inline time_t PlayerObject::getChatSpamNextTimeToNotifyPlayerWhenLimited() const +{ + return m_chatSpamNextTimeToNotifyPlayerWhenLimited; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setChatSpamNextTimeToNotifyPlayerWhenLimited(time_t chatSpamNextTimeToNotifyPlayerWhenLimited) +{ + m_chatSpamNextTimeToNotifyPlayerWhenLimited = chatSpamNextTimeToNotifyPlayerWhenLimited; +} + +// ---------------------------------------------------------------------- + +inline NetworkId const & PlayerObject::getSquelchedById() const +{ + return m_squelchedById.get(); +} + +// ---------------------------------------------------------------------- + +inline bool PlayerObject::getShowHelmet() const +{ + return m_showHelmet.get(); +} + +// ---------------------------------------------------------------------- + +inline bool PlayerObject::getShowBackpack() const +{ + return m_showBackpack.get(); +} + +// ---------------------------------------------------------------------- + +inline PlayerObject::StringVector const & PlayerObject::getSortedLowercaseFriendList() const +{ + return m_friendList.get(); +} + +// ---------------------------------------------------------------------- + +inline PlayerObject::StringVector const & PlayerObject::getSortedLowercaseIgnoreList() const +{ + return m_ignoreList.get(); +} + +// ---------------------------------------------------------------------- + +inline EnvironmentInfo PlayerObject::getEnvironmentFlags() const +{ + return m_environmentFlags.get(); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::overrideDefaultAttack(std::string const & attack) +{ + m_defaultAttackOverride = attack; +} + +// ---------------------------------------------------------------------- + +inline std::string const & PlayerObject::getDefaultAttackOverride() const +{ + return m_defaultAttackOverride.get(); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setGuildRank(BitArray const & guildRank) +{ + m_guildRank.set(guildRank); +} + +// ---------------------------------------------------------------------- + +inline BitArray const & PlayerObject::getGuildRank() const +{ + return m_guildRank.get(); +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setCitizenRank(BitArray const & citizenRank) +{ + m_citizenRank.set(citizenRank); +} + +// ---------------------------------------------------------------------- + +inline BitArray const & PlayerObject::getCitizenRank() const +{ + return m_citizenRank.get(); +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getPickupDropAllItemsOperationId() const +{ + return m_pickupDropAllItemsOperationId; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setPickupDropAllItemsOperationId(int pickupDropAllItemsOperationId) +{ + m_pickupDropAllItemsOperationId = pickupDropAllItemsOperationId; +} + +// ---------------------------------------------------------------------- + +inline NetworkId const & PlayerObject::getPickupDropAllItemsCellId() const +{ + return m_pickupDropAllItemsCellId; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setPickupDropAllItemsCellId(NetworkId const & pickupDropAllItemsCellId) +{ + m_pickupDropAllItemsCellId = pickupDropAllItemsCellId; +} + +// ---------------------------------------------------------------------- + +inline bool PlayerObject::getPickupAllItemsAllowInventoryOverload() const +{ + return m_pickupAllItemsAllowInventoryOverload; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setPickupAllItemsAllowInventoryOverload(bool pickupAllItemsAllowInventoryOverload) +{ + m_pickupAllItemsAllowInventoryOverload = pickupAllItemsAllowInventoryOverload; +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getPickupDropAllItemsNumItemsSoFar() const +{ + return m_pickupDropAllItemsNumItemsSoFar; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setPickupDropAllItemsNumItemsSoFar(int pickupDropAllItemsNumItemsSoFar) +{ + m_pickupDropAllItemsNumItemsSoFar = pickupDropAllItemsNumItemsSoFar; +} + +// ---------------------------------------------------------------------- + +inline std::set & PlayerObject::getPickupDropAllItemsProcessedItemsSoFar() +{ + return m_pickupDropAllItemsProcessedItemsSoFar; +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getRestoreDecorationOperationId() const +{ + return m_restoreDecorationOperationId; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setRestoreDecorationOperationId(int restoreDecorationOperationId) +{ + m_restoreDecorationOperationId = restoreDecorationOperationId; +} + +// ---------------------------------------------------------------------- + +inline NetworkId const & PlayerObject::getRestoreDecorationPobId() const +{ + return m_restoreDecorationPobId; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setRestoreDecorationPobId(NetworkId const & restoreDecorationPobId) +{ + m_restoreDecorationPobId = restoreDecorationPobId; +} + +// ---------------------------------------------------------------------- + +inline NetworkId const & PlayerObject::getRestoreDecorationObjectBeingRestored() const +{ + return m_restoreDecorationObjectBeingRestored; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setRestoreDecorationObjectBeingRestored(NetworkId const & restoreDecorationObjectBeingRestored) +{ + m_restoreDecorationObjectBeingRestored = restoreDecorationObjectBeingRestored; +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getRestoreDecorationTotalCount() const +{ + return m_restoreDecorationTotalCount; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setRestoreDecorationTotalCount(int restoreDecorationTotalCount) +{ + m_restoreDecorationTotalCount = restoreDecorationTotalCount; +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getRestoreDecorationAttemptedCount() const +{ + return m_restoreDecorationAttemptedCount; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setRestoreDecorationAttemptedCount(int restoreDecorationAttemptedCount) +{ + m_restoreDecorationAttemptedCount = restoreDecorationAttemptedCount; +} + +// ---------------------------------------------------------------------- + +inline int PlayerObject::getRestoreDecorationSuccessCount() const +{ + return m_restoreDecorationSuccessCount; +} + +// ---------------------------------------------------------------------- + +inline void PlayerObject::setRestoreDecorationSuccessCount(int restoreDecorationSuccessCount) +{ + m_restoreDecorationSuccessCount = restoreDecorationSuccessCount; +} + +// ---------------------------------------------------------------------- + +inline std::list, std::pair > > & PlayerObject::getRestoreDecorationLayoutList() +{ + return m_restoreDecorationLayoutList; +} + +// ---------------------------------------------------------------------- + +inline int8 PlayerObject::getGalacticReserveDeposit() const +{ + return m_galacticReserveDeposit.get(); +} + +// ---------------------------------------------------------------------- + +inline std::string const & PlayerObject::getCurrentGcwRegion() const +{ + return m_currentGcwRegion.get(); +} + +// ---------------------------------------------------------------------- + +inline std::pair > const & PlayerObject::getCityGcwDefenderRegionInfo() const +{ + return m_cityGcwDefenderRegion.get(); +} + +// ---------------------------------------------------------------------- + +inline std::pair > const & PlayerObject::getGuildGcwDefenderRegionInfo() const +{ + return m_guildGcwDefenderRegion.get(); +} + +// ====================================================================== + +#endif // _PLAYER_OBJECT_H diff --git a/src/engine/server/library/serverGame/src/shared/object/ServerObject.cpp b/src/engine/server/library/serverGame/src/shared/object/ServerObject.cpp index aa95fe699..0ffc18429 100644 --- a/src/engine/server/library/serverGame/src/shared/object/ServerObject.cpp +++ b/src/engine/server/library/serverGame/src/shared/object/ServerObject.cpp @@ -1,8560 +1,8566 @@ -// ====================================================================== -// -//ServerObject.cpp -// -//Copyright 2000-2003 Sony Online Entertainment -// -// ====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/ServerObject.h" - -#include "UnicodeUtils.h" -#include "serverGame/AuthTransferTracker.h" -#include "serverGame/BuildingObject.h" -#include "serverGame/CellObject.h" -#include "serverGame/Chat.h" -#include "serverGame/Client.h" -#include "serverGame/CommoditiesMarket.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ConnectionServerConnection.h" -#include "serverGame/ConsoleManager.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/ContainmentMessageManager.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/DistributionListStack.h" -#include "serverGame/GameServer.h" -#include "serverGame/InstantDeleteList.h" -#include "serverGame/IntangibleVolumeContainer.h" -#include "serverGame/LineOfSightCache.h" -#include "serverGame/LogoutTracker.h" -#include "serverGame/MessageToQueue.h" -#include "serverGame/NetworkTriggerVolume.h" -#include "serverGame/NewbieTutorial.h" -#include "serverGame/ObjectIdManager.h" -#include "serverGame/ObjectTracker.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PatrolPathNodeProperty.h" -#include "serverGame/PatrolPathRootProperty.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerQuestObject.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/PlayerSanityChecker.h" -#include "serverGame/PlayerShipController.h" -#include "serverGame/PositionUpdateTracker.h" -#include "serverGame/ResourceContainerObject.h" -#include "serverGame/ServerClearCollidableFloraNotification.h" -#include "serverGame/ServerController.h" -#include "serverGame/ServerCreatureObjectTemplate.h" -#include "serverGame/ServerMessageForwarding.h" -#include "serverGame/ServerNoBuildNotification.h" -#include "serverGame/ServerObjectTemplate.h" -#include "serverGame/ServerObjectTerrainModificationNotification.h" -#include "serverGame/ServerResourceContainerObjectTemplate.h" -#include "serverGame/ServerSecureTrade.h" -#include "serverGame/ServerSynchronizedUi.h" -#include "serverGame/ServerUIManager.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/SpaceVisibilityManager.h" -#include "serverGame/SceneGlobalData.h" -#include "serverGame/TangibleObject.h" -#include "serverGame/TangibleVolumeContainer.h" -#include "serverGame/TeleportFixupHandler.h" -#include "serverGame/TriggerVolume.h" -#include "serverGame/VeteranRewardManager.h" -#include "serverNetworkMessages/AccountFeatureIdRequest.h" -#include "serverNetworkMessages/AdjustAccountFeatureIdResponse.h" -#include "serverNetworkMessages/FlagObjectForDeleteMessage.h" -#include "serverNetworkMessages/GameConnectionServerMessages.h" -#include "serverNetworkMessages/LoadContainedObjectMessage.h" -#include "serverNetworkMessages/LoadContentsMessage.h" -#include "serverNetworkMessages/MessageQueueTeleportObject.h" -#include "serverNetworkMessages/MessageToAckMessage.h" -#include "serverNetworkMessages/MessageToMessage.h" -#include "serverNetworkMessages/MessageToPayload.h" -#include "serverNetworkMessages/UnloadObjectMessage.h" -#include "serverPathfinding/ServerPathfindingConstants.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptParameters.h" -#include "serverUtility/ChatLogManager.h" -#include "serverUtility/ServerClock.h" -#include "Session/CommonAPI/CommonAPI.h" -#include "sharedCollision/BaseExtent.h" -#include "sharedCollision/CollisionProperty.h" -#include "sharedCollision/CollisionWorld.h" -#include "sharedDebug/Profiler.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/Clock.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/DynamicVariableLocationData.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/GameControllerMessage.h" -#include "sharedFoundation/Os.h" -#include "sharedGame/LfgCharacterData.h" -#include "sharedGame/PlatformFeatureBits.h" -#include "sharedGame/ProsePackage.h" -#include "sharedGame/QuestManager.h" -#include "sharedGame/SharedObjectTemplate.h" -#include "sharedGame/SharedStringIds.h" -#include "sharedGame/SocialsManager.h" -#include "sharedGame/SpatialChatManager.h" -#include "sharedLog/Log.h" -#include "sharedMathArchive/TransformArchive.h" -#include "sharedMessageDispatch/Message.h" -#include "sharedMessageDispatch/Transceiver.h" -#include "sharedNetworkMessages/AIDebuggingMessages.h" -#include "sharedNetworkMessages/ChatAvatarId.h" -#include "sharedNetworkMessages/CommandChannelMessages.h" -#include "sharedNetworkMessages/DeltasMessage.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/LogoutMessage.h" -#include "sharedNetworkMessages/MessageQueueCombatSpam.h" -#include "sharedNetworkMessages/MessageQueueDataTransform.h" -#include "sharedNetworkMessages/MessageQueueDataTransformWithParent.h" -#include "sharedNetworkMessages/MessageQueueGeneric.h" -#include "sharedNetworkMessages/MessageQueueGenericValueType.h" -#include "sharedNetworkMessages/MessageQueueNetworkIdAndTransform.h" -#include "sharedNetworkMessages/MessageQueueSocial.h" -#include "sharedNetworkMessages/MessageQueueSpatialChat.h" -#include "sharedNetworkMessages/ObjectChannelMessages.h" -#include "sharedObject/AlterResult.h" -#include "sharedObject/AlterScheduler.h" -#include "sharedObject/Appearance.h" -#include "sharedObject/ArrangementDescriptor.h" -#include "sharedObject/CellProperty.h" -#include "sharedObject/ContainedByProperty.h" -#include "sharedObject/Container.h" -#include "sharedObject/CustomizationData.h" -#include "sharedObject/CustomizationDataProperty.h" -#include "sharedObject/LayerProperty.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedObject/PortalProperty.h" -#include "sharedObject/RangedIntCustomizationVariable.h" -#include "sharedObject/SlotDescriptor.h" -#include "sharedObject/SlotDescriptorList.h" -#include "sharedObject/SlotIdManager.h" -#include "sharedObject/SlottedContainer.h" -#include "sharedObject/SlottedContainmentProperty.h" -#include "sharedObject/VolumeContainmentProperty.h" -#include "sharedTerrain/TerrainObject.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" -#include "swgServerNetworkMessages/MessageQueueScriptTransferMoney.h" -#include - -// ====================================================================== - -namespace DeleteReasons -{ - const std::string & describeDeleteReason(const int reason) - { - switch(reason) - { - case NotDeleted: - { - static const std::string r = "NotDeleted"; - return r; - } - break; - case Decay: - { - static const std::string r = "Decay"; - return r; - } - break; - case God: - { - static const std::string r = "God"; - return r; - } - break; - case Player: - { - static const std::string r = "Player"; - return r; - } - break; - case Script: - { - static const std::string r = "Script"; - return r; - } - break; - case CharacterDeleted: - { - static const std::string r = "CharacterDeleted"; - return r; - } - break; - case ContainerDeleted: - { - static const std::string r = "ContainerDeleted"; - return r; - } - break; - case Publish: - { - static const std::string r = "Publish"; - return r; - } - break; - case BadContainerTransfer: - { - static const std::string r = "BadContainerTransfer"; - return r; - } - break; - case Consumed: - { - static const std::string r = "Consumed"; - return r; - } - break; - case SetupFailed: - { - static const std::string r = "SetupFailed"; - return r; - } - break; - case Replaced: - { - static const std::string r = "Replaced"; - return r; - } - break; - } - static const std::string unknown = "UNKNOWN"; - return unknown; - } -} - -using namespace DeleteReasons; - -// ====================================================================== - -namespace ServerObjectNamespace -{ - const std::string OBJVAR_STRUCTURE_PLAYER_PACK("structure.player.pack"); - - const std::string OBJVAR_OPEN_BANK_TERMINAL_ID("open_bank_location"); - - unsigned long gs_objectCount = 0; - - const char * const portalPropertyCrcObjectVariableName = "portalProperty.crc"; - - // ---------------------------------------------------------------------- - - const std::string objvar_item_attribute_keys = "item_attrib_keys"; - const std::string objvar_item_attribute_values = "item_attrib_values"; - - // ---------------------------------------------------------------------- - - const uint32 s_clearLocalFlagsOnConcludeMask = - ~( - (1u<, MessageToId> s_currentMessageToBeingHandled = std::make_pair(std::make_pair(0, 0), MessageToId::cms_invalid); - - // ---------------------------------------------------------------------- - - // list of object types that supports no trade "shared" behavior - // (no trade item of those types can be picked up by another character - // on the same account as the character who currently owns the item) - std::set s_noTradeSharedTemplateItemType; - std::set s_noTradeSharedStaticItemType; - - // ---------------------------------------------------------------------- - - void sendDeleteToDatabase(const ServerObject& obj, int reason) - { - bool const immediate = InstantDeleteList::isOnList(*obj.getObjectTemplate()); - bool const cascadeDeleteReason = !obj.getLoadContents() && reason == DeleteReasons::House; // Anything that is deleted by house deletion and is demanded-loaded (i.e. cells) should have the delete reason of its contents set to DeleteReasons::House also, instead of DeleteReasons::ContainerDeleted. This is so the /restoreHouse command can identify these items - - FlagObjectForDeleteMessage const dm(obj.getNetworkId(), reason, immediate, !obj.getLoadContents(), cascadeDeleteReason); - GameServer::getInstance().sendToDatabaseServer(dm); - } - - //---------------------------------------------------------------------- - - void flagChildObjectsForDeletion(ServerObject &obj, int reason) - { - Container * const container = ContainerInterface::getContainer(obj); - if (container) - { - for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) - { - ServerObject * const containedObject = safe_cast((*containerIterator).getObject()); - if (containedObject && containedObject->isPersisted()) - { - sendDeleteToDatabase(*containedObject, reason); - LOG("CustomerService",("Deletion:%s deleted from game. Reason: %s", ServerObject::getLogDescription(containedObject).c_str(), describeDeleteReason(reason).c_str())); - flagChildObjectsForDeletion(*containedObject, reason); - } - } - } - } - - //---------------------------------------------------------------------- - - void endBaselinesInitializeScript(ServerObject& obj, bool doChildCheck) - { - if (doChildCheck) - { - ServerObject * parent = safe_cast(ContainerInterface::getContainedByObject(obj)); - if (parent && !parent->isInitialized()) - return; - } - - obj.getScriptObject()->initScriptInstances(); - obj.getScriptObject()->setOwnerIsInitialized(); - - Container* container = ContainerInterface::getContainer(obj); - if (container) - - { - std::vector initList; - - for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) - { - initList.push_back(*containerIterator); - } - for(std::vector::iterator i = initList.begin(); i != initList.end(); ++i) - { - ServerObject * containedObject = safe_cast((*i).getObject()); - if (!containedObject) - { - WARNING_STRICT_FATAL(true, ("Cannot initialize object %s because it did not resolve to an object from an id", (*i).getValueString().c_str())); - } - else - endBaselinesInitializeScript(*containedObject, false); - } - } - } - - //---------------------------------------------------------------------- - - const std::string OBJVAR_BANK_NAME_ID = "banking_bankid"; - - //---------------------------------------------------------------------- - - bool checkBankTransfer(ServerObject* dest, const ServerObject& item, const ServerObject* transferer) - { - if (!dest || !transferer) - return true; - - bool isBankTransfer = false; - const CreatureObject * const creature = transferer->asCreatureObject(); - if (creature && dest == creature->getBankContainer()) - { - float distance = 0.0f; - //Banks are carried along with the player, so their distance - //is always going to be 0. This block changes the parentInWorld - //to be the bank terminal that was opened rather than the bank - //itself. - const ServerObject * const bank = creature->getBankContainer(); - if (bank) - { - NetworkId bankTerminalId; - if (bank->areContentsLoaded() && creature->getObjVars().getItem(OBJVAR_OPEN_BANK_TERMINAL_ID,bankTerminalId)) - { - - const TangibleObject * const bankTerminal = safe_cast(NetworkIdManager::getObjectById(bankTerminalId)); - if (bankTerminal) - { - isBankTransfer = true; - Unicode::String bankName; - if (bankTerminal->getObjVars().getItem(OBJVAR_BANK_NAME_ID, bankName)) - { - if (!creature->isBankMember(bankName)) - { - return false; - } - } - - distance = creature->getPosition_w().magnitudeBetween(bankTerminal->getPosition_w()); - distance -= dest->getRadius(); - distance -= bankTerminal->getRadius(); - // Check range on the server with a 1m fudge factor in it. - if (distance > 6.0f + 1.0f) //todo MLS make that range of 6.0 configurable - { - static const StringId message("system_msg", "out_of_range"); - Chat::sendSystemMessage(*creature, message, Unicode::emptyString); - return false; - } - } - else - { - return false; - } - } - else - { - return false; - } - } - } - - return true; - - } - - //---------------------------------------------------------------------- - - void getPlayerControlledContents(ServerObject &obj, std::vector &results) - { - if (obj.isPlayerControlled()) - results.push_back(CachedNetworkId(obj)); - - Container *container = ContainerInterface::getContainer(obj); - if (container) - { - for (ContainerIterator i = container->begin(); i != container->end(); ++i) - { - ServerObject *containedObject = safe_cast((*i).getObject()); - if (containedObject) - getPlayerControlledContents(*containedObject, results); - } - } - } - - // ---------------------------------------------------------------------- - - void getContainedClients(ServerObject &obj, std::vector > &containedClients) - { - // find all clients for primary controlled objects in the containment hierarchy under obj (including obj) - - Client * const client = obj.getClient(); - if (client && client->getCharacterObjectId() == obj.getNetworkId()) - containedClients.push_back(Watcher(client)); - - Container * const container = ContainerInterface::getContainer(obj); - if (container) - { - for (ContainerIterator i = container->begin(); i != container->end(); ++i) - { - ServerObject * const containedObject = safe_cast((*i).getObject()); - if (containedObject) - getContainedClients(*containedObject, containedClients); - } - } - } - - // ---------------------------------------------------------------------- - - unsigned int getPackedObjVarField(std::string const &buf, unsigned int offset, std::string &result) - { - std::vector s; - while (offset < buf.size()) - { - if (buf[offset] == '|') - break; - s.push_back(buf[offset++]); - } - s.push_back('\0'); - result = &(s[0]); - return offset+1; - } - - // ---------------------------------------------------------------------- - - unsigned int getPackedObjVarField(std::string const &buf, unsigned int offset, int &result) - { - std::string s; - offset = getPackedObjVarField(buf, offset, s); - result = atoi(s.c_str()); - return offset; - } - - // ---------------------------------------------------------------------- - - void appendPackedObjVarField(std::vector &buf, char const *s) - { - while (*s) - { - if ((*s) != '|') - buf.push_back(*s); - ++s; - } - buf.push_back('|'); - } - - // ---------------------------------------------------------------------- - - void appendPackedObjVarField(std::vector &buf, int val) - { - char tempbuf[32]; - sprintf(tempbuf, "%d", val); - appendPackedObjVarField(buf, tempbuf); - } - - // ---------------------------------------------------------------------- - - void remove() - { - } -} - -using namespace ServerObjectNamespace; - -// ====================================================================== - -const SharedObjectTemplate * ServerObject::m_defaultSharedTemplate = NULL; -float ServerObject::ms_buildingUpdateRadiusMultiplier = 0; - -// ====================================================================== - -class ServerObject::PobFixupNotification : public ObjectNotification -{ -public: - PobFixupNotification(); - ~PobFixupNotification(); - - virtual void pobFixupComplete(Object &object) const; - -private: - PobFixupNotification(const PobFixupNotification & ); - PobFixupNotification& operator= (const PobFixupNotification&); -}; - -//------------------------------------------------------------------------------------------ - -ServerObject::PobFixupNotification::PobFixupNotification() : ObjectNotification() - { - } - -//------------------------------------------------------------------------------------------ - -ServerObject::PobFixupNotification::~PobFixupNotification() -{ -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::PobFixupNotification::pobFixupComplete(Object &object) const -{ - static_cast(&object)->onPobFixupComplete(); -// object.removeNotification(*this); -} - -//------------------------------------------------------------------------------------------ - -static ServerObject::PobFixupNotification pobFixupNotification; - -//------------------------------------------------------------------------------------------ - -class ServerObject::MoveNotification : public ObjectNotification -{ -public: - MoveNotification(); - ~MoveNotification(); - virtual void addToWorld(Object &object) const; - virtual void cellChanged(Object &object, bool dueToParentChange) const; - virtual bool positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; - virtual void rotationChanged(Object &object, bool dueToParentChange) const; - virtual bool positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; - virtual void visibilityDataChanged(Object &object) const; - -private: - void checkForGoldObject(const Object &object) const; - -private: - MoveNotification(const MoveNotification &); - MoveNotification & operator= (const MoveNotification &); -}; - -static ServerObject::MoveNotification moveNotification; - - -//------------------------------------------------------------------------------------------ -ServerObject::MoveNotification::MoveNotification() : - ObjectNotification() -{ - -} - -//------------------------------------------------------------------------------------------ - -ServerObject::MoveNotification::~MoveNotification() -{ - -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::MoveNotification::addToWorld(Object &object) const -{ - static_cast(object).updateWorldSphere(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::MoveNotification::checkForGoldObject(const Object &object) const -{ - if (ConfigServerGame::getMaxGoldNetworkId()!=NetworkId::cms_invalid && object.getNetworkId() < ConfigServerGame::getMaxGoldNetworkId()) - { - FATAL(ConfigServerGame::getFatalOnMovingGoldObject(),("Attempted to move object %s, which is a gold object that should not be movable.", object.getNetworkId().getValueString().c_str())); - WARNING(true,("Attempted to move object %s, which is a gold object that should not be movable.", object.getNetworkId().getValueString().c_str())); - } -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::MoveNotification::cellChanged(Object &object, bool dueToParentChange) const -{ - checkForGoldObject(object); - - static_cast(object).updateWorldSphere(); - if (!dueToParentChange) - { - DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing cells")); - static_cast(object).setTransformChanged(true); - } -} - -//------------------------------------------------------------------------------------------ - -bool ServerObject::MoveNotification::positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const -{ - checkForGoldObject(object); - - UNREF(oldPosition); - static_cast(object).updateWorldSphere(); - if (!dueToParentChange) - { - DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing position")); - static_cast(object).setTransformChanged(true); - } - return true; -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::MoveNotification::rotationChanged(Object &object, bool dueToParentChange) const -{ - checkForGoldObject(object); - - static_cast(object).updateWorldSphere(); - if (!dueToParentChange) - { - DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing rotation")); - static_cast(object).setTransformChanged(true); - } -} - -//------------------------------------------------------------------------------------------ - -bool ServerObject::MoveNotification::positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const -{ - checkForGoldObject(object); - - UNREF(oldPosition); - static_cast(object).updateWorldSphere(); - if (!dueToParentChange) - { - DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing position and rotation")); - static_cast(object).setTransformChanged(true); - } - return true; -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::MoveNotification::visibilityDataChanged(Object &object) const -{ - static_cast(object).updateWorldSphere(); - static_cast(object).addObjectToConcludeList(); -} - -// ====================================================================== - -void ServerObject::AuthProcessIdCallback::modified(ServerObject &target, uint32 oldValue, uint32, bool) const -{ - AuthTransferTracker::sendConfirmAuthTransfer(target.getNetworkId(), oldValue); -} - -void ServerObject::ObserversCountCallback::modified(ServerObject &target, int oldValue, int, bool) const -{ - target.observersCountChanged(); -} - -// ====================================================================== - -ServerObject::ServerObject(const ServerObjectTemplate* newTemplate, const ObjectNotification ¬ification, bool const hyperspaceOnCreate) : -Object (newTemplate, NetworkId::cms_invalid), -m_oldPosition (), -m_sharedTemplate (NULL), -m_client (0), -m_observers (), -m_localFlags (0), -m_scriptObject (new GameScriptObject), -m_objVars (), -m_observersCount (0), -m_volume (newTemplate->getVolume()), -m_complexity (newTemplate->getComplexity()), -m_sceneId (ServerWorld::getSceneId()), -m_objectName (), -m_includeInBuildout (false), -m_nameStringId (), -m_staticItemName (), -m_staticItemVersion (0), -m_conversionId (0), -m_playerControlled (false), -m_synchronizedUi (), -m_pendingSyncUi (0), -m_persisted (false), -m_authServerProcessId (), -m_proxyServerProcessIds (), -m_transformSequence (), -m_cacheVersion (0), -m_loadContents (true), -m_contentsLoaded (false), -m_contentsRequested (false), -m_loadWith (NetworkId::cms_invalid), -m_cashBalance (0), -m_bankBalance (0), -m_defaultAlterTime (AlterResult::cms_keepNoAlter), -m_broadcastListeners (), -m_broadcastBroadcasters (), -m_authClientServerPackage (), -m_authClientServerPackage_np (), -m_firstParentAuthClientServerPackage(), -m_firstParentAuthClientServerPackage_np(), -m_serverPackage (), -m_serverPackage_np (), -m_sharedPackage (), -m_sharedPackage_np (), -m_networkUpdateFar (NULL), -m_triggerVolumes (), -m_attributesAttained (), -m_attributesInterested (), -m_triggerVolumeInfo (), -m_messageTos (), -m_worldSphere (Sphere::unit), -m_dirtyArchiveCallback (), -m_unreliableControllerMessageSequenceNumber(0), -m_gameObjectType (0), -m_calledTriggerDestroy (false), -m_calledTriggerRemovingFromWorld(false), -m_loadCTSBank(false), -m_loadCTSPackedHouses(false) -{ - synchronizationOnConstruct(); - - m_observersCount.setSourceObject(this); - m_authServerProcessId.setSourceObject(this); - - NOT_NULL(newTemplate); - - setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate, hyperspaceOnCreate); - setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct, false); - -#ifdef _DEBUG - setDebugName(getTemplateName()); -#endif - - updateWorldSphere(); - - const std::string & sharedTemplateName = newTemplate->getSharedTemplate(); - m_sharedTemplate = dynamic_cast(ObjectTemplateList::fetch(sharedTemplateName)); - if (m_sharedTemplate == NULL) - { - WARNING_STRICT_FATAL(!sharedTemplateName.empty(), ("Template %s has an invalid shared template %s. We will use the default shared template for now.", - newTemplate->getName(), sharedTemplateName.c_str())); - } - - if (getSharedTemplate() != NULL) - { - m_nameStringId = getSharedTemplate()->getObjectName(); - m_descriptionStringId = getSharedTemplate()->getDetailedDescription(); - } - - m_scriptObject->setOwner(this); - - ContainedByProperty *containedBy = new ContainedByProperty(*this, NULL); - addProperty(*containedBy); - - //-- create the SlottedContainment property - SlottedContainmentProperty *slottedProperty = new SlottedContainmentProperty(*this); - addProperty(*slottedProperty); - - //-- get ArrangementDescriptor if specified - if (getSharedTemplate() != NULL) - { - const ArrangementDescriptor *const arrangementDescriptor = getSharedTemplate()->getArrangementDescriptor(); - if (arrangementDescriptor) - { - const int arrangementCount = arrangementDescriptor->getArrangementCount(); - for (int i = 0; i < arrangementCount; ++i) - { - slottedProperty->addArrangement(arrangementDescriptor->getArrangement(i)); - } - } - } - - //set up containers on this object if it has any - if (getSharedTemplate() != NULL) - { - SharedObjectTemplate::ContainerType const containerType = getSharedTemplate()->getContainerType(); - - switch (containerType) - { - //buildings (portal properties get added below - case SharedObjectTemplate::CT_none: - break; - - case SharedObjectTemplate::CT_slotted: - case SharedObjectTemplate::CT_ridable: - { - const SlotDescriptor *const slotDescriptor = getSharedTemplate()->getSlotDescriptor(); - if (slotDescriptor) - { - //-- create a SlottedContainer with the given slots - SlottedContainer* slotContainer = new SlottedContainer(*this, slotDescriptor->getSlots()); - addProperty(*slotContainer); - slotContainer = 0; - } - else - { - DEBUG_WARNING(true, ("DATA ERROR: specified slotted container type but could not get slot descriptor")); - } - break; - } - case SharedObjectTemplate::CT_volume: - { - VolumeContainer * volumeContainer = 0; - int maxVolume = getSharedTemplate()->getContainerVolumeLimit(); - if (maxVolume <= 0) - { - maxVolume = VolumeContainer::VL_NoVolumeLimit; - } - volumeContainer = new TangibleVolumeContainer(*this, maxVolume); - addProperty(*volumeContainer); - volumeContainer = 0; - break; - } - case SharedObjectTemplate::CT_volumeIntangible: - { - int maxVolume = getSharedTemplate()->getContainerVolumeLimit(); - if (maxVolume <= 0) - { - maxVolume = VolumeContainer::VL_NoVolumeLimit; - } - VolumeContainer * volumeContainer = new IntangibleVolumeContainer(*this, maxVolume); - addProperty(*volumeContainer); - volumeContainer = 0; - break; - } - case SharedObjectTemplate::CT_volumeGeneric: - { - int maxVolume = getSharedTemplate()->getContainerVolumeLimit(); - if (maxVolume <= 0) - { - maxVolume = VolumeContainer::VL_NoVolumeLimit; - } - VolumeContainer * volumeContainer = new VolumeContainer(*this, maxVolume); - addProperty(*volumeContainer); - volumeContainer = 0; - break; - } - - default: - DEBUG_WARNING(true, ("Invalid container type specified.")); - break; - } - - setLocalFlag(LocalObjectFlags::ServerObject_SendToClient, getSharedTemplate()->getSendToClient()); - m_gameObjectType = static_cast(getSharedTemplate()->getGameObjectType()); - } - - //If the object template specifies a volume, give it a volumeContainment - int vol = newTemplate->getVolume(); - VolumeContainmentProperty* volumeProperty = new VolumeContainmentProperty(*this, (vol < 1 ? 1 : vol) ); - addProperty(*volumeProperty); - volumeProperty = 0; //lint !e423 // creation of memory leak // no, managed by property list - - - // add the portal property if one is requested - if (getSharedTemplate() != NULL) - { - const std::string &portalLayoutFileName = getSharedTemplate()->getPortalLayoutFilename(); - if (!portalLayoutFileName.empty()) - { - PortalProperty *portalProperty = new PortalProperty(*this, portalLayoutFileName.c_str()); - addProperty(*portalProperty); - } - } - - m_triggerVolumeInfo.setOnChanged(this, &ServerObject::updateTriggerVolumes); - - addMembersToPackages(); - - addNotification(notification); - - addNotification(moveNotification); - - gs_objectCount++; - ObjectTracker::addObject(); - - //-- add the no build notification - { - if (getSharedTemplate () && getSharedTemplate ()->getNoBuildRadius () > 0.f) - addNotification (ServerNoBuildNotification::getInstance ()); - } - - //-- add the clear flora notification - { - if (getSharedTemplate () && getSharedTemplate ()->getClearFloraRadius () > 0.f) - addNotification (ServerClearCollidableFloraNotification::getInstance ()); - } -} - -//----------------------------------------------------------------------- - -ServerObject::~ServerObject() -{ - //-- This must be the first line in the destructor to invalidate any watchers watching this object - nullWatchers(); - - ObserveTracker::onObjectDestroyed(*this, getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct)); - PositionUpdateTracker::serverObjDestroyed(*this); - - synchronizationOnDestruct(); - - if (getLayer()) - ObjectTracker::removeRunTimeRule(); - - if (getClient()) - getClient()->removeControlledObject(*this); - - WARNING_STRICT_FATAL(getClient(),("Deleting server object %s which had a client.",getNetworkId().getValueString().c_str())); - - { - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject removeFromWorld"); - //remove from world - if (isInWorld()) - removeFromWorld(); - } - - WARNING_STRICT_FATAL(!m_triggerVolumes.empty(), ("Deleting object %s that still has trigger volumes attached", getNetworkId().getValueString().c_str())); - - { - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject destroyTriggerVolumes"); - // make absolutely sure our trigger volumes are removed from the world - destroyTriggerVolumes(); - } - - if (m_sharedTemplate != NULL) - { - m_sharedTemplate->releaseReference(); - m_sharedTemplate = NULL; - } - - if (getClient()) - { - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject dropClient"); - //Object has a client!! - WARNING(true, ("Destroying object %s which isAuth: %d", getNetworkId().getValueString().c_str(), isAuthoritative())); - GameServer::getInstance().dropClient(getNetworkId()); - } - - { - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject removeObjectFromGame"); - // clean ourselves off any of ServerWorlds lists. - ServerWorld::removeObjectFromGame(*this); - } - - delete m_pendingSyncUi; - m_pendingSyncUi = 0; - - delete m_synchronizedUi; - m_synchronizedUi = 0; - - { - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject delete script object"); - if (m_scriptObject != NULL) - delete m_scriptObject; - } - m_scriptObject = NULL; - - gs_objectCount--; - - { - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject ObjectTracker::removeObject"); - ObjectTracker::removeObject(); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::install() -{ - // read in list of object types that supports no trade "shared" behavior - // (no trade item of those types can be picked up by another character - // on the same account as the character who currently owns the item) - char const * const noTradeSharedDataTableName = "datatables/no_trade/no_trade_shared.iff"; - DataTable * table = DataTableManager::getTable(noTradeSharedDataTableName, true); - if (table) - { - int const columnObjectTemplate = table->findColumnNumber("Object Template"); - if (columnObjectTemplate >= 0) - { - std::string objectTemplate; - - for (int i = 0, numRows = table->getNumRows(); i < numRows; ++i) - { - objectTemplate = table->getStringValue(columnObjectTemplate, i); - if (objectTemplate.empty()) - continue; - - if (objectTemplate.find(".iff") != std::string::npos) - s_noTradeSharedTemplateItemType.insert(CrcLowerString::calculateCrc(objectTemplate.c_str())); - else - s_noTradeSharedStaticItemType.insert(objectTemplate); - } - } - - DataTableManager::close(noTradeSharedDataTableName); - } - - ExitChain::add(ServerObjectNamespace::remove, "ServerObjectNamespace::remove"); -} - -//----------------------------------------------------------------------- - -ServerObject * ServerObject::getServerObject(NetworkId const & networkId) -{ - return asServerObject(NetworkIdManager::getObjectById(networkId)); -} - -//----------------------------------------------------------------------- - -ServerObject * ServerObject::asServerObject(Object * const object) -{ - return (object != NULL) ? object->asServerObject() : NULL; -} - -//----------------------------------------------------------------------- - -ServerObject const * ServerObject::asServerObject(Object const * const object) -{ - return (object != NULL) ? object->asServerObject() : NULL; -} - -//----------------------------------------------------------------------- - -ServerObject * ServerObject::asServerObject() -{ - return this; -} - -//----------------------------------------------------------------------- - -ServerObject const * ServerObject::asServerObject() const -{ - return this; -} - -//----------------------------------------------------------------------- - -CreatureObject * ServerObject::asCreatureObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -CreatureObject const * ServerObject::asCreatureObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -BuildingObject * ServerObject::asBuildingObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -BuildingObject const * ServerObject::asBuildingObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -StaticObject * ServerObject::asStaticObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -StaticObject const * ServerObject::asStaticObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -TangibleObject * ServerObject::asTangibleObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -TangibleObject const * ServerObject::asTangibleObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -IntangibleObject *ServerObject::asIntangibleObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -IntangibleObject const *ServerObject::asIntangibleObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -MissionObject * ServerObject::asMissionObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -MissionObject const * ServerObject::asMissionObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -CellObject * ServerObject::asCellObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -CellObject const * ServerObject::asCellObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -GroupObject * ServerObject::asGroupObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -GroupObject const * ServerObject::asGroupObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -ShipObject * ServerObject::asShipObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -ShipObject const * ServerObject::asShipObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -PlayerObject *ServerObject::asPlayerObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -PlayerObject const * ServerObject::asPlayerObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -WeaponObject *ServerObject::asWeaponObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -WeaponObject const * ServerObject::asWeaponObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -ManufactureSchematicObject *ServerObject::asManufactureSchematicObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -ManufactureSchematicObject const * ServerObject::asManufactureSchematicObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -PlayerQuestObject * ServerObject::asPlayerQuestObject() -{ - return 0; -} - -//----------------------------------------------------------------------- - -PlayerQuestObject const * ServerObject::asPlayerQuestObject() const -{ - return 0; -} - -//----------------------------------------------------------------------- - -/** - * Returns a shared template if none was given for this object. - * - * @return the shared template - */ -const SharedObjectTemplate * ServerObject::getDefaultSharedTemplate(void) const -{ -static const ConstCharCrcLowerString templateName("object/object/base/shared_object_default.iff"); - - if (m_defaultSharedTemplate == NULL) - { - m_defaultSharedTemplate = safe_cast( - ObjectTemplateList::fetch(templateName)); - WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create default shared object template %s", templateName.getString())); - if (m_defaultSharedTemplate != NULL) - ExitChain::add (removeDefaultTemplate, "ServerObject::removeDefaultTemplate"); - } - return m_defaultSharedTemplate; -} // ServerObject::getDefaultSharedTemplate - -//----------------------------------------------------------------------- - -const unsigned long ServerObject::getObjectCount() -{ - return gs_objectCount; -} - -//----------------------------------------------------------------------- - -/** - * Cleans up the default shared template. - */ -void ServerObject::removeDefaultTemplate(void) -{ - if (m_defaultSharedTemplate != NULL) - { - m_defaultSharedTemplate->releaseReference(); - m_defaultSharedTemplate = NULL; - } -} // ServerObject::removeDefaultTemplate - -// ---------------------------------------------------------------------- - -void ServerObject::addObjectToConcludeList() -{ - if (!isInitialized()) - return; - if (!isGoingToConclude()) - { - setGoingToConclude(true); - ServerWorld::addObjectToConcludeList(this); - } -} - -// ---------------------------------------------------------------------- - -/** - * Called during the alter phase of the game. - * - * @param time time since last frame - * - * @return true or false - */ -float ServerObject::alter(float time) -{ - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::alter"); - - //Check initialization - WARNING_STRICT_FATAL(!isInitialized(), ("Alter called on unitialized object %s.", getNetworkId().getValueString().c_str())); - if (!isInitialized()) - return 1.0f; - - // Alter the base class. - float result = Object::alter(time); - - if (isPlacing()) - { - TerrainObject* terrain = TerrainObject::getInstance(); - if (terrain && getSharedTemplate() && getSharedTemplate()->getSnapToTerrain() && isInWorldCell() && isInWorld()) - { - terrain->placeObject(*this, false, true); - } - setPlacing(false); - } - - if (result == AlterResult::cms_kill) - { - if (isAuthoritative()) - { - //If we are being deleted this frame, make sure to update our deltas, position, etc. - sendDeltasForSelfAndContents(); - } - if (isUnloading()) - { - Object * const containerObject = ContainerInterface::getContainedByObject(*this); - //If we're contained, remove ourself from the container before destruction - if (containerObject) - { - Container * const container = ContainerInterface::getContainer(*containerObject); - NOT_NULL(container); - container->internalItemRemoved(*this); - DEBUG_REPORT_LOG(true, ("Removing %s from container %s because it is being unloaded\n", - getNetworkId().getValueString().c_str(), - containerObject->getNetworkId().getValueString().c_str())); - } - } - } - - return result; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::canDropInWorld() const -{ - return false; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::canManipulateObject(ServerObject const &target, bool movingObject, bool checkPermissions, bool checkPermissionsOnParent, float maxDistance, Container::ContainerErrorCode&, bool skipNoTradeCheck, bool * allowedByGodMode) const -{ - //In general objects cannot manipulate other objects, unless they are creatures. This may not be true of all - //objects, however, which is why the function is implemented this way (ie a player object that derives from ServerObject). - UNREF(target); - UNREF(maxDistance); - UNREF(checkPermissions); - UNREF(checkPermissionsOnParent); - UNREF(movingObject); - UNREF(skipNoTradeCheck); - UNREF(allowedByGodMode); - return false; -} - -//----------------------------------------------------------------------- - -bool ServerObject::canTrade() const -{ - if( isInBazaarOrVendor() ) - { - return false; - } - - return !markedNoTrade(); -} - -//----------------------------------------------------------------------- - -bool ServerObject::canTradeRecursive(bool testPlayers) const -{ - if( testPlayers || !isPlayerControlled() ) - { - if( !canTrade() ) - { - return false; - } - else - { - // check the contained items - const Container * const container = ContainerInterface::getContainer(*this); - if( container ) - { - for( ContainerConstIterator i = container->begin(); i != container->end(); ++i ) - { - const ServerObject * const content = safe_cast((*i).getObject()); - if( content ) - { - if( !content->canTradeRecursive(testPlayers) ) - return false; - } - } - } - } - } - - return true; -} - -//----------------------------------------------------------------------- - -bool ServerObject::markedNoTrade() const -{ - return ( getObjVars().hasItem("noTrade") || getObjVars().hasItem("notrade") ); -} - -//----------------------------------------------------------------------- - -bool ServerObject::markedNoTradeRecursive(bool testPlayers, bool testOnlyContainedItems) const -{ - if( testPlayers || !isPlayerControlled() ) - { - if( !testOnlyContainedItems && markedNoTrade() ) - { - return true; - } - else - { - // check the contained items - const Container * const container = ContainerInterface::getContainer(*this); - if( container ) - { - for( ContainerConstIterator i = container->begin(); i != container->end(); ++i ) - { - const ServerObject * const content = safe_cast((*i).getObject()); - if( content ) - { - if( content->markedNoTradeRecursive(testPlayers) ) - return true; - } - } - } - } - } - - return false; -} - -//----------------------------------------------------------------------- - -bool ServerObject::markedNoTradeShared(bool includeCheckForNoTrade) const -{ - if (includeCheckForNoTrade) - { - if (!markedNoTrade()) - return false; - } - - if (getObjVars().hasItem("noTradeShared")) - return true; - - // see if the item type is no trade "shared" - if (m_staticItemName.get().empty()) - return (s_noTradeSharedTemplateItemType.count(getTemplateCrc()) > 0); - - return (s_noTradeSharedStaticItemType.count(m_staticItemName.get()) > 0); -} - -//----------------------------------------------------------------------- - -bool ServerObject::isInSecureTrade() const -{ - const ServerObject *parent = safe_cast(ContainerInterface::getFirstParentInWorld(*this)); - if( parent ) - { - const CreatureObject *creatureObjParent = parent->asCreatureObject(); - if( creatureObjParent ) - { - const CreatureController *cc = creatureObjParent->getCreatureController(); - if( cc ) - { - const ServerSecureTrade *trade = cc->getSecureTrade(); - if( trade && trade->hasItemInSecureTrade(*creatureObjParent, *this) ) - { - return true; - } - } - } - } - - return false; -} - -// ---------------------------------------------------------------------- - -/** - * Returns whether an object is bio-linked - * - * @return true if a the object is bio-linked - */ -bool ServerObject::isBioLinked() const -{ - // By default, objects are not bio-linked - return false; -} - -// ---------------------------------------------------------------------- - -/** - * Returns whether an object, or any contained object, is biolinked - * - * @return true if a biolinked object is found - */ -bool ServerObject::isBioLinkedRecursive() const -{ - if( isBioLinked() ) - { - return true; - } - else - { - // If we are a container, see if any of the contained objects are bio-linked - const Container * const container = ContainerInterface::getContainer(*this); - if( container ) - { - for( ContainerConstIterator i = container->begin(); i != container->end(); ++i ) - { - const ServerObject * const content = safe_cast((*i).getObject()); - if( content ) - { - if( content->isBioLinkedRecursive() ) - { - return true; - } - } - } - } - } - - return false; -} - -//----------------------------------------------------------------------- - -bool ServerObject::isWaypoint() const -{ - return getObjectTemplate()->derivesFrom(SERVER_PATHFINDING_WAYPOINT_TEMPLATE_BASE); -} - -//----------------------------------------------------------------------- - -bool ServerObject::isInBazaarOrVendor() const -{ - bool inBazaarOrVendor = false; - const ServerObject *parent = safe_cast(ContainerInterface::getFirstParentInWorld(*this)); - const ServerObject *grandParent = NULL; - if( parent ) - { - grandParent = safe_cast(ContainerInterface::getFirstParentInWorld(*parent)); - } - - if( parent && (parent->isVendor() || parent->isBazaarTerminal() ) ) - { - inBazaarOrVendor = true; - } - else if( grandParent && (grandParent->isVendor() || grandParent->isBazaarTerminal()) ) - { - inBazaarOrVendor = true; - } - - return inBazaarOrVendor; -} - -void ServerObject::removeAllAuctions() -{ - if ( isVendor() ) - { - ServerObject *inv = getBazaarContainer(); - NetworkId playerOwnerId; - getObjVars().getItem("vendor_owner", playerOwnerId); - if( inv && playerOwnerId.getValue()>0 ) - { - // if this was an uninitialized vendor, remove objvar from owner - ServerObject *owner = dynamic_cast(NetworkIdManager::getObjectById(playerOwnerId)); - if (owner) - { - NetworkId notInitalizedVendor; - if (owner->getObjVars().getItem("vendor_not_initialized", notInitalizedVendor)) - { - if (notInitalizedVendor == Object::getNetworkId()) - { - owner->removeObjVarItem("vendor_not_initialized"); - } - } - } - CommoditiesMarket::destroyVendorMarket(playerOwnerId, *inv); - } - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::checkLOSTo(ServerObject const &target) const -{ - return LineOfSightCache::checkLOS(*this, target); -} - -//----------------------------------------------------------------------- - -bool ServerObject::checkLOSTo(Location const &target) const -{ - return LineOfSightCache::checkLOS(*this, target); -} - -//----------------------------------------------------------------------- - -void ServerObject::conclude() -{ - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::conclude"); - - // everything has updated, check trigger volume - - if (getTransformChanged() && isInWorld()) - { - Vector const &newPosition = getTransform_o2w().getPosition_p(); - // move the object and trigger volumes, detect volume enter/leave - ServerWorld::moveObject(*this, m_oldPosition, newPosition); - updatePositionOnPlanetServer(); - m_oldPosition = newPosition; - } - - m_localFlags &= s_clearLocalFlagsOnConcludeMask; - - { - PROFILER_AUTO_BLOCK_DEFINE("Object::conclude"); - Object::conclude(); - } -} - -//----------------------------------------------------------------------- - -/** - * Creates a default controller for this object. - * - * @return the object's controller - * @todo This function should be removed. Use the controller factory instead. - */ -Controller* ServerObject::createDefaultController(void) -{ - Controller* controller = new ServerController(this); - NOT_NULL(controller); - - setController(controller); - return controller; -} // Object::createDefaultController - -//----------------------------------------------------------------------- -/** Called by the container system when this object's contained By value is changed - */ - -void ServerObject::containedByModified(NetworkId const &oldValue, NetworkId const &newValue, bool isLocal) -{ - UNREF(isLocal); - - if (oldValue == newValue) - return; - - ServerObject * const oldContainer = safe_cast(NetworkIdManager::getObjectById(oldValue)); - ServerObject * const newContainer = safe_cast(NetworkIdManager::getObjectById(newValue)); - - // TODO: reenable these fatals after container proxying changes are done - //FATAL(oldValue.isValid() && !oldContainer, ("ServerObject::containedByModified: obj %s, could not resolve old container %s.", getDebugInformation().c_str(), oldValue.getValueString().c_str())); - //FATAL(newValue.isValid() && !newContainer, ("ServerObject::containedByModified: obj %s, could not resolve new container %s.", getDebugInformation().c_str(), newValue.getValueString().c_str())); - - if (isAuthoritative()) - { - FATAL((newContainer && !newContainer->isAuthoritative()), ("Invalid container transfer with auth object to/from non-auth containers.")); - } - else if (isInitialized()) - { - FATAL((oldContainer && oldContainer->isAuthoritative()) || (newContainer && newContainer->isAuthoritative()), ("Invalid container transfer with non-auth object to/from auth containers.")); - - // For proxy objects and mounts, it is essential for this function - // to setup new container state before calling - // isContentItemExposedWith. Failure to do this causes proxy - // server objects of a rider to handle dismounting improperly - // because wasInWorld will be set to false erroneously. - // Also, it is essential to call this function prior to calling - // containerHandleUpdateClients() below since that function - // assumes the objects are in the new containment state. - containerDepersistContents(oldContainer, newContainer); - - Container const * const newContainerProperty = newContainer ? ContainerInterface::getContainer(*newContainer) : 0; - bool const wasInWorld = isInWorld(); - bool const nowInWorld = newValue == NetworkId::cms_invalid || (newContainerProperty && newContainer->isInWorld() && newContainerProperty->isContentItemExposedWith(*this)); - -// DEBUG_REPORT_LOG(true, ("Updating %s with old container %s and new container %s\n", -// getNetworkId().getValueString().c_str(), -// oldValue.getValueString().c_str(), -// newValue.getValueString().c_str())); - containerHandleUpdateClients(oldContainer, newContainer, (wasInWorld && !nowInWorld), (!wasInWorld && nowInWorld)); - } - - scheduleForAlter(); -} - -//----------------------------------------------------------------------- - -void ServerObject::arrangementModified(int oldValue, int newValue, bool isLocal) -{ - if (!isLocal && !isAuthoritative() && isInitialized()) - { - ServerObject * const parent = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (parent) - { - SlottedContainer * const slotContainer = ContainerInterface::getSlottedContainer(*parent); - if (slotContainer) - { - SlottedContainmentProperty* const slotted = ContainerInterface::getSlottedContainmentProperty(*this); - DEBUG_FATAL(!slotted, ("Error unpacking non slotted objects into a slotted container")); - slotContainer->updateArrangement(*this, oldValue, slotted->getCurrentArrangement()); - } - } - ObserveTracker::onObjectArrangementChanged(*this); - } -} - -//----------------------------------------------------------------------- - -void ServerObject::destroyTriggerVolumes() -{ - // get rid of any trigger volumes - for (TriggerVolumeMap::iterator i = m_triggerVolumes.begin(); i != m_triggerVolumes.end(); ++i) - { - ServerWorld::removeObjectTriggerVolume((*i).second); - delete (*i).second; - } - m_triggerVolumes.clear(); - m_networkUpdateFar = 0; -} - -//----------------------------------------------------------------------- - -void ServerObject::updateTriggerVolumes() -{ - ServerObject *topMost = safe_cast(ContainerInterface::getFirstParentInWorld(*this)); - if (!topMost || topMost != this || !topMost->isInWorld()) - { - destroyTriggerVolumes(); - return; - } - - // keep track of what trigger volumes should exist so we can destroy the rest afterwards - std::vector newVolumes; - - // create any new volumes - { - for (std::vector::const_iterator i = m_triggerVolumeInfo.begin(); i != m_triggerVolumeInfo.end(); ++i) - { - const TriggerVolumeMap::iterator j = m_triggerVolumes.find((*i).name); - if (j != m_triggerVolumes.end()) - { - TriggerVolume *t = (*j).second; - // if we already have one that matches, leave it alone - if ( t->getPromiscuous() == (*i).isPromiscuous - && t->getRadius() == (*i).radius) - { - newVolumes.push_back(t); - continue; - } - // does not match, so destroy it and fall through to creating the new one - ServerWorld::removeObjectTriggerVolume(t); - delete t; - m_triggerVolumes.erase(j); - } - - TriggerVolume * t = new TriggerVolume(*this, (*i).radius, (*i).name, (*i).isPromiscuous); - addTriggerVolume(t); - newVolumes.push_back(t); - } - } - - // remove any volumes which no longer exist - { - TriggerVolumeMap::iterator i = m_triggerVolumes.begin(); - while (i != m_triggerVolumes.end()) - { - TriggerVolume *t = (*i).second; - if ( t != m_networkUpdateFar - && std::find(newVolumes.begin(), newVolumes.end(), t) == newVolumes.end()) - { - ServerWorld::removeObjectTriggerVolume(t); - delete t; - m_triggerVolumes.erase(i++); - } - else - ++i; - } - } -} - -//----------------------------------------------------------------------- - -void ServerObject::addTriggerVolume(TriggerVolume * t) -{ - if (!t) - { - WARNING_STRICT_FATAL(true, ("Cannot add null volume")); - return; - } - m_triggerVolumes.insert(std::make_pair(t->getName(), t)); - ServerWorld::addObjectTriggerVolume(t); -} - -//----------------------------------------------------------------------- - -void ServerObject::createTriggerVolume(const real radius, const std::string & name, const bool isPromiscuous) -{ - removeTriggerVolume(name); - - TriggerVolumeInfo triggerVolumeInfo; - triggerVolumeInfo.name = name; - triggerVolumeInfo.radius = radius; - triggerVolumeInfo.isPromiscuous = isPromiscuous; - m_triggerVolumeInfo.push_back(triggerVolumeInfo); -} - -//----------------------------------------------------------------------- - -void ServerObject::serverObjectEndBaselines(bool fromDatabase) -{ - setInEndBaselines(true); - - // handle trying to create a player in an incorrect scene, or without a PlayerObject - bool needSceneFix = false; - - if (isPlayerControlled()) - { - bool doUnload = false; - if (!PlayerCreatureController::getPlayerObject(asCreatureObject())) - { - WARNING(true, ("TRACE_LOGIN: Loading a player controlled creature object (%s) without a player object.", getNetworkId().getValueString().c_str())); - doUnload = true; - } - else if (getSceneId() != ServerWorld::getSceneId()) - { - Client* p_client = GameServer::getInstance().getClient( getNetworkId() ); - - - if ( (p_client) && ( p_client->getSendToStarport() ) ) - { - needSceneFix = true; - GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this),"tatooine",Vector(3528,5,-4804), - NetworkId::cms_invalid,Vector(3528,5,-4804)); - } - else if (isAuthoritative() && ContainerInterface::getContainedByObject(*this)) - { - needSceneFix = true; - } - - else - { - WARNING(true, - ("Unloading object id=[%s] on game server id=[%d] due to incorrect scene during baselines: server scene=[%s], object scene=[%s], fromDatabase=[%s], authoritative=[%s])", - getNetworkId().getValueString().c_str(), - static_cast(GameServer::getInstance().getProcessId()), - ServerWorld::getSceneId().c_str(), - getSceneId().c_str(), - fromDatabase ? "true" : "false", - isAuthoritative() ? "true" : "false" - )); - - //-- As a precautionary measure, force CentralServer to clear out its player id/scene id map since a bug in the updating of Central's map probably is the origin of this routing error. - GenericValueTypeMessage > > const setSceneMsg("SetSceneForPlayer", std::make_pair(getNetworkId(), std::make_pair(std::string(""), false))); - GameServer::getInstance().sendToCentralServer(setSceneMsg); - - doUnload = true; - } - } - if (doUnload) - { - if (getClient()) - GameServer::getInstance().dropClient(getNetworkId()); - unload(); - delete this; - return; - } - } - - //This is the public interface to end baselines. ::endBaselines is a protected virtual function now - // so that we can enforce order. - endBaselines(); - - if (needSceneFix) - { - WARNING(true, ("Fixing scene id for contained object %s due to incorrect scene id during baselines", getNetworkId().getValueString().c_str())); - setSceneIdOnThisAndContents(ServerWorld::getSceneId()); - } - - if (fromDatabase) - onLoadedFromDatabase(); - - updateWorldSphere(); - if (getScriptObject() != NULL) - { - endBaselinesInitializeScript(*this, true); - // If the object was created authoritative, trigger if needed - if (isAuthoritative()) - triggerMadeAuthoritative(); - } - - if (isPlayerControlled()) - PlayerSanityChecker::add(getNetworkId()); - - //-- Validate the object transform. - checkAndLogInvalidTransform(); - - //-- Schedule for alter just in case something needs an alter. - scheduleForAlter(); -} - -//----------------------------------------------------------------------- - -void ServerObject::onLoadedFromDatabase() -{ -} - -//----------------------------------------------------------------------- - -void ServerObject::endBaselines() -{ - // This should always go first: it ensures there are no deltas - // accumulated for this object at the time we start processing - // our baselined data. Only changes after this point will - // generate deltas. - clearDeltas(); - - //Handle updating container info - bool addToWorldFlag = handleContentsSetup(); - setInitialized(true); - - ServerController * c = safe_cast(getController()); - c->endBaselines(); - setTransformChanged(false); - - // check for parent getting uncached - if (isAuthoritative() && getCacheVersion() != 0) - { - ServerObject *parent = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (parent && parent->getCacheVersion() == 0) - setCacheVersion(0); - } - - // handle version numbering for contents on portal properties - PortalProperty *portalProperty = getPortalProperty(); - if (portalProperty) - { - int crcValue=0; - getObjVars().getItem(portalPropertyCrcObjectVariableName,crcValue); - std::vector unfixables; - if (portalProperty->serverEndBaselines(crcValue, unfixables, isAuthoritative())) - { - FATAL(ConfigServerGame::getFatalOnGoldPobChange() && getCacheVersion() != 0, - ("Object %s is a client cached object and the POB changed from [%d] to [%d]", getNetworkId().getValueString().c_str(), crcValue, portalProperty->getCrc())); -#ifdef DEBUG - WARNING(getCacheVersion() != 0, ("Object %s is a client cached object and the POB changed from [%d] to [%d]", getNetworkId().getValueString().c_str(), crcValue, portalProperty->getCrc())); -#endif - if (isAuthoritative()) - setCacheVersion(0); - } - if (isAuthoritative()) - setObjVarItem(portalPropertyCrcObjectVariableName, portalProperty->getCrc()); - - if (!unfixables.empty()) - { - WARNING(true, ("Object %s contained objects that could not be placed after pob fixup", getNetworkId().getValueString().c_str())); - } - } - - if (addToWorldFlag) - addToWorld(); - - if (isAuthoritative()) - { - // don't allow login if the character is in the middle of CTS or has been successfully CTS(ed) - Client * const client = GameServer::getInstance().getClient(getNetworkId()); - if (client && !getClient() && (client->getCharacterObjectId() == getNetworkId())) - { - bool kickRequested = false; - - DynamicVariableList const & objVars = getObjVars(); - int timeOut; - if (objVars.getItem("disableLoginCtsInProgress", timeOut)) - { - if (timeOut > static_cast(ServerClock::getInstance().getGameTimeSeconds())) - { - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); - kickRequested = true; - } - else - { - removeObjVarItem("disableLoginCtsInProgress"); - } - } - - int transferredTime; - if (!kickRequested && objVars.getItem("disableLoginCtsCompleted", transferredTime) && !client->isUsingAdminLogin()) - { - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); - kickRequested = true; - } - } - - // attach a pending client to this object if needed - checkAndAddClientControl(client); - - // Make sure the PlanetServer knows about the new object if it needs to - updatePositionOnPlanetServer(true); - - // for initialized, unpacked vendor, sync the vendor location with the commodities server - if (isVendor()) - CommoditiesMarket::updateVendorLocation(*this); - - // if this is a reward item that supports trade in, attach the trade in script to it to provide the trade in functionality - VeteranRewardManager::attachTradeInScriptToItem(*this); - - // sanity check - fix up any player character negative cash/bank balance - if (client) - { - if (m_cashBalance.get() < 0) - m_cashBalance = 0; - - if (m_bankBalance.get() < 0) - m_bankBalance = 0; - } - } - - // If our immediate container is initialized, we were just added to the container so update the ObserveTracker - ServerObject *immediateContainer = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (immediateContainer && immediateContainer->isInitialized()) - { - // handle the case of a player who logged out in a buildout cell - // and that buildout id got changed to some other object, like a rock - if (isPlayerControlled() && isAuthoritative() && (immediateContainer->getNetworkId().getValue() < static_cast(0))) - { - if (immediateContainer->asCellObject() != NULL || ContainerInterface::getCell(*immediateContainer) != NULL) - ObserveTracker::onObjectContainerChanged(*this); - else - { - WARNING(true, ("ServerObject::endBaselines player (%s) is trying to be put into non-cell object (%s). We will put the player in the world instead.", - PlayerObject::getAccountDescription(this).c_str(), immediateContainer->getDebugInformation().c_str())); - ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*this); - if (cby) - { - cby->setContainedBy(NetworkId::cms_invalid, true); - if (!ServerWorld::isSpaceScene()) - { - // if the player was in a building, try and put them at the building's ejection point - DynamicVariableLocationData ejectionPoint; - if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) - { - removeObjVarItem("building_ejection_point"); - setPosition_p(ejectionPoint.pos); - } - } - addToWorld(); - } - } - } - else - { - //@todo: we may want to do something here if this call fails - ObserveTracker::onObjectContainerChanged(*this); - } - } - - if (isAuthoritative() && (!isPlayerControlled() || getClient()) && getObjVars().hasItem("teleportFixup")) - TeleportFixupHandler::add(*this); - - setInEndBaselines(false); -} - -// ---------------------------------------------------------------------- - -void ServerObject::getAuthClients(std::set &authClients) const -{ - Client const * const client = getClient(); - if (client) - IGNORE_RETURN(authClients.insert(client)); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::handlePlayerInInteriorSetup(ContainedByProperty *containedBy) -{ - // If we are player-controlled, assume that it may have been a while since we logged in. - // If we were in a POB, it might have changed. So, ignore the persisted cell number and look - // for the best cell. If anything goes wrong looking for the cell, warp to a good location. - - bool retval = false; - - Object * const originalCell = containedBy->getContainedBy(); - if (originalCell) - { - bool fixOk = false; - - CellProperty * const originalCellProp = originalCell->getCellProperty(); - ServerObject * const pob = safe_cast(ContainerInterface::getContainedByObject(*originalCell)); - BuildingObject * const building = pob ? pob->asBuildingObject() : 0; - PortalProperty * const portal = pob ? pob->getPortalProperty() : 0; - - // Don't ever put the character into a packed house - if ((building) && (!building->isInWorld())) - { - DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building is packed\n",getNetworkId().getValueString().c_str(), building->getNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building is packed",getNetworkId().getValueString().c_str(), building->getNetworkId().getValueString().c_str())); - - // settting fixOk to false will cause the character to get moved - // into the world at the building ejection point (see below) - fixOk = false; - } - else if (portal) - { - originalCellProp->depersistContents(*this); - - if (pob->isInitialized()) - { - if (isAuthoritative()) - { - Transform const saveTransform(getTransform_o2p()); - Container::ContainerErrorCode tmp = Container::CEC_Success; - originalCellProp->remove(*this, tmp); - containedBy->setContainedBy(NetworkId::cms_invalid); - - fixOk = portal->fixupObject(*this, saveTransform); - containerHandleUpdateProxies(NULL, safe_cast(ContainerInterface::getContainedByObject(*this))); - - if (building) - building->gainedPlayer(*this); - } - else - { - fixOk = true; - DEBUG_REPORT_LOG(true,("Skipping POB fixup on non-authoritative player %s\n",getNetworkId().getValueString().c_str())); - retval = true; - } - } - else - { - if (isAuthoritative()) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - portal->queueObjectForFixup(*this); - originalCellProp->remove(*this, tmp); - containedBy->setContainedBy(NetworkId::cms_invalid); - setNeedsPobFixup(true); - addNotification(pobFixupNotification); - } - else - DEBUG_REPORT_LOG(true,("Skipping POB fixup on non-authoritative player %s\n",getNetworkId().getValueString().c_str())); - fixOk = true; - } - } - - if (!fixOk) - { - // warp to safe location - DEBUG_WARNING(true,("Player-controlled object %s was warped outside of its container because a good cell could not be found.",getNetworkId().getValueString().c_str())); - - containedBy->setContainedBy(NetworkId::cms_invalid); - - // attempt to put the character at the ejection point of the building - if (!ServerWorld::isSpaceScene()) - { - DynamicVariableLocationData ejectionPoint; - if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) - { - removeObjVarItem("building_ejection_point"); - setPosition_p(ejectionPoint.pos); - } - } - - retval = true; - } - } - else - { - // the container (most likely a building) we were in doesn't exist any more - DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building does not exist anymore\n",getNetworkId().getValueString().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building does not exist anymore",getNetworkId().getValueString().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); - - containedBy->setContainedBy(NetworkId::cms_invalid); - - // attempt to put the character at the ejection point of the building - if (!ServerWorld::isSpaceScene()) - { - DynamicVariableLocationData ejectionPoint; - if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) - { - removeObjVarItem("building_ejection_point"); - setPosition_p(ejectionPoint.pos); - } - else - // warp the player to the Mos Eisley Starport - { - DEBUG_REPORT_LOG(true, ("Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); - LOG("CustomerService",("Login: Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); - GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this),"tatooine",Vector(3528,5,-4804),NetworkId::cms_invalid,Vector(3528,5,-4804)); - } - } - - retval = true; - } - return retval; -} - -//----------------------------------------------------------------------- -/** - * Handle setting up the contents of any containedby objects while de-persisting this object - */ - -bool ServerObject::handleContentsSetup() -{ - ContainedByProperty * const containedBy = ContainerInterface::getContainedByProperty(*this); - if (!containedBy || containedBy->getContainedByNetworkId() == NetworkId::cms_invalid) - return true; - - ServerObject * const containingObject = safe_cast(containedBy->getContainedBy()); - DEBUG_REPORT_LOG(!containingObject, ("Could not depersist object %s into non-existant object %s.\n", getNetworkId().getValueString().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); - - // handle special case of player controlled objects depersisting into interiors - if ( isPlayerControlled() - && ( (containingObject && containingObject->getCellProperty()) - || (containedBy->getContainedByNetworkId() != NetworkId::cms_invalid && !containingObject))) - return handlePlayerInInteriorSetup(containedBy); - - if (containingObject) - { - Container * const container = ContainerInterface::getContainer(*containingObject); - SlottedContainer * const slotContainer = dynamic_cast(container); - if (slotContainer) - { - SlottedContainmentProperty * const slottedProperty = ContainerInterface::getSlottedContainmentProperty(*this); - if (slottedProperty) - slotContainer->depersistSlotContents(*this, slottedProperty->getCurrentArrangement()); - else - WARNING_STRICT_FATAL(true, ("Tried to depersist an object with no arrangement into a slotted container")); - } - else if (container) - { - container->depersistContents(*this); - if (containingObject->isInitialized() && containingObject->isInWorld() && container->isContentItemExposedWith(*this)) - addToWorld(); - } - - synchronizationOnLoadedInContainer(); - return false; - } - - LOG("CustomerService", ("BadContainerDepersist: Tried to depersist non-player object %s into container %s which could not be found.", getDebugInformation().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); - unload(); - return false; -} - -//----------------------------------------------------------------------- - -unsigned long ServerObject::getAndIncrementMoveSequenceNumber() -{ - unsigned long newValue = m_transformSequence.get(); - newValue++; - m_transformSequence = newValue; - return newValue; -} - -//----------------------------------------------------------------------- - -const bool ServerObject::getPositionChanged() const -{ - return (getTransform_o2w().getPosition_p() != m_oldPosition); -} - -//----------------------------------------------------------------------- - -const int ServerObject::getCacheVersion() const -{ - return m_cacheVersion.get(); -} - -//----------------------------------------------------------------------- - -const char * ServerObject::getSharedTemplateName() const -{ - if (getSharedTemplate() == NULL) - return NULL; - return getSharedTemplate()->ObjectTemplate::getName(); -} - -//----------------------------------------------------------------------- - -const char * ServerObject::getClientSharedTemplateName () const -{ - return getSharedTemplateName(); -} - -//----------------------------------------------------------------------- - -const Unicode::String ServerObject::getObjectName(void) const -{ - // try the player defined name first - const Unicode::String & name = m_objectName.get(); - if (!name.empty ()) - return name; - - // try the stringId name - const StringId & nameId = m_nameStringId.get(); - if (!nameId.isInvalid ()) - return Unicode::narrowToWide(nameId.getDebugString ()); - - // use the template name - return Unicode::narrowToWide(getTemplateName()); -} - -//----------------------------------------------------------------------- - -const Sphere & ServerObject::getSphereExtent() const -{ - return m_worldSphere; -} - -//----------------------------------------------------------------------- - -const Sphere ServerObject::getLocalSphere() const -{ - Sphere sphere (Sphere::unit); - const CollisionProperty * collision = getCollisionProperty(); - if (collision) - { - sphere = collision->getBoundingSphere_l(); - } - else - { - const Appearance * appearance = getAppearance(); - if (appearance) - { - sphere = appearance->getSphere(); - } - } - - if (sphere.getRadius() == 0.0f) - { - sphere.setRadius(1.0f); - } - return sphere; -} - -//----------------------------------------------------------------------- - -void ServerObject::updateWorldSphere() -{ - Sphere sphere (getLocalSphere()); - m_worldSphere.setCenter (rotateTranslate_o2w(sphere.getCenter())); - m_worldSphere.setRadius(sphere.getRadius()); -} - -//----------------------------------------------------------------------- - -/** - * Gets the approximate height of the object. - * - * @return the object's height - */ -float ServerObject::getHeight() const -{ - return getSphereExtent().getRadius() * 2.0f * getScale().y; -} // ServerObject::getHeight - -//----------------------------------------------------------------------- - -/** - * Gets the approximate radius of the object. - * - * @return the object's radius - */ -float ServerObject::getRadius() const -{ - return getSphereExtent().getRadius() * std::max(getScale().x, getScale().z); -} // ServerObject::getHeight - -//----------------------------------------------------------------------- - -/** - * Returns the volume of this object (and it's contents, if it's a container) - * - * @return the object's volume - */ -int ServerObject::getVolume(void) const -{ - const VolumeContainmentProperty* volumeProperty = ContainerInterface::getVolumeContainmentProperty(*this); - return volumeProperty ? volumeProperty->getVolume() : 1; -#if 0 - const VolumeContainer * container = ContainerInterface::getVolumeContainer(*this); - if (container) - return m_volume.get()+container->getCurrentVolume(); - else - return m_volume.get(); -#endif -} - -//----------------------------------------------------------------------- - - -const TriggerVolume * ServerObject::getTriggerVolume(const std::string & triggerVolumeName) const -{ - const TriggerVolume * result = 0; - const TriggerVolumeMap::const_iterator i = m_triggerVolumes.find(triggerVolumeName); - if(i != m_triggerVolumes.end()) - { - result = (*i).second; - } - return result; -} - -//----------------------------------------------------------------------- - -TriggerVolume * ServerObject::getTriggerVolume(const std::string & triggerVolumeName) -{ - TriggerVolume * result = 0; - const TriggerVolumeMap::iterator i = m_triggerVolumes.find(triggerVolumeName); - if (i != m_triggerVolumes.end()) - { - result = (*i).second; - } - return result; -} - -//---------------------------------------------------------------------- - -void ServerObject::seeCombatSpam (const MessageQueueCombatSpam & spamMsg) -{ - if (!isPlayerControlled()) - return; - - if (!isAuthoritative ()) - { - sendControllerMessageToAuthServer(CM_combatSpam, new MessageQueueCombatSpam(spamMsg)); - return; - } - - if (getClient ()) - { - bool shouldSend = (spamMsg.m_attacker == getNetworkId()); - if (!shouldSend) - { - ServerObject * sourceObject = safe_cast(NetworkIdManager::getObjectById(spamMsg.m_attacker)); - if ( sourceObject - && ObserveTracker::isObserving(*getClient(), *sourceObject) - && !PlayerObject::isIgnoring(getNetworkId(), spamMsg.m_attacker)) - { - shouldSend = true; - } - } - - if (shouldSend) - { - MessageQueueCombatSpam * const msg = new MessageQueueCombatSpam (spamMsg); - Controller *const controller = NON_NULL (getController()); - controller->appendMessage(CM_combatSpam, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } -} - -//---------------------------------------------------------------------- - -void ServerObject::seeSocial (const MessageQueueSocial & socialMsg) -{ - Controller * const controller = NON_NULL (getController()); - - if (!isAuthoritative ()) - { - MessageQueueSocial * const msg = new MessageQueueSocial (socialMsg); - controller->appendMessage(CM_socialReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - return; - } - - if (getClient ()) - { - ServerObject *sourceObject = safe_cast(NetworkIdManager::getObjectById(socialMsg.getSourceId())); - if ( sourceObject - && ( sourceObject->getCacheVersion() > 0 - || ( ObserveTracker::isObserving(*getClient(), *sourceObject) - && !PlayerObject::isIgnoring(getNetworkId(), socialMsg.getSourceId())))) - { - MessageQueueSocial * const msg = new MessageQueueSocial (socialMsg); - controller->appendMessage(CM_socialReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } -} - -//----------------------------------------------------------------------- - -bool ServerObject::serverObjectInitializeFirstTimeObject(ServerObject *cell, Transform const &transform) -{ - //This is the public interface for initializeFirstTimeObject. ::initializeFirstTimeObject has been made - //protected virtual so that we could enforce order. - - initializeFirstTimeObject(); - - // attach template scripts to this object - NOT_NULL(getScriptObject()); - getScriptObject()->initScriptInstances(); - - ServerObjectTemplate const * const newTemplate = safe_cast(getObjectTemplate()); - NOT_NULL(newTemplate); - - int count = newTemplate->getScriptsCount(); - for (int i = 0; i < count; ++i) - getScriptObject()->attachScript(newTemplate->getScripts(i), true); - - if (cell) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - if (!ContainerInterface::transferItemToCell(*cell, *this, transform, NULL, tmp)) - { - WARNING(true, ("ServerWorld::createNewObjectIntermediate tried to create a new object in a cell, but it failed.")); - return false; - } - } - else if (transform != Transform::identity) - setTransform_o2p(transform); - - getScriptObject()->setOwnerIsInitialized(); - - addObjectToConcludeList(); - - // validate the object transform - checkAndLogInvalidTransform(); - - //-- Initialize the controller - { - ServerController * const controller = safe_cast(getController()); - controller->endBaselines(); - } - - return true; -} - -//----------------------------------------------------------------------- - -void ServerObject::initializeFirstTimeObject() -{ - DEBUG_FATAL(!isAuthoritative(), ("Calling initialize on non authoritative object %s", getNetworkId().getValueString().c_str())); - setInitialized(true); - setPlacing(true); - - const ServerObjectTemplate* newTemplate = safe_cast(getObjectTemplate()); - NOT_NULL(newTemplate); - - // set up objvars - we know we are authoritative so we can get by with this - newTemplate->getObjvars(m_objVars); - - // record the crc of the pob used to create this object - PortalProperty *portalProperty = getPortalProperty(); - if (portalProperty) - m_objVars.setItem(portalPropertyCrcObjectVariableName, portalProperty->getCrc()); - - // add template equipment to this object - int i; - int count = newTemplate->getContentsCount(); - for (i = 0; i < count; ++i) - { - //Don't move this declaration of contents out of the loop or you will leak a ref. - ServerObjectTemplate::Contents contents; - newTemplate->getContents(contents, i); - if (contents.content == NULL) - { - DEBUG_WARNING(true, ("No template for contents item %d", i)); - continue; - } - if (contents.equipObject) - { - // find out where the contents go - const SlotId & slotId = SlotIdManager::findSlotId(CrcLowerString(contents.slotName.c_str())); - if (slotId != SlotId::invalid) - { - //We'll persist the contents automatically if the parent object is persisted. - ServerObject * newObject = ServerWorld::createNewObject(*(safe_cast(contents.content)), *this,slotId, false); - if (newObject == NULL) - { - DEBUG_WARNING(true, ("Can't create object from template %s",contents.content->getName())); - } - } - else - { - DEBUG_WARNING(true, ("Slot %s is not a valid slot name", contents.slotName.c_str())); - } - } - else - { - // get the object (which we assume is a volume container) in the - // desired slot - SlottedContainer * const container = ContainerInterface::getSlottedContainer(*this); - if (container != NULL) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - CachedNetworkId equippedObjectId = container->getObjectInSlot(SlotIdManager::findSlotId(CrcLowerString(contents.slotName.c_str())), tmp); - if (equippedObjectId != NetworkId::cms_invalid) - { - // put the contents in the volume container - ServerObject * equippedObject = safe_cast(equippedObjectId.getObject()); - if (equippedObject != NULL) - { - - //We'll persist the contents automatically if the parent object is persisted. - ServerObject * newObject = ServerWorld::createNewObject(*(safe_cast(contents.content)), *equippedObject,false); - if (newObject == NULL) - { - DEBUG_WARNING(true, ("Can't create object from template %s", contents.content->getName())); - } - } - else - { - DEBUG_WARNING(true, ("Object in slot %s not loaded",contents.slotName.c_str())); - } - } - else - { - DEBUG_WARNING(true, ("No object in slot %s", contents.slotName.c_str())); - } - } - else - DEBUG_WARNING(true, ("No slotted container for object")); - } - } - { - const PropertyList::iterator iEnd = m_propertyList->end(); - for (PropertyList::iterator i = m_propertyList->begin(); i != iEnd; ++i) - (*i)->initializeFirstTimeObject(); - } - - SharedObjectTemplate::GameObjectType got = - static_cast (getGameObjectType()); - if (got == SharedObjectTemplate::GOT_terminal_bazaar) - { - setLoadContents(false); - } - - //-- Assume this object wants to be altered. - scheduleForAlter(); -} - -//----------------------------------------------------------------------- - -void ServerObject::kill() -{ - Object::kill(); -} - -// ---------------------------------------------------------------------- - -/** - * Mark all the children of this object as persisted. - */ -void ServerObject::markChildrenPersisted() -{ - if (!safe_cast(getObjectTemplate())->getPersistContents()) - return; - - Container *container = ContainerInterface::getContainer(*this); - if (container) - { - for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) - { - ServerObject *containedObject = safe_cast((*containerIterator).getObject()); - if (containedObject) - { - containedObject->m_persisted=true; - containedObject->markChildrenPersisted(); - } - } - } - -} - -//----------------------------------------------------------------------- - -void ServerObject::addToWorld() -{ - if (getKill()) - return; - - if (isInWorld()) - { - DEBUG_WARNING(true, ("Calling add to world on object already in it %s", getNetworkId().getValueString().c_str())); - return; - } - updateWorldSphere(); - - Object::addToWorld(); - updateTriggerVolumes(); - - if (getScriptObject() != NULL) - getScriptObject()->setOwnerIsLoaded(); - - onAddedToWorld(); -} - -//----------------------------------------------------------------------- - -void ServerObject::onAddedToWorld() -{ - m_oldPosition = getTransform_o2w().getPosition_p(); - - // sanity check whether we should really be in the world or not - ContainedByProperty const * const containedByProperty = getContainedByProperty(); - if (containedByProperty && containedByProperty->getContainedByNetworkId().isValid()) - { - Object const * const containedByObject = containedByProperty->getContainedBy(); - if (containedByObject) - { - WARNING_DEBUG_FATAL( - !containedByObject->isInWorld(), - ( - "Tried to add object %s to the world with container %s which is not in the world.", - getDebugInformation().c_str(), - containedByObject->getDebugInformation().c_str())); - Container const * const containerProperty = ContainerInterface::getContainer(*containedByObject); - if (containerProperty) - { - WARNING_DEBUG_FATAL( - !containerProperty->isContentItemExposedWith(*this), - ( - "Tried to add object %s to the world with container %s which does not expose it.", - getDebugInformation().c_str(), - containedByObject->getDebugInformation().c_str())); - } - else - { - WARNING_DEBUG_FATAL( - true, - ( - "Tried to add object %s to the world with container %s with no container property.", - getDebugInformation().c_str(), - containedByObject->getDebugInformation().c_str())); - } - } - else - { - WARNING_DEBUG_FATAL( - true, - ( - "Tried to add object %s to the world with unresolvable container %s", - getDebugInformation().c_str(), - containedByProperty->getContainedByNetworkId().getValueString().c_str())); - } - } - - // Add networkUpdate volume - if (isInWorldCell()) - onAddedToWorldCell(); - - if (isAuthoritative()) - { - //Tell scripts we are added to world - ScriptParams params; - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_ADDED_TO_WORLD, params)); - - //remove the vendor reinitialization flag if it exists - removeObjVarItem(CommoditiesMarket::OBJVAR_VENDOR_REINITIALIZING); - } -} - -//----------------------------------------------------------------------- - -bool ServerObject::checkAndAddClientControl(Client* client) -{ - if (isPlayerControlled()) - { - CreatureObject* creature = asCreatureObject(); - if (client && creature && isInitialized() && isAuthoritative() && !isNeedingPobFixup()) - { - client->onLoadPlayer(*creature); - return true; - } - } - return false; - } - -//----------------------------------------------------------------------- - -void ServerObject::onPobFixupComplete() -{ - setNeedsPobFixup(false); - checkAndAddClientControl(GameServer::getInstance().getClient(getNetworkId())); - BuildingObject * const building = static_cast(ContainerInterface::getTopmostContainer(*this))->asBuildingObject(); - if (building) - building->gainedPlayer(*this); - -} - -//----------------------------------------------------------------------- - -void ServerObject::onClientReady(Client *c) -{ - NOT_NULL(c); - CmdSceneReady const readyMessage; - c->send(readyMessage, true); - - ScriptParams params; - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_LOGIN, params)); - - int galacticReserve = 0; - if (!getObjVars().getItem("galactic_reserve", galacticReserve)) - { - galacticReserve = 0; - } - - LOG("CustomerService", ("Money:%s logged in with %d money, %d galactic reserve", PlayerObject::getAccountDescription(getNetworkId()).c_str(), getTotalMoney(), galacticReserve)); - - if (getClient() && getClient()->isFreeTrialAccount()) - { - bool addToConcludeList = false; - - if ((m_cashBalance.get() + m_bankBalance.get()) > ConfigServerGame::getMaxFreeTrialMoney()) - { - int amountOver = (m_cashBalance.get() + m_bankBalance.get()) - ConfigServerGame::getMaxFreeTrialMoney(); - if (amountOver <= m_bankBalance.get()) - { - m_bankBalance = m_bankBalance.get() - amountOver; - LOG("CustomerService", ("Money:%s is a free trial user and logged in with too much. Deducting %d from bank.", PlayerObject::getAccountDescription(getNetworkId()).c_str(), amountOver)); - } - else - { - m_cashBalance = m_cashBalance.get() - (amountOver - m_bankBalance.get()); - LOG("CustomerService", ("Money:%s is a free trial user and logged in with too much. Deducting %d from bank and %d from cash.", PlayerObject::getAccountDescription(getNetworkId()).c_str(), m_bankBalance.get(), amountOver - m_bankBalance.get())); - m_bankBalance = 0; - } - - // sanity check - fix up any negative cash/bank balance - if (m_cashBalance.get() < 0) - m_cashBalance = 0; - - if (m_bankBalance.get() < 0) - m_bankBalance = 0; - - addToConcludeList = true; - } - - // trial accounts cannot have galactic reserve - if (galacticReserve > 0) - { - LOG("CustomerService", ("Money:%s is a free trial user and logged in with %d galactic reserve. Setting galactic reserve to 0.", PlayerObject::getAccountDescription(getNetworkId()).c_str(), galacticReserve)); - removeObjVarItem("galactic_reserve"); - PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); - if (po) - { - po->depersistGalacticReserveDeposit(); - } - - addToConcludeList = true; - } - - if (addToConcludeList) - addObjectToConcludeList(); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::onClientAboutToLoad() -{ -} - -// ---------------------------------------------------------------------- - -void ServerObject::onLoadingScreenComplete() -{ -} - -// ---------------------------------------------------------------------- - -bool ServerObject::onContainerAboutToLoseItem(ServerObject * destination, ServerObject& item, ServerObject* transferer) -{ - if (transferer && !checkBankTransfer(this, item, transferer)) - return false; - - Object *parent = ContainerInterface::getContainedByObject(*this); - if (parent && parent->asServerObject()) - return parent->asServerObject()->onContainerChildAboutToLoseItem(destination, item, transferer); - - return true; -} - -//----------------------------------------------------------------------- - -bool ServerObject::onContainerAboutToTransfer(ServerObject * destination, ServerObject* transferer) -{ - UNREF(destination); - UNREF(transferer); - return true; -} - -//----------------------------------------------------------------------- - -int ServerObject::onContainerAboutToGainItem(ServerObject& item, ServerObject* transferer) -{ - if (transferer && !checkBankTransfer(this, item, transferer)) - return Container::CEC_BlockedByDestinationContainer; - - Object *parent = ContainerInterface::getContainedByObject(*this); - //disallow putting crafting stations in other crafting stations - if (transferer && parent && parent->asServerObject()) - { - SharedObjectTemplate::GameObjectType parentGot = static_cast (parent->asServerObject()->getGameObjectType()); - SharedObjectTemplate::GameObjectType itemGot = static_cast (item.getGameObjectType()); - - if (parentGot == SharedObjectTemplate::GOT_misc_crafting_station && itemGot == parentGot) - { - return Container::CEC_BlockedByDestinationContainer; - } - } - - if (parent && parent->asServerObject()) - return parent->asServerObject()->onContainerChildAboutToGainItem(item, this, transferer) ? Container::CEC_Success : Container::CEC_BlockedByDestinationContainer; - - return Container::CEC_Success; -} - -//----------------------------------------------------------------------- - -void ServerObject::onContainerLostItem(ServerObject * destination, ServerObject& item, ServerObject* transferer) -{ - Object *parent = ContainerInterface::getContainedByObject(*this); - if (parent && parent->asServerObject()) - parent->asServerObject()->onContainerChildLostItem(destination, item, this, transferer); -} - -//----------------------------------------------------------------------- - -void ServerObject::onContainerTransfer(ServerObject * destination, ServerObject* transferer) -{ - UNREF(destination); - UNREF(transferer); -} - -//----------------------------------------------------------------------- - -void ServerObject::onContainerGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) -{ - Object *parent = ContainerInterface::getContainedByObject(*this); - if (parent && parent->asServerObject()) - parent->asServerObject()->onContainerChildGainItem(item, source, transferer); - combineResourceContainers(item); -} - -//----------------------------------------------------------------------- - -void ServerObject::onContainerTransferComplete(ServerObject *oldContainer, ServerObject *newContainer) -{ - if (!isAuthoritative()) - { - WARNING_STRICT_FATAL(true, ("onContainerTransferComplete called on non auth object %s", getNetworkId().getValueString().c_str())); - return; - } - - if (newContainer) - { - //If this object is not persisted, but it placed into a container that is - // Then persist the object - if (!isPersisted() && newContainer->isPersisted() && safe_cast(newContainer->getObjectTemplate())->getPersistContents()) - persist(); - } - - DEBUG_FATAL(getCellProperty(), ("Cell object container transfer complete")); - - setTransformChanged(true); - - if ( (oldContainer && !oldContainer->asCellObject()) - || (newContainer && !newContainer->asCellObject())) - PositionUpdateTracker::flushPositionUpdate(*this); - - containerHandleUpdateProxies(oldContainer, newContainer); - - Container const * const newContainerProperty = newContainer ? ContainerInterface::getContainer(*newContainer) : 0; - bool const wasInWorld = isInWorld(); - bool const nowInWorld = !newContainer || (newContainerProperty && newContainer->isInWorld() && newContainerProperty->isContentItemExposedWith(*this)); - - containerHandleUpdateClients(oldContainer, newContainer, (wasInWorld && !nowInWorld), (!wasInWorld && nowInWorld)); - - ObserveTracker::onObjectArrangementChanged(*this); - scheduleForAlter(); - - updatePositionOnPlanetServer(true); -} - -//----------------------------------------------------------------------- - -void ServerObject::containerDepersistContents(ServerObject * oldParent, ServerObject * newParent) -{ - Container * const oldContainer = oldParent ? ContainerInterface::getContainer(*oldParent) : NULL; - Container * const newContainer = newParent ? ContainerInterface::getContainer(*newParent) : NULL; - - if (oldContainer) - oldContainer->internalItemRemoved(*this); - if (newContainer) - { - SlottedContainer * const slotContainer = dynamic_cast(newContainer); - if (slotContainer) - { - SlottedContainmentProperty* const slotted = ContainerInterface::getSlottedContainmentProperty(*this); - DEBUG_FATAL(!slotted, ("Error unpacking non slotted objects into a slotted container")); - slotContainer->depersistSlotContents(*this, -1); - slotContainer->updateArrangement(*this, -1, slotted->getCurrentArrangement()); - } - else - { - newContainer->depersistContents(*this); - } - } -} - -//----------------------------------------------------------------------- - -void ServerObject::containerHandleUpdateClients(ServerObject* oldContainer, ServerObject* newContainer, bool remFromWorld, bool addWorld) -{ - if (remFromWorld) - removeFromWorld(); - - // If we're moving in or out of the world cell, update as appropriate (adds or removes farUpdateVolume) - if (oldContainer && !newContainer && !addWorld) - onAddedToWorldCell(); - else if (newContainer && !oldContainer && !remFromWorld) - onRemovedFromWorldCell(); - - if (addWorld) - addToWorld(); - - ObserveTracker::onObjectContainerChanged(*this); - synchronizationOnContainerChange(oldContainer, newContainer); -} - -//----------------------------------------------------------------------- - -void ServerObject::createFarNetworkUpdateVolume(float const overrideVal) -{ - if (isBeingDestroyed() || isUnloading()) - { - DEBUG_REPORT_LOG(true, ("Not creating volume for object that is being destroyed\n")); - return; - } - if (m_networkUpdateFar) - { - WARNING_STRICT_FATAL(true, ("Object %s already has a far update volume", getNetworkId().getValueString().c_str())); - return; - } - - // There's no reason for a contained item to have a far network update volume - // if this object is contained by something else. - Object const *const containedByObject = ContainerInterface::getContainedByObject(*this); - if (containedByObject) - { - DEBUG_REPORT_LOG(true, ("SO::createFarNetworkUpdateVolume(): server id=[%lu],object id=[%s],container id=[%s]: skipping creation of far network update volume because item is contained.\n", - GameServer::getInstance().getProcessId(), - getNetworkId().getValueString().c_str(), - containedByObject->getNetworkId().getValueString().c_str())); - return; - } - - if (getCacheVersion() == 0) - { - const ServerObjectTemplate * myTemplate = safe_cast(getObjectTemplate()); - UNREF(myTemplate); - float const radius_far = overrideVal != 0.0f ? overrideVal : getFarNetworkUpdateRadius(); - if (radius_far > 0) - { - if (ServerWorld::isSpaceScene()) - { - DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("creating far update volume (space version) for %s (template=%s, radius=%g)\n", getNetworkId().getValueString().c_str(), myTemplate->getName(), radius_far)); - // don't make link-dead creatures visible to other people at the top level in space - if (getSendToClient() && (getClient() || !asCreatureObject())) - SpaceVisibilityManager::addObject (*this, static_cast(radius_far)); - } - else - { - DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("creating far update volume for %s (template=%s, radius=%g)\n", getNetworkId().getValueString().c_str(), myTemplate->getName(), radius_far)); - TriggerVolume * t = new NetworkTriggerVolume(*this, radius_far); - addTriggerVolume(t); - m_networkUpdateFar = t; - } - } - } -} - -//----------------------------------------------------------------------- - -void ServerObject::destroyFarNetworkUpdateVolume() -{ - if (!m_networkUpdateFar) - return; - - DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("Removing far update volume for %s\n", getNetworkId().getValueString().c_str())); - ServerWorld::removeObjectTriggerVolume(m_networkUpdateFar); - TriggerVolumeMap::iterator i = m_triggerVolumes.find(NetworkTriggerVolumeNamespace::NetworkTriggerVolumeName); - if (i == m_triggerVolumes.end() || i->second != m_networkUpdateFar) - { - WARNING_STRICT_FATAL(true, ("Called destroyFarNetworkUpdateVolume but could not find it in m_triggerVolumes")); - } - else - m_triggerVolumes.erase(i); - - delete m_networkUpdateFar; - m_networkUpdateFar = 0; -} - -//----------------------------------------------------------------------- - -bool ServerObject::isNetworkUpdateFarTriggerVolume(TriggerVolume const &triggerVolume) const -{ - return triggerVolume.isNetworkTriggerVolume(); -} - -// ---------------------------------------------------------------------- - -TriggerVolume *ServerObject::getNetworkTriggerVolume() -{ - return m_networkUpdateFar; -} - -// ---------------------------------------------------------------------- - -float ServerObject::getFarNetworkUpdateRadius() const -{ - if (ServerWorld::getSceneId() == NewbieTutorial::getSceneId()) - return 0.f; - - // Overide update radius for all scenes for all objects gloablly with config entry - int const overrideRadius = ConfigServerGame::getOverrideUpdateRadius(); - // Overide the update radius for a specific scene if the above global overide is not set - // If Scene overide is disabled in ConfigServerGame::getEnableSceneGlobalData() it will return zero - float radius = overrideRadius > 0 ? static_cast(overrideRadius) : SceneGlobalData::getUpdateRadius(ServerWorld::getSceneId()); - // Set the radius to the far update range of from the object template if it hasn't already been overiden - radius = radius > 0 ? radius : safe_cast(getObjectTemplate())->getUpdateRanges(ServerObjectTemplate::UR_far); - - if (!ServerWorld::isSpaceScene()) - { - if (ms_buildingUpdateRadiusMultiplier == 0) - setBuildingUpdateRadiusMultiplier(ConfigServerGame::getBuildingUpdateRadiusMultiplier()); - - // Potentially allow larger objects to come into range sooner if the cfg setting to do so is set - if (radius >= 127.0f && radius < 512.0f && !asCreatureObject()) - radius *= ms_buildingUpdateRadiusMultiplier; - } - return radius; -} - -// ---------------------------------------------------------------------- - -void ServerObject::onTriggerEnter(ServerObject & object, TriggerVolume & triggerVolume) -{ -} - -//----------------------------------------------------------------------- -// object is leaving this' volume -void ServerObject::onTriggerExit(ServerObject & object, TriggerVolume & triggerVolume) -{ -} - -// ---------------------------------------------------------------------- -// this object got added to a trigger volume -void ServerObject::onAddedToTriggerVolume(TriggerVolume & triggerVolume) -{ - // only CreatureObject should ever be added to a TriggerVolume - WARNING(true, ("ServerObject (%s) being added to TriggerVolume (%s) owned by (%s)", - getDebugInformation().c_str(), - triggerVolume.getName().c_str(), - triggerVolume.getOwner().getDebugInformation().c_str())); -} - -// ---------------------------------------------------------------------- -// this object got removed from a trigger volume -void ServerObject::onRemovedFromTriggerVolume(TriggerVolume & triggerVolume) -{ - // NOTE: be careful about referencing the TriggerVolume because this - // function can be called from the TriggerVolume's dtor - - // only CreatureObject should ever be added to a TriggerVolume - WARNING(true, ("ServerObject (%s) being removed from TriggerVolume (%s) owned by (%s)", - getDebugInformation().c_str(), - triggerVolume.getName().c_str(), - triggerVolume.getOwner().getDebugInformation().c_str())); -} - -// ---------------------------------------------------------------------- - -/** - * Send an object to the database process to be persisted, if it isn't already. - * After this function is called, changes to this object will be sent to the database. - */ - -void ServerObject::persist() -{ - // Do not persist buildout objects (buildout objects have negative networkIds) - if (getNetworkId() < NetworkId::cms_invalid) - return; - - if (isAuthoritative()) - { - ContainedByProperty *containedBy = getContainedByProperty(); - - bool const contained = containedBy && containedBy->getContainedByNetworkId().isValid(); - - if (ServerWorld::isSpaceScene()) - { - // in space, non-player objects are only allowed to persist at the origin - if (!contained && !isPlayerControlled() && getPosition_p() != Vector::zero) - { - WARNING_STRICT_FATAL(true, ("Tried to persist non-player object %s in a space scene away from the origin (not persisting).", getDebugInformation().c_str())); - return; - } - } - else - { - WARNING_STRICT_FATAL((getPosition_w() == Vector::zero) && !contained && (getSceneId() != "universe"), ("Persisting object %s (%s) at (0,0,0)",getNetworkId().getValueString().c_str(),getTemplateName())); - } - - if (!m_persisted.get()) - { -#ifdef _DEBUG - ServerObject *parent = static_cast(ContainerInterface::getContainedByObject(*this)); - if (parent && !parent->isPersisted()) - { - WARNING(true, ("Persisting %s into %s which is not persisted!", getNetworkId().getValueString().c_str(), parent->getNetworkId().getValueString().c_str())); - } -#endif - - m_persisted = true; - - markChildrenPersisted(); - sendCreateAndBaselinesToDatabaseServer(); - - PositionUpdateTracker::sendPositionUpdate(*this); - } - } - else - { - sendControllerMessageToAuthServer(CM_persistObject, 0); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::removeTriggerVolume(const std::string & name) -{ - for (unsigned int i = 0; i < m_triggerVolumeInfo.size(); ++i) - { - if (m_triggerVolumeInfo[i].name == name) - { - m_triggerVolumeInfo.erase(i); - break; - } - } -} - -//----------------------------------------------------------------------- - -void ServerObject::sendControllerMessageToAuthServer(enum GameControllerMessage cm, MessageQueue::Data * msg, float value) -{ -#ifdef _DEBUG - // debug stuff done this way so it is easy to break on - if (!isInitialized() || isInEndBaselines()) - { - WARNING(isInEndBaselines(), ("sendControllerMessageToAuthServer while ending baselines: message id=(%d) from object id=[%s], template=[%s], on server id=[%d]", static_cast(cm), getNetworkId().getValueString().c_str(), getObjectTemplateName(), static_cast(GameServer::getInstance().getProcessId()))); - WARNING(!isInitialized(), ("sendControllerMessageToAuthServer while uninitialized: message id=(%d) from object id=[%s], template=[%s], on server id=[%d]", static_cast(cm), getNetworkId().getValueString().c_str(), getObjectTemplateName(), static_cast(GameServer::getInstance().getProcessId()))); - } -#endif - - Controller * controller = getController(); - if(controller) - { - controller->appendMessage(cm, value, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - } - else - { - DEBUG_WARNING(true, ("No controller for sendControllerMessageToAuthServer")); - delete msg; - } -} - -//----------------------------------------------------------------------- - -bool ServerObject::getSendToClient() const -{ - return getCacheVersion() == 0 && getLocalFlag(LocalObjectFlags::ServerObject_SendToClient); -} - -//----------------------------------------------------------------------- - -void ServerObject::sendToClientsInUpdateRange(const GameNetworkMessage & message, bool reliable, bool includeSelf) const -{ - std::set const &clients = getObservers(); - std::set::const_iterator i; - std::map > &tmpDistributionList = DistributionListStack::alloc(); - - Client const * const myClient = getClient(); - - float minDistanceSquared = 0.0f; - - if (!reliable) - { - if (m_unreliableControllerMessageSequenceNumber == 0) - { - // Send reliable - - reliable = true; - ++m_unreliableControllerMessageSequenceNumber; - } - else - { - // Send un-reliable based on distance - - switch (m_unreliableControllerMessageSequenceNumber) - { - // The server is guaranteed to send one reliable transform update per 2 seconds (8:1 ratio for unreliable/reliable) - - case 1: { minDistanceSquared = ConfigServerGame::getUpdateRange7PacketsSquared(); } break; // 7 unreliable per 2 seconds - case 2: { minDistanceSquared = ConfigServerGame::getUpdateRange3PacketsSquared(); } break; // 3 unreliable per 2 seconds - case 3: { minDistanceSquared = ConfigServerGame::getUpdateRange5PacketsSquared(); } break; // 5 unreliable per 2 seconds - case 4: { minDistanceSquared = ConfigServerGame::getUpdateRange1PacketsSquared(); } break; // 1 unreliable per 2 seconds - case 5: { minDistanceSquared = ConfigServerGame::getUpdateRange4PacketsSquared(); } break; // 4 unreliable per 2 seconds - case 6: { minDistanceSquared = ConfigServerGame::getUpdateRange2PacketsSquared(); } break; // 2 unreliable per 2 seconds - case 7: { minDistanceSquared = ConfigServerGame::getUpdateRange6PacketsSquared(); } break; // 6 unreliable per 2 seconds - default: - { - DEBUG_WARNING(true, ("All cases should be handled for the sequence numbers: %d", m_unreliableControllerMessageSequenceNumber)); - } - - } - - if (m_unreliableControllerMessageSequenceNumber >= 7) - { - m_unreliableControllerMessageSequenceNumber = 0; - } - else - { - ++m_unreliableControllerMessageSequenceNumber; - } - } - } - - // need to do special handling for CM_combatSpam controller - // message to determine if the client should get the message - bool isCombatSpamMessage = false; - NetworkId combatSpamAttacker, combatSpamDefender; - Vector combatSpamAttackerPosition_w, combatSpamDefenderPosition_w; - if (!clients.empty()) - { - static unsigned long int const controllerMessageCrc = MessageDispatch::MessageBase::makeMessageTypeFromString("ObjControllerMessage"); - if (controllerMessageCrc == message.getType()) - { - ObjControllerMessage const & ocm = static_cast(message); - if (ocm.getMessage() == CM_combatSpam) - { - MessageQueueCombatSpam const * mqcs = static_cast(ocm.getData()); - - if (mqcs) - { - isCombatSpamMessage = true; - combatSpamAttacker = mqcs->m_attacker; - combatSpamAttackerPosition_w = mqcs->m_attackerPosition_w; - combatSpamDefender = mqcs->m_defender; - combatSpamDefenderPosition_w = mqcs->m_defenderPosition_w; - } - } - } - } - - for (i = clients.begin(); i != clients.end(); ++i) - { - // build connection list - Client * const c = (*i); - - if (isCombatSpamMessage && !c->shouldReceiveCombatSpam(combatSpamAttacker, combatSpamAttackerPosition_w, combatSpamDefender, combatSpamDefenderPosition_w)) - continue; - - if (!reliable) - { - // if it's time to try to send to this client - // because it is close enough, add it to the - // target list, otherwise continue looking - // through clients. - - ServerObject * const obj = c->getCharacterObject(); - - if (obj != NULL) - { - if ( (ConfigServerGame::getSkipUnreliableTransformsForOtherCells() && obj->getAttachedTo() != getAttachedTo()) - || (obj->getPosition_w().magnitudeBetweenSquared(getPosition_w()) > minDistanceSquared) - || (!CellProperty::areAdjacent(getParentCell(), obj->getParentCell()))) - { - // Throw out this un-reliable packet due to distance - - continue; - } - } - } - - if(includeSelf || ( (!includeSelf) && c != myClient) ) - { - ConnectionServerConnection * const n = c->getConnection(); - if (n) - tmpDistributionList[n].push_back(c->getCharacterObjectId()); - } - } - - for (std::map >::const_iterator connIter = tmpDistributionList.begin(); connIter != tmpDistributionList.end(); ++connIter) - { - GameClientMessage const msg((*connIter).second, reliable, message); - (*connIter).first->send(msg, reliable); - } - - DistributionListStack::release(); -} - -//----------------------------------------------------------------------- - -void ServerObject::sendToSpecifiedClients(const GameNetworkMessage & message, bool reliable, const std::vector & clients) -{ - for (std::vector::const_iterator i = clients.begin(); i != clients.end(); ++i) - { - ServerObject * o = safe_cast(NetworkIdManager::getObjectById(*i)); - if (o != NULL && o->getClient() != NULL) - o->getClient()->send(message, reliable); - } -} - -//----------------------------------------------------------------------- - -void ServerObject::appendMessage(int const message, float const value, uint32 const flags) -{ - Controller * const co = getController(); - if (co) - co->appendMessage(message, value, flags); - else - DEBUG_REPORT_LOG(true, ("ServerObject::appendMessage: %s called without a controller.\n", getDebugInformation().c_str())); -} - -//----------------------------------------------------------------------- - -void ServerObject::appendMessage(int const message, float const value, MessageQueue::Data * const data, uint32 const flags) -{ - Controller * const co = getController(); - if (co) - co->appendMessage(message, 0.0f, data, flags); - else - DEBUG_REPORT_LOG(true, ("ServerObject::appendMessage: %s called without a controller.\n", getDebugInformation().c_str())); -} - -//----------------------------------------------------------------------- - -void ServerObject::forwardServerObjectSpecificBaselines() const -{ -} - -//----------------------------------------------------------------------- - -void ServerObject::sendObjectSpecificBaselinesToClient(Client const &) const -{ -} - -//----------------------------------------------------------------------- - -BaselinesMessage * ServerObject::createSharedBaselinesMessage() const -{ - return new BaselinesMessage(getNetworkId(), getObjectType(), m_sharedPackage, BaselinesMessage::BASELINES_SHARED); -} - -//----------------------------------------------------------------------- - -BaselinesMessage * ServerObject::createSharedNpBaselinesMessage() const -{ - return new BaselinesMessage(getNetworkId(), getObjectType(), m_sharedPackage_np, BaselinesMessage::BASELINES_SHARED_NP); -} - -//----------------------------------------------------------------------- - -void ServerObject::setAuthority() -{ - // We make sure to send out deltas before setting authority, so that we don't push out deltas at the - // end of the frame which were intended to be nonauthoritative. - if (isInitialized()) - sendDeltasForSelfAndContents(); - - DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("Called setAuthority on %s\n", getNetworkId().getValueString().c_str())); - - Container * const container = ContainerInterface::getContainer(*this); - if (container) - { - std::vector idList; - idList.reserve(container->getNumberOfItems()); - for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) - idList.push_back(*containerIterator); - - for (std::vector::iterator i = idList.begin(); i != idList.end(); ++i) - { - ServerObject * const containedObject = safe_cast(i->getObject()); - if (containedObject) - containedObject->setAuthority(); - } - } - - safe_cast(getController())->setAuthoritative(true); - - if (getScriptObject()) - getScriptObject()->setOwnerIsAuthoritative(true, GameServer::getInstance().getProcessId()); - - setAuthServerProcessId(GameServer::getInstance().getProcessId()); - - if (isInitialized()) - updatePositionOnPlanetServer(true); - - if (isAuthoritative() && (!isPlayerControlled() || getClient()) && getObjVars().hasItem("teleportFixup")) - TeleportFixupHandler::add(*this); - - // Update loadWith so we don't depend on a stale value for objects that - // drop authority and regain it later without unloading. - setLoadWith(ContainerInterface::getLoadWithContainerId(*this)); - - virtualOnSetAuthority(); - scheduleForAlter(); - if (!m_messageTos.empty()) - MessageToQueue::getInstance().addToScheduler(*this, m_messageTos.begin()->second.getCallTime()); - - if (isPlayerControlled()) - { - // Make sure Central knows the right sceneId for the player - GenericValueTypeMessage > > const msg( - "SetSceneForPlayer", - std::make_pair( - getNetworkId(), - std::make_pair(ServerWorld::getSceneId(), false))); - - GameServer::getInstance().sendToCentralServer(msg); - - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); - if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.locationPlanet != ServerWorld::getSceneId())) - ServerUniverse::setConnectedCharacterPlanetData(getNetworkId(), ServerWorld::getSceneId()); - } - - // When a top level object or an object whose contiaining object is - // authoritative gets to this point, all its contents have been - // made authoritative, so it is now safe to trigger appropriate objects - // to notify them of gaining authority. - ServerObject * const containingObject = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (!containingObject || containingObject->isAuthoritative()) - triggerMadeAuthoritative(); -} - -//----------------------------------------------------------------------- - -void ServerObject::virtualOnSetClient() -{ - if (getObjVars().hasItem("teleportFixup")) - TeleportFixupHandler::add(*this); - - if (m_pendingSyncUi) - { - for (std::vector::const_iterator i = m_pendingSyncUi->begin(); i != m_pendingSyncUi->end(); ++i) - { - ServerObject *uiObject = safe_cast(NetworkIdManager::getObjectById(*i)); - if (uiObject && uiObject->getSynchronizedUi()) - uiObject->addSynchronizedUiClient(*this); - } - delete m_pendingSyncUi; - m_pendingSyncUi = 0; - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::setClient(Client &newClient) -{ - m_client = &newClient; - - virtualOnSetClient(); - - safe_cast(getController())->onClientReady(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::clearClient() -{ - if (m_client) - { - safe_cast(getController())->onClientLost(); - m_client = 0; - } -} - -//----------------------------------------------------------------------- - -void ServerObject::setCacheVersion(const int c) -{ - if (isAuthoritative()) - { - bool const becomingUncached = c == 0 && m_cacheVersion.get() != 0; - - if (becomingUncached) - ObserveTracker::onObjectDestroyed(*this, false); - - m_cacheVersion.set(c); - if (c == 0) - { - Container* container = ContainerInterface::getContainer(*this); - if (container) - { - for (ContainerIterator i = container->begin(); i != container->end(); ++i) - { - ServerObject *containedObject = safe_cast((*i).getObject()); - if (containedObject && containedObject->getCacheVersion() != 0) - containedObject->setCacheVersion(0); - } - } - - if (becomingUncached && isInWorld() && !ContainerInterface::getContainedByObject(*this)) - createFarNetworkUpdateVolume(); - } - } - else - { - sendControllerMessageToAuthServer(CM_setCacheVersion, new MessageQueueGenericValueType(c)); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::setDefaultAlterTime(float time) -{ - // if the server is running in build mode, always alter, so that designers' changes - // will be made even if there are no players around - if (ConfigServerGame::getBuildoutAreaEditingEnabled() && time > AlterResult::cms_alterQuickly) - time = AlterResult::cms_alterQuickly; - m_defaultAlterTime = time; -} - -// ---------------------------------------------------------------------- -// CellProperty::addObject_w calls around this function (it calls Object::setParentCell directly) -// to ensure that server-side objects send cellChanged notifications correctly. - -void ServerObject::setParentCell(CellProperty * newCell) -{ - // Uninitialized or proxy objects can set the parent cell directly - - if (!isInitialized() || !isAuthoritative()) - { - Object::setParentCell(newCell); - return; - } - - // Everything else has to go through ContainerInterface - - Transform oldTransform = getTransform_o2p(); - - bool result = false; - - CellProperty * oldCell = getParentCell(); - - if(oldCell == NULL) oldCell = CellProperty::getWorldCellProperty(); - if(newCell == NULL) newCell = CellProperty::getWorldCellProperty(); - - // ---------- - - if(oldCell == newCell) - { - // Cells are the same - nothing to do - } - if(newCell == CellProperty::getWorldCellProperty()) - { - // Object was in a cell and is moving to the world, transfer from cell container to world - - Object * oldCellObject = &oldCell->getOwner(); - - Transform oldCellTransform = oldCellObject->getTransform_o2w(); - - Transform newTransform; - - newTransform.multiply(oldCellTransform,oldTransform); - - Container::ContainerErrorCode tmp = Container::CEC_Success; - result = ContainerInterface::transferItemToWorld(*this, newTransform, NULL, tmp); - - DEBUG_REPORT_LOG(!result, ("Object %s (id=%s) transfer to world was denied via ContainerInterface::transferItemToWorld()\n", getObjectTemplateName(), getNetworkId().getValueString().c_str())); - } - else - { - // Object is moving to a different cell - - Object * newCellObject = &newCell->getOwner(); - - ServerObject * newCellServerObject = safe_cast(newCellObject); - - Container::ContainerErrorCode tmp = Container::CEC_Success; - result = ContainerInterface::transferItemToCell(*newCellServerObject, *this, NULL, tmp); - - DEBUG_REPORT_LOG(!result, ("Object %s (id=%s) transfer to cell (id=%s) was denied via ContainerInterface::transferItemToCell()\n", getObjectTemplateName(), getNetworkId().getValueString().c_str(), newCellObject->getNetworkId().getValueString().c_str())); - } - - // ---------- - - if(!result) - { - // A failed transfer may have mucked up the transform, so restore it now. - - setTransform_o2p(oldTransform); - } -} - -//----------------------------------------------------------------------- - -NetworkId const &ServerObject::getOwnerId() const -{ - return NetworkId::cms_invalid; -} - -//----------------------------------------------------------------------- - -bool ServerObject::isOwner(NetworkId const &, Client const *client) const -{ - return client && client->isGod(); -} - -//----------------------------------------------------------------------- - -void ServerObject::setOwnerId(NetworkId const &) -{ -} - -//----------------------------------------------------------------------- - -/** - * Rename an object. - * @param newName The new name for the object - * You cannot rename a player-controlled object using this function. - * @see PlayerCreationManagerServer::renamePlayer() - */ - -void ServerObject::setObjectName(const Unicode::String &newName) -{ - if(isAuthoritative()) - { - if (isPlayerControlled()) - { - DEBUG_WARNING(true, ("You cannot set the name of a player controlled object directly. Name:<%s>", Unicode::wideToNarrow(newName).c_str())); - return; - } - - std::string UTF8String = Unicode::wideToUTF8(newName); - if (UTF8String.length() > 127) - { - DEBUG_WARNING(true, ("Tried to set object %s's name to something too long (truncating). [%s]", getNetworkId().getValueString().c_str(), UTF8String.c_str())); - m_objectName = Unicode::utf8ToWide(UTF8String.substr(0, 127)); - } - else - m_objectName = newName; - - if (newName[0] == '@') - { - StringId id(Unicode::wideToNarrow(newName)); - setObjectNameStringId(id); - setObjectName(Unicode::emptyString); - } - } - else - { - sendControllerMessageToAuthServer(CM_setObjectName, new MessageQueueGenericValueType(newName)); - } -} - -//----------------------------------------------------------------- - -void ServerObject::setObjectNameStringId (const StringId & id) -{ - if(isAuthoritative()) - { - m_nameStringId = id; - } - else - { - sendControllerMessageToAuthServer(CM_setObjectNameStringId, new MessageQueueGenericValueType(id)); - } -} - -//---------------------------------------------------------------------- - -void ServerObject::setSceneIdOnThisAndContents (const std::string & sceneId) -{ - setSceneId(sceneId); - Container *container = ContainerInterface::getContainer(*this); - if (container) - { - for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) - { - ServerObject *containedObject = safe_cast((*containerIterator).getObject()); - if (containedObject) - { - containedObject->setSceneIdOnThisAndContents(sceneId); - } - } - } -} - -//---------------------------------------------------------------------- - -void ServerObject::speakText(NetworkId const &target, uint32 chatType, uint32 mood, uint32 flags, Unicode::String const &speech, int language, Unicode::String const &oob) -{ - if (speech.empty()) - { - return; - } - - if (chatType > 16384 || mood > 16384 || flags > 16384) - { - WARNING (true, ("ChatType, Mood, or Flags are out of 16 bit range. %d, %d, %d", chatType, mood, flags)); - return; - } - - const bool isTypePrivate = SpatialChatManager::isPrivate (chatType); - if (isTypePrivate) - flags |= MessageQueueSpatialChat::F_isPrivate; - - const uint16 volume = SpatialChatManager::getVolume (chatType); - - MessageQueueSpatialChat const chatMessage( - getNetworkId(), - target, - speech, - volume, - static_cast(chatType), - static_cast(mood), - flags, - language, - oob); - speakText(chatMessage); -} - -//----------------------------------------------------------------------- - -void ServerObject::speakText(MessageQueueSpatialChat const &spatialChat) -{ - if (!isAuthoritative ()) - { - Controller * const controller = getController(); - NOT_NULL (controller); - - MessageQueueSpatialChat * msg = new MessageQueueSpatialChat (spatialChat); - controller->appendMessage(CM_spatialChatSend, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - return; - } - - if (m_scriptObject) - { - ScriptParams params; - params.addParam(spatialChat.getText ()); - if (m_scriptObject->trigAllScripts(Scripting::TRIG_SPEAKING, params) != SCRIPT_CONTINUE) - { - LOG("ScriptInvestigation", ("Chat could not speak for %s because scripts said not to", getNetworkId().getValueString().c_str())); - return; - } - } - - const float distance = static_cast(spatialChat.getVolume ()); - const uint32 flags = spatialChat.getFlags(); - const bool isPrivate = (flags & MessageQueueSpatialChat::F_isPrivate) != 0; - const bool isTargetOnly = (flags & MessageQueueSpatialChat::F_targetOnly) != 0; - const bool isTargetGroupOnly = (flags & MessageQueueSpatialChat::F_targetGroupOnly) != 0; - const bool isTargetAndSourceGroup = (flags & MessageQueueSpatialChat::F_targetAndSourceGroup) != 0; - - const NetworkId & chatTargetId = spatialChat.getTargetId (); - const NetworkId & chatSourceId = spatialChat.getSourceId (); - - typedef std::vector ServerObjectVector; - ServerObjectVector results; - ServerWorld::getSpatialChatListeners(*this, distance, results); - - const ServerObject * const chatTarget = safe_cast(NetworkIdManager::getObjectById (chatTargetId)); - const CreatureObject * const chatTargetCreature = chatTarget ? chatTarget->asCreatureObject () : 0; - int const chatMessageIndex = ChatLogManager::getNextMessageIndex(); - - const ServerObject * const chatSource = safe_cast(NetworkIdManager::getObjectById (chatSourceId)); - const CreatureObject * const chatSourceCreature = chatSource ? chatSource->asCreatureObject () : 0; - - for(ServerObjectVector::iterator i = results.begin(); i != results.end(); ++i) - { - ServerObject * const target = NON_NULL (*i); - - const NetworkId & targetId = target->getNetworkId (); - - //-- see if the target is valid for the flags - if ((spatialChat.getFlags() & MessageQueueSpatialChat::F_skipTarget) != 0 && target->getNetworkId() == spatialChat.getTargetId()) - continue; - if ((spatialChat.getFlags() & MessageQueueSpatialChat::F_skipSource) != 0 && target->getNetworkId() == spatialChat.getSourceId()) - continue; - - if (isTargetAndSourceGroup) - { - const CreatureObject * const targetCreature = target->asCreatureObject (); - if (!targetCreature) - { - continue; - } - - const GroupObject * const chatSourceGroup = chatSourceCreature ? chatSourceCreature->getGroup () : 0; - const GroupObject * const chatTargetGroup = chatTargetCreature ? chatTargetCreature->getGroup () : 0; - const GroupObject * const targetGroup = targetCreature ? targetCreature->getGroup () : 0; - - //continue if targetCreature is not in a group with the chat source or chat target - if (targetId != chatTargetId && targetId != chatSourceId) - { - if (!targetGroup || (targetGroup != chatSourceGroup && targetGroup != chatTargetGroup)) - { - continue; - } - } - - } - else if (isTargetGroupOnly) - { - if (!chatTargetCreature) - continue; - - if (targetId != chatTargetId) - { - const CreatureObject * const targetCreature = target->asCreatureObject (); - if (!targetCreature || !targetCreature->getGroup() || targetCreature->getGroup () != chatTargetCreature->getGroup ()) - continue; - } - } - else if (isTargetOnly) - { - if (targetId != chatTargetId) - continue; - } - - if (isPrivate) - { - if (targetId == chatTargetId || getNetworkId () == chatTargetId || getNetworkId () == chatSourceId) - { - //-- don't send text to ourselves if we are an NPC - if (isPlayerControlled () || chatSourceId != getNetworkId ()) - { - target->hearText(*this, spatialChat, chatMessageIndex); - } - } - else - { - const MessageQueueSpatialChat noTextMsg (spatialChat.getSourceId (), - spatialChat.getTargetId (), - Unicode::emptyString, - spatialChat.getVolume (), - spatialChat.getChatType (), - spatialChat.getMoodType (), - spatialChat.getFlags (), - spatialChat.getLanguage (), - Unicode::emptyString); - - target->hearText(*this, noTextMsg, chatMessageIndex); - } - } - else - { - target->hearText(*this, spatialChat, chatMessageIndex); - } - } -} - -//----------------------------------------------------------------------- - -void ServerObject::hearText(ServerObject const &source, MessageQueueSpatialChat const &spatialChat, int chatMessageIndex) -{ - Controller * const controller = NON_NULL (getController()); - if (!isAuthoritative()) - { - MessageQueueSpatialChat * const msg = new MessageQueueSpatialChat (spatialChat); - controller->appendMessage(CM_spatialChatReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - return; - } - - if (m_scriptObject) - { - ScriptParams params; - params.addParam(spatialChat.getSourceId()); - params.addParam(spatialChat.getText()); - if (!m_scriptObject->trigAllScripts(Scripting::TRIG_HEAR_SPEECH_STRING, params)) - return; - } - - if (getClient ()) - { - if ( source.getCacheVersion() > 0 - || ( ObserveTracker::isObserving(*getClient(), source) - && !PlayerObject::isIgnoring(getNetworkId(), spatialChat.getSourceId()))) - { - // Log the chat a player hears - - CreatureObject * const creatureObject = asCreatureObject(); - - if (creatureObject != NULL) - { - PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - - if (playerObject != NULL) - { - ChatAvatarId playerChatAvatarId(Chat::constructChatAvatarId(source)); - Unicode::String playerName(Unicode::narrowToWide(playerChatAvatarId.getFullName())); - - std::string chatTypeName; - - if (spatialChat.getChatType() == 0) - { - chatTypeName = "spatial"; - } - else - { - if (!SpatialChatManager::getChatNameByType(spatialChat.getChatType(), chatTypeName)) - { - chatTypeName = "error"; - } - } - - ChatLogManager::logChat(playerName, Unicode::emptyString, spatialChat.getText(), Unicode::narrowToWide(chatTypeName), chatMessageIndex, Os::getRealSystemTime()); - - playerObject->logChat(chatMessageIndex); - } - } - - MessageQueueSpatialChat * const msg = new MessageQueueSpatialChat (spatialChat); - controller->appendMessage(CM_spatialChatReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } -} - -//---------------------------------------------------------------------- - -void ServerObject::performSocial (const NetworkId & target, uint32 socialType, bool animationOk, bool textOk) -{ - const MessageQueueSocial socialMsg (CachedNetworkId (*this), CachedNetworkId (target), socialType, animationOk, textOk); - performSocial (socialMsg); -} - -//---------------------------------------------------------------------- - -void ServerObject::performSocial (const MessageQueueSocial & socialMsg) -{ - // a permanently squelched player cannot do any emote - PlayerObject * p = PlayerCreatureController::getPlayerObject(asCreatureObject()); - if (p && (p->getSecondsUntilUnsquelched() < 0)) - { - return; - } - - if (!isAuthoritative ()) - { - Controller *const controller = NON_NULL (getController()); - - MessageQueueSocial * const msg = new MessageQueueSocial (socialMsg); - controller->appendMessage(CM_socialSend, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - return; - } - - // todo: this needs to have a better value sometime - static const float distance = 50.0f; - - const Vector & pos_w = getPosition_w (); - typedef std::vector ServerObjectVector; - ServerObjectVector results; - ServerWorld::findObjectsInRange (pos_w, distance, results); - - - bool triggerOk = false; - std::string socialTypeName; - triggerOk = SocialsManager::getSocialNameByType (socialMsg.getSocialType(), socialTypeName); - Unicode::String unicodeSocialTypeName(Unicode::narrowToWide(socialTypeName)); - - // allow scripts to prevent the player from performing the emote - ScriptParams params; - - if (getScriptObject() != NULL) - { - params.addParam(unicodeSocialTypeName); - if (getScriptObject()->trigAllScripts(Scripting::TRIG_PERFORM_EMOTE, params) != SCRIPT_CONTINUE) - return; - params.clear(); - } - - if (triggerOk) - { - params.addParam(getNetworkId()); - params.addParam(unicodeSocialTypeName); - } - - static const float trigger_range = 4.0f; - - for (ServerObjectVector::const_iterator it = results.begin(); it != results.end(); ++it) - { - ServerObject * const target = *it; - NOT_NULL (target); - - if (triggerOk && this != target) - { - const float target_trigger_range_sqr = sqr (trigger_range + target->getSphereExtent ().getRadius ()); - const float distance_sqr = pos_w.magnitudeBetweenSquared (target->getPosition_w ()); - - if (distance_sqr < target_trigger_range_sqr) - IGNORE_RETURN(target->getScriptObject()->trigAllScripts(Scripting::TRIG_SAW_EMOTE, params)); - } - - (*it)->seeSocial (socialMsg); - } -} - -//---------------------------------------------------------------------- - -void ServerObject::performCombatSpam (const MessageQueueCombatSpam & spamMsg, bool sendToSelf, bool sendToTarget, bool sendToBystanders) -{ - if (!isAuthoritative ()) - { - WARNING_STRICT_FATAL (true, ("Do not call performCombatSpam on non-authoritative objects")); - return; - } - - if (sendToSelf && !sendToBystanders) - seeCombatSpam (spamMsg); - - if (sendToTarget && !sendToBystanders) - { - ServerObject * const target = safe_cast(NetworkIdManager::getObjectById(spamMsg.m_defender)); - if (target) - if (target->getNetworkId() != spamMsg.m_attacker) - target->seeCombatSpam (spamMsg); - else - WARNING_STRICT_FATAL (!sendToSelf && !sendToBystanders, ("null target_obj in commandFuncCombatSpam, when sendToTarget was set true")); - } - - if (sendToBystanders) - { - Controller *const controller = NON_NULL (getController()); - controller->appendMessage (CM_combatSpam, 0, new MessageQueueCombatSpam(spamMsg), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); - } -} - -// --------------------------------------------------------------------- - -void ServerObject::teleportObject(Vector const &position_w, NetworkId const &targetContainer, std::string const &targetCellName, Vector const &position_p, std::string const &scriptCallback, bool forceLoadScreen) -{ - Vector destPosition_w(position_w); - - // clamp destination if in space - if ( ServerWorld::isSpaceScene() - && ( std::abs(position_w.x) > 8000.f - || std::abs(position_w.y) > 8000.f - || std::abs(position_w.z) > 8000.f)) - { - WARNING(true, ("Tried to warp object %s outside of space zone boundaries (%g,%g,%g)", getDebugInformation().c_str(), position_w.x, position_w.y, position_w.z)); - destPosition_w.set( - clamp(-8000.f, position_w.x, 8000.f), - clamp(-8000.f, position_w.y, 8000.f), - clamp(-8000.f, position_w.z, 8000.f)); - } - - - - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_teleportObject, new MessageQueueTeleportObject(destPosition_w, targetContainer, targetCellName, position_p, scriptCallback)); - return; - } - - // make a copy of the destination position, as it might change if we are - // warping to a cloning facility - Vector finalPosition_p(position_p); - - bool doWarp = forceLoadScreen; - bool ignoreContainer = true; - - Client * const client = m_client; - std::vector > containedClients; - getContainedClients(*this, containedClients); - - ServerObject *targetContainerObject = 0; - if (targetContainer != NetworkId::cms_invalid) - { - ignoreContainer = false; - targetContainerObject = safe_cast(NetworkIdManager::getObjectById(targetContainer)); - if (targetContainerObject && !targetCellName.empty()) - { - PortalProperty *portalProp = targetContainerObject->getPortalProperty(); - targetContainerObject = 0; // clear in case we have a building that doesn't have the cell - if (portalProp != NULL) - { - CellProperty *cellProp = portalProp->getCell(targetCellName.c_str()); - if (cellProp != NULL) - targetContainerObject = safe_cast(&(cellProp->getOwner())); - } - if (!targetContainerObject) - { - WARNING(true, ("Tried to teleport to nonexistant cell '%s' of building %s.", targetCellName.c_str(), targetContainer.getValueString().c_str())); - ignoreContainer = true; - } - } - } - - Vector const oldPosition_w(NON_NULL(ContainerInterface::getTopmostContainer(*this))->getPosition_w()); - if ( destPosition_w.magnitudeBetweenSquared(oldPosition_w) >= sqr(ConfigServerGame::getMaxTeleportDistanceWithoutSceneWarp()) - || ( targetContainer != NetworkId::cms_invalid - && ( !targetContainerObject - || ( getClient() - && !ObserveTracker::isObserving(*getClient(), *targetContainerObject))))) - doWarp = true; - - if (doWarp && !containedClients.empty()) - { - for (std::vector >::const_iterator i = containedClients.begin(); i != containedClients.end(); ++i) - { - Client * const containedClient = (*i).getPointer(); - if (containedClient) - { - ServerObject * const characterObject = containedClient->getCharacterObject(); - if (characterObject) - characterObject->onClientAboutToLoad(); - containedClient->clearControlledObjects(); - } - } - } - - bool moveNeeded = true; - if (!ignoreContainer && targetContainer != NetworkId::cms_invalid) - { - if (!doWarp && targetContainerObject && targetContainerObject->isAuthoritative()) - { - // allow the destination container to change the warp position - float yaw = getObjectFrameK_p().theta(); - const ServerObject * targetObject = safe_cast( - ContainerInterface::getTopmostContainer(*targetContainerObject)); - if (targetObject && targetObject->isAuthoritative()) - targetObject->changeTeleportDestination(finalPosition_p, yaw); - - // teleporting to a container on this server - if (targetContainerObject->asCellObject()) - { - Transform worldToCell; - worldToCell.invert(targetContainerObject->getTransform_o2w()); - Transform objectToCell; - objectToCell.multiply(worldToCell, getTransform_o2w()); - objectToCell.setPosition_p(finalPosition_p); - yaw -= getObjectFrameK_p().theta(); - if (yaw != 0.0f) - { - objectToCell.yaw_l(yaw); - objectToCell.reorthonormalize(); - } - safe_cast(getController())->teleport(objectToCell, targetContainerObject); - } - else - { - if (isPlayerControlled()) - { - WARNING(true, ("Tried to use ServerObject::teleportObject to teleport a player controlled object into a non-cell container!")); - return; - } - - Container::ContainerErrorCode err = Container::CEC_Success; - ContainerInterface::transferItemToGeneralContainer(*targetContainerObject, *this, 0, err, false); - } - - moveNeeded = false; - } - else - { - // container is on a different server - flag to move us into the container as soon as we change authority - setInteriorTeleportDestination(targetContainer, targetCellName, position_p); - } - } - - //-- setup the script callback - if (!scriptCallback.empty()) - setTeleportScriptCallback(scriptCallback); - - if (moveNeeded) - { - // Moves the object. If the new area is on a different server, the PlanetServer will change our authority. - - // What we really want to check here is whether we want to use the ServerController's teleport - // if a player has logged out, but we still have them loaded in game, their client will be null, - // but we still want to use the ServerController's teleport method - // so, we check against the player creature controller and player ship controller as well - ServerController * controller = safe_cast(getController()); - if (controller && (client || dynamic_cast(controller) || dynamic_cast(controller))) - { - Transform newTransform(getTransform_o2w()); - newTransform.setPosition_p(destPosition_w); - controller->teleport(newTransform, 0); - } - else - { - if (ContainerInterface::getContainedByObject(*this)) - { - Transform newTransform(getTransform_o2w()); - newTransform.setPosition_p(destPosition_w); - Container::ContainerErrorCode err = Container::CEC_Success; - ContainerInterface::transferItemToWorld(*this, newTransform, 0, err); - } - else - setPosition_p(destPosition_w); - } - } - - if (doWarp && !containedClients.empty()) - { - for (std::vector >::const_iterator i = containedClients.begin(); i != containedClients.end(); ++i) - { - Client * const containedClient = (*i).getPointer(); - if (containedClient) - { - ServerObject * const so = NON_NULL(safe_cast(NetworkIdManager::getObjectById(containedClient->getCharacterObjectId()))); - CreatureObject * const primaryControlledCreature = NON_NULL(so->asCreatureObject()); - containedClient->assumeControl(*primaryControlledCreature); - } - } - } - - CollisionWorld::objectWarped(this); - - if (isAuthoritative() && (!isPlayerControlled() || getClient()) && getObjVars().hasItem("teleportFixup")) - TeleportFixupHandler::add(*this); -} - -// ---------------------------------------------------------------------- - -void ServerObject::changeTeleportDestination(Vector &, float &) const -{ -} - -// ---------------------------------------------------------------------- - -void ServerObject::updatePositionOnPlanetServer(bool forceUpdate) -{ - PROFILER_AUTO_BLOCK_DEFINE("updatePositionOnPlanetServer"); - // In space, only send the forced updates - if (isAuthoritative() && isInitialized() && (forceUpdate || !ServerWorld::isSpaceScene())) - updatePlanetServerInternal(forceUpdate); -} - -//---------------------------------------------------------------------- - -void ServerObject::updatePlanetServerInternal(bool) const -{ -} - -//---------------------------------------------------------------------- - -/** -* Attempts to create a synchronized ui object. If the synchronized ui object -* does not exist, its creation is attempted via createSynchronizedUi. The default implementation -* of createSynchronizedUi returns null, and renders this method a no-op. -*/ -void ServerObject::addSynchronizedUi(const std::vector & clients) -{ - if (!m_synchronizedUi.getPointer()) - m_synchronizedUi = createSynchronizedUi (); - - if (m_synchronizedUi.getPointer()) - { - for (std::vector::const_iterator i = clients.begin(); i != clients.end(); ++i) - { - ServerObject * client = safe_cast( - NetworkIdManager::getObjectById(*i)); - if (client != NULL) - { - if (client->getClient() != NULL) - m_synchronizedUi->addClientObject (*client); - else - { - client->addPendingSynchronizedUi(*this); - } - } - else - { - WARNING(true, ("Object %s tried to add non-existant client %s to its sync ui", - getNetworkId().getValueString().c_str(), i->getValueString().c_str())); - } - } - scheduleForAlter(); - } -} - -//---------------------------------------------------------------------- - -/** -* Attempts to add a client to the synchronized ui object. If the synchronized ui object -* does not exist, its creation is attempted via createSynchronizedUi. The default implementation -* of createSynchronizedUi returns null, and renders this method a no-op. -* -*/ -void ServerObject::addSynchronizedUiClient(ServerObject & client) -{ - if (isAuthoritative()) - { - if (!m_synchronizedUi.getPointer()) - m_synchronizedUi = createSynchronizedUi (); - - if (!m_synchronizedUi.getPointer()) - return; - - m_synchronizedUi->addClientObject (client); - scheduleForAlter(); - } - else - { - WARNING_STRICT_FATAL(true, ("Non-authoritative object %s is being asked to create a synchronizedUi for client %s", - getNetworkId().getValueString().c_str(), client.getNetworkId().getValueString().c_str())); - } -} - -//---------------------------------------------------------------------- - -void ServerObject::removeSynchronizedUiClient(const NetworkId & clientId) -{ - if (!m_synchronizedUi.getPointer()) - return; - - WARNING(!isAuthoritative(), ("ServerObject::removeSynchronizedUiClient being called on non-authoritative object %s for client %s", - getNetworkId().getValueString().c_str(), clientId.getValueString().c_str())); - - m_synchronizedUi->removeClientObject (clientId); - - if (m_synchronizedUi->getNumClients () == 0) - { - delete m_synchronizedUi.getPointer(); - } - scheduleForAlter(); -} - -//---------------------------------------------------------------------- - -/** -* Subclasses implement this if they have an appropriate synchronized ui object. -* Base class implementation returns null. -*/ -ServerSynchronizedUi * ServerObject::createSynchronizedUi () -{ - return 0; -} - -//---------------------------------------------------------------------- - -/** - * Adds a object to the list of objects that have a synchronized ui and are - * waiting for this object to have a client attached. - * - * @param uiObject the object with the synchronized ui - */ -void ServerObject::addPendingSynchronizedUi(const ServerObject & uiObject) -{ - if (getClient() != NULL) - { - WARNING(true, ("ServerObject::addPendingSynchronizedUi called on object %s that already has a client", getNetworkId().getValueString().c_str())); - return; - } - - if (m_pendingSyncUi == NULL) - m_pendingSyncUi = new std::vector; - m_pendingSyncUi->push_back(uiObject.getNetworkId()); -} - -//---------------------------------------------------------------------- - -void ServerObject::setPlayerControlled(bool newValue) -{ - if(isAuthoritative()) - { - m_playerControlled=newValue; - if (newValue) - setDefaultAlterTime(0); - else - setDefaultAlterTime(AlterResult::cms_keepNoAlter); - } - else - { - sendControllerMessageToAuthServer(CM_setPlayerControlled, new MessageQueueGenericValueType(newValue)); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::internalAdjustBankBalance(int const amount, bool makeRoom) -{ - if ((amount > 0) && ((amount + m_bankBalance.get()) > ConfigServerGame::getMaxMoney()) && makeRoom && isAuthoritative()) - { - PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); - if (po && po->isAuthoritative()) - { - int attempt = 0; - do - { - int amountToMove = amount + m_bankBalance.get() - ConfigServerGame::getMaxMoney(); - if (amountToMove > m_bankBalance.get()) - { - amountToMove = m_bankBalance.get(); - } - - if (amountToMove <= 0) - break; - - if ((amountToMove + m_cashBalance.get()) > ConfigServerGame::getMaxMoney()) - { - // not enough room in cash, see if there's still room in galactic reserve - int8 const galacticReserve = po->getGalacticReserveDeposit(); - if (static_cast(galacticReserve) < ConfigServerGame::getMaxGalacticReserveDepositBillion()) - { - // transfer 1 billion into galactic reserve, and try again, if necessary - po->depositToGalacticReserve(true); - - // failed to transfer to galactic reserve, don't try again - if (galacticReserve == po->getGalacticReserveDeposit()) - { - break; - } - } - else - { - // no more room in galactic reserve, move as much as possible into cash - amountToMove = ConfigServerGame::getMaxMoney() - m_cashBalance.get(); - if (amountToMove > m_bankBalance.get()) - { - amountToMove = m_bankBalance.get(); - } - - if (amountToMove > 0) - { - withdrawCashFromBank(amountToMove); - } - - break; - } - } - else - { - if (amountToMove > 0) - { - withdrawCashFromBank(amountToMove); - } - - break; - } - - ++attempt; - - } while (((amount + m_bankBalance.get()) > ConfigServerGame::getMaxMoney()) && (attempt < 2)); - } - } - - m_bankBalance = m_bankBalance.get() + amount; - if (m_bankBalance.get() > ConfigServerGame::getMaxMoney()) - { - LOG("CustomerService",("SuspectedCheaterChannel: %s has %i credits in the bank.", PlayerObject::getAccountDescription(this).c_str(), m_bankBalance.get())); - m_bankBalance = ConfigServerGame::getMaxMoney(); - } - - if (getClient() && getClient()->isFreeTrialAccount() - && (m_cashBalance.get() + m_bankBalance.get()) > ConfigServerGame::getMaxFreeTrialMoney()) - { - LOG("CustomerService",("FreeTrial: %s has exceeded max free trial balance of %d from a bank transfer amount of %d. Money lost: %d.",PlayerObject::getAccountDescription(this).c_str(), ConfigServerGame::getMaxFreeTrialMoney(), amount, m_cashBalance.get() + m_bankBalance.get() - ConfigServerGame::getMaxFreeTrialMoney())); - m_bankBalance = ConfigServerGame::getMaxFreeTrialMoney() - m_cashBalance.get(); - ProsePackage prosePackage; - prosePackage.stringId = StringId("ui_trade", "err_max_free_trial_money"); - prosePackage.digitInteger = ConfigServerGame::getMaxFreeTrialMoney(); - Chat::sendSystemMessage(*this, prosePackage); - } - - // sanity check - fix up any player character negative cash/bank balance - if ((m_cashBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) - m_cashBalance = 0; - - if ((m_bankBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) - m_bankBalance = 0; - - addObjectToConcludeList(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::internalAdjustCashBalance(int const amount, bool makeRoom) -{ - if ((amount > 0) && ((amount + m_cashBalance.get()) > ConfigServerGame::getMaxMoney()) && makeRoom && isAuthoritative()) - { - PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); - if (po && po->isAuthoritative()) - { - int attempt = 0; - do - { - int amountToMove = amount + m_cashBalance.get() - ConfigServerGame::getMaxMoney(); - if (amountToMove > m_cashBalance.get()) - { - amountToMove = m_cashBalance.get(); - } - - if (amountToMove <= 0) - break; - - if ((amountToMove + m_bankBalance.get()) > ConfigServerGame::getMaxMoney()) - { - // not enough room in bank, see if there's still room in galactic reserve - int8 const galacticReserve = po->getGalacticReserveDeposit(); - if (static_cast(galacticReserve) < ConfigServerGame::getMaxGalacticReserveDepositBillion()) - { - // transfer 1 billion into galactic reserve, and try again, if necessary - po->depositToGalacticReserve(true); - - // failed to transfer to galactic reserve, don't try again - if (galacticReserve == po->getGalacticReserveDeposit()) - { - break; - } - } - else - { - // no more room in galactic reserve, move as much as possible into bank - amountToMove = ConfigServerGame::getMaxMoney() - m_bankBalance.get(); - if (amountToMove > m_cashBalance.get()) - { - amountToMove = m_cashBalance.get(); - } - - if (amountToMove > 0) - { - depositCashToBank(amountToMove); - } - - break; - } - } - else - { - if (amountToMove > 0) - { - depositCashToBank(amountToMove); - } - - break; - } - - ++attempt; - - } while (((amount + m_cashBalance.get()) > ConfigServerGame::getMaxMoney()) && (attempt < 2)); - } - } - - m_cashBalance = m_cashBalance.get() + amount; - if (m_cashBalance.get() > ConfigServerGame::getMaxMoney()) - { - LOG("CustomerService",("SuspectedCheaterChannel: %s has %i credits cash.",PlayerObject::getAccountDescription(this).c_str(), m_cashBalance.get())); - m_cashBalance = ConfigServerGame::getMaxMoney(); - } - - if (getClient() && getClient()->isFreeTrialAccount() - && (m_cashBalance.get() + m_bankBalance.get()) > ConfigServerGame::getMaxFreeTrialMoney()) - { - LOG("CustomerService",("FreeTrial: %s has exceeded max free trial balance of %d from a cash transfer amount of %d. Money lost: %d.",PlayerObject::getAccountDescription(this).c_str(), ConfigServerGame::getMaxFreeTrialMoney(), amount, m_cashBalance.get() + m_bankBalance.get() - ConfigServerGame::getMaxFreeTrialMoney())); - m_cashBalance = ConfigServerGame::getMaxFreeTrialMoney() - m_bankBalance.get(); - ProsePackage prosePackage; - prosePackage.stringId = StringId("ui_trade", "err_max_free_trial_money"); - prosePackage.digitInteger = ConfigServerGame::getMaxFreeTrialMoney(); - Chat::sendSystemMessage(*this, prosePackage); - } - - // sanity check - fix up any player character negative cash/bank balance - if ((m_cashBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) - m_cashBalance = 0; - - if ((m_bankBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) - m_bankBalance = 0; - - addObjectToConcludeList(); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::transferCashTo(const NetworkId &target, int amount, const NetworkId &transactionId) -{ - if (amount <= 0) - { - DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); - return false; - } - - if (isAuthoritative()) - { - if (amount > ConfigServerGame::getMaxMoneyTransfer()) - { - DEBUG_REPORT_LOG(true,("Tried to transfer too much cash. Source object %s, target %s, amount %i", - getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); - return false; - } - - int sourceBalance=getCashBalance(); - if (sourceBalance < amount) - { - DEBUG_REPORT_LOG(true,("Tried to transfer too much cash. Source object %s, target %s, amount %i", - getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); - return false; - } - internalAdjustCashBalance(-amount, true); - - // send persistent message to add money to target. - char buffer[100]; - snprintf(buffer,100,"%i",amount); - MessageToQueue::getInstance().sendMessageToC(target, "C++FinishCashTransfer", buffer, 0, true); - - LOG("CustomerService", ("Money: cash transfer from %s to %s, amount %i, total(from) %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(),PlayerObject::getAccountDescription(target).c_str(),amount, getTotalMoney())); - - return true; - } - else - { - //TODO: handle multi-server banking - DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); - return false; - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::transferBankCreditsTo(const NetworkId &target, int amount, const NetworkId &transactionId) -{ - if (amount <= 0) - { - DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); - return false; - } - - - if (isAuthoritative()) - { - if (amount > ConfigServerGame::getMaxMoneyTransfer()) - { - DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", - getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); - return false; - } - - int sourceBalance=getBankBalance(); - if (sourceBalance < amount) - { - DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", - getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); - return false; - } - internalAdjustBankBalance(-amount, true); - - // send persistent message to add money to target. - char buffer[100]; - snprintf(buffer,100,"%i",amount); - MessageToQueue::getInstance().sendMessageToC(target, "C++FinishBankTransfer", buffer, 0, true); - - LOG("CustomerService", ("Money: bank transfer from %s to %s, amount %i, total(from) %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(),PlayerObject::getAccountDescription(target).c_str(),amount, getTotalMoney())); - - return true; - } - else - { - //TODO: handle multi-server banking - DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); - return false; - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::transferBankCreditsTo(const std::string &target, int amount, const NetworkId &transactionId) -{ - if (amount <= 0) - { - DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); - return false; - } - - if (isAuthoritative()) - { - // allow transfers to/from the commodities escrow account or galactic reserve to bypass - // the max transfer limit because commodities item can be sold/bought for more than the - // transfer limit and the galactic reserve transfers 1 billion credits at a time - if ((target != CommoditiesMarket::getCommoditiesNamedEscrowAccount()) && (target != std::string("galactic_reserve"))) - { - if (amount > ConfigServerGame::getMaxMoneyTransfer()) - { - DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", - getNetworkId().getValueString().c_str(),target.c_str(),amount)); - return false; - } - } - - int sourceBalance=getBankBalance(); - if (sourceBalance < amount) - { - DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", - getNetworkId().getValueString().c_str(),target.c_str(),amount)); - return false; - } - internalAdjustBankBalance(-amount, true); - - LOG("CustomerService", ("Money: bank transfer from %s to named account %s, amount %i, total %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(),target.c_str(), amount, getTotalMoney())); - - return true; - } - else - { - //TODO: handle multi-server banking - DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); - return false; - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::transferBankCreditsFrom(const std::string &target, int amount, const NetworkId &transactionId) -{ - if (amount <= 0) - { - DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); - return false; - } - - if (isAuthoritative()) - { - // allow transfers to/from the commodities escrow account or galactic reserve to bypass - // the max transfer limit because commodities item can be sold/bought for more than the - // transfer limit and the galactic reserve transfers 1 billion credits at a time - if ((target != CommoditiesMarket::getCommoditiesNamedEscrowAccount()) && (target != std::string("galactic_reserve"))) - { - if (amount > ConfigServerGame::getMaxMoneyTransfer()) - { - DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", - getNetworkId().getValueString().c_str(),target.c_str(),amount)); - return false; - } - } - - internalAdjustBankBalance(amount, true); - - LOG("CustomerService", ("Money: bank transfer from named account %s to %s, amount %i, total %i", target.c_str(),PlayerObject::getAccountDescription(getNetworkId()).c_str(), amount, getTotalMoney())); - - return true; - } - else - { - //TODO: handle multi-server banking - DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); - return false; - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::withdrawCashFromBank(int amount, const NetworkId &transactionId) -{ - if (amount <= 0) - { - DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); - return false; - } - if (isAuthoritative()) - { - // adjust amount so it won't overflow the cash limit - if ((getCashBalance() + amount) > ConfigServerGame::getMaxMoney()) - { - amount = ConfigServerGame::getMaxMoney() - getCashBalance(); - } - - if (amount > 0) - { - int bankBalance=getBankBalance(); - - if (bankBalance < amount) - { - DEBUG_REPORT_LOG(true,("Object %s tried to bounce a check. Bank balance %i, requested %i.\n",getNetworkId().getValueString().c_str(),bankBalance,amount)); - return false; - } - - internalAdjustBankBalance(-amount, false); - internalAdjustCashBalance(amount, false); - - LOG("CustomerService", ("Money: cash withdraw from bank by %s, amount %i, total %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(), amount, getTotalMoney())); - } - - return true; - } - else - { - //TODO: handle multi-server banking - DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); - return false; - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::depositCashToBank(int amount, const NetworkId &transactionId) -{ - if (amount <= 0) - { - DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); - return false; - } - - if (isAuthoritative()) - { - // adjust amount so it won't overflow the bank limit - if ((getBankBalance() + amount) > ConfigServerGame::getMaxMoney()) - { - amount = ConfigServerGame::getMaxMoney() - getBankBalance(); - } - - if (amount > 0) - { - int cashBalance=getCashBalance(); - - if (cashBalance < amount) - { - DEBUG_REPORT_LOG(true,("Object %s tried to deposit %i credits, but only has %i credits\n",getNetworkId().getValueString().c_str(),amount,cashBalance)); - return false; - } - - internalAdjustCashBalance(-amount, false); - internalAdjustBankBalance(amount, false); - - LOG("CustomerService", ("Money: cash deposit to bank by %s, amount %i, total %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(), amount, getTotalMoney())); - } - - return true; - } - else - { - //TODO: handle multi-server banking - DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); - return false; - } -} - -// ---------------------------------------------------------------------- - -char const *ServerObject::getTemplateName() const -{ - return getObjectTemplate()->getName(); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::getHyperspaceOnCreate () const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setHyperspaceOnCreate (bool const hyperspaceOnCreate) -{ - setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate, hyperspaceOnCreate); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::getHyperspaceOnDestroy () const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setHyperspaceOnDestroy (bool const hyperspaceOnDestroy) -{ - setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct, hyperspaceOnDestroy); -} - -// ---------------------------------------------------------------------- - -std::string const ServerObject::getPackedObjVars(std::string const &prefix) const -{ - std::vector buf; - for (DynamicVariableList::MapType::const_iterator i = getObjVars().begin(); i != getObjVars().end(); ++i) - { - if (!(*i).first.compare(0, prefix.size(), prefix)) - { - appendPackedObjVarField(buf, (*i).first.c_str()); - appendPackedObjVarField(buf, (*i).second.getType()); - appendPackedObjVarField(buf, Unicode::wideToNarrow((*i).second.getPackedValueString()).c_str()); - } - } - appendPackedObjVarField(buf, "$"); - return std::string(buf.begin(), buf.end()); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::setPackedObjVars(std::string const &packedVarString) - { - unsigned int offset = 0; - - while (offset < packedVarString.size()) - { - std::string name; - offset = getPackedObjVarField(packedVarString, offset, name); - if (name == "$") - return true; - int typeId; - offset = getPackedObjVarField(packedVarString, offset, typeId); - std::string valueString; - offset = getPackedObjVarField(packedVarString, offset, valueString); - DynamicVariable value; - value.load(0, typeId, Unicode::narrowToWide(valueString)); - setObjVarItem(name, value); -} - return false; -} - -// ---------------------------------------------------------------------- - -#ifdef _WIN32 -#define atoll(a) _atoi64(a) -#endif - -// ---------------------------------------------------------------------- - -std::string ServerObject::debugGetMessageToList() const -{ - unsigned long const now = ServerClock::getInstance().getGameTimeSeconds(); - std::string result; - time_t const timeNow = ::time(NULL); - for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) - { - char temp[256]; - - if (i->second.getCallTime() > now) - { - snprintf(temp,sizeof(temp)-1,"%s: %s [call time = %lu (%s) (%s) (%s), persisted = %s, recurring = %i]\n",i->second.getMessageId().getValueString().c_str(), i->second.getMethod().c_str(), i->second.getCallTime(), CalendarTime::convertSecondsToDHMS(static_cast(i->second.getCallTime() - now)).c_str(), CalendarTime::convertEpochToTimeStringGMT(i->second.getCallTime() - now + timeNow).c_str(), CalendarTime::convertEpochToTimeStringLocal(i->second.getCallTime() - now + timeNow).c_str(), (i->second.getPersisted() ? "true" : "false"), i->second.getRecurringTime()); - } - else - { - snprintf(temp,sizeof(temp)-1,"%s: %s [call time = %lu, persisted = %s, recurring = %i]\n",i->second.getMessageId().getValueString().c_str(), i->second.getMethod().c_str(), i->second.getCallTime(), (i->second.getPersisted() ? "true" : "false"), i->second.getRecurringTime()); - } - - temp[sizeof(temp)-1]='\0'; - result += temp; - } - return result; -} - -// ---------------------------------------------------------------------- - -/** - * Go through the list of messageTos and handle any whose time has been - * reached. - * @param effectiveMessageToTime The current Server Clock, for the purpose of MessageTos - * @return The delivery time of the next message, or 0 if there are no more messages - */ - -unsigned long ServerObject::processQueuedMessageTos(unsigned long effectiveMessageToTime) -{ - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::processQueuedMessageTos"); - - if (isAuthoritative()) - { - int handledMessageCount = 0; - unsigned long startTime = Clock::timeMs(); - while (!m_messageTos.empty() && m_messageTos.begin()->second.getCallTime() <= effectiveMessageToTime) - { - ++handledMessageCount; - if ((ConfigServerGame::getMaxMessageTosPerObjectPerFrame() !=0 ) && - (handledMessageCount > ConfigServerGame::getMaxMessageTosPerObjectPerFrame())) - { - std::string nextTenMessages; - { - int count = 1; - for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator iter = m_messageTos.begin(); ((iter != m_messageTos.end()) && (count <= 10)); ++iter, ++count) - { - nextTenMessages += iter->second.getMethod(); - nextTenMessages += ", "; - } - } - - WARNING(true,("MessageTo Backlog: object %s had more than %i messages to be handled in one frame. Remaining %d messages will be delayed until next frame. Next ten messages are (%s).", getNetworkId().getValueString().c_str(), ConfigServerGame::getMaxMessageTosPerObjectPerFrame(), m_messageTos.size(), nextTenMessages.c_str())); - MessageToQueue::getInstance().incrementBackloggedObjectCount(); - break; - } - if ((ConfigServerGame::getMaxMessageToTimePerObjectPerFrame() != 0) && - (static_cast(Clock::timeMs() - startTime) > ConfigServerGame::getMaxMessageToTimePerObjectPerFrame())) - { - WARNING(true,("MessageTo Backlog: object %s spent more than %i ms processing messages. Remaining %d messages will be delayed until next frame.", getNetworkId().getValueString().c_str(), ConfigServerGame::getMaxMessageToTimePerObjectPerFrame(), m_messageTos.size())); - MessageToQueue::getInstance().incrementBackloggedObjectCount(); - break; - } - - Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator message = m_messageTos.begin(); - - // if the message is going to be recurring, create a - // new messageTo to reschedule the recurring message - MessageToPayload * copyOfRecurringMessage = NULL; - if (message->second.getRecurringTime() > 0) - { - copyOfRecurringMessage = new MessageToPayload( - getNetworkId(), - message->second.getMessageId(), - message->second.getMethod(), - message->second.getPackedDataVector(), - ServerClock::getInstance().getGameTimeSeconds() + static_cast(message->second.getRecurringTime()), - false, - message->second.getDeliveryType(), - NetworkId::cms_invalid, - "", - message->second.getRecurringTime()); - } - - // set sentinel to prevent this message from being removed - // from m_messageTos while it is being handled - s_currentMessageToBeingHandled = message->first; - handleMessageTo(message->second); - - // remove message that just got handled - IGNORE_RETURN(m_messageTos.erase(s_currentMessageToBeingHandled)); - - s_currentMessageToBeingHandled = std::make_pair(std::make_pair(0, 0), MessageToId::cms_invalid); - - // Reschedule the recurring message, if necessary - if (copyOfRecurringMessage) - { - deliverMessageTo(*copyOfRecurringMessage); - delete copyOfRecurringMessage; - } - } - - // Make sure object will handle messages again when the next message is due - if (!m_messageTos.empty()) - return m_messageTos.begin()->second.getCallTime(); - else - return 0; - } - else - return 0; -} - -// ---------------------------------------------------------------------- - -void ServerObject::handleMessageTo(MessageToPayload const & message) -{ - if (message.getDeliveryType() == MessageToPayload::DT_c) - { - handleCMessageTo(message); - } - else if (message.getDeliveryType() == MessageToPayload::DT_java) - { - GameScriptObject *scriptObj=getScriptObject(); - if (scriptObj) - { - if (!scriptObj->handleMessage(message.getMethod(), message.getPackedDataVector())) - { - WARNING_STRICT_FATAL(true, ("ServerObject::handleMessageTo, message %s to object %s - script function was not called!", - message.getMethod().c_str(), message.getNetworkId().getValueString().c_str())); - } - } - else - { - WARNING_STRICT_FATAL(true, ("ServerObject::handleMessageTo, message %s to object %s - object does not have a ScriptObject attached!", - message.getMethod().c_str(), message.getNetworkId().getValueString().c_str())); - } - } - else - WARNING_STRICT_FATAL(true,("Called ServerObject::handleMessageTo with a message that had an unrecognized delivery type. Message is %s, delivery type is %i", message.getMethod().c_str(), message.getDeliveryType())); - - if (message.getPersisted()) - { - MessageToAckMessage const reply(message.getMessageId()); - GameServer::getInstance().sendToDatabaseServer(reply); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::handleCMessageTo(const MessageToPayload &message) -{ - std::vector const &packedData = message.getPackedDataVector(); - - if (message.getMethod() == "C++ForceAlter") - { - scheduleForAlter(); - } - else if (message.getMethod() == "C++RenameCharacter") - { - //TODO: resolve Unicode issues with messageto's - m_objectName=Unicode::narrowToWide(std::string(packedData.begin(), packedData.end())); - - // rename has been completed, remove the objvar so the system won't think there's a pending rename request - Unicode::String previousRenameName; - if (getObjVars().getItem("renameCharacterRequest.requestNewName", previousRenameName) && (previousRenameName == m_objectName.get())) - removeObjVarItem("renameCharacterRequest.requestNewName"); - - // if character is connected, update the client (character selection) with the new name - Client * const client = getClient(); - if (client) - { - GenericValueTypeMessage, Unicode::String> > const characterNameChanged("CharacterNameChanged", std::make_pair(std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId()), m_objectName.get())); - client->send(characterNameChanged, true); - } - } - else if (message.getMethod() == "C++FinishBankTransfer") - { - std::string packedDataString(packedData.begin(), packedData.end()); - int m_amount=strtoul(packedDataString.c_str(), 0, 10); - DEBUG_FATAL(m_amount < 0,("C++FinishBankTransaction had a negative amount. This message should always have a positive amount.\n")); - internalAdjustBankBalance(m_amount, true); - } - // transfers money from a named account to the bank - else if( message.getMethod() == "C++FromNamedAccountToBank") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - //DEBUG_WARNING(true, ("Processing C++FromNamedAccountToBank. Params = '%s' MessageId=%Ld", params, message.getMessageId().getValue() )); - char *splitPos = strstr(params, " "); - if( splitPos) - { - *splitPos = 0; - std::string const named_account(params); - int const amount = atoi(splitPos+1); - DEBUG_FATAL(amount < 0,("C++FromNamedAccountToBank had a negative amount. This message should always have a positive amount.\n")); - transferBankCreditsFrom(named_account, amount); - } - delete [] params; - } - else if (message.getMethod() == "C++FinishCashTransfer") - { - std::string packedDataString(packedData.begin(), packedData.end()); - int m_amount=strtoul(packedDataString.c_str(), 0, 10); - DEBUG_FATAL(m_amount < 0,("C++FinishCashTransaction had a negative amount. This message should always have a positive amount.\n")); - internalAdjustCashBalance(m_amount, true); - } - else if (message.getMethod() == "C++ModifyCash") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - char *splitPos = strstr(params, " "); - if (splitPos) - { - *splitPos = 0; - NetworkId recipient(atoll(params)); - int amount = atoi(splitPos+1); - transferCashTo(recipient, amount); - } - delete [] params; - } - else if (message.getMethod() == "C++ModifyBank") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - char *splitPos = strstr(params, " "); - if (splitPos) - { - *splitPos = 0; - NetworkId recipient(atoll(params)); - int amount = atoi(splitPos+1); - transferBankCreditsTo(recipient, amount); - } - delete [] params; - } - else if (message.getMethod() == "C++DestroySelf") - { - permanentlyDestroy(DeleteReasons::Script); - } - else if (message.getMethod() == "C++VendorStatusChange") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - int status = atoi(params); - CommoditiesMarket::vendorStatusChange(getNetworkId(), status); - delete [] params; - } - else if (message.getMethod() == "C++Unstick") - { - CreatureObject* creatureObject = asCreatureObject(); - if (creatureObject && creatureObject->isInWorld()) - { - PlayerObject * p = PlayerCreatureController::getPlayerObject(creatureObject); - if (p && p->getIsUnsticking()) - { - //Receive positional information with this unstick message. If you change - //the format of this positional information, you must also change it in the sender in CommandCppFuncs.cpp - Vector position = getPosition_p(); - char buf[255]; - snprintf(buf, sizeof(buf), "%f:%f", position.x, position.z); - buf[sizeof(buf) - 1] = '\0'; - - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - - if (strcmp(buf, params) == 0) - { - //handle unstick - static MessageDispatch::Emitter e; - Chat::sendSystemMessageSimple(*this, SharedStringIds::unstick_request_complete, NULL); - RequestUnstick r; - r.setClientId(getNetworkId()); - e.emitMessage(r); - p->setIsUnsticking(false); - } - delete [] params; - } - } - } - else if (message.getMethod() == "C++WaitForPatrolPreload") - { - WARNING(true, ("Non-creature object %s received a C++WaitForPatrolPreload message", - getNetworkId().getValueString().c_str())); - MessageToQueue::cancelRecurringMessageTo(getNetworkId(), "C++WaitForPatrolPreload"); - } - else if (message.getMethod() == "CancelRecurringMessageTo") - { - std::string const & methodName = message.getDataAsString(); - for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) - { - if ((i->second.getRecurringTime() != 0) && (i->second.getMethod() == methodName) && (i->first != s_currentMessageToBeingHandled)) - { - IGNORE_RETURN(m_messageTos.erase(i)); - break; - } - } - } - else if (message.getMethod() == "C++updateObserversCount") - { - std::string const & buffer = message.getDataAsString(); - if (!buffer.empty()) - { - int count = atoi(buffer.c_str()); - updateObserversCount(count); - } - } - else if (message.getMethod() == "C++addBroadcastListener") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - char *splitPos = strstr(params, " "); - if (splitPos) - { - *splitPos = 0; - addBroadcastListener(std::string(params), NetworkId(std::string(splitPos+1))); - } - delete [] params; - } - else if (message.getMethod() == "C++removeBroadcastListener") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - char *splitPos = strstr(params, " "); - if (splitPos) - { - *splitPos = 0; - removeBroadcastListener(std::string(params), NetworkId(std::string(splitPos+1))); - } - delete [] params; - } - else if (message.getMethod() == "C++removeBroadcastListenerAllMessage") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - removeBroadcastListener(NetworkId(std::string(params))); - delete [] params; - } - else if (message.getMethod() == "C++listenToBroadcastMessage") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - char *splitPos = strstr(params, " "); - if (splitPos) - { - *splitPos = 0; - listenToBroadcastMessage(std::string(params), NetworkId(std::string(splitPos+1))); - } - delete [] params; - } - else if (message.getMethod() == "C++stopListeningToBroadcastMessage") - { - char *params = new char[packedData.size()+1]; - memcpy(params, &(*packedData.begin()), packedData.size()); - params[packedData.size()] = 0; - char *splitPos = strstr(params, " "); - if (splitPos) - { - *splitPos = 0; - stopListeningToBroadcastMessage(std::string(params), NetworkId(std::string(splitPos+1))); - } - delete [] params; - } - else if (message.getMethod() == "C++stopListeningToAllBroadcastMessage") - { - stopListeningToAllBroadcastMessages(); - } - else if (message.getMethod() == "C++AdjustAccountFeatureIdResponse") - { - if (!packedData.empty()) - { - Archive::ByteStream bs; - bs.put(reinterpret_cast(&packedData[0]), static_cast(packedData.size())); - - Archive::ReadIterator ri = bs.begin(); - AdjustAccountFeatureIdResponse const msg(ri); - - if (msg.getTargetPlayer() == getNetworkId()) - { - if (msg.getResultCode() == RESULT_SUCCESS) - { - Client * client = getClient(); - if (client) - { - if (msg.getGameCode() == PlatformGameCode::SWG) - { - // request an updated list of feature id - AccountFeatureIdRequest const req(NetworkId::cms_invalid, GameServer::getInstance().getProcessId(), msg.getTargetPlayer(), msg.getTargetStationId(), msg.getGameCode(), AccountFeatureIdRequest::RR_Reload); - client->sendToConnectionServer(req); - - // let player know that the reward was successfully traded in - if (VeteranRewardManager::isTradeInRewardFeatureId(msg.getFeatureId()) && !msg.getTargetPlayerDescription().empty() && msg.getTargetItem().isValid() && !msg.getTargetItemDescription().empty()) - Chat::sendSystemMessage(*this, StringId("veteran_new", "trade_in_success"), Unicode::emptyString); - } - else if (msg.getGameCode() == PlatformGameCode::SWGTCG) - { - // let player know that the card was successfully redeemed - Chat::sendSystemMessage(*this, StringId("veteran_new", "redeem_tcg_card_success"), Unicode::emptyString); - } - } - } - else if (msg.getGameCode() == PlatformGameCode::SWGTCG) - { - Client * client = getClient(); - if (client) - { - // let player know that the card failed to redeem - Chat::sendSystemMessage(*this, StringId("veteran_new", "redeem_tcg_card_failure"), Unicode::emptyString); - } - } - else if ((msg.getGameCode() == PlatformGameCode::SWG) && VeteranRewardManager::isTradeInRewardFeatureId(msg.getFeatureId()) && !msg.getTargetPlayerDescription().empty() && msg.getTargetItem().isValid() && !msg.getTargetItemDescription().empty()) - { - Client * client = getClient(); - if (client) - { - // let player know that the reward trade in failed - Chat::sendSystemMessage(*this, StringId("veteran_new", "trade_in_failure"), Unicode::emptyString); - } - } - } - - if (msg.getRequestingPlayer() == getNetworkId()) - { - if (msg.getResultCode() == RESULT_SUCCESS) - { - if (msg.getResultCameFromSession()) - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("feature Id (%lu) on account (%lu) has been adjusted from (%d) to (%d); session/Platform reported successful result code (%u, %s:%s)", msg.getFeatureId(), msg.getTargetStationId(), msg.getOldValue(), msg.getNewValue(), msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str()), getClient()); - else - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("feature Id (%lu) on account (%lu) has been adjusted from (%d) to (%d)", msg.getFeatureId(), msg.getTargetStationId(), msg.getOldValue(), msg.getNewValue()), getClient()); - } - else - { - if (msg.getResultCameFromSession()) - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request to adjust feature Id for account (%lu) failed with error code (%u, %s:%s)", msg.getTargetStationId(), msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str()), getClient()); - else - ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request to adjust feature Id for account (%lu) failed", msg.getTargetStationId()), getClient()); - } - } - - if (msg.getTargetItem() == getNetworkId()) - { - if (msg.getGameCode() == PlatformGameCode::SWGTCG) - VeteranRewardManager::handleTcgRedemptionResponse(*this, msg); - else if ((msg.getGameCode() == PlatformGameCode::SWG) && VeteranRewardManager::isTradeInRewardFeatureId(msg.getFeatureId()) && !msg.getTargetPlayerDescription().empty() && !msg.getTargetItemDescription().empty()) - VeteranRewardManager::handleTradeInResponse(*this, msg); - } - } - } - else if (message.getMethod() == "C++kickPlayerCtsCompletedOrInProgress") - { - LOG("CustomerService",("Login: dropping %s because of CTS completed or in progress", PlayerObject::getAccountDescription(this).c_str())); - - KickPlayer const kickMessage(getNetworkId(), "CTS completed or in progress"); - GameServer::getInstance().sendToConnectionServers(kickMessage); - GameServer::getInstance().dropClient(getNetworkId(), true); - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::handleTeleportFixup(bool force) -{ - if (getObjVars().hasItem("teleportFixup")) - { - LOG("TeleportFixup", ("Teleport fixup called for %s\n", getNetworkId().getValueString().c_str())); - if (getObjVars().hasItem("teleportFixup.x")) - { - // Ignore the container portion of a teleport fixup if we are already contained - if (!ContainerInterface::getContainedByObject(*this)) - { - ServerObject *container = 0; - NetworkId destContainer; - std::string destCellName; - Vector destPosition_p; - - getObjVars().getItem("teleportFixup.x", destPosition_p.x); - getObjVars().getItem("teleportFixup.y", destPosition_p.y); - getObjVars().getItem("teleportFixup.z", destPosition_p.z); - getObjVars().getItem("teleportFixup.container", destContainer); - - - if (getObjVars().getItem("teleportFixup.cellname", destCellName)) - { - ServerObject * const destBuilding = safe_cast(NetworkIdManager::getObjectById(destContainer)); - if (destBuilding) - { - PortalProperty * const portalProp = destBuilding->getPortalProperty(); - if (portalProp) - { - CellProperty * const cellProp = portalProp->getCell(destCellName.c_str()); - if (cellProp) - container = safe_cast(&(cellProp->getOwner())); - } - } - } - else - container = safe_cast(NetworkIdManager::getObjectById(destContainer)); - - if (container) - { - // allow the destination container to change the warp position - float yaw = 0.0f; - ServerObject * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*container)); - if (topmost && topmost->isAuthoritative()) - topmost->changeTeleportDestination(destPosition_p, yaw); - - Transform t; - t.setPosition_p(destPosition_p); - yaw -= getObjectFrameK_p().theta(); - if (yaw != 0.0f) - { - t.yaw_l(yaw); - t.reorthonormalize(); - } - LOG("TeleportFixup", ("TeleportFixup from (%g,%g,%g) in world to (%g,%g,%g) in %s\n", - getPosition_w().x, getPosition_w().y, getPosition_w().z, - t.getPosition_p().x, t.getPosition_p().y, t.getPosition_p().z, - container->getNetworkId().getValueString().c_str())); - safe_cast(getController())->teleport(t, container); - } - else if (destContainer != NetworkId::cms_invalid && !force) - { - LOG("TeleportFixup", ("Failing teleport fixup because object %s is in a null dest container and force was passed in\n", getNetworkId().getValueString().c_str())); - return false; // going to a container and it wasn't loaded, defer - } - } - else - LOG("TeleportFixup", ("Ignoring teleport fixup because object %s is already contained by %s\n", getNetworkId().getValueString().c_str(), ContainerInterface::getContainedByObject(*this)->getNetworkId().getValueString().c_str())); - } - - // Teleporting may cause us to become nonauthoritative here, and if so we should not clear the fixup, so it is - // reapplied on the new auth server. - if (!isAuthoritative()) - return true; - - std::string scriptCallback; - if (getObjVars().getItem("teleportFixup.callback", scriptCallback)) - { - DEBUG_REPORT_LOG(true, ("Player warp making callback %s\n", scriptCallback.c_str())); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), scriptCallback, std::vector(), 0, true); - } - - LOG("TeleportFixup", ("Removing teleport fixup objvars for object %s\n", getNetworkId().getValueString().c_str())); - removeObjVarItem("teleportFixup"); - } - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Sets customization data for this object. - * - * @param customName name of the customization parameter - * @param value value to set the customization to - */ -void ServerObject::customize(const std::string & customName, int value) -{ - if(isAuthoritative()) - { - CustomizationDataProperty *const cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); - if (cdProperty != NULL) - { - CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); - if (customizationData != NULL) - { - RangedIntCustomizationVariable * variable = dynamic_cast< - RangedIntCustomizationVariable*>(customizationData->findVariable( - customName)); - if (variable != NULL) - variable->setValue(value); - else - { - DEBUG_WARNING(true, ("ServerObject::customize() tried to access var [%s] as ranged int, but not right type.", customName.c_str())); - } - //-- release local references - customizationData->release(); - } - else - { - // this shouldn't happen - DEBUG_WARNING(true, ("CustomizationDataProperty returned NULL CustomizationData on fetch.")); - } - } - else - { - // this shouldn't happen - DEBUG_WARNING(true, ("ServerObject::customize() object does not have customization property")); - } - } - else - { - sendControllerMessageToAuthServer(CM_customize, new MessageQueueGenericValueType >(std::make_pair(customName, value))); - } -} // ServerObject::customize - -// ---------------------------------------------------------------------- - -bool ServerObject::isInWorldCell() const -{ - return isInWorld() && (ContainerInterface::getTopmostContainer(*this) == this); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::canDestroy() const -{ - if (isPlayerControlled()) - return false; - const Container * container = ContainerInterface::getContainer(*this); - if (container) - { - //Check contents to make sure they can be destroyed. - ContainerConstIterator i = container->begin(); - for (; i != container->end(); ++i) - { - const ServerObject* child = safe_cast((*i).getObject()); - if (child && !child->canDestroy()) - { - DEBUG_REPORT_LOG(true, ("Tried to delete object %s but could not delete child %s\n", getNetworkId().getValueString().c_str(), child->getNetworkId().getValueString().c_str())); - return false; - } - } - } - - return true; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::permanentlyDestroy(DeleteReasons::Enumerator reason) -{ - // prevent recursion - if (isBeingDestroyed()) - return true; - - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_permanentlyDestroy, new MessageQueueGenericValueType(reason)); - return false; - } - - if (!canDestroy()) - { - return false; - } - - // can't destroy an initialized vendor unless the commodities server is up because - // there is commodities server data that *MUST* be removed when the vendor is - // destroyed, or else the commodities server will think the player has more - // vendors than he actually has - if ( isVendor() && getObjVars().hasItem("vendor_initialized") && !CommoditiesMarket::isCommoditiesServerAvailable() ) - { - return false; - } - - BuildingObject* buildingObject = asBuildingObject(); - const bool houseDestroyedByScript = (reason == DeleteReasons::Script && buildingObject && buildingObject->isPlayerPlaced()); - - // tell scripts we want to destroy the object - if (getScriptObject() != NULL && !m_calledTriggerDestroy) - { - m_calledTriggerDestroy = true; - ScriptParams params; - if (getScriptObject()->trigAllScripts(Scripting::TRIG_DESTROY, params) == SCRIPT_OVERRIDE) - { - if(reason != DeleteReasons::God) - { - m_calledTriggerDestroy = false; - return false; - } - } - } - - if (isAuthoritative() && (getScriptObject() != NULL) && !m_calledTriggerRemovingFromWorld) - { - ScriptParams params; - m_calledTriggerRemovingFromWorld = true; - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_REMOVING_FROM_WORLD, params)); - } - - setBeingDestroyed(true); - - if (isInBazaarOrVendor()) - { - CommoditiesMarket::auctionCancel(getOwnerId(), getNetworkId().getValue()); - } - - // need to remove all the items from the Commodities Market - // TODO: how to remove an item that might get deleted from a vendor's inventory without the vendor being deleted? (GM deleting and item for instance) - // TODO PROBLEM: contents of vendors aren't guaranteed to be loaded - if ( isVendor() ) - { - ServerObject *inv = getBazaarContainer(); - NetworkId playerOwnerId; - getObjVars().getItem("vendor_owner", playerOwnerId); - if( inv && playerOwnerId.getValue()>0 ) - { - // if this was an uninitialized vendor, remove objvar from owner - ServerObject *owner = dynamic_cast(NetworkIdManager::getObjectById(playerOwnerId)); - if (owner) - { - NetworkId notInitalizedVendor; - if (owner->getObjVars().getItem("vendor_not_initialized", notInitalizedVendor)) - { - if (notInitalizedVendor == Object::getNetworkId()) - { - owner->removeObjVarItem("vendor_not_initialized"); - } - } - } - CommoditiesMarket::destroyVendorMarket(playerOwnerId, *inv); - } - } - - if (isPersisted()) - { - sendDeleteToDatabase(*this, houseDestroyedByScript ? DeleteReasons::House : reason); - ServerObject const * const oldContainer = safe_cast(ContainerInterface::getContainedByObject(*this)); - LOG("CustomerService",("Deletion: %s in container: %s deleted from game. Reason: %s", ServerObject::getLogDescription(this).c_str(), oldContainer ? ServerObject::getLogDescription(oldContainer).c_str() : "none", describeDeleteReason(static_cast(reason)).c_str())); - int childReason = DeleteReasons::ContainerDeleted; - if (houseDestroyedByScript) - childReason = DeleteReasons::House; - flagChildObjectsForDeletion(*this, childReason); - } - - // grab the proxy list prior to removing it from the container, because it's about to lose its proxy list - ProxyList const &proxyList = getExposedProxyList(); - if (!proxyList.empty()) - { - ServerMessageForwarding::begin(std::vector(proxyList.begin(), proxyList.end())); - - UnloadObjectMessage const unloadMessage(getNetworkId()); - ServerMessageForwarding::send(unloadMessage); - - ServerMessageForwarding::end(); - } - - onPermanentlyDestroyed(); - unload(); - - //-- Ensure state is set to initialized (i.e. have received end baselines or - // created on this server). This is required so that the AlterScheduler - // can accept the Object. If changing initialization state, warn about it here. - if (!isInitialized()) - { - DEBUG_WARNING(true, ("ServerObject::permanentlyDestroy(): object is not initialized, setting to initialized to allow submission to alter scheduler for delete. id=[%s],template=[%s].", getNetworkId().getValueString().c_str(), getObjectTemplateName())); - setInitialized(true); - } - - //-- Ensure this object gets altered next frame so that kill() can take effect. - AlterScheduler::submitForAlter(*this); - - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Allows an object to do pre-deletion cleanup. - */ -void ServerObject::onRemovingFromWorld() -{ - // If we're being removed from the world, we may need to remove ourselves from the parent container list. - if (isAuthoritative() && isPlayerControlled() && isUnloading()) - { - Object * const parent = ContainerInterface::getContainedByObject(*this); - if (parent) - { - Container * const container = parent->getCellProperty(); - if (container) - { - container->internalItemRemoved(*this); - } - } - } - - if (m_networkUpdateFar) - onRemovedFromWorldCell(); - - destroyTriggerVolumes(); -} - -// ---------------------------------------------------------------------- -/* Why would I unload something? - * - It might be a player character logging out - * - Or the planet server might be telling me to unload an object */ -// ---------------------------------------------------------------------- - -void ServerObject::unload() -{ - scheduleForAlter(); - addObjectToConcludeList(); - - // prevent recursion - if (isUnloading()) - { - kill(); - return; - } - - setUnloading(true); - - DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Unloading object (%s : %s)\n", getObjectTemplateName(), getNetworkId().getValueString().c_str())); - - // If the object has a client, uncontrol it. When the primary controlled - // object is unloaded, this prevents us from sending destroys to ourself, - if (getClient()) - getClient()->removeControlledObject(*this); - - synchronizationOnUnload(); - - if (isAuthoritative()) - { - ScriptParams params; - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_UNLOADED_FROM_MEMORY, params)); - } - - kill(); - - // if this object is in a slot in a slotted container, immediately remove - // it from the slot, because another object may be immediately put into - // the slot before this object is eventually destroyed and removed from the container - Object * const containedBy = ContainerInterface::getContainedByObject(*this); - if (containedBy) - { - Container * const container = ContainerInterface::getContainer(*containedBy); - SlottedContainer * const slotContainer = dynamic_cast(container); - if (slotContainer) - slotContainer->removeItemFromSlotOnly(*this); - } -} - -// ---------------------------------------------------------------------- - -/** - * Unload the object, and tell the database to move it to a specified player - */ -void ServerObject::moveToPlayerAndUnload(const NetworkId &player) -{ - GenericValueTypeMessage > const moveToPlayerMessage( - "MoveToPlayer", - std::make_pair(getNetworkId(), player)); - GameServer::getInstance().sendToDatabaseServer(moveToPlayerMessage); - - unload(); -} - - -// ---------------------------------------------------------------------- - -/** - * Unload the object, and tell the database to move it to a specified player's bank - */ -void ServerObject::moveToPlayerBankAndUnload(const NetworkId &player) -{ - GenericValueTypeMessage > const moveToPlayerMessage( - "MoveToPlayerBankMessage", - std::make_pair(getNetworkId(), player)); - GameServer::getInstance().sendToDatabaseServer(moveToPlayerMessage); - - unload(); -} - -// ---------------------------------------------------------------------- - -/** - * Unload the object, and tell the database to move it to a specified player's bank - */ -void ServerObject::moveToPlayerDatapadAndUnload(const NetworkId &player, int maxDepth) -{ - GenericValueTypeMessage, int> > const moveToPlayerMessage( - "MoveToPlayerDatapadMessage", - std::make_pair(std::make_pair(getNetworkId(), player), maxDepth)); - GameServer::getInstance().sendToDatabaseServer(moveToPlayerMessage); - - unload(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::onPermanentlyDestroyed() -{ - IGNORE_RETURN(ContainerInterface::onObjectDestroy(*this)); -} - -// ------------------------------------------------------------------------------------------ - - -/** - * Request to load a specific object contained by this object. - * (This object must be a demand-load container, i.e. m_loadContents==false.) - */ - -void ServerObject::loadContainedObjectFromDB(const NetworkId &oid) const -{ - LoadContainedObjectMessage const msg(getNetworkId(), oid); - GameServer::getInstance().sendToDatabaseServer(msg); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::areContentsLoaded() const -{ - return m_contentsLoaded.get(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::loadAllContentsFromDB() const -{ - if (m_contentsLoaded.get() || m_contentsRequested.get()) - { - DEBUG_REPORT_LOG(true,("Ignoring LoadAllContentsFromDB for object %s because they are already loaded\n",getNetworkId().getValueString().c_str())); - return; - } - - DEBUG_REPORT_LOG(true,("LoadAllContentsFromDB, object %s\n",getNetworkId().getValueString().c_str())); - - if (m_loadContents.get()) - WARNING_STRICT_FATAL(true,("Requested loading contents of container %s, but the container is not a demand-load container.",getNetworkId().getValueString().c_str())); - else - { - m_contentsRequested = true; - LoadContentsMessage const msg(getNetworkId()); - GameServer::getInstance().sendToDatabaseServer(msg); - } -} - -//---------------------------------------------------------------------- - -void ServerObject::setLoadContents(bool loadContents) -{ - if (isAuthoritative()) - { - m_loadContents = loadContents; - } - else - { - // this function should probably never be called on a proxy object - WARNING_STRICT_FATAL(true,("Setting loadContent across game servers is not allowed.")); - } -} - -//---------------------------------------------------------------------- - -void ServerObject::unloadPersistedContents() -{ - if (!areContentsLoaded()) - { - return; - } - - Container *container = ContainerInterface::getContainer(*this); - if (container) - { - for (ContainerIterator j = container->begin(); j != container->end(); ++j) - { - ServerObject * obj = safe_cast((*j).getObject()); - if (obj && obj->isPersisted()) - { - obj->unload(); - } - } - m_contentsLoaded = false; - m_contentsRequested = false; - } -} - -//---------------------------------------------------------------------- - -const Unicode::String ServerObject::getAssignedObjectFirstName () const -{ - const Unicode::String & name = m_objectName.get (); - // split off the last name from toName - std::string::size_type spacePos = name.find(' '); - if (spacePos != std::string::npos) - return name.substr(0, spacePos); - - return name; -} - -//---------------------------------------------------------------------- - -/** - * This function is used to obtain a client-displayable name regardless of whether - * the object has an assigned name or string id. - */ - -const Unicode::String ServerObject::getEncodedObjectName () const -{ - static const Unicode::String at (1, '@'); - - if (!m_objectName.get ().empty ()) - return m_objectName.get (); - else - return at + Unicode::narrowToWide (m_nameStringId.get().getCanonicalRepresentation ()); -} - -// ---------------------------------------------------------------------- - -/** - * Do a money transfer and send the reply to a script - * @param target Target of the money transfer - * @param replyTo Object that wants the reply message (this object does not need to be involved in the transaction) - * @param successCallback Script method on the object to call on success. - * @param failCallback Script method on the object to call on failure. - * @param packedDictionary Dictionary to be passed to the script (packed into a string) - */ -void ServerObject::scriptTransferCashTo(const NetworkId &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) -{ - if (isAuthoritative()) - { - bool result = transferCashTo(target, amount); - if (result) - { - if (!successCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); - } - else - { - if (!failCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); - } - } - else - { - MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_cashTransfer, target, "", amount, replyTo, successCallback, failCallback, packedDictionary); - Controller *const controller = getController(); - NOT_NULL(controller); - controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -// ---------------------------------------------------------------------- - -/** - * Do a money transfer and send the reply to a script - * @param target Target of the money transfer - * @param replyTo Object that wants the reply message (this object does not need to be involved in the transaction) - * @param successCallback Script method on the object to call on success. - * @param failCallback Script method on the object to call on failure. - * @param packedDictionary Dictionary to be passed to the script (packed into a string) - */ -void ServerObject::scriptTransferBankCreditsTo(const NetworkId &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) -{ - if (isAuthoritative()) - { - bool result = transferBankCreditsTo(target, amount); - if (result) - { - if (!successCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); - } - else - { - if (!failCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); - } - } - else - { - MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankTransfer, target, "", amount, replyTo, successCallback, failCallback, packedDictionary); - Controller *const controller = getController(); - NOT_NULL(controller); - controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::scriptWithdrawCashFromBank(int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) -{ - if (isAuthoritative()) - { - bool result = withdrawCashFromBank(amount); - if (result) - { - if (!successCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); - } - else - { - if (!failCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); - } - } - else - { - MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankWithdrawal, NetworkId::cms_invalid, "", amount, replyTo, successCallback, failCallback, packedDictionary); - Controller *const controller = getController(); - NOT_NULL(controller); - controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::scriptDepositCashToBank(int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) -{ - if (isAuthoritative()) - { - bool result = depositCashToBank(amount); - if (result) - { - if (!successCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); - } - else - { - if (!failCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); - } - } - else - { - MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankDeposit, NetworkId::cms_invalid, "", amount, replyTo, successCallback, failCallback, packedDictionary); - Controller *const controller = getController(); - NOT_NULL(controller); - controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -// ---------------------------------------------------------------------- - -/** - * Do a money transfer and send the reply to a script - * @param target Target of the money transfer - * @param replyTo Object that wants the reply message (this object does not need to be involved in the transaction) - * @param successCallback Script method on the object to call on success. - * @param failCallback Script method on the object to call on failure. - * @param packedDictionary Dictionary to be passed to the script (packed into a string) - */ -void ServerObject::scriptTransferBankCreditsTo(const std::string &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) -{ - if (isAuthoritative()) - { - bool result = transferBankCreditsTo(target, amount); - if (result) - { - if (!successCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); - } - else - { - if (!failCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); - } - } - else - { - MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankTransferToNamedAccount, NetworkId::cms_invalid, target, amount, replyTo, successCallback, failCallback, packedDictionary); - Controller *const controller = getController(); - NOT_NULL(controller); - controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::scriptTransferBankCreditsFrom(const std::string &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) -{ - if (isAuthoritative()) - { - bool result = transferBankCreditsFrom(target, amount); - if (result) - { - if (!successCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); - } - else - { - if (!failCallback.empty()) - MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); - } - } - else - { - MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankTransferFromNamedAccount, NetworkId::cms_invalid, target, amount, replyTo, successCallback, failCallback, packedDictionary); - Controller *const controller = getController(); - NOT_NULL(controller); - controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); - } -} - -//---------------------------------------------------------------------- - -void ServerObject::getAttributes(const NetworkId & playerId, AttributeVector &data) const -{ - getAttributes (data); - - if (!isAuthoritative()) - { - DEBUG_WARNING (true, ("ServerObject::getAttributes invoked on non-auth object %s", getNetworkId ().getValueString ().c_str ())); - return; - } - - GameScriptObject * const gso = const_cast(getScriptObject()); - - if (gso->hasTrigger (Scripting::TRIG_GET_ATTRIBS)) - { - const CreatureObject * player = safe_cast(ServerWorld::findObjectByNetworkId(playerId)); - int MAX_ATTRIBS = 80; - if(player) - { - if(player->getClient()) - { - if(player->getClient()->isGod()) - { - MAX_ATTRIBS = 2000; - } - } - } - - // allow scripts to add attribute data to the vector - static std::vector names (MAX_ATTRIBS, static_cast(0)); - static std::vector attribs (MAX_ATTRIBS, static_cast(0)); - - //-- clear the vectors - names.clear (); - attribs.clear (); - names.resize (MAX_ATTRIBS, static_cast(0)); - attribs.resize (MAX_ATTRIBS, static_cast(0)); - - ScriptParams params; - params.addParam (playerId); - params.addParam (names); - params.addParam (attribs); - - NOT_NULL (gso); - - IGNORE_RETURN(gso->trigAllScripts(Scripting::TRIG_GET_ATTRIBS, params)); - - const std::vector & newNames = params.getStringArrayParam (1); - const std::vector & newAttribs = params.getUnicodeArrayParam (2); - - // copy the returned strings to data - for (int i = 0; i < MAX_ATTRIBS; ++i) - { - const char * const newName = newNames [i]; - const Unicode::String * const newAttrib = newAttribs [i]; - - if (newName && *newName && newAttrib && !newAttrib->empty ()) - { - data.push_back (std::make_pair (std::string (newName), *newAttrib)); - } - else - break; - } - - // if the requestor is a gm, add objvars and scriptvars - // to result data (ignore max attribs as well!) - - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::getAttributes(AttributeVector &) const -{ -} - -// ---------------------------------------------------------------------- - -/** - * Return all the standard attributes for an item, plus special - * auction-specific attributes. - * - * May eventually make this into a virtual function if we add more to it. - */ -void ServerObject::getAttributesForAuction(AttributeVector &data) const -{ - static const std::string attributeClientSharedTemplateName("ClientSharedTemplateName"); - static const std::string attributeAppearanceData("AppearanceData"); - - DEBUG_FATAL(strlen(getClientSharedTemplateName()) > 1000,("Client shared template name was more than 1000 characters long, too long to save.")); - - getAttributes(NetworkId::cms_invalid,data); - data.push_back(std::make_pair(attributeClientSharedTemplateName, Unicode::narrowToWide(getClientSharedTemplateName()))); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::alwaysSendReliableTransform() const -{ - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Called when a request to load a contained object has been completed. - * - * Two Important Notes: - * 1) This is called in response to loadContainedObjectFromDB. It is not - * called in response to loadAllContentsFromDB - * 2) There is no guarantee the requested object exists. If the object - * id was wrong or the object wasn't in the container, it will not - * have been loaded. - */ -void ServerObject::onContainedObjectLoaded(NetworkId const &oid) -{ - CommoditiesMarket::checkPendingLoads(oid); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isBazaarTerminal() const -{ - SharedObjectTemplate::GameObjectType got = - static_cast (getGameObjectType()); - return (got == SharedObjectTemplate::GOT_terminal_bazaar); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isVendor() const -{ - const TangibleObject *tangibleObject = asTangibleObject(); - if (tangibleObject) - { - return tangibleObject->hasCondition(ServerTangibleObjectTemplate::C_vendor); - } - return false; -} - -// ---------------------------------------------------------------------- - -void ServerObject::makeVendor() -{ - CreatureObject *creatureObject = asCreatureObject(); - if (creatureObject) - { - const char* s_inventoryTemplate = "object/tangible/inventory/vendor_inventory.iff"; - std::set inventoryObservers; - ServerObject *inventory = creatureObject->getInventory(); - if (inventory) - { - // if there's already a vendor inventory on the creature, - // then it means this creature is already a vendor; we - // don't want to destroy that vendor inventory and create - // another vendor inventory, because the vendor inventory - // is already registered with the commodities server and - // may have items in it, and deleting the vendor inventory - // would cause those items to be orphaned; - - // doing what we are doing here will cause the existing - // vendor inventory to be registered with the commodities - // server again, but it won't hurt, and it covers the - // recovery case where if for some reason the first - // registration failed, we will try the registration again - if(strcmp(inventory->getTemplateName(), s_inventoryTemplate) == 0) - { - LOG("CustomerService", ("vendor: Calling makeVendor() for vendor (%s) who already has a vendor inventory object (%s)", getDebugInformation().c_str(), inventory->getDebugInformation().c_str())); - return; - } - - // make a copy of the current inventory observers - inventoryObservers = inventory->getObservers(); - - // destroy the existing inventory - LOG("CustomerService", ("vendor: makeVendor() for vendor (%s), destroying existing inventory object (%s)", getDebugInformation().c_str(), inventory->getDebugInformation().c_str())); - - inventory->permanentlyDestroy(DeleteReasons::Replaced); - } - const SlotId invenSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("inventory")); - ServerObject *vendorInventory = ServerWorld::createNewObject(std::string(s_inventoryTemplate), *this, invenSlot, true); - if (vendorInventory) - { - LOG("CustomerService", ("vendor: makeVendor() for vendor (%s), created vendor inventory object (%s)", getDebugInformation().c_str(), vendorInventory->getDebugInformation().c_str())); - - vendorInventory->setLoadContents(false); - - // make sure that the new inventory object has - // the same observers as the old inventory object - ObserveTracker::onMakeVendorInventory(*vendorInventory, inventoryObservers); - } - else - { - LOG("CustomerService", ("vendor: makeVendor() for vendor (%s), failed to create vendor inventory object", getDebugInformation().c_str())); - } - } - else - { - setLoadContents(false); - } -} - -// ---------------------------------------------------------------------- - -ServerObject *ServerObject::getBazaarContainer() -{ - CreatureObject *creatureObject = asCreatureObject(); - if (creatureObject) - { - return creatureObject->getInventory(); - } - else - { - return this; - } -} - - -// ---------------------------------------------------------------------- - -const ServerObject *ServerObject::getBazaarContainer() const -{ - const CreatureObject *creatureObject = asCreatureObject(); - if (creatureObject) - { - return creatureObject->getInventory(); - } - else - { - return this; - } -} - -// ---------------------------------------------------------------------- - -/** - * Called when a request to load a contained object has been completed. - * - * Two Important Notes: - * 1) This is called in response to loadAllContentsFromDB. It is not - * called in response to loadContainedObjectFromDB - * 2) There is no guarantee the container now contains any objects. - * If there were no contained objects in the database, the container - * will be empty. - */ -void ServerObject::onAllContentsLoaded() -{ - GameServer::removePendingLoadRequest(getNetworkId()); - - m_contentsLoaded=true; - if (getObjVars().hasItem(CommoditiesMarket::OBJVAR_VENDOR_REINITIALIZING)) - { - //vendor is re-initializing - setLoadContents( false ); - CommoditiesMarket::reinitializeVendorContents(*this); - } - else if (getObjVars().hasItem(OBJVAR_STRUCTURE_PLAYER_PACK)) - { - //Get player initiating load - NetworkId playerId; - - if (getObjVars().getItem(OBJVAR_STRUCTURE_PLAYER_PACK, playerId)) - { - bool failed = true; - - if (isAuthoritative()) - { - ServerObject *player = NULL; - if ((player = getServerObject(playerId)) != NULL) - { - //Tell scripts we are loaded - ScriptParams params; - params.addParam( getNetworkId() ); - IGNORE_RETURN(player->getScriptObject()->trigAllScripts(Scripting::TRIG_BUILDING_CONTENTS_LOADED, params)); - failed = false; - } - } - - if (failed) - { - // fail pack-up as authority lost on player - notify script - MessageToQueue::getInstance().sendMessageToJava(playerId, "handleFailedStructurePackup", std::vector(), 0, false); - } - } - - //remove the vendor reinitialization flag if it exists - removeObjVarItem(OBJVAR_STRUCTURE_PLAYER_PACK); - } - else - { - ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (containedBy) - { - Client * const client = containedBy->getClient(); - if (client) - { - CreatureObject const * const containedByCreature = containedBy->asCreatureObject(); - if (containedByCreature && containedByCreature->getBankContainer() == this) - { - if (containedBy->getLoadCTSBank()) - { - LOG("CustomerService", ("CharacterTransfer: serverObject has LoadCTSBank flag set, sending ReplyBankCTSLoaded message")); - GenericValueTypeMessage setFromCTSLoadBank("ReplyBankCTSLoaded", containedBy->getNetworkId()); - client->sendToConnectionServer(setFromCTSLoadBank); - } - else - client->openContainer(*this, 0, std::string()); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::immediateLogoutAllowed() -{ - return true; -} - -// ---------------------------------------------------------------------- - -void ServerObject::disconnect() -{ - if (!isAuthoritative()) - sendControllerMessageToAuthServer(CM_disconnect, 0); - else if (getClient()) - GameServer::getInstance().dropClient(getNetworkId()); -} - -// ---------------------------------------------------------------------- - -void ServerObject::handleDisconnect(bool immediate) -{ - if (isPlayerControlled()) - { - // client has disconnected, log pertinent information about the play session - CreatureObject * const creatureObject = asCreatureObject(); - PlayerObject * playerObject = NULL; - if (creatureObject) - { - playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if (playerObject && (playerObject->getSessionStartPlayTime() != 0)) - { - char buffer[128]; - std::string logText; - - // leading delimiter - logText += "|"; - - // character name - logText += Unicode::wideToNarrow(getObjectName()); - logText += "|"; - - // character id - logText += getNetworkId().getValueString(); - logText += "|"; - - // character birth date - // get the base date of Jan 1st, 2001 - struct tm baseTimeData; - baseTimeData.tm_hour = 0; - baseTimeData.tm_isdst = 0; - baseTimeData.tm_mday = 1; - baseTimeData.tm_min = 0; - baseTimeData.tm_mon = 0; - baseTimeData.tm_sec = 0; - baseTimeData.tm_wday = 0; - baseTimeData.tm_yday = 0; - baseTimeData.tm_year = 101; - time_t baseTime = mktime(&baseTimeData); - - // the birth date is the number of days since Jan 1st, 2001 - baseTime += static_cast(playerObject->getBornDate() * 60 * 60 * 24); - - struct tm * birthDateTimeData = gmtime(&baseTime); - - snprintf(buffer, sizeof(buffer)-1, "%d%02d%02d", (birthDateTimeData->tm_year + 1900), (birthDateTimeData->tm_mon + 1), birthDateTimeData->tm_mday); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // station id - snprintf(buffer, sizeof(buffer)-1, "%lu", playerObject->getStationId()); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // session play time - logText += CalendarTime::convertSecondsToHMS(static_cast(playerObject->getSessionPlayTimeDuration())); - logText += "|"; - - // session active play time - logText += CalendarTime::convertSecondsToHMS(static_cast(playerObject->getSessionActivePlayTimeDuration())); - logText += "|"; - - // session activity - snprintf(buffer, sizeof(buffer)-1, "%lu", playerObject->getSessionActivity()); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // scene name - logText += ServerWorld::getSceneId(); - logText += "|"; - - // container id (0 if in world cell) - Object const * const container = ContainerInterface::getContainedByObject(*this); - snprintf(buffer, sizeof(buffer)-1, "%s", (container ? container->getNetworkId().getValueString().c_str() : "0")); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // x,y,z in container - Vector const posContainer = getPosition_p(); - snprintf(buffer, sizeof(buffer)-1, "%d %d %d", static_cast(posContainer.x), static_cast(posContainer.y), static_cast(posContainer.z)); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // x,y,z in world - Vector const posWorld = getPosition_w(); - snprintf(buffer, sizeof(buffer)-1, "%d %d %d", static_cast(posWorld.x), static_cast(posWorld.y), static_cast(posWorld.z)); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // profession - logText += playerObject->getSkillTemplate(); - logText += "|"; - - // level - snprintf(buffer, sizeof(buffer)-1, "%d", creatureObject->getLevel()); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // current quest id - snprintf(buffer, sizeof(buffer)-1, "%lu", playerObject->getCurrentQuest()); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - logText += "|"; - - // current quest name - if (playerObject->getCurrentQuest() != 0) - { - logText += QuestManager::getQuestName(playerObject->getCurrentQuest()); - } - else - { - logText += "none"; - } - logText += "|"; - - // xp - bool hasLoggedFirstXp = false; - std::map const & xp = playerObject->getExperiencePoints(); - for (std::map::const_iterator iter = xp.begin(); iter != xp.end(); ++iter) - { - if (iter->second == 0) - continue; - - if (hasLoggedFirstXp) - logText += ","; - - logText += iter->first; - logText += "="; - - snprintf(buffer, sizeof(buffer)-1, "%d", iter->second); - buffer[sizeof(buffer)-1] = '\0'; - logText += buffer; - - hasLoggedFirstXp = true; - } - logText += "|"; - - // log it - LOG("CustomerService", ("Logout:%s", logText.c_str())); - - // clear the session play time info - playerObject->setSessionPlayTimeInfo(0, 0, 0); - - // clear the session activity info - playerObject->clearSessionActivity(); - } - } - - if (!immediate && !immediateLogoutAllowed()) - LogoutTracker::add(getNetworkId()); - else - { - virtualOnLogout(); - - if (ConfigServerGame::getLogoutTriggerEnabled()) - { - ScriptParams params; - getScriptObject()->trigAllScripts(Scripting::TRIG_LOGOUT, params); - } - - Client * const client = getClient(); - if (client) - { - LogoutMessage const logoutMessage; - client->send(logoutMessage, true); - } - - PositionUpdateTracker::flushPositionUpdate(*this); - LogoutTracker::addPendingSave(this); - - // get rid of the proxies - clearProxyList(); - - // if we're inside a container, it's the topmost parent that contains our proxy - // list, so the above clearProxyList() call will not get rid of the proxies - synchronizationOnUnload(); - - // don't allow anyone to continue observing this object (and associated PlayerObject) - if (playerObject) - ObserveTracker::onObjectDestroyed(*playerObject, false); - - ObserveTracker::onObjectDestroyed(*this, false); - - // remove from world and/or container as necessary but keep containment information available - if (isInWorld()) - removeFromWorld(); - else - WARNING(getTriggerVolumeEntered() && !getTriggerVolumeEntered()->empty(), ("ServerObject::handleDisconnect called for (%s) which is not in the world but is contained in one or more trigger volumes", getDebugInformation().c_str())); - - // the object should have been removed from all TriggerVolumes - // (from removeFromWorld() above) by now, but as a safety measure, - // we'll do a final check and remove the object from any - // TriggerVolumes that it is still in - if (getTriggerVolumeEntered()) - { - std::set const triggerVolumeEntered = *(getTriggerVolumeEntered()); - for (std::set::const_iterator i = triggerVolumeEntered.begin(); i != triggerVolumeEntered.end(); ++i) - { - WARNING(true, ("Object (%s) added to LogoutTracker but hasn't been removed from TriggerVolume (%s) owned by (%s)", - getDebugInformation().c_str(), - (*i)->getName().c_str(), - (*i)->getOwner().getDebugInformation().c_str())); - - (*i)->removeObject(*this); - } - } - - Object *containerObject = ContainerInterface::getContainedByObject(*this); - if (containerObject) - { - NON_NULL(ContainerInterface::getContainer(*containerObject))->internalItemRemoved(*this); - - // if the character was in a building, tell the building it has lost - // the player so the building demand load/unload system can work correctly - Object *buildingObj = ContainerInterface::getTopmostContainer(*containerObject); - if (buildingObj && buildingObj->isAuthoritative() && buildingObj->asServerObject() && buildingObj->asServerObject()->asBuildingObject()) - buildingObj->asServerObject()->asBuildingObject()->lostPlayer(*this); - } - - // remove all sui pages for character - ServerUIManager::onPlayerLogout(getNetworkId()); - } - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::setAttributeAttained(int attribute) -{ - BitArray tmp(m_attributesAttained.get()); - tmp.setBit(attribute); - m_attributesAttained = tmp; -} - -// ---------------------------------------------------------------------- - -void ServerObject::clearAttributeAttained(int attribute) -{ - BitArray tmp(m_attributesAttained.get()); - tmp.clearBit(attribute); - m_attributesAttained = tmp; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::hasAttributeAttained(int attribute) const -{ - return m_attributesAttained.get().testBit(attribute); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setAttributeInterested(int attribute) -{ - BitArray tmp(m_attributesInterested.get()); - tmp.setBit(attribute); - m_attributesInterested = tmp; -} - -// ---------------------------------------------------------------------- - -void ServerObject::clearAttributeInterested(int attribute) -{ - BitArray tmp(m_attributesInterested.get()); - tmp.clearBit(attribute); - m_attributesInterested = tmp; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::hasAttributeInterest(int attribute) const -{ - return m_attributesInterested.get().testBit(attribute); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isInterested(const ServerObject &rhs) const -{ - return m_attributesInterested.get().matchAnyBit(rhs.m_attributesAttained.get()); -} - -// ---------------------------------------------------------------------- - -std::string ServerObject::getItemLog() const -{ - return getNetworkId().getValueString() + ' ' + Unicode::wideToNarrow(getObjectName()); -} - -// ---------------------------------------------------------------------- - -void ServerObject::checkAndLogInvalidTransform() const -{ - Transform const &transform_o2p = getTransform_o2p(); - bool const isValid = transform_o2p.validate(true); - - if (!isValid) - { - Object const *const container = ContainerInterface::getContainedByObject(*this); - Vector const position = transform_o2p.getPosition_p(); - Vector const containerPosition = container ? container->getTransform_o2w().getPosition_p() : Vector::zero; - - WARNING(!isValid, - ("transform is invalid for object id=[%s], object template name=[%s], server id=[%d], server scene id=[%s], position=[%.2f,%.2f,%.2f], container id=[%s], container position=[%.2f,%.2f,%.2f]", - getNetworkId().getValueString().c_str(), - getObjectTemplateName(), - static_cast(GameServer::getInstance().getProcessId()), - ServerWorld::getSceneId().c_str(), - position.x, - position.y, - position.z, - container ? container->getNetworkId().getValueString().c_str() : "", - containerPosition.x, - containerPosition.y, - containerPosition.z - )); - } -} - -// ---------------------------------------------------------------------- - -ServerObject * ServerObject::combineResourceContainers(ServerObject &item) -{ - if (isVendor() || isBazaarTerminal() || isInBazaarOrVendor() ) - { - //Do not combine resources on vendors or bazaars, as they need - //to remain separate to sell separately. - return &item; - } - - ServerObject * returnedItem = &item; - typedef std::vector SimilarContainers; - static SimilarContainers similarContainers; - - if (item.getObjectType() == ServerResourceContainerObjectTemplate::ServerResourceContainerObjectTemplate_tag) - { - ResourceContainerObject *resourceContainerObject = safe_cast(&item); - - if (resourceContainerObject != NULL) - { - // If this is a container, see if it contains another resource container of the same type - - Container *container = ContainerInterface::getContainer(*this); - - if (container != NULL) - { - ContainerIterator iterContainer = container->begin(); - - for (; iterContainer != container->end(); ++iterContainer) - { - Object *containedObject = NetworkIdManager::getObjectById(*iterContainer); - - // Make sure the contained item is not the item we are gaining and that - // the item is a resource container - - if ((containedObject != &item) && - (containedObject != NULL) && - (containedObject->getObjectType() == ServerResourceContainerObjectTemplate::ServerResourceContainerObjectTemplate_tag)) - { - ResourceContainerObject *containedResourceContainerObject = safe_cast(containedObject); - - if ((containedResourceContainerObject != NULL) && - (resourceContainerObject->getResourceType() == containedResourceContainerObject->getResourceType())) - { - // This is a container of similar type, if it is not full, save it to the list - - int const quantity = containedResourceContainerObject->getQuantity(); - int const maxQuantity = containedResourceContainerObject->getMaxQuantity(); - - if (quantity != maxQuantity) - { - similarContainers.push_back(containedResourceContainerObject); - } - } - } - } - } - } - - // Combine the resources as much as possible - - bool done = false; - int resourcesLeftToAdd = resourceContainerObject->getQuantity(); - - while (!done) - { - // Find the most full container - - SimilarContainers::iterator iterSimilarContainers = similarContainers.begin(); - SimilarContainers::iterator fullestContainer = similarContainers.end(); - - for (; iterSimilarContainers != similarContainers.end(); ++iterSimilarContainers) - { - if (fullestContainer == similarContainers.end()) - { - fullestContainer = iterSimilarContainers; - } - else - { - int const currentQuantity = (*iterSimilarContainers)->getQuantity(); - int const fullestQuantity = (*fullestContainer)->getQuantity(); - - if (currentQuantity > fullestQuantity) - { - fullestContainer = iterSimilarContainers; - } - } - } - - // Add as much as we can to the fullest container - - if (fullestContainer != similarContainers.end()) - { - int const fullestQuantity = (*fullestContainer)->getQuantity(); - int const fullestMaxQuantity = (*fullestContainer)->getMaxQuantity(); - int const amountToAdd = std::min(resourcesLeftToAdd, fullestMaxQuantity - fullestQuantity); - - // Add the amount to the fullest container - - ResourceContainerObject *sourceObj = resourceContainerObject; - ResourceContainerObject *destObj = *fullestContainer; - - if (sourceObj && destObj && (amountToAdd > 0)) - { - sourceObj->transferTo(*destObj, amountToAdd); - if (sourceObj->isBeingDestroyed()) - returnedItem = destObj; - } - - resourcesLeftToAdd -= amountToAdd; - - // Remove this container from the list - - similarContainers.erase(fullestContainer); - } - else - { - // There are no more containers to combine to, so we are done - - done = true; - } - - if (resourcesLeftToAdd <= 0) - { - // If there is no more resources left to combine, then we are done - - done = true; - } - } - - similarContainers.clear(); - } - return returnedItem; -} - -// ---------------------------------------------------------------------- - -/** - * Determines if this object is contained by another object. - * - * @param container the object that might contain this one - * @param includeContents if true, return true if one of the container's contents contains us - * - * @return true if we are contained by the container (or its contents) - */ -bool ServerObject::isContainedBy(const ServerObject & container, bool includeContents) const -{ - // we actually check what we are contained by instead of checking the - // container's contents - const Object * test = ContainerInterface::getContainedByObject(*this); - if (test == &container) - { - // our container is the desired container - return true; - } - else if (test != NULL && test != this && includeContents) - { - // our container isn't the desired container, see if it is contained - return safe_cast(test)->isContainedBy(container, true); - } - return false; -} - -// ---------------------------------------------------------------------- - -void ServerObject::concludeScriptVars() -{ - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::concludeScriptVars"); - GameScriptObject::packAllScriptVarDeltas(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::scheduleForAlter() -{ - // ServerObjects do not recurse into containers, so are always responsible for scheduling themselves directly. - if (isInitialized()) - { -// DEBUG_REPORT_LOG(true, ("[aitest] Scheduling %s for alter\n", getNetworkId().getValueString().c_str())); - AlterScheduler::submitForAlter(*this); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::onAddedToWorldCell() -{ - createFarNetworkUpdateVolume(); - virtualOnAddedToWorldCell(); - updatePositionOnPlanetServer(true); -} - - -// ---------------------------------------------------------------------- - -void ServerObject::virtualOnAddedToWorldCell() -{ -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::onRemovedFromWorldCell() -{ - virtualOnRemovedFromWorldCell(); -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::virtualOnRemovedFromWorldCell() -{ - destroyFarNetworkUpdateVolume(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::virtualOnSetAuthority() -{ -} - -// ---------------------------------------------------------------------- - -void ServerObject::virtualOnReleaseAuthority() -{ -} - -// ---------------------------------------------------------------------- - -void ServerObject::virtualOnLogout() -{ -} - -//------------------------------------------------------------------------------------------ - -bool ServerObject::wantSawAttackTriggers() const -{ - return false; -} - -// ---------------------------------------------------------------------- - -void ServerObject::setTeleportScriptCallback(std::string const &scriptCallback) -{ - setObjVarItem("teleportFixup.callback", scriptCallback); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setInteriorTeleportDestination(NetworkId const &destContainerId, std::string const &destCellName, Vector const &destPosition_p) -{ - LOG("TeleportFixup", ("Setting interior telerport destination for %s: into %f %f %f %s %s\n", getNetworkId().getValueString().c_str(), destPosition_p.x, destPosition_p.y, destPosition_p.z, destCellName.c_str(), destContainerId.getValueString().c_str())); - removeObjVarItem("teleportFixup"); - setObjVarItem("teleportFixup.x", destPosition_p.x); - setObjVarItem("teleportFixup.y", destPosition_p.y); - setObjVarItem("teleportFixup.z", destPosition_p.z); - setObjVarItem("teleportFixup.container", destContainerId); - if (!destCellName.empty()) - setObjVarItem("teleportFixup.cellname", destCellName); -} - -// ---------------------------------------------------------------------- - -Vector const &ServerObject::getTriggerPosition() const -{ - return m_oldPosition; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::getTransformChanged() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_TransformChanged); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setTransformChanged(bool c) -{ - setLocalFlag(LocalObjectFlags::ServerObject_TransformChanged, c); - if (c) - { - addObjectToConcludeList(); - if (isAuthoritative() && isPersisted()) - PositionUpdateTracker::positionChanged(*this); - } -} - -// ---------------------------------------------------------------------- - -bool ServerObject::onContainerChildAboutToLoseItem(ServerObject * destination, ServerObject& item, ServerObject* transferer) -{ - if (transferer && !checkBankTransfer(this, item, transferer)) - return false; - - Object * const parent = ContainerInterface::getContainedByObject(*this); - if (parent && parent->asServerObject()) - return parent->asServerObject()->onContainerChildAboutToLoseItem(destination, item, transferer); - - return true; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::onContainerChildAboutToGainItem(ServerObject& item, ServerObject* destination, ServerObject* transferer) -{ - if (transferer && !checkBankTransfer(this, item, transferer)) - return false; - - Object * const parent = ContainerInterface::getContainedByObject(*this); - if (parent && parent->asServerObject()) - return parent->asServerObject()->onContainerChildAboutToGainItem(item, destination, transferer); - - return true; -} - -// ---------------------------------------------------------------------- - -void ServerObject::onContainerChildLostItem(ServerObject * destination, ServerObject& item, ServerObject* source, ServerObject* transferer) -{ - Object * const parent = ContainerInterface::getContainedByObject(*this); - if (parent && parent->asServerObject()) - parent->asServerObject()->onContainerChildLostItem(destination, item, source, transferer); -} - -// ---------------------------------------------------------------------- - -void ServerObject::onContainerChildGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) -{ - Object * const parent = ContainerInterface::getContainedByObject(*this); - if (parent && parent->asServerObject()) - parent->asServerObject()->onContainerChildGainItem(item, source, transferer); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setLoadCTSBank(bool isForCTS) -{ - m_loadCTSBank = isForCTS; -} - -// ---------------------------------------------------------------------- - -void ServerObject::setLoadCTSPackedHouses(bool isForCTS) -{ - m_loadCTSPackedHouses = isForCTS; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::getLoadCTSBank() const -{ - return m_loadCTSBank; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::getLoadCTSPackedHouses() const -{ - return m_loadCTSPackedHouses; -} - -// ---------------------------------------------------------------------- - -void ServerObject::packedHouseLoaded() -{ - // see if we have the objvar - if (getLoadCTSPackedHouses()) - { - if (getObjVars().hasItem("cts.packed_house_count")) - { - int count = 0; - if (getObjVars().getItem("cts.packed_house_count", count)) - { - --count; - if (count <= 0) - { - LOG("CustomerService", ("CharacterTransfer: all houses loaded, responding to connection server.")); - removeObjVarItem("cts.packed_house_count"); - - // tell the connection server. - Client * client = getClient(); - if (client && client->getConnection()) - { - GenericValueTypeMessage loadedMsg("PackedHousesLoaded", getNetworkId()); - client->getConnection()->send(loadedMsg, true); - } - } - else - { - LOG("CustomerService", ("CharacterTransfer: packed house is loaded, but we expect %d more.", count)); - setObjVarItem("cts.packed_house_count", count); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::setLoadWith(const NetworkId& id) -{ - m_loadWith = id; -} - -//----------------------------------------------------------------------- - -std::string ServerObject::getLogDescription(const NetworkId & id) -{ - std::string const result = getLogDescription(safe_cast(NetworkIdManager::getObjectById(id))); - if (result.empty()) - return id.getValueString(); - return result; -} - -//----------------------------------------------------------------------- - -std::string ServerObject::getLogDescription(const ServerObject * source) -{ - std::string desc = ""; - if(source) - { - desc += "NonPlayerObject "; - desc += Unicode::wideToNarrow(source->getObjectName()); - desc += "("; - desc += source->getNetworkId().getValueString(); - desc += ") "; - desc += source->getObjectTemplateName(); - } - return desc; -} - -//---------------------------------------------------------------------- - -void ServerObject::retrieveStoredObjectAttributes (AttributeVector & av) const -{ - typedef stdvector::fwd UnicodeStringVector; - - static UnicodeStringVector kv; - static UnicodeStringVector vv; - - kv.clear (); - vv.clear (); - - getObjVars ().getItem (objvar_item_attribute_keys, kv); - getObjVars ().getItem (objvar_item_attribute_values, vv); - - if (kv.size () == vv.size ()) - { - const size_t size = vv.size (); - - av.reserve (av.size () + kv.size ()); - - for (size_t i = 0; i < size; ++i) - { - const std::string & key = Unicode::wideToNarrow (kv [i]); - const Unicode::String & value = vv [i]; - - av.push_back (std::make_pair (key, value)); - } - } -} - -//---------------------------------------------------------------------- - -void ServerObject::storeObjectAttributes (const ServerObject & prototype) -{ - typedef stdvector::fwd UnicodeStringVector; - - static UnicodeStringVector kv; - static UnicodeStringVector vv; - static AttributeVector av; - - av.clear (); - kv.clear (); - vv.clear (); - - prototype.getAttributes (NetworkId::cms_invalid, av); - - kv.reserve (av.size()); - vv.reserve (av.size()); - - for (AttributeVector::const_iterator it = av.begin (); it != av.end (); ++it) - { - const std::string & key = (*it).first; - const Unicode::String & value = (*it).second; - - kv.push_back (Unicode::narrowToWide (key)); - vv.push_back (value); - } - - setObjVarItem (objvar_item_attribute_keys, kv); - setObjVarItem (objvar_item_attribute_values, vv); -} - -//---------------------------------------------------------------------- - -void ServerObject::clearStoredObjectAttributes () -{ - m_objVars.removeItemByName (objvar_item_attribute_keys); - m_objVars.removeItemByName (objvar_item_attribute_values); -} - -//---------------------------------------------------------------------- - -void ServerObject::replaceStoredObjectAttribute(Unicode::String const & attribute, Unicode::String const & value) -{ - typedef stdvector::fwd UnicodeStringVector; - - static UnicodeStringVector kv; - static UnicodeStringVector vv; - - kv.clear (); - vv.clear (); - - getObjVars ().getItem (objvar_item_attribute_keys, kv); - getObjVars ().getItem (objvar_item_attribute_values, vv); - - if (kv.size () == vv.size ()) - { - const size_t size = vv.size (); - for (size_t i = 0; i < size; ++i) - { - if (kv [i] == attribute) - { - vv [i] = value; - setObjVarItem (objvar_item_attribute_values, vv); - - break; - } - } - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::setInitialized(bool initialized) -{ - setLocalFlag(LocalObjectFlags::ServerObject_Initialized, initialized); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setBeingDestroyed(bool beingDestroyed) -{ - setLocalFlag(LocalObjectFlags::ServerObject_BeingDestroyed, beingDestroyed); - - // set corresponding flag in script - if (beingDestroyed && isAuthoritative() && getScriptObject()) - getScriptObject()->setOwnerDestroyed(); - - // stop listening to broadcast messages - if (beingDestroyed && isAuthoritative()) - stopListeningToAllBroadcastMessages(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setPlacing(bool placing) -{ - setLocalFlag(LocalObjectFlags::ServerObject_Placing, placing); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setUnloading(bool unloading) -{ - setLocalFlag(LocalObjectFlags::ServerObject_Unloading, unloading); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setGoingToConclude(bool goingToConclude) -{ - setLocalFlag(LocalObjectFlags::ServerObject_GoingToConclude, goingToConclude); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setInEndBaselines(bool inEndBaselines) -{ - setLocalFlag(LocalObjectFlags::ServerObject_InEndBaselines, inEndBaselines); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setNeedsPobFixup(bool needsFixup) -{ - setLocalFlag(LocalObjectFlags::ServerObject_NeedsPobFixup, needsFixup); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isInitialized() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_Initialized); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isPlacing() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_Placing); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isUnloading() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_Unloading); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isBeingDestroyed() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_BeingDestroyed); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isGoingToConclude() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_GoingToConclude); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isInEndBaselines() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_InEndBaselines); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isNeedingPobFixup() const -{ - return getLocalFlag(LocalObjectFlags::ServerObject_NeedsPobFixup); -} - -// ---------------------------------------------------------------------- - -float ServerObject::getLocationReservationRadius() const -{ - return getSharedTemplate() ? getSharedTemplate()->getLocationReservationRadius() : 0.f; -} - -// ---------------------------------------------------------------------- - -void ServerObject::sendDirtyObjectMenuNotification() -{ - if (getLocalFlag(LocalObjectFlags::ServerObject_DirtyObjectMenuSent)) - return; - setLocalFlag(LocalObjectFlags::ServerObject_DirtyObjectMenuSent, true); - - Controller * const controller = getController(); - if (controller) - controller->appendMessage(CM_objectMenuDirty, 0, NULL, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); -} - -// ---------------------------------------------------------------------- - -void ServerObject::sendDirtyAttributesNotification() -{ - if (getLocalFlag(LocalObjectFlags::ServerObject_DirtyAttributesSent)) - return; - setLocalFlag(LocalObjectFlags::ServerObject_DirtyAttributesSent, true); - - Controller * const controller = getController(); - if (controller) - controller->appendMessage(CM_attributesDirty, 0, NULL, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::setBuildingUpdateRadiusMultiplier(float m) -{ - if (m <= 0) - { - ms_buildingUpdateRadiusMultiplier = 1.0f; - DEBUG_WARNING(true, ("Building Update Radius Multiplier was set to a value (%f) <= 0", m)); - } - else - ms_buildingUpdateRadiusMultiplier = m; - -} - -// ---------------------------------------------------------------------- - -void ServerObject::triggerMadeAuthoritative() -{ - std::vector trigObjs; - getPlayerControlledContents(*this, trigObjs); - for (std::vector::const_iterator i = trigObjs.begin(); i != trigObjs.end(); ++i) - { - ServerObject *trigObj = safe_cast((*i).getObject()); - if (trigObj && trigObj->isAuthoritative()) - { - ScriptParams params; - IGNORE_RETURN(trigObj->getScriptObject()->trigAllScripts(Scripting::TRIG_MADE_AUTHORITATIVE, params)); - } - } -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::setLayer(TerrainGenerator::Layer* layer) -{ - LayerProperty * layerProperty = NULL; - Property * property = getProperty(LayerProperty::getClassPropertyId()); - if (property != NULL) - layerProperty = safe_cast(property); - else - layerProperty = new LayerProperty(*this); - - layerProperty->setLayer(layer); - if (property == NULL) - { - addProperty(*layerProperty, true); - ObjectTracker::addRunTimeRule(); - addNotification (ServerObjectTerrainModificationNotification::getInstance ()); - } -} - -//------------------------------------------------------------------------------------------ - -TerrainGenerator::Layer* ServerObject::getLayer() const -{ - const Property * property = getProperty(LayerProperty::getClassPropertyId()); - if (property != NULL) - { - const LayerProperty * layerProperty = safe_cast(property); - return layerProperty->getLayer(); - } - return NULL; -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const -{ - if(name == "complexity") - { - m_complexity.pack(target); - } - else if(name == "bankBalance") - { - m_bankBalance.pack(target); - } -} - -//------------------------------------------------------------------------------------------ - -void ServerObject::setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source) -{ - Archive::ReadIterator ri(source); - if(name == "complexity") - { - m_complexity.unpackDelta(ri); - } - else if(name == "bankBalance") - { - m_bankBalance.unpackDelta(ri); - } - addObjectToConcludeList(); -} - -// ---------------------------------------------------------------------- - -/** - * Deliver a MessageTo to this object. If the object is not - * authoritative, send the message to the authoritative server. - * If the MessageTo's time has expired, handle it. If not, enqueue it - * for later. - */ -void ServerObject::deliverMessageTo(MessageToPayload & message) -{ - PROFILER_AUTO_BLOCK_DEFINE("ServerObject::deliverMessageTo"); - - if (message.getRecurringTime() != 0) - { - // Recurring messages can have only one instance each. Ignore - // this message if there is already a recurring one with the same method name. - for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) - { - if ((i->second.getRecurringTime() != 0) && (i->second.getMethod() == message.getMethod())) - return; - } - } - - if (isAuthoritative()) - { - if (message.getCallTime() <= MessageToQueue::getInstance().getEffectiveMessageToTime()) - { - // Message is already due, handle it right away - handleMessageTo(message); - } - else - { - if (isPersisted() && message.getGuaranteed() && !message.getPersisted()) - { - // Message is guaranteed. Since it's being delayed, make sure the DB saves it - // in case of a server crash - message.setPersisted(true); - MessageToMessage const msg(message, GameServer::getInstance().getProcessId()); - GameServer::getInstance().sendToDatabaseServer(msg); - } - if (m_messageTos.empty() || message.getCallTime() < m_messageTos.begin()->second.getCallTime()) - MessageToQueue::getInstance().addToScheduler(*this, message.getCallTime()); - pushMessageTo(message); - } - } - else - { - message.addBounceServer(GameServer::getInstance().getProcessId()); - ServerMessageForwarding::begin(getAuthServerProcessId()); - ServerMessageForwarding::send(MessageToMessage(message, GameServer::getInstance().getProcessId())); - ServerMessageForwarding::end(); - } -} - -// ---------------------------------------------------------------------- - -/** - * Add a MessageTo to the sorted vector of pending messages - * - * Does a binary search to find the appropriate insertion point. - */ -void ServerObject::pushMessageTo(MessageToPayload const & newMessage) -{ - m_messageTos.set(std::make_pair(std::make_pair(newMessage.getCallTime(), newMessage.getCounterMessageToPayload()), newMessage.getMessageId()), newMessage); -} - -// ---------------------------------------------------------------------- - -int ServerObject::cancelMessageTo(std::string const & messageName) -{ - int removeCount; - - if (isAuthoritative()) - { - removeCount = 0; - - for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end();) - { - if ((i->second.getMethod() == messageName) && (i->first != s_currentMessageToBeingHandled)) - { - i = m_messageTos.erase(i); - ++removeCount; - } - else - ++i; - } - } - else - { - sendControllerMessageToAuthServer( - CM_cancelMessageTo, - new MessageQueueGenericValueType(messageName)); - - // -1 means request has been forward to authoritative server for processing - removeCount = -1; - } - - return removeCount; -} - -// ---------------------------------------------------------------------- - -int ServerObject::cancelMessageToByMessageId(NetworkId const & messageId) -{ - int removeCount; - - if (isAuthoritative()) - { - removeCount = 0; - - for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end();) - { - if ((i->second.getMessageId() == messageId) && (i->first != s_currentMessageToBeingHandled)) - { - i = m_messageTos.erase(i); - ++removeCount; - break; - } - else - ++i; - } - } - else - { - sendControllerMessageToAuthServer( - CM_cancelMessageTo, - new MessageQueueGenericValueType(messageId.getValueString())); - - // -1 means request has been forward to authoritative server for processing - removeCount = -1; - } - - return removeCount; -} - -// ---------------------------------------------------------------------- -// returns the number of seconds until the messageTo fires, which *CAN* be 0 -// returns -1 if object doesn't have the messageTo -int ServerObject::timeUntilMessageTo(std::string const & messageName) const -{ - for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) - { - if (i->second.getMethod() == messageName) - { - if ((i->first != s_currentMessageToBeingHandled) || (i->second.getRecurringTime() > 0)) - { - unsigned long const now = ServerClock::getInstance().getGameTimeSeconds(); - unsigned long const callTime = i->second.getCallTime(); - if (callTime > now) - return static_cast(callTime - now); - - return 0; - } - } - } - - return -1; // doesn't have the messageTo -} - -// ---------------------------------------------------------------------- - -/** - * Sets the root node for a patrol path node. - * - * @param root the root node - * - * NOTE: Does not work multiserver! - */ -void ServerObject::setPatrolPathRoot(const ServerObject & root) -{ - if (!isAuthoritative()) - { - WARNING(true, ("ServerObject::setPatrolPathRoot called on non-authoritative object %s for %s", - getNetworkId().getValueString().c_str(), root.getNetworkId().getValueString().c_str())); - return; - } - - // make sure we aren't already a root node - Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); - if (p != NULL) - { - if (root.getNetworkId() != getNetworkId()) - { - WARNING(true, ("ServerObject::setPatrolPathRoot trying to set root node %s on node %s that is already a root", - root.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); - } - return; - } - - // see if we are going to be the root node - if (root.getNetworkId() == getNetworkId()) - { - p = new PatrolPathRootProperty(*this); - addProperty(*p, true); - } - else - { - // add the root node to our node list - p = getProperty(PatrolPathNodeProperty::getClassPropertyId()); - if (p == NULL) - { - p = new PatrolPathNodeProperty(*this); - addProperty(*p, true); - } - else if (safe_cast(p)->hasRoot(root)) - return; - safe_cast(p)->addRoot(root); - - if (!root.isPatrolPathRoot()) - { - // the root has not been set up, do it now - WARNING(true, ("ServerObject::setPatrolPathRoot for node %s: root node %s was not initialized, doing it now (THIS SHOULD NEVER HAPPEN)", - getNetworkId().getValueString().c_str(), root.getNetworkId().getValueString().c_str())); - const_cast(root).setPatrolPathRoot(root); - } - } - - // we need to add any players in range to our path observer count - TriggerVolume * triggerVolume = getNetworkTriggerVolume(); - if (triggerVolume != NULL) - { - TriggerVolume::ContentsSet const & contents = triggerVolume->getContents(); - for (TriggerVolume::ContentsSet::const_iterator i = contents.begin(); i != contents.end(); ++i) - { - if (*i != NULL) - { - Client * client = (*i)->getClient(); - if (client != NULL) - { - if (!ObserveTracker::isObserving(*client, *this)) - ObserveTracker::onClientEnteredNetworkTriggerVolume(*client, *triggerVolume); - else - { - // note: we call addPatrolPathObserver() on the root instead of us so - // that we don't update the count of any paths we already belong to - const_cast(root).addPatrolPathObserver(); - } - } - } - } - } -} // ServerObject::setPatrolPathRoot - -// ---------------------------------------------------------------------- - -/** - * Returns the root node for a patrol path node. - * - * @return the root node, or NULL if this isn't a patrol path node - */ -const std::set & ServerObject::getPatrolPathRoots() const -{ -static const std::set noRoots; - - const Property * p = getProperty(PatrolPathNodeProperty::getClassPropertyId()); - if (p != NULL) - { - return safe_cast(p)->getRoots(); - } - return noRoots; -} // ServerObject::getPatrolPathRoot - -// ---------------------------------------------------------------------- - -/** - * Adds an object that is moving along a patrol path where this object is the - * root node. If our path goes from being unobserved to observed, all the objects - * using this path will be scheduled for alter. - * - * @param ai the object that's on our path - * - * NOTE: Does not work multiserver! - */ -void ServerObject::addPatrolPathingObject(const ServerObject & ai) -{ - if (!isAuthoritative()) - { - WARNING(true, ("ServerObject::addPatrolPathingObject called on non-authoritative object %s for %s", - getNetworkId().getValueString().c_str(), ai.getNetworkId().getValueString().c_str())); - return; - } - - Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); - if (p != NULL) - { - safe_cast(p)->addPatrollingObject(ai); - DEBUG_REPORT_LOG(true, ("[patrolpath] add patrol ai %s to root %s\n", - ai.getNetworkId().getValueString().c_str(), - getNetworkId().getValueString().c_str())); - } - else - { - // if we are not a root, try to add the ai to our root (but only do so if we have - // one root) - DEBUG_WARNING(true, ("ServerObject::addPatrolPathingObject trying to add an ai %s to a non-root path node %s, going to use our root", - ai.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); - const std::set & roots = getPatrolPathRoots(); - if (roots.size() == 1) - { - ServerObject * root = safe_cast(roots.begin()->getObject()); - if (root != NULL) - root->addPatrolPathingObject(ai); - } - else - { - WARNING(true, ("ServerObject::addPatrolPathingObject trying to add an ai %s to a non-root path node %s which has muliple roots.", - ai.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); - } - } -} // ServerObject::addPatrolPathingObject - -// ---------------------------------------------------------------------- - -/** - * Removes an object that is moving along our patrol path. - * - * @param ai the object to remove - * - * NOTE: Does not work multiserver! - */ -void ServerObject::removePatrolPathingObject(const ServerObject & ai) -{ - if (!isAuthoritative()) - { - WARNING(true, ("ServerObject::removePatrolPathingObject called on non-authoritative object %s for %s", - getNetworkId().getValueString().c_str(), ai.getNetworkId().getValueString().c_str())); - return; - } - - Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); - if (p != NULL) - { - safe_cast(p)->removePatrollingObject(ai); - DEBUG_REPORT_LOG(true, ("[patrolpath] remove patrol ai %s from root %s\n", - ai.getNetworkId().getValueString().c_str(), - getNetworkId().getValueString().c_str())); - } - else - { - // if we are not a root, try to remove the ai to our root (but only do so if we have - // one root) - const std::set & roots = getPatrolPathRoots(); - if (roots.size() == 1) - { - ServerObject * root = safe_cast(roots.begin()->getObject()); - if (root != NULL) - root->removePatrolPathingObject(ai); - } - else - { - WARNING(true, ("ServerObject::removePatrolPathingObject trying to remove an ai %s from a non-root path node %s which has muliple roots.", - ai.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); - } - } -} // ServerObject::removePatrolPathingObject - -// ---------------------------------------------------------------------- - -/** - * Increments the observer count for this patrol path. If this is the first observer, - * schedules any patrolling objects for alter. - * - * NOTE: Does not work multiserver! - */ -void ServerObject::addPatrolPathObserver() -{ - if (!isAuthoritative()) - { - WARNING(true, ("ServerObject::addPatrolPathObserver called on non-authoritative object %s", - getNetworkId().getValueString().c_str())); - return; - } - - // if we are a root node, increment our observer count - Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); - if (p != NULL) - { - PatrolPathRootProperty * pprp = safe_cast(p); - pprp->incrementObserverCount(); - DEBUG_REPORT_LOG(true, ("[patrolpath] add observer to %s, count = %d\n", - getNetworkId().getValueString().c_str(), pprp->getObserverCount())); - if (pprp->getObserverCount() == 1) - { - // we need to wake up hibernating ai - const std::set > & ai = pprp->getPatrollingObjects(); - for (std::set >::const_iterator i = ai.begin(); i != ai.end(); ++i) - { - if (*i != NULL) - { - const ServerObject * ai = *i; - if (ai->getController()->asCreatureController() != NULL) - { - const CreatureController * controller = ai->getController()->asCreatureController(); - if (controller->getHibernate()) - { - DEBUG_REPORT_LOG(true, ("[patrolpath] path root %s waking up ai %s", - getNetworkId().getValueString().c_str(), - ai->getNetworkId().getValueString().c_str())); - const_cast(ai)->scheduleForAlter(); - } - } - } - } - } - } - else - { - // increment the count of the root nodes of any paths we belong to - const std::set & roots = getPatrolPathRoots(); - for (std::set::const_iterator i = roots.begin(); i != roots.end(); ++i) - { - ServerObject * root = safe_cast(i->getObject()); - if (root != NULL) - { - root->addPatrolPathObserver(); - } - } - } -} // ServerObject::addPatrolPathObserver - -// ---------------------------------------------------------------------- - -/** - * Decrements the observer count for this patrol path. - * - * NOTE: Does not work multiserver! - */ -void ServerObject::removePatrolPathObserver() -{ - if (!isAuthoritative()) - { - WARNING(true, ("ServerObject::removePatrolPathObserver called on non-authoritative object %s", - getNetworkId().getValueString().c_str())); - return; - } - - // if we are a root node, decrement our observer count - Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); - if (p != NULL) - { - PatrolPathRootProperty * pprp = safe_cast(p); - pprp->decrementObserverCount(); - DEBUG_REPORT_LOG(true, ("[patrolpath] remove observer from %s, count = %d\n", - getNetworkId().getValueString().c_str(), pprp->getObserverCount())); - if (pprp->getObserverCount() < 0) - { - WARNING(true, ("ServerObject::removePatrolPathObserver %s has negative patrol path observer count of %d", - getNetworkId().getValueString().c_str(), pprp->getObserverCount())); - } - } - else - { - // decrement the count of the root nodes of any paths we belong to - const std::set & roots = getPatrolPathRoots(); - for (std::set::const_iterator i = roots.begin(); i != roots.end(); ++i) - { - ServerObject * root = safe_cast(i->getObject()); - if (root != NULL) - { - root->removePatrolPathObserver(); - } - } - } -} // ServerObject::removePatrolPathObserver - -// ---------------------------------------------------------------------- - -/** - * Returns the number of observers of this patrol path. If this node connects to multiple - * roots, we will return the total for all paths it connects to. - * - * @return the observer count - */ -int ServerObject::getPatrolPathObservers() const -{ - int observers = 0; - - const Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); - if (p != NULL) - { - observers = safe_cast(p)->getObserverCount(); - } - else - { - const std::set & roots = getPatrolPathRoots(); - for (std::set::const_iterator i = roots.begin(); i != roots.end(); ++i) - { - const ServerObject * root = safe_cast(i->getObject()); - if (root != NULL && root->isPatrolPathRoot()) - { - observers += root->getPatrolPathObservers(); - } - } - } - return observers; -} // ServerObject::getPatrolPathObservers - -// ---------------------------------------------------------------------- - -bool ServerObject::isPatrolPathNode() const -{ - return (getProperty(PatrolPathNodeProperty::getClassPropertyId()) != NULL) || isPatrolPathRoot(); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::isPatrolPathRoot() const -{ - return getProperty(PatrolPathRootProperty::getClassPropertyId()) != NULL; -} - -// ---------------------------------------------------------------------- - -bool ServerObject::hasAttributeCaching() const -{ - // rls - if attribute caching breaks for an object, you can disable - // caching by returning false here. - return true; -} - -// ---------------------------------------------------------------------- - -int ServerObject::getAttributeRevision() const -{ - return m_objVars.getRevision(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setAttributeRevisionDirty() -{ - m_objVars.updateRevision(); -} - -// ---------------------------------------------------------------------- - -bool ServerObject::getIncludeInBuildout() const -{ - return m_includeInBuildout.get(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::setIncludeInBuildout( bool value ) -{ - m_includeInBuildout = value; -} - -// ---------------------------------------------------------------------- - -void ServerObject::setDescriptionStringId(const StringId & id) -{ - m_descriptionStringId.set(id); -} - -// ---------------------------------------------------------------------- - -StringId const & ServerObject::getDescriptionStringId() -{ - return m_descriptionStringId.get(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::addBroadcastListener(std::string const & messageName, NetworkId const & listener) -{ - if (!isAuthoritative()) - return; - - m_broadcastListeners.insert(std::make_pair(messageName, listener)); -} - -// ---------------------------------------------------------------------- - -void ServerObject::removeBroadcastListener(std::string const & messageName, NetworkId const & listener) -{ - if (!isAuthoritative()) - return; - - IGNORE_RETURN(m_broadcastListeners.erase(std::make_pair(messageName, listener))); -} - -// ---------------------------------------------------------------------- - -void ServerObject::removeBroadcastListener(NetworkId const & listener) -{ - if (!isAuthoritative()) - return; - - for (BroadcastMap::const_iterator iter = m_broadcastListeners.begin(); iter != m_broadcastListeners.end();) - { - if (iter->second == listener) - { - // AutoDeltaSet's erase() will increment iter to point to the next item - m_broadcastListeners.erase(iter); - } - else - { - ++iter; - } - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::addBroadcastBroadcaster(std::string const & messageName, NetworkId const & broadcaster) -{ - if (!isAuthoritative()) - return; - - m_broadcastBroadcasters.insert(std::make_pair(messageName, broadcaster)); -} - -// ---------------------------------------------------------------------- - -void ServerObject::removeBroadcastBroadcaster(std::string const & messageName, NetworkId const & broadcaster) -{ - if (!isAuthoritative()) - return; - - IGNORE_RETURN(m_broadcastBroadcasters.erase(std::make_pair(messageName, broadcaster))); -} - -// ---------------------------------------------------------------------- - -void ServerObject::removeBroadcastAllBroadcasters() -{ - if (!isAuthoritative()) - return; - - m_broadcastBroadcasters.clear(); -} - -// ---------------------------------------------------------------------- - -void ServerObject::listenToBroadcastMessage(std::string const & messageName, NetworkId const & broadcaster) -{ - if (messageName.empty() || !broadcaster.isValid()) - return; - - if (!isAuthoritative()) - { - char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), broadcaster.getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++listenToBroadcastMessage", buffer, 0, false); - } - else - { - // need to send a message to the broadcaster if the broadcaster is not on this game server - ServerObject * objBroadcaster = ServerWorld::findObjectByNetworkId(broadcaster); - if (objBroadcaster && objBroadcaster->isAuthoritative()) - { - // tell broadcaster that I want to listen - objBroadcaster->addBroadcastListener(messageName, getNetworkId()); - } - else - { - char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), getNetworkId().getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - MessageToQueue::getInstance().sendMessageToC(broadcaster, "C++addBroadcastListener", buffer, 0, false); - } - - // this object is now listening to the broadcaster - // @TODO: technically, we should have the remote broadcaster - // send a message back confirming that this object has - // been added to the broadcaster's listener list before - // we mark this object as listening to the broadcaster - addBroadcastBroadcaster(messageName, broadcaster); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::stopListeningToBroadcastMessage(std::string const & messageName, NetworkId const & broadcaster) -{ - if (messageName.empty() || !broadcaster.isValid()) - return; - - if (!isAuthoritative()) - { - char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), broadcaster.getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++stopListeningToBroadcastMessage", buffer, 0, false); - } - else - { - // need to send a message to the broadcaster if the broadcaster is not on this game server - ServerObject * objBroadcaster = ServerWorld::findObjectByNetworkId(broadcaster); - if (objBroadcaster && objBroadcaster->isAuthoritative()) - { - // tell broadcaster that I no longer want to listen - objBroadcaster->removeBroadcastListener(messageName, getNetworkId()); - } - else - { - char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), getNetworkId().getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - MessageToQueue::getInstance().sendMessageToC(broadcaster, "C++removeBroadcastListener", buffer, 0, false); - } - - // this object is no longer listening to the broadcaster - // @TODO: technically, we should have the remote broadcaster - // send a message back confirming that this object has - // been removed from the broadcaster's listener list before - // we mark this object as no longer listening to the broadcaster - removeBroadcastBroadcaster(messageName, broadcaster); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::stopListeningToAllBroadcastMessages() -{ - if (!isAuthoritative()) - { - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++stopListeningToAllBroadcastMessage", "", 0, false); - } - else - { - // build list of all broadcasters this object is currently listening to - std::unordered_set broadcasters; - for (BroadcastMap::const_iterator iter = m_broadcastBroadcasters.begin(); iter != m_broadcastBroadcasters.end(); ++iter) - IGNORE_RETURN(broadcasters.insert(iter->second)); - - for (std::unordered_set::const_iterator iter2 = broadcasters.begin(); iter2 != broadcasters.end(); ++iter2) - { - // need to send a message to the broadcaster if the broadcaster is not on this game server - ServerObject * objBroadcaster = ServerWorld::findObjectByNetworkId(*iter2); - if (objBroadcaster && objBroadcaster->isAuthoritative()) - { - // tell broadcaster that I no longer want to listen - objBroadcaster->removeBroadcastListener(getNetworkId()); - } - else - { - char buffer[128]; - snprintf(buffer, sizeof(buffer)-1, "%s", getNetworkId().getValueString().c_str()); - buffer[sizeof(buffer)-1] = '\0'; - MessageToQueue::getInstance().sendMessageToC(*iter2, "C++removeBroadcastListenerAllMessage", buffer, 0, false); - } - } - - // this object is no longer listening to any broadcasters - // @TODO: technically, we should have the remote broadcaster - // send a message back confirming that this object has - // been removed from the broadcaster's listener list before - // we mark this object as no longer listening to the broadcaster - removeBroadcastAllBroadcasters(); - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::addObserver(Client * client) -{ - std::pair::const_iterator, bool> result = m_observers.insert(client); - - if (result.second) - { - if (isAuthoritative()) - { - m_observersCount = m_observersCount.get() + 1; - } - else - { - sendControllerMessageToAuthServer(CM_updateObserversCount, new MessageQueueGenericValueType(1)); - } - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::removeObserver(Client * client) -{ - int erased = m_observers.erase(client); - - if (erased > 0) - { - if (isAuthoritative()) - { - m_observersCount = m_observersCount.get() - erased; - if (m_observersCount.get() < 0) - { - WARNING(true, ("ServerObject::removeObserver for object %s has observer count of %d", getNetworkId().getValueString().c_str(), m_observersCount.get())); - m_observersCount = 0; - } - } - else - { - sendControllerMessageToAuthServer(CM_updateObserversCount, new MessageQueueGenericValueType(-erased)); - } - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::clearObservers() -{ - int erased = m_observers.size(); - m_observers.clear(); - - if (erased > 0) - { - if (isAuthoritative()) - { - m_observersCount = m_observersCount.get() - erased; - if (m_observersCount.get() < 0) - { - WARNING(true, ("ServerObject::clearObservers for object %s has observer count of %d", getNetworkId().getValueString().c_str(), m_observersCount.get())); - m_observersCount = 0; - } - } - else - { - // if we aren't being deleted, send a controller message, otherwise send a messageTo - if (!getKill()) - sendControllerMessageToAuthServer(CM_updateObserversCount, new MessageQueueGenericValueType(-erased)); - else - { - char buffer[32]; - _itoa(-erased, buffer, 10); - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++updateObserversCount", buffer, 0, false); - } - } - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::clearObserversCount() -{ - if (isAuthoritative()) - { - m_observersCount = 0; - } -} - -// ---------------------------------------------------------------------- - -void ServerObject::updateObserversCount(int delta) -{ - if (isAuthoritative()) - { - m_observersCount = m_observersCount.get() + delta; - if (m_observersCount.get() < 0) - { - WARNING(m_observersCount.get() < 0, ("ServerObject::updateObserversCount for object %s has observer count of %d", getNetworkId().getValueString().c_str(), m_observersCount.get())); - m_observersCount = 0; - } - } -} - -// ---------------------------------------------------------------------- - -/** - * Do nothing; this function is base virtual function so that creatures can go - * in and out of hibernation when observed. - */ -void ServerObject::observersCountChanged() -{ -} - -// ====================================================================== - -namespace Archive -{ - void put(Archive::ByteStream &target, TriggerVolumeInfo const &source) - { - put(target, source.name); - put(target, source.radius); - put(target, source.isPromiscuous); - } - - void get(Archive::ReadIterator &source, TriggerVolumeInfo &target) - { - get(source, target.name); - get(source, target.radius); - get(source, target.isPromiscuous); - } -} - -// ====================================================================== - +// ====================================================================== +// +//ServerObject.cpp +// +//Copyright 2000-2003 Sony Online Entertainment +// +// ====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/ServerObject.h" + +#include "UnicodeUtils.h" +#include "serverGame/AuthTransferTracker.h" +#include "serverGame/BuildingObject.h" +#include "serverGame/CellObject.h" +#include "serverGame/Chat.h" +#include "serverGame/Client.h" +#include "serverGame/CommoditiesMarket.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ConnectionServerConnection.h" +#include "serverGame/ConsoleManager.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/ContainmentMessageManager.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/DistributionListStack.h" +#include "serverGame/GameServer.h" +#include "serverGame/InstantDeleteList.h" +#include "serverGame/IntangibleVolumeContainer.h" +#include "serverGame/LineOfSightCache.h" +#include "serverGame/LogoutTracker.h" +#include "serverGame/MessageToQueue.h" +#include "serverGame/NetworkTriggerVolume.h" +#include "serverGame/NewbieTutorial.h" +#include "serverGame/ObjectIdManager.h" +#include "serverGame/ObjectTracker.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PatrolPathNodeProperty.h" +#include "serverGame/PatrolPathRootProperty.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerQuestObject.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/PlayerSanityChecker.h" +#include "serverGame/PlayerShipController.h" +#include "serverGame/PositionUpdateTracker.h" +#include "serverGame/ResourceContainerObject.h" +#include "serverGame/ServerClearCollidableFloraNotification.h" +#include "serverGame/ServerController.h" +#include "serverGame/ServerCreatureObjectTemplate.h" +#include "serverGame/ServerMessageForwarding.h" +#include "serverGame/ServerNoBuildNotification.h" +#include "serverGame/ServerObjectTemplate.h" +#include "serverGame/ServerObjectTerrainModificationNotification.h" +#include "serverGame/ServerResourceContainerObjectTemplate.h" +#include "serverGame/ServerSecureTrade.h" +#include "serverGame/ServerSynchronizedUi.h" +#include "serverGame/ServerUIManager.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/SpaceVisibilityManager.h" +#include "serverGame/SceneGlobalData.h" +#include "serverGame/TangibleObject.h" +#include "serverGame/TangibleVolumeContainer.h" +#include "serverGame/TeleportFixupHandler.h" +#include "serverGame/TriggerVolume.h" +#include "serverGame/VeteranRewardManager.h" +#include "serverNetworkMessages/AccountFeatureIdRequest.h" +#include "serverNetworkMessages/AdjustAccountFeatureIdResponse.h" +#include "serverNetworkMessages/FlagObjectForDeleteMessage.h" +#include "serverNetworkMessages/GameConnectionServerMessages.h" +#include "serverNetworkMessages/LoadContainedObjectMessage.h" +#include "serverNetworkMessages/LoadContentsMessage.h" +#include "serverNetworkMessages/MessageQueueTeleportObject.h" +#include "serverNetworkMessages/MessageToAckMessage.h" +#include "serverNetworkMessages/MessageToMessage.h" +#include "serverNetworkMessages/MessageToPayload.h" +#include "serverNetworkMessages/UnloadObjectMessage.h" +#include "serverPathfinding/ServerPathfindingConstants.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptParameters.h" +#include "serverUtility/ChatLogManager.h" +#include "serverUtility/ServerClock.h" +#include "Session/CommonAPI/CommonAPI.h" +#include "sharedCollision/BaseExtent.h" +#include "sharedCollision/CollisionProperty.h" +#include "sharedCollision/CollisionWorld.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/DynamicVariableLocationData.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedFoundation/Os.h" +#include "sharedGame/LfgCharacterData.h" +#include "sharedGame/PlatformFeatureBits.h" +#include "sharedGame/ProsePackage.h" +#include "sharedGame/QuestManager.h" +#include "sharedGame/SharedObjectTemplate.h" +#include "sharedGame/SharedStringIds.h" +#include "sharedGame/SocialsManager.h" +#include "sharedGame/SpatialChatManager.h" +#include "sharedLog/Log.h" +#include "sharedMathArchive/TransformArchive.h" +#include "sharedMessageDispatch/Message.h" +#include "sharedMessageDispatch/Transceiver.h" +#include "sharedNetworkMessages/AIDebuggingMessages.h" +#include "sharedNetworkMessages/ChatAvatarId.h" +#include "sharedNetworkMessages/CommandChannelMessages.h" +#include "sharedNetworkMessages/DeltasMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/LogoutMessage.h" +#include "sharedNetworkMessages/MessageQueueCombatSpam.h" +#include "sharedNetworkMessages/MessageQueueDataTransform.h" +#include "sharedNetworkMessages/MessageQueueDataTransformWithParent.h" +#include "sharedNetworkMessages/MessageQueueGeneric.h" +#include "sharedNetworkMessages/MessageQueueGenericValueType.h" +#include "sharedNetworkMessages/MessageQueueNetworkIdAndTransform.h" +#include "sharedNetworkMessages/MessageQueueSocial.h" +#include "sharedNetworkMessages/MessageQueueSpatialChat.h" +#include "sharedNetworkMessages/ObjectChannelMessages.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/AlterScheduler.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/ArrangementDescriptor.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Container.h" +#include "sharedObject/CustomizationData.h" +#include "sharedObject/CustomizationDataProperty.h" +#include "sharedObject/LayerProperty.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/PortalProperty.h" +#include "sharedObject/RangedIntCustomizationVariable.h" +#include "sharedObject/SlotDescriptor.h" +#include "sharedObject/SlotDescriptorList.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedObject/SlottedContainmentProperty.h" +#include "sharedObject/VolumeContainmentProperty.h" +#include "sharedTerrain/TerrainObject.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" +#include "swgServerNetworkMessages/MessageQueueScriptTransferMoney.h" +#include + +// ====================================================================== + +namespace DeleteReasons +{ + const std::string & describeDeleteReason(const int reason) + { + switch(reason) + { + case NotDeleted: + { + static const std::string r = "NotDeleted"; + return r; + } + break; + case Decay: + { + static const std::string r = "Decay"; + return r; + } + break; + case God: + { + static const std::string r = "God"; + return r; + } + break; + case Player: + { + static const std::string r = "Player"; + return r; + } + break; + case Script: + { + static const std::string r = "Script"; + return r; + } + break; + case CharacterDeleted: + { + static const std::string r = "CharacterDeleted"; + return r; + } + break; + case ContainerDeleted: + { + static const std::string r = "ContainerDeleted"; + return r; + } + break; + case Publish: + { + static const std::string r = "Publish"; + return r; + } + break; + case BadContainerTransfer: + { + static const std::string r = "BadContainerTransfer"; + return r; + } + break; + case Consumed: + { + static const std::string r = "Consumed"; + return r; + } + break; + case SetupFailed: + { + static const std::string r = "SetupFailed"; + return r; + } + break; + case Replaced: + { + static const std::string r = "Replaced"; + return r; + } + break; + } + static const std::string unknown = "UNKNOWN"; + return unknown; + } +} + +using namespace DeleteReasons; + +// ====================================================================== + +namespace ServerObjectNamespace +{ + const std::string OBJVAR_STRUCTURE_PLAYER_PACK("structure.player.pack"); + + const std::string OBJVAR_OPEN_BANK_TERMINAL_ID("open_bank_location"); + + unsigned long gs_objectCount = 0; + + const char * const portalPropertyCrcObjectVariableName = "portalProperty.crc"; + + // ---------------------------------------------------------------------- + + const std::string objvar_item_attribute_keys = "item_attrib_keys"; + const std::string objvar_item_attribute_values = "item_attrib_values"; + + // ---------------------------------------------------------------------- + + const uint32 s_clearLocalFlagsOnConcludeMask = + ~( + (1u<, MessageToId> s_currentMessageToBeingHandled = std::make_pair(std::make_pair(0, 0), MessageToId::cms_invalid); + + // ---------------------------------------------------------------------- + + // list of object types that supports no trade "shared" behavior + // (no trade item of those types can be picked up by another character + // on the same account as the character who currently owns the item) + std::set s_noTradeSharedTemplateItemType; + std::set s_noTradeSharedStaticItemType; + + // ---------------------------------------------------------------------- + + void sendDeleteToDatabase(const ServerObject& obj, int reason) + { + bool const immediate = InstantDeleteList::isOnList(*obj.getObjectTemplate()); + bool const cascadeDeleteReason = !obj.getLoadContents() && reason == DeleteReasons::House; // Anything that is deleted by house deletion and is demanded-loaded (i.e. cells) should have the delete reason of its contents set to DeleteReasons::House also, instead of DeleteReasons::ContainerDeleted. This is so the /restoreHouse command can identify these items + + FlagObjectForDeleteMessage const dm(obj.getNetworkId(), reason, immediate, !obj.getLoadContents(), cascadeDeleteReason); + GameServer::getInstance().sendToDatabaseServer(dm); + } + + //---------------------------------------------------------------------- + + void flagChildObjectsForDeletion(ServerObject &obj, int reason) + { + Container * const container = ContainerInterface::getContainer(obj); + if (container) + { + for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) + { + ServerObject * const containedObject = safe_cast((*containerIterator).getObject()); + if (containedObject && containedObject->isPersisted()) + { + sendDeleteToDatabase(*containedObject, reason); + LOG("CustomerService",("Deletion:%s deleted from game. Reason: %s", ServerObject::getLogDescription(containedObject).c_str(), describeDeleteReason(reason).c_str())); + flagChildObjectsForDeletion(*containedObject, reason); + } + } + } + } + + //---------------------------------------------------------------------- + + void endBaselinesInitializeScript(ServerObject& obj, bool doChildCheck) + { + if (doChildCheck) + { + ServerObject * parent = safe_cast(ContainerInterface::getContainedByObject(obj)); + if (parent && !parent->isInitialized()) + return; + } + + obj.getScriptObject()->initScriptInstances(); + obj.getScriptObject()->setOwnerIsInitialized(); + + Container* container = ContainerInterface::getContainer(obj); + if (container) + + { + std::vector initList; + + for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) + { + initList.push_back(*containerIterator); + } + for(std::vector::iterator i = initList.begin(); i != initList.end(); ++i) + { + ServerObject * containedObject = safe_cast((*i).getObject()); + if (!containedObject) + { + WARNING_STRICT_FATAL(true, ("Cannot initialize object %s because it did not resolve to an object from an id", (*i).getValueString().c_str())); + } + else + endBaselinesInitializeScript(*containedObject, false); + } + } + } + + //---------------------------------------------------------------------- + + const std::string OBJVAR_BANK_NAME_ID = "banking_bankid"; + + //---------------------------------------------------------------------- + + bool checkBankTransfer(ServerObject* dest, const ServerObject& item, const ServerObject* transferer) + { + if (!dest || !transferer) + return true; + + bool isBankTransfer = false; + const CreatureObject * const creature = transferer->asCreatureObject(); + if (creature && dest == creature->getBankContainer()) + { + float distance = 0.0f; + //Banks are carried along with the player, so their distance + //is always going to be 0. This block changes the parentInWorld + //to be the bank terminal that was opened rather than the bank + //itself. + const ServerObject * const bank = creature->getBankContainer(); + if (bank) + { + NetworkId bankTerminalId; + if (bank->areContentsLoaded() && creature->getObjVars().getItem(OBJVAR_OPEN_BANK_TERMINAL_ID,bankTerminalId)) + { + + const TangibleObject * const bankTerminal = safe_cast(NetworkIdManager::getObjectById(bankTerminalId)); + if (bankTerminal) + { + isBankTransfer = true; + Unicode::String bankName; + if (bankTerminal->getObjVars().getItem(OBJVAR_BANK_NAME_ID, bankName)) + { + if (!creature->isBankMember(bankName)) + { + return false; + } + } + + distance = creature->getPosition_w().magnitudeBetween(bankTerminal->getPosition_w()); + distance -= dest->getRadius(); + distance -= bankTerminal->getRadius(); + // Check range on the server with a 1m fudge factor in it. + if (distance > 6.0f + 1.0f) //todo MLS make that range of 6.0 configurable + { + static const StringId message("system_msg", "out_of_range"); + Chat::sendSystemMessage(*creature, message, Unicode::emptyString); + return false; + } + } + else + { + return false; + } + } + else + { + return false; + } + } + } + + return true; + + } + + //---------------------------------------------------------------------- + + void getPlayerControlledContents(ServerObject &obj, std::vector &results) + { + if (obj.isPlayerControlled()) + results.push_back(CachedNetworkId(obj)); + + Container *container = ContainerInterface::getContainer(obj); + if (container) + { + for (ContainerIterator i = container->begin(); i != container->end(); ++i) + { + ServerObject *containedObject = safe_cast((*i).getObject()); + if (containedObject) + getPlayerControlledContents(*containedObject, results); + } + } + } + + // ---------------------------------------------------------------------- + + void getContainedClients(ServerObject &obj, std::vector > &containedClients) + { + // find all clients for primary controlled objects in the containment hierarchy under obj (including obj) + + Client * const client = obj.getClient(); + if (client && client->getCharacterObjectId() == obj.getNetworkId()) + containedClients.push_back(Watcher(client)); + + Container * const container = ContainerInterface::getContainer(obj); + if (container) + { + for (ContainerIterator i = container->begin(); i != container->end(); ++i) + { + ServerObject * const containedObject = safe_cast((*i).getObject()); + if (containedObject) + getContainedClients(*containedObject, containedClients); + } + } + } + + // ---------------------------------------------------------------------- + + unsigned int getPackedObjVarField(std::string const &buf, unsigned int offset, std::string &result) + { + std::vector s; + while (offset < buf.size()) + { + if (buf[offset] == '|') + break; + s.push_back(buf[offset++]); + } + s.push_back('\0'); + result = &(s[0]); + return offset+1; + } + + // ---------------------------------------------------------------------- + + unsigned int getPackedObjVarField(std::string const &buf, unsigned int offset, int &result) + { + std::string s; + offset = getPackedObjVarField(buf, offset, s); + result = atoi(s.c_str()); + return offset; + } + + // ---------------------------------------------------------------------- + + void appendPackedObjVarField(std::vector &buf, char const *s) + { + while (*s) + { + if ((*s) != '|') + buf.push_back(*s); + ++s; + } + buf.push_back('|'); + } + + // ---------------------------------------------------------------------- + + void appendPackedObjVarField(std::vector &buf, int val) + { + char tempbuf[32]; + sprintf(tempbuf, "%d", val); + appendPackedObjVarField(buf, tempbuf); + } + + // ---------------------------------------------------------------------- + + void remove() + { + } +} + +using namespace ServerObjectNamespace; + +// ====================================================================== + +const SharedObjectTemplate * ServerObject::m_defaultSharedTemplate = NULL; +float ServerObject::ms_buildingUpdateRadiusMultiplier = 0; + +// ====================================================================== + +class ServerObject::PobFixupNotification : public ObjectNotification +{ +public: + PobFixupNotification(); + ~PobFixupNotification(); + + virtual void pobFixupComplete(Object &object) const; + +private: + PobFixupNotification(const PobFixupNotification & ); + PobFixupNotification& operator= (const PobFixupNotification&); +}; + +//------------------------------------------------------------------------------------------ + +ServerObject::PobFixupNotification::PobFixupNotification() : ObjectNotification() + { + } + +//------------------------------------------------------------------------------------------ + +ServerObject::PobFixupNotification::~PobFixupNotification() +{ +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::PobFixupNotification::pobFixupComplete(Object &object) const +{ + static_cast(&object)->onPobFixupComplete(); +// object.removeNotification(*this); +} + +//------------------------------------------------------------------------------------------ + +static ServerObject::PobFixupNotification pobFixupNotification; + +//------------------------------------------------------------------------------------------ + +class ServerObject::MoveNotification : public ObjectNotification +{ +public: + MoveNotification(); + ~MoveNotification(); + virtual void addToWorld(Object &object) const; + virtual void cellChanged(Object &object, bool dueToParentChange) const; + virtual bool positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + virtual void rotationChanged(Object &object, bool dueToParentChange) const; + virtual bool positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const; + virtual void visibilityDataChanged(Object &object) const; + +private: + void checkForGoldObject(const Object &object) const; + +private: + MoveNotification(const MoveNotification &); + MoveNotification & operator= (const MoveNotification &); +}; + +static ServerObject::MoveNotification moveNotification; + + +//------------------------------------------------------------------------------------------ +ServerObject::MoveNotification::MoveNotification() : + ObjectNotification() +{ + +} + +//------------------------------------------------------------------------------------------ + +ServerObject::MoveNotification::~MoveNotification() +{ + +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::MoveNotification::addToWorld(Object &object) const +{ + static_cast(object).updateWorldSphere(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::MoveNotification::checkForGoldObject(const Object &object) const +{ + if (ConfigServerGame::getMaxGoldNetworkId()!=NetworkId::cms_invalid && object.getNetworkId() < ConfigServerGame::getMaxGoldNetworkId()) + { + FATAL(ConfigServerGame::getFatalOnMovingGoldObject(),("Attempted to move object %s, which is a gold object that should not be movable.", object.getNetworkId().getValueString().c_str())); + WARNING(true,("Attempted to move object %s, which is a gold object that should not be movable.", object.getNetworkId().getValueString().c_str())); + } +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::MoveNotification::cellChanged(Object &object, bool dueToParentChange) const +{ + checkForGoldObject(object); + + static_cast(object).updateWorldSphere(); + if (!dueToParentChange) + { + DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing cells")); + static_cast(object).setTransformChanged(true); + } +} + +//------------------------------------------------------------------------------------------ + +bool ServerObject::MoveNotification::positionChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const +{ + checkForGoldObject(object); + + UNREF(oldPosition); + static_cast(object).updateWorldSphere(); + if (!dueToParentChange) + { + DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing position")); + static_cast(object).setTransformChanged(true); + } + return true; +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::MoveNotification::rotationChanged(Object &object, bool dueToParentChange) const +{ + checkForGoldObject(object); + + static_cast(object).updateWorldSphere(); + if (!dueToParentChange) + { + DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing rotation")); + static_cast(object).setTransformChanged(true); + } +} + +//------------------------------------------------------------------------------------------ + +bool ServerObject::MoveNotification::positionAndRotationChanged(Object &object, bool dueToParentChange, const Vector &oldPosition) const +{ + checkForGoldObject(object); + + UNREF(oldPosition); + static_cast(object).updateWorldSphere(); + if (!dueToParentChange) + { + DEBUG_FATAL(object.getCellProperty() && !object.getKill(), ("Cell object changing position and rotation")); + static_cast(object).setTransformChanged(true); + } + return true; +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::MoveNotification::visibilityDataChanged(Object &object) const +{ + static_cast(object).updateWorldSphere(); + static_cast(object).addObjectToConcludeList(); +} + +// ====================================================================== + +void ServerObject::AuthProcessIdCallback::modified(ServerObject &target, uint32 oldValue, uint32, bool) const +{ + AuthTransferTracker::sendConfirmAuthTransfer(target.getNetworkId(), oldValue); +} + +void ServerObject::ObserversCountCallback::modified(ServerObject &target, int oldValue, int, bool) const +{ + target.observersCountChanged(); +} + +// ====================================================================== + +ServerObject::ServerObject(const ServerObjectTemplate* newTemplate, const ObjectNotification ¬ification, bool const hyperspaceOnCreate) : +Object (newTemplate, NetworkId::cms_invalid), +m_oldPosition (), +m_sharedTemplate (NULL), +m_client (0), +m_observers (), +m_localFlags (0), +m_scriptObject (new GameScriptObject), +m_objVars (), +m_observersCount (0), +m_volume (newTemplate->getVolume()), +m_complexity (newTemplate->getComplexity()), +m_sceneId (ServerWorld::getSceneId()), +m_objectName (), +m_includeInBuildout (false), +m_nameStringId (), +m_staticItemName (), +m_staticItemVersion (0), +m_conversionId (0), +m_playerControlled (false), +m_synchronizedUi (), +m_pendingSyncUi (0), +m_persisted (false), +m_authServerProcessId (), +m_proxyServerProcessIds (), +m_transformSequence (), +m_cacheVersion (0), +m_loadContents (true), +m_contentsLoaded (false), +m_contentsRequested (false), +m_loadWith (NetworkId::cms_invalid), +m_cashBalance (0), +m_bankBalance (0), +m_defaultAlterTime (AlterResult::cms_keepNoAlter), +m_broadcastListeners (), +m_broadcastBroadcasters (), +m_authClientServerPackage (), +m_authClientServerPackage_np (), +m_firstParentAuthClientServerPackage(), +m_firstParentAuthClientServerPackage_np(), +m_serverPackage (), +m_serverPackage_np (), +m_sharedPackage (), +m_sharedPackage_np (), +m_networkUpdateFar (NULL), +m_triggerVolumes (), +m_attributesAttained (), +m_attributesInterested (), +m_triggerVolumeInfo (), +m_messageTos (), +m_worldSphere (Sphere::unit), +m_dirtyArchiveCallback (), +m_unreliableControllerMessageSequenceNumber(0), +m_gameObjectType (0), +m_calledTriggerDestroy (false), +m_calledTriggerRemovingFromWorld(false), +m_loadCTSBank(false), +m_loadCTSPackedHouses(false) +{ + synchronizationOnConstruct(); + + m_observersCount.setSourceObject(this); + m_authServerProcessId.setSourceObject(this); + + NOT_NULL(newTemplate); + + setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate, hyperspaceOnCreate); + setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct, false); + +#ifdef _DEBUG + setDebugName(getTemplateName()); +#endif + + updateWorldSphere(); + + const std::string & sharedTemplateName = newTemplate->getSharedTemplate(); + m_sharedTemplate = dynamic_cast(ObjectTemplateList::fetch(sharedTemplateName)); + if (m_sharedTemplate == NULL) + { + WARNING_STRICT_FATAL(!sharedTemplateName.empty(), ("Template %s has an invalid shared template %s. We will use the default shared template for now.", + newTemplate->getName(), sharedTemplateName.c_str())); + } + + if (getSharedTemplate() != NULL) + { + m_nameStringId = getSharedTemplate()->getObjectName(); + m_descriptionStringId = getSharedTemplate()->getDetailedDescription(); + } + + m_scriptObject->setOwner(this); + + ContainedByProperty *containedBy = new ContainedByProperty(*this, NULL); + addProperty(*containedBy); + + //-- create the SlottedContainment property + SlottedContainmentProperty *slottedProperty = new SlottedContainmentProperty(*this); + addProperty(*slottedProperty); + + //-- get ArrangementDescriptor if specified + if (getSharedTemplate() != NULL) + { + const ArrangementDescriptor *const arrangementDescriptor = getSharedTemplate()->getArrangementDescriptor(); + if (arrangementDescriptor) + { + const int arrangementCount = arrangementDescriptor->getArrangementCount(); + for (int i = 0; i < arrangementCount; ++i) + { + slottedProperty->addArrangement(arrangementDescriptor->getArrangement(i)); + } + } + } + + //set up containers on this object if it has any + if (getSharedTemplate() != NULL) + { + SharedObjectTemplate::ContainerType const containerType = getSharedTemplate()->getContainerType(); + + switch (containerType) + { + //buildings (portal properties get added below + case SharedObjectTemplate::CT_none: + break; + + case SharedObjectTemplate::CT_slotted: + case SharedObjectTemplate::CT_ridable: + { + const SlotDescriptor *const slotDescriptor = getSharedTemplate()->getSlotDescriptor(); + if (slotDescriptor) + { + //-- create a SlottedContainer with the given slots + SlottedContainer* slotContainer = new SlottedContainer(*this, slotDescriptor->getSlots()); + addProperty(*slotContainer); + slotContainer = 0; + } + else + { + DEBUG_WARNING(true, ("DATA ERROR: specified slotted container type but could not get slot descriptor")); + } + break; + } + case SharedObjectTemplate::CT_volume: + { + VolumeContainer * volumeContainer = 0; + int maxVolume = getSharedTemplate()->getContainerVolumeLimit(); + if (maxVolume <= 0) + { + maxVolume = VolumeContainer::VL_NoVolumeLimit; + } + volumeContainer = new TangibleVolumeContainer(*this, maxVolume); + addProperty(*volumeContainer); + volumeContainer = 0; + break; + } + case SharedObjectTemplate::CT_volumeIntangible: + { + int maxVolume = getSharedTemplate()->getContainerVolumeLimit(); + if (maxVolume <= 0) + { + maxVolume = VolumeContainer::VL_NoVolumeLimit; + } + VolumeContainer * volumeContainer = new IntangibleVolumeContainer(*this, maxVolume); + addProperty(*volumeContainer); + volumeContainer = 0; + break; + } + case SharedObjectTemplate::CT_volumeGeneric: + { + int maxVolume = getSharedTemplate()->getContainerVolumeLimit(); + if (maxVolume <= 0) + { + maxVolume = VolumeContainer::VL_NoVolumeLimit; + } + VolumeContainer * volumeContainer = new VolumeContainer(*this, maxVolume); + addProperty(*volumeContainer); + volumeContainer = 0; + break; + } + + default: + DEBUG_WARNING(true, ("Invalid container type specified.")); + break; + } + + setLocalFlag(LocalObjectFlags::ServerObject_SendToClient, getSharedTemplate()->getSendToClient()); + m_gameObjectType = static_cast(getSharedTemplate()->getGameObjectType()); + } + + //If the object template specifies a volume, give it a volumeContainment + int vol = newTemplate->getVolume(); + VolumeContainmentProperty* volumeProperty = new VolumeContainmentProperty(*this, (vol < 1 ? 1 : vol) ); + addProperty(*volumeProperty); + volumeProperty = 0; //lint !e423 // creation of memory leak // no, managed by property list + + + // add the portal property if one is requested + if (getSharedTemplate() != NULL) + { + const std::string &portalLayoutFileName = getSharedTemplate()->getPortalLayoutFilename(); + if (!portalLayoutFileName.empty()) + { + PortalProperty *portalProperty = new PortalProperty(*this, portalLayoutFileName.c_str()); + addProperty(*portalProperty); + } + } + + m_triggerVolumeInfo.setOnChanged(this, &ServerObject::updateTriggerVolumes); + + addMembersToPackages(); + + addNotification(notification); + + addNotification(moveNotification); + + gs_objectCount++; + ObjectTracker::addObject(); + + //-- add the no build notification + { + if (getSharedTemplate () && getSharedTemplate ()->getNoBuildRadius () > 0.f) + addNotification (ServerNoBuildNotification::getInstance ()); + } + + //-- add the clear flora notification + { + if (getSharedTemplate () && getSharedTemplate ()->getClearFloraRadius () > 0.f) + addNotification (ServerClearCollidableFloraNotification::getInstance ()); + } +} + +//----------------------------------------------------------------------- + +ServerObject::~ServerObject() +{ + //-- This must be the first line in the destructor to invalidate any watchers watching this object + nullWatchers(); + + ObserveTracker::onObjectDestroyed(*this, getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct)); + PositionUpdateTracker::serverObjDestroyed(*this); + + synchronizationOnDestruct(); + + if (getLayer()) + ObjectTracker::removeRunTimeRule(); + + if (getClient()) + getClient()->removeControlledObject(*this); + + WARNING_STRICT_FATAL(getClient(),("Deleting server object %s which had a client.",getNetworkId().getValueString().c_str())); + + { + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject removeFromWorld"); + //remove from world + if (isInWorld()) + removeFromWorld(); + } + + WARNING_STRICT_FATAL(!m_triggerVolumes.empty(), ("Deleting object %s that still has trigger volumes attached", getNetworkId().getValueString().c_str())); + + { + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject destroyTriggerVolumes"); + // make absolutely sure our trigger volumes are removed from the world + destroyTriggerVolumes(); + } + + if (m_sharedTemplate != NULL) + { + m_sharedTemplate->releaseReference(); + m_sharedTemplate = NULL; + } + + if (getClient()) + { + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject dropClient"); + //Object has a client!! + WARNING(true, ("Destroying object %s which isAuth: %d", getNetworkId().getValueString().c_str(), isAuthoritative())); + GameServer::getInstance().dropClient(getNetworkId()); + } + + { + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject removeObjectFromGame"); + // clean ourselves off any of ServerWorlds lists. + ServerWorld::removeObjectFromGame(*this); + } + + delete m_pendingSyncUi; + m_pendingSyncUi = 0; + + delete m_synchronizedUi; + m_synchronizedUi = 0; + + { + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject delete script object"); + if (m_scriptObject != NULL) + delete m_scriptObject; + } + m_scriptObject = NULL; + + gs_objectCount--; + + { + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::~ServerObject ObjectTracker::removeObject"); + ObjectTracker::removeObject(); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::install() +{ + // read in list of object types that supports no trade "shared" behavior + // (no trade item of those types can be picked up by another character + // on the same account as the character who currently owns the item) + char const * const noTradeSharedDataTableName = "datatables/no_trade/no_trade_shared.iff"; + DataTable * table = DataTableManager::getTable(noTradeSharedDataTableName, true); + if (table) + { + int const columnObjectTemplate = table->findColumnNumber("Object Template"); + if (columnObjectTemplate >= 0) + { + std::string objectTemplate; + + for (int i = 0, numRows = table->getNumRows(); i < numRows; ++i) + { + objectTemplate = table->getStringValue(columnObjectTemplate, i); + if (objectTemplate.empty()) + continue; + + if (objectTemplate.find(".iff") != std::string::npos) + s_noTradeSharedTemplateItemType.insert(CrcLowerString::calculateCrc(objectTemplate.c_str())); + else + s_noTradeSharedStaticItemType.insert(objectTemplate); + } + } + + DataTableManager::close(noTradeSharedDataTableName); + } + + ExitChain::add(ServerObjectNamespace::remove, "ServerObjectNamespace::remove"); +} + +//----------------------------------------------------------------------- + +ServerObject * ServerObject::getServerObject(NetworkId const & networkId) +{ + return asServerObject(NetworkIdManager::getObjectById(networkId)); +} + +//----------------------------------------------------------------------- + +ServerObject * ServerObject::asServerObject(Object * const object) +{ + return (object != NULL) ? object->asServerObject() : NULL; +} + +//----------------------------------------------------------------------- + +ServerObject const * ServerObject::asServerObject(Object const * const object) +{ + return (object != NULL) ? object->asServerObject() : NULL; +} + +//----------------------------------------------------------------------- + +ServerObject * ServerObject::asServerObject() +{ + return this; +} + +//----------------------------------------------------------------------- + +ServerObject const * ServerObject::asServerObject() const +{ + return this; +} + +//----------------------------------------------------------------------- + +CreatureObject * ServerObject::asCreatureObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +CreatureObject const * ServerObject::asCreatureObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +BuildingObject * ServerObject::asBuildingObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +BuildingObject const * ServerObject::asBuildingObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +StaticObject * ServerObject::asStaticObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +StaticObject const * ServerObject::asStaticObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +TangibleObject * ServerObject::asTangibleObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +TangibleObject const * ServerObject::asTangibleObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +IntangibleObject *ServerObject::asIntangibleObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +IntangibleObject const *ServerObject::asIntangibleObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +MissionObject * ServerObject::asMissionObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +MissionObject const * ServerObject::asMissionObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +CellObject * ServerObject::asCellObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +CellObject const * ServerObject::asCellObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +GroupObject * ServerObject::asGroupObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +GroupObject const * ServerObject::asGroupObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +ShipObject * ServerObject::asShipObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +ShipObject const * ServerObject::asShipObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +PlayerObject *ServerObject::asPlayerObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +PlayerObject const * ServerObject::asPlayerObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +WeaponObject *ServerObject::asWeaponObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +WeaponObject const * ServerObject::asWeaponObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +ManufactureSchematicObject *ServerObject::asManufactureSchematicObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +ManufactureSchematicObject const * ServerObject::asManufactureSchematicObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +PlayerQuestObject * ServerObject::asPlayerQuestObject() +{ + return 0; +} + +//----------------------------------------------------------------------- + +PlayerQuestObject const * ServerObject::asPlayerQuestObject() const +{ + return 0; +} + +//----------------------------------------------------------------------- + +/** + * Returns a shared template if none was given for this object. + * + * @return the shared template + */ +const SharedObjectTemplate * ServerObject::getDefaultSharedTemplate(void) const +{ +static const ConstCharCrcLowerString templateName("object/object/base/shared_object_default.iff"); + + if (m_defaultSharedTemplate == NULL) + { + m_defaultSharedTemplate = safe_cast( + ObjectTemplateList::fetch(templateName)); + WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create default shared object template %s", templateName.getString())); + if (m_defaultSharedTemplate != NULL) + ExitChain::add (removeDefaultTemplate, "ServerObject::removeDefaultTemplate"); + } + return m_defaultSharedTemplate; +} // ServerObject::getDefaultSharedTemplate + +//----------------------------------------------------------------------- + +const unsigned long ServerObject::getObjectCount() +{ + return gs_objectCount; +} + +//----------------------------------------------------------------------- + +/** + * Cleans up the default shared template. + */ +void ServerObject::removeDefaultTemplate(void) +{ + if (m_defaultSharedTemplate != NULL) + { + m_defaultSharedTemplate->releaseReference(); + m_defaultSharedTemplate = NULL; + } +} // ServerObject::removeDefaultTemplate + +// ---------------------------------------------------------------------- + +void ServerObject::addObjectToConcludeList() +{ + if (!isInitialized()) + return; + if (!isGoingToConclude()) + { + setGoingToConclude(true); + ServerWorld::addObjectToConcludeList(this); + } +} + +// ---------------------------------------------------------------------- + +/** + * Called during the alter phase of the game. + * + * @param time time since last frame + * + * @return true or false + */ +float ServerObject::alter(float time) +{ + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::alter"); + + //Check initialization + WARNING_STRICT_FATAL(!isInitialized(), ("Alter called on unitialized object %s.", getNetworkId().getValueString().c_str())); + if (!isInitialized()) + return 1.0f; + + // Alter the base class. + float result = Object::alter(time); + + if (isPlacing()) + { + TerrainObject* terrain = TerrainObject::getInstance(); + if (terrain && getSharedTemplate() && getSharedTemplate()->getSnapToTerrain() && isInWorldCell() && isInWorld()) + { + terrain->placeObject(*this, false, true); + } + setPlacing(false); + } + + if (result == AlterResult::cms_kill) + { + if (isAuthoritative()) + { + //If we are being deleted this frame, make sure to update our deltas, position, etc. + sendDeltasForSelfAndContents(); + } + if (isUnloading()) + { + Object * const containerObject = ContainerInterface::getContainedByObject(*this); + //If we're contained, remove ourself from the container before destruction + if (containerObject) + { + Container * const container = ContainerInterface::getContainer(*containerObject); + NOT_NULL(container); + container->internalItemRemoved(*this); + DEBUG_REPORT_LOG(true, ("Removing %s from container %s because it is being unloaded\n", + getNetworkId().getValueString().c_str(), + containerObject->getNetworkId().getValueString().c_str())); + } + } + } + + return result; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::canDropInWorld() const +{ + return false; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::canManipulateObject(ServerObject const &target, bool movingObject, bool checkPermissions, bool checkPermissionsOnParent, float maxDistance, Container::ContainerErrorCode&, bool skipNoTradeCheck, bool * allowedByGodMode) const +{ + //In general objects cannot manipulate other objects, unless they are creatures. This may not be true of all + //objects, however, which is why the function is implemented this way (ie a player object that derives from ServerObject). + UNREF(target); + UNREF(maxDistance); + UNREF(checkPermissions); + UNREF(checkPermissionsOnParent); + UNREF(movingObject); + UNREF(skipNoTradeCheck); + UNREF(allowedByGodMode); + return false; +} + +//----------------------------------------------------------------------- + +bool ServerObject::canTrade() const +{ + if( isInBazaarOrVendor() ) + { + return false; + } + + return !markedNoTrade(); +} + +//----------------------------------------------------------------------- + +bool ServerObject::canTradeRecursive(bool testPlayers) const +{ + if( testPlayers || !isPlayerControlled() ) + { + if( !canTrade() ) + { + return false; + } + else + { + // check the contained items + const Container * const container = ContainerInterface::getContainer(*this); + if( container ) + { + for( ContainerConstIterator i = container->begin(); i != container->end(); ++i ) + { + const ServerObject * const content = safe_cast((*i).getObject()); + if( content ) + { + if( !content->canTradeRecursive(testPlayers) ) + return false; + } + } + } + } + } + + return true; +} + +//----------------------------------------------------------------------- + +bool ServerObject::markedNoTrade() const +{ + return ( getObjVars().hasItem("noTrade") || getObjVars().hasItem("notrade") ); +} + +//----------------------------------------------------------------------- + +bool ServerObject::markedNoTradeRecursive(bool testPlayers, bool testOnlyContainedItems) const +{ + if( testPlayers || !isPlayerControlled() ) + { + if( !testOnlyContainedItems && markedNoTrade() ) + { + return true; + } + else + { + // check the contained items + const Container * const container = ContainerInterface::getContainer(*this); + if( container ) + { + for( ContainerConstIterator i = container->begin(); i != container->end(); ++i ) + { + const ServerObject * const content = safe_cast((*i).getObject()); + if( content ) + { + if( content->markedNoTradeRecursive(testPlayers) ) + return true; + } + } + } + } + } + + return false; +} + +//----------------------------------------------------------------------- + +bool ServerObject::markedNoTradeShared(bool includeCheckForNoTrade) const +{ + if (includeCheckForNoTrade) + { + if (!markedNoTrade()) + return false; + } + + if (getObjVars().hasItem("noTradeShared")) + return true; + + // see if the item type is no trade "shared" + if (m_staticItemName.get().empty()) + return (s_noTradeSharedTemplateItemType.count(getTemplateCrc()) > 0); + + return (s_noTradeSharedStaticItemType.count(m_staticItemName.get()) > 0); +} + +//----------------------------------------------------------------------- + +bool ServerObject::isInSecureTrade() const +{ + const ServerObject *parent = safe_cast(ContainerInterface::getFirstParentInWorld(*this)); + if( parent ) + { + const CreatureObject *creatureObjParent = parent->asCreatureObject(); + if( creatureObjParent ) + { + const CreatureController *cc = creatureObjParent->getCreatureController(); + if( cc ) + { + const ServerSecureTrade *trade = cc->getSecureTrade(); + if( trade && trade->hasItemInSecureTrade(*creatureObjParent, *this) ) + { + return true; + } + } + } + } + + return false; +} + +// ---------------------------------------------------------------------- + +/** + * Returns whether an object is bio-linked + * + * @return true if a the object is bio-linked + */ +bool ServerObject::isBioLinked() const +{ + // By default, objects are not bio-linked + return false; +} + +// ---------------------------------------------------------------------- + +/** + * Returns whether an object, or any contained object, is biolinked + * + * @return true if a biolinked object is found + */ +bool ServerObject::isBioLinkedRecursive() const +{ + if( isBioLinked() ) + { + return true; + } + else + { + // If we are a container, see if any of the contained objects are bio-linked + const Container * const container = ContainerInterface::getContainer(*this); + if( container ) + { + for( ContainerConstIterator i = container->begin(); i != container->end(); ++i ) + { + const ServerObject * const content = safe_cast((*i).getObject()); + if( content ) + { + if( content->isBioLinkedRecursive() ) + { + return true; + } + } + } + } + } + + return false; +} + +//----------------------------------------------------------------------- + +bool ServerObject::isWaypoint() const +{ + return getObjectTemplate()->derivesFrom(SERVER_PATHFINDING_WAYPOINT_TEMPLATE_BASE); +} + +//----------------------------------------------------------------------- + +bool ServerObject::isInBazaarOrVendor() const +{ + bool inBazaarOrVendor = false; + const ServerObject *parent = safe_cast(ContainerInterface::getFirstParentInWorld(*this)); + const ServerObject *grandParent = NULL; + if( parent ) + { + grandParent = safe_cast(ContainerInterface::getFirstParentInWorld(*parent)); + } + + if( parent && (parent->isVendor() || parent->isBazaarTerminal() ) ) + { + inBazaarOrVendor = true; + } + else if( grandParent && (grandParent->isVendor() || grandParent->isBazaarTerminal()) ) + { + inBazaarOrVendor = true; + } + + return inBazaarOrVendor; +} + +void ServerObject::removeAllAuctions() +{ + if ( isVendor() ) + { + ServerObject *inv = getBazaarContainer(); + NetworkId playerOwnerId; + getObjVars().getItem("vendor_owner", playerOwnerId); + if( inv && playerOwnerId.getValue()>0 ) + { + // if this was an uninitialized vendor, remove objvar from owner + ServerObject *owner = dynamic_cast(NetworkIdManager::getObjectById(playerOwnerId)); + if (owner) + { + NetworkId notInitalizedVendor; + if (owner->getObjVars().getItem("vendor_not_initialized", notInitalizedVendor)) + { + if (notInitalizedVendor == Object::getNetworkId()) + { + owner->removeObjVarItem("vendor_not_initialized"); + } + } + } + CommoditiesMarket::destroyVendorMarket(playerOwnerId, *inv); + } + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::checkLOSTo(ServerObject const &target) const +{ + return LineOfSightCache::checkLOS(*this, target); +} + +//----------------------------------------------------------------------- + +bool ServerObject::checkLOSTo(Location const &target) const +{ + return LineOfSightCache::checkLOS(*this, target); +} + +//----------------------------------------------------------------------- + +void ServerObject::conclude() +{ + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::conclude"); + + // everything has updated, check trigger volume + + if (getTransformChanged() && isInWorld()) + { + Vector const &newPosition = getTransform_o2w().getPosition_p(); + // move the object and trigger volumes, detect volume enter/leave + ServerWorld::moveObject(*this, m_oldPosition, newPosition); + updatePositionOnPlanetServer(); + m_oldPosition = newPosition; + } + + m_localFlags &= s_clearLocalFlagsOnConcludeMask; + + { + PROFILER_AUTO_BLOCK_DEFINE("Object::conclude"); + Object::conclude(); + } +} + +//----------------------------------------------------------------------- + +/** + * Creates a default controller for this object. + * + * @return the object's controller + * @todo This function should be removed. Use the controller factory instead. + */ +Controller* ServerObject::createDefaultController(void) +{ + Controller* controller = new ServerController(this); + NOT_NULL(controller); + + setController(controller); + return controller; +} // Object::createDefaultController + +//----------------------------------------------------------------------- +/** Called by the container system when this object's contained By value is changed + */ + +void ServerObject::containedByModified(NetworkId const &oldValue, NetworkId const &newValue, bool isLocal) +{ + UNREF(isLocal); + + if (oldValue == newValue) + return; + + ServerObject * const oldContainer = safe_cast(NetworkIdManager::getObjectById(oldValue)); + ServerObject * const newContainer = safe_cast(NetworkIdManager::getObjectById(newValue)); + + // TODO: reenable these fatals after container proxying changes are done + //FATAL(oldValue.isValid() && !oldContainer, ("ServerObject::containedByModified: obj %s, could not resolve old container %s.", getDebugInformation().c_str(), oldValue.getValueString().c_str())); + //FATAL(newValue.isValid() && !newContainer, ("ServerObject::containedByModified: obj %s, could not resolve new container %s.", getDebugInformation().c_str(), newValue.getValueString().c_str())); + + if (isAuthoritative()) + { + FATAL((newContainer && !newContainer->isAuthoritative()), ("Invalid container transfer with auth object to/from non-auth containers.")); + } + else if (isInitialized()) + { + FATAL((oldContainer && oldContainer->isAuthoritative()) || (newContainer && newContainer->isAuthoritative()), ("Invalid container transfer with non-auth object to/from auth containers.")); + + // For proxy objects and mounts, it is essential for this function + // to setup new container state before calling + // isContentItemExposedWith. Failure to do this causes proxy + // server objects of a rider to handle dismounting improperly + // because wasInWorld will be set to false erroneously. + // Also, it is essential to call this function prior to calling + // containerHandleUpdateClients() below since that function + // assumes the objects are in the new containment state. + containerDepersistContents(oldContainer, newContainer); + + Container const * const newContainerProperty = newContainer ? ContainerInterface::getContainer(*newContainer) : 0; + bool const wasInWorld = isInWorld(); + bool const nowInWorld = newValue == NetworkId::cms_invalid || (newContainerProperty && newContainer->isInWorld() && newContainerProperty->isContentItemExposedWith(*this)); + +// DEBUG_REPORT_LOG(true, ("Updating %s with old container %s and new container %s\n", +// getNetworkId().getValueString().c_str(), +// oldValue.getValueString().c_str(), +// newValue.getValueString().c_str())); + containerHandleUpdateClients(oldContainer, newContainer, (wasInWorld && !nowInWorld), (!wasInWorld && nowInWorld)); + } + + scheduleForAlter(); +} + +//----------------------------------------------------------------------- + +void ServerObject::arrangementModified(int oldValue, int newValue, bool isLocal) +{ + if (!isLocal && !isAuthoritative() && isInitialized()) + { + ServerObject * const parent = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (parent) + { + SlottedContainer * const slotContainer = ContainerInterface::getSlottedContainer(*parent); + if (slotContainer) + { + SlottedContainmentProperty* const slotted = ContainerInterface::getSlottedContainmentProperty(*this); + DEBUG_FATAL(!slotted, ("Error unpacking non slotted objects into a slotted container")); + slotContainer->updateArrangement(*this, oldValue, slotted->getCurrentArrangement()); + } + } + ObserveTracker::onObjectArrangementChanged(*this); + } +} + +//----------------------------------------------------------------------- + +void ServerObject::destroyTriggerVolumes() +{ + // get rid of any trigger volumes + for (TriggerVolumeMap::iterator i = m_triggerVolumes.begin(); i != m_triggerVolumes.end(); ++i) + { + ServerWorld::removeObjectTriggerVolume((*i).second); + delete (*i).second; + } + m_triggerVolumes.clear(); + m_networkUpdateFar = 0; +} + +//----------------------------------------------------------------------- + +void ServerObject::updateTriggerVolumes() +{ + ServerObject *topMost = safe_cast(ContainerInterface::getFirstParentInWorld(*this)); + if (!topMost || topMost != this || !topMost->isInWorld()) + { + destroyTriggerVolumes(); + return; + } + + // keep track of what trigger volumes should exist so we can destroy the rest afterwards + std::vector newVolumes; + + // create any new volumes + { + for (std::vector::const_iterator i = m_triggerVolumeInfo.begin(); i != m_triggerVolumeInfo.end(); ++i) + { + const TriggerVolumeMap::iterator j = m_triggerVolumes.find((*i).name); + if (j != m_triggerVolumes.end()) + { + TriggerVolume *t = (*j).second; + // if we already have one that matches, leave it alone + if ( t->getPromiscuous() == (*i).isPromiscuous + && t->getRadius() == (*i).radius) + { + newVolumes.push_back(t); + continue; + } + // does not match, so destroy it and fall through to creating the new one + ServerWorld::removeObjectTriggerVolume(t); + delete t; + m_triggerVolumes.erase(j); + } + + TriggerVolume * t = new TriggerVolume(*this, (*i).radius, (*i).name, (*i).isPromiscuous); + addTriggerVolume(t); + newVolumes.push_back(t); + } + } + + // remove any volumes which no longer exist + { + TriggerVolumeMap::iterator i = m_triggerVolumes.begin(); + while (i != m_triggerVolumes.end()) + { + TriggerVolume *t = (*i).second; + if ( t != m_networkUpdateFar + && std::find(newVolumes.begin(), newVolumes.end(), t) == newVolumes.end()) + { + ServerWorld::removeObjectTriggerVolume(t); + delete t; + m_triggerVolumes.erase(i++); + } + else + ++i; + } + } +} + +//----------------------------------------------------------------------- + +void ServerObject::addTriggerVolume(TriggerVolume * t) +{ + if (!t) + { + WARNING_STRICT_FATAL(true, ("Cannot add null volume")); + return; + } + m_triggerVolumes.insert(std::make_pair(t->getName(), t)); + ServerWorld::addObjectTriggerVolume(t); +} + +//----------------------------------------------------------------------- + +void ServerObject::createTriggerVolume(const real radius, const std::string & name, const bool isPromiscuous) +{ + removeTriggerVolume(name); + + TriggerVolumeInfo triggerVolumeInfo; + triggerVolumeInfo.name = name; + triggerVolumeInfo.radius = radius; + triggerVolumeInfo.isPromiscuous = isPromiscuous; + m_triggerVolumeInfo.push_back(triggerVolumeInfo); +} + +//----------------------------------------------------------------------- + +void ServerObject::serverObjectEndBaselines(bool fromDatabase) +{ + setInEndBaselines(true); + + // handle trying to create a player in an incorrect scene, or without a PlayerObject + bool needSceneFix = false; + + if (isPlayerControlled()) + { + bool doUnload = false; + if (!PlayerCreatureController::getPlayerObject(asCreatureObject())) + { + WARNING(true, ("TRACE_LOGIN: Loading a player controlled creature object (%s) without a player object.", getNetworkId().getValueString().c_str())); + doUnload = true; + } + else if (getSceneId() != ServerWorld::getSceneId()) + { + Client* p_client = GameServer::getInstance().getClient( getNetworkId() ); + + + if ( (p_client) && ( p_client->getSendToStarport() ) ) + { + needSceneFix = true; + GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this),"tatooine",Vector(3528,5,-4804), + NetworkId::cms_invalid,Vector(3528,5,-4804)); + } + else if (isAuthoritative() && ContainerInterface::getContainedByObject(*this)) + { + needSceneFix = true; + } + + else + { + WARNING(true, + ("Unloading object id=[%s] on game server id=[%d] due to incorrect scene during baselines: server scene=[%s], object scene=[%s], fromDatabase=[%s], authoritative=[%s])", + getNetworkId().getValueString().c_str(), + static_cast(GameServer::getInstance().getProcessId()), + ServerWorld::getSceneId().c_str(), + getSceneId().c_str(), + fromDatabase ? "true" : "false", + isAuthoritative() ? "true" : "false" + )); + + //-- As a precautionary measure, force CentralServer to clear out its player id/scene id map since a bug in the updating of Central's map probably is the origin of this routing error. + GenericValueTypeMessage > > const setSceneMsg("SetSceneForPlayer", std::make_pair(getNetworkId(), std::make_pair(std::string(""), false))); + GameServer::getInstance().sendToCentralServer(setSceneMsg); + + doUnload = true; + } + } + if (doUnload) + { + if (getClient()) + GameServer::getInstance().dropClient(getNetworkId()); + unload(); + delete this; + return; + } + } + + //This is the public interface to end baselines. ::endBaselines is a protected virtual function now + // so that we can enforce order. + endBaselines(); + + if (needSceneFix) + { + WARNING(true, ("Fixing scene id for contained object %s due to incorrect scene id during baselines", getNetworkId().getValueString().c_str())); + setSceneIdOnThisAndContents(ServerWorld::getSceneId()); + } + + if (fromDatabase) + onLoadedFromDatabase(); + + updateWorldSphere(); + if (getScriptObject() != NULL) + { + endBaselinesInitializeScript(*this, true); + // If the object was created authoritative, trigger if needed + if (isAuthoritative()) + triggerMadeAuthoritative(); + } + + if (isPlayerControlled()) + PlayerSanityChecker::add(getNetworkId()); + + //-- Validate the object transform. + checkAndLogInvalidTransform(); + + //-- Schedule for alter just in case something needs an alter. + scheduleForAlter(); +} + +//----------------------------------------------------------------------- + +void ServerObject::onLoadedFromDatabase() +{ +} + +//----------------------------------------------------------------------- + +void ServerObject::endBaselines() +{ + // This should always go first: it ensures there are no deltas + // accumulated for this object at the time we start processing + // our baselined data. Only changes after this point will + // generate deltas. + clearDeltas(); + + //Handle updating container info + bool addToWorldFlag = handleContentsSetup(); + setInitialized(true); + + ServerController * c = safe_cast(getController()); + c->endBaselines(); + setTransformChanged(false); + + // check for parent getting uncached + if (isAuthoritative() && getCacheVersion() != 0) + { + ServerObject *parent = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (parent && parent->getCacheVersion() == 0) + setCacheVersion(0); + } + + // handle version numbering for contents on portal properties + PortalProperty *portalProperty = getPortalProperty(); + if (portalProperty) + { + int crcValue=0; + getObjVars().getItem(portalPropertyCrcObjectVariableName,crcValue); + std::vector unfixables; + if (portalProperty->serverEndBaselines(crcValue, unfixables, isAuthoritative())) + { + FATAL(ConfigServerGame::getFatalOnGoldPobChange() && getCacheVersion() != 0, + ("Object %s is a client cached object and the POB changed from [%d] to [%d]", getNetworkId().getValueString().c_str(), crcValue, portalProperty->getCrc())); +#ifdef DEBUG + WARNING(getCacheVersion() != 0, ("Object %s is a client cached object and the POB changed from [%d] to [%d]", getNetworkId().getValueString().c_str(), crcValue, portalProperty->getCrc())); +#endif + if (isAuthoritative()) + setCacheVersion(0); + } + if (isAuthoritative()) + setObjVarItem(portalPropertyCrcObjectVariableName, portalProperty->getCrc()); + + if (!unfixables.empty()) + { + WARNING(true, ("Object %s contained objects that could not be placed after pob fixup", getNetworkId().getValueString().c_str())); + } + } + + if (addToWorldFlag) + addToWorld(); + + if (isAuthoritative()) + { + // don't allow login if the character is in the middle of CTS or has been successfully CTS(ed) + Client * const client = GameServer::getInstance().getClient(getNetworkId()); + if (client && !getClient() && (client->getCharacterObjectId() == getNetworkId())) + { + bool kickRequested = false; + + DynamicVariableList const & objVars = getObjVars(); + int timeOut; + if (objVars.getItem("disableLoginCtsInProgress", timeOut)) + { + if (timeOut > static_cast(ServerClock::getInstance().getGameTimeSeconds())) + { + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); + kickRequested = true; + } + else + { + removeObjVarItem("disableLoginCtsInProgress"); + } + } + + int transferredTime; + if (!kickRequested && objVars.getItem("disableLoginCtsCompleted", transferredTime) && !client->isUsingAdminLogin()) + { + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++kickPlayerCtsCompletedOrInProgress", "", 0, false); + kickRequested = true; + } + } + + // attach a pending client to this object if needed + checkAndAddClientControl(client); + + // Make sure the PlanetServer knows about the new object if it needs to + updatePositionOnPlanetServer(true); + + // for initialized, unpacked vendor, sync the vendor location with the commodities server + if (isVendor()) + CommoditiesMarket::updateVendorLocation(*this); + + // if this is a reward item that supports trade in, attach the trade in script to it to provide the trade in functionality + VeteranRewardManager::attachTradeInScriptToItem(*this); + + // sanity check - fix up any player character negative cash/bank balance + if (client) + { + if (m_cashBalance.get() < 0) + m_cashBalance = 0; + + if (m_bankBalance.get() < 0) + m_bankBalance = 0; + } + } + + // If our immediate container is initialized, we were just added to the container so update the ObserveTracker + ServerObject *immediateContainer = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (immediateContainer && immediateContainer->isInitialized()) + { + // handle the case of a player who logged out in a buildout cell + // and that buildout id got changed to some other object, like a rock + if (isPlayerControlled() && isAuthoritative() && (immediateContainer->getNetworkId().getValue() < static_cast(0))) + { + if (immediateContainer->asCellObject() != NULL || ContainerInterface::getCell(*immediateContainer) != NULL) + ObserveTracker::onObjectContainerChanged(*this); + else + { + WARNING(true, ("ServerObject::endBaselines player (%s) is trying to be put into non-cell object (%s). We will put the player in the world instead.", + PlayerObject::getAccountDescription(this).c_str(), immediateContainer->getDebugInformation().c_str())); + ContainedByProperty * const cby = ContainerInterface::getContainedByProperty(*this); + if (cby) + { + cby->setContainedBy(NetworkId::cms_invalid, true); + if (!ServerWorld::isSpaceScene()) + { + // if the player was in a building, try and put them at the building's ejection point + DynamicVariableLocationData ejectionPoint; + if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) + { + removeObjVarItem("building_ejection_point"); + setPosition_p(ejectionPoint.pos); + } + } + addToWorld(); + } + } + } + else + { + //@todo: we may want to do something here if this call fails + ObserveTracker::onObjectContainerChanged(*this); + } + } + + if (isAuthoritative() && (!isPlayerControlled() || getClient()) && getObjVars().hasItem("teleportFixup")) + TeleportFixupHandler::add(*this); + + setInEndBaselines(false); +} + +// ---------------------------------------------------------------------- + +void ServerObject::getAuthClients(std::set &authClients) const +{ + Client const * const client = getClient(); + if (client) + IGNORE_RETURN(authClients.insert(client)); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::handlePlayerInInteriorSetup(ContainedByProperty *containedBy) +{ + // If we are player-controlled, assume that it may have been a while since we logged in. + // If we were in a POB, it might have changed. So, ignore the persisted cell number and look + // for the best cell. If anything goes wrong looking for the cell, warp to a good location. + + bool retval = false; + + Object * const originalCell = containedBy->getContainedBy(); + if (originalCell) + { + bool fixOk = false; + + CellProperty * const originalCellProp = originalCell->getCellProperty(); + ServerObject * const pob = safe_cast(ContainerInterface::getContainedByObject(*originalCell)); + BuildingObject * const building = pob ? pob->asBuildingObject() : 0; + PortalProperty * const portal = pob ? pob->getPortalProperty() : 0; + + // Don't ever put the character into a packed house + if ((building) && (!building->isInWorld())) + { + DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building is packed\n",getNetworkId().getValueString().c_str(), building->getNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building is packed",getNetworkId().getValueString().c_str(), building->getNetworkId().getValueString().c_str())); + + // settting fixOk to false will cause the character to get moved + // into the world at the building ejection point (see below) + fixOk = false; + } + else if (portal) + { + originalCellProp->depersistContents(*this); + + if (pob->isInitialized()) + { + if (isAuthoritative()) + { + Transform const saveTransform(getTransform_o2p()); + Container::ContainerErrorCode tmp = Container::CEC_Success; + originalCellProp->remove(*this, tmp); + containedBy->setContainedBy(NetworkId::cms_invalid); + + fixOk = portal->fixupObject(*this, saveTransform); + containerHandleUpdateProxies(NULL, safe_cast(ContainerInterface::getContainedByObject(*this))); + + if (building) + building->gainedPlayer(*this); + } + else + { + fixOk = true; + DEBUG_REPORT_LOG(true,("Skipping POB fixup on non-authoritative player %s\n",getNetworkId().getValueString().c_str())); + retval = true; + } + } + else + { + if (isAuthoritative()) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + portal->queueObjectForFixup(*this); + originalCellProp->remove(*this, tmp); + containedBy->setContainedBy(NetworkId::cms_invalid); + setNeedsPobFixup(true); + addNotification(pobFixupNotification); + } + else + DEBUG_REPORT_LOG(true,("Skipping POB fixup on non-authoritative player %s\n",getNetworkId().getValueString().c_str())); + fixOk = true; + } + } + + if (!fixOk) + { + // warp to safe location + DEBUG_WARNING(true,("Player-controlled object %s was warped outside of its container because a good cell could not be found.",getNetworkId().getValueString().c_str())); + + containedBy->setContainedBy(NetworkId::cms_invalid); + + // attempt to put the character at the ejection point of the building + if (!ServerWorld::isSpaceScene()) + { + DynamicVariableLocationData ejectionPoint; + if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) + { + removeObjVarItem("building_ejection_point"); + setPosition_p(ejectionPoint.pos); + } + } + + retval = true; + } + } + else + { + // the container (most likely a building) we were in doesn't exist any more + DEBUG_REPORT_LOG(true,("Ejecting player %s from building %s, because the building does not exist anymore\n",getNetworkId().getValueString().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Ejecting player %s from building %s, because the building does not exist anymore",getNetworkId().getValueString().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); + + containedBy->setContainedBy(NetworkId::cms_invalid); + + // attempt to put the character at the ejection point of the building + if (!ServerWorld::isSpaceScene()) + { + DynamicVariableLocationData ejectionPoint; + if (getObjVars().getItem("building_ejection_point", ejectionPoint) && (ServerWorld::getSceneId() == ejectionPoint.scene) && (!ejectionPoint.cell.isValid())) + { + removeObjVarItem("building_ejection_point"); + setPosition_p(ejectionPoint.pos); + } + else + // warp the player to the Mos Eisley Starport + { + DEBUG_REPORT_LOG(true, ("Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); + LOG("CustomerService",("Login: Tried to load creature %s into invalid container. Moving to Mos Eisley Starport.\n", getNetworkId().getValueString().c_str())); + GameServer::getInstance().requestSceneWarp(CachedNetworkId(*this),"tatooine",Vector(3528,5,-4804),NetworkId::cms_invalid,Vector(3528,5,-4804)); + } + } + + retval = true; + } + return retval; +} + +//----------------------------------------------------------------------- +/** + * Handle setting up the contents of any containedby objects while de-persisting this object + */ + +bool ServerObject::handleContentsSetup() +{ + ContainedByProperty * const containedBy = ContainerInterface::getContainedByProperty(*this); + if (!containedBy || containedBy->getContainedByNetworkId() == NetworkId::cms_invalid) + return true; + + ServerObject * const containingObject = safe_cast(containedBy->getContainedBy()); + DEBUG_REPORT_LOG(!containingObject, ("Could not depersist object %s into non-existant object %s.\n", getNetworkId().getValueString().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); + + // handle special case of player controlled objects depersisting into interiors + if ( isPlayerControlled() + && ( (containingObject && containingObject->getCellProperty()) + || (containedBy->getContainedByNetworkId() != NetworkId::cms_invalid && !containingObject))) + return handlePlayerInInteriorSetup(containedBy); + + if (containingObject) + { + Container * const container = ContainerInterface::getContainer(*containingObject); + SlottedContainer * const slotContainer = dynamic_cast(container); + if (slotContainer) + { + SlottedContainmentProperty * const slottedProperty = ContainerInterface::getSlottedContainmentProperty(*this); + if (slottedProperty) + slotContainer->depersistSlotContents(*this, slottedProperty->getCurrentArrangement()); + else + WARNING_STRICT_FATAL(true, ("Tried to depersist an object with no arrangement into a slotted container")); + } + else if (container) + { + container->depersistContents(*this); + if (containingObject->isInitialized() && containingObject->isInWorld() && container->isContentItemExposedWith(*this)) + addToWorld(); + } + + synchronizationOnLoadedInContainer(); + return false; + } + + LOG("CustomerService", ("BadContainerDepersist: Tried to depersist non-player object %s into container %s which could not be found.", getDebugInformation().c_str(), containedBy->getContainedByNetworkId().getValueString().c_str())); + unload(); + return false; +} + +//----------------------------------------------------------------------- + +unsigned long ServerObject::getAndIncrementMoveSequenceNumber() +{ + unsigned long newValue = m_transformSequence.get(); + newValue++; + m_transformSequence = newValue; + return newValue; +} + +//----------------------------------------------------------------------- + +const bool ServerObject::getPositionChanged() const +{ + return (getTransform_o2w().getPosition_p() != m_oldPosition); +} + +//----------------------------------------------------------------------- + +const int ServerObject::getCacheVersion() const +{ + return m_cacheVersion.get(); +} + +//----------------------------------------------------------------------- + +const char * ServerObject::getSharedTemplateName() const +{ + if (getSharedTemplate() == NULL) + return NULL; + return getSharedTemplate()->ObjectTemplate::getName(); +} + +//----------------------------------------------------------------------- + +const char * ServerObject::getClientSharedTemplateName () const +{ + return getSharedTemplateName(); +} + +//----------------------------------------------------------------------- + +const Unicode::String ServerObject::getObjectName(void) const +{ + // try the player defined name first + const Unicode::String & name = m_objectName.get(); + if (!name.empty ()) + return name; + + // try the stringId name + const StringId & nameId = m_nameStringId.get(); + if (!nameId.isInvalid ()) + return Unicode::narrowToWide(nameId.getDebugString ()); + + // use the template name + return Unicode::narrowToWide(getTemplateName()); +} + +//----------------------------------------------------------------------- + +const Sphere & ServerObject::getSphereExtent() const +{ + return m_worldSphere; +} + +//----------------------------------------------------------------------- + +const Sphere ServerObject::getLocalSphere() const +{ + Sphere sphere (Sphere::unit); + const CollisionProperty * collision = getCollisionProperty(); + if (collision) + { + sphere = collision->getBoundingSphere_l(); + } + else + { + const Appearance * appearance = getAppearance(); + if (appearance) + { + sphere = appearance->getSphere(); + } + } + + if (sphere.getRadius() == 0.0f) + { + sphere.setRadius(1.0f); + } + return sphere; +} + +//----------------------------------------------------------------------- + +void ServerObject::updateWorldSphere() +{ + Sphere sphere (getLocalSphere()); + m_worldSphere.setCenter (rotateTranslate_o2w(sphere.getCenter())); + m_worldSphere.setRadius(sphere.getRadius()); +} + +//----------------------------------------------------------------------- + +/** + * Gets the approximate height of the object. + * + * @return the object's height + */ +float ServerObject::getHeight() const +{ + return getSphereExtent().getRadius() * 2.0f * getScale().y; +} // ServerObject::getHeight + +//----------------------------------------------------------------------- + +/** + * Gets the approximate radius of the object. + * + * @return the object's radius + */ +float ServerObject::getRadius() const +{ + return getSphereExtent().getRadius() * std::max(getScale().x, getScale().z); +} // ServerObject::getHeight + +//----------------------------------------------------------------------- + +/** + * Returns the volume of this object (and it's contents, if it's a container) + * + * @return the object's volume + */ +int ServerObject::getVolume(void) const +{ + const VolumeContainmentProperty* volumeProperty = ContainerInterface::getVolumeContainmentProperty(*this); + return volumeProperty ? volumeProperty->getVolume() : 1; +#if 0 + const VolumeContainer * container = ContainerInterface::getVolumeContainer(*this); + if (container) + return m_volume.get()+container->getCurrentVolume(); + else + return m_volume.get(); +#endif +} + +//----------------------------------------------------------------------- + + +const TriggerVolume * ServerObject::getTriggerVolume(const std::string & triggerVolumeName) const +{ + const TriggerVolume * result = 0; + const TriggerVolumeMap::const_iterator i = m_triggerVolumes.find(triggerVolumeName); + if(i != m_triggerVolumes.end()) + { + result = (*i).second; + } + return result; +} + +//----------------------------------------------------------------------- + +TriggerVolume * ServerObject::getTriggerVolume(const std::string & triggerVolumeName) +{ + TriggerVolume * result = 0; + const TriggerVolumeMap::iterator i = m_triggerVolumes.find(triggerVolumeName); + if (i != m_triggerVolumes.end()) + { + result = (*i).second; + } + return result; +} + +//---------------------------------------------------------------------- + +void ServerObject::seeCombatSpam (const MessageQueueCombatSpam & spamMsg) +{ + if (!isPlayerControlled()) + return; + + if (!isAuthoritative ()) + { + sendControllerMessageToAuthServer(CM_combatSpam, new MessageQueueCombatSpam(spamMsg)); + return; + } + + if (getClient ()) + { + bool shouldSend = (spamMsg.m_attacker == getNetworkId()); + if (!shouldSend) + { + ServerObject * sourceObject = safe_cast(NetworkIdManager::getObjectById(spamMsg.m_attacker)); + if ( sourceObject + && ObserveTracker::isObserving(*getClient(), *sourceObject) + && !PlayerObject::isIgnoring(getNetworkId(), spamMsg.m_attacker)) + { + shouldSend = true; + } + } + + if (shouldSend) + { + MessageQueueCombatSpam * const msg = new MessageQueueCombatSpam (spamMsg); + Controller *const controller = NON_NULL (getController()); + controller->appendMessage(CM_combatSpam, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } +} + +//---------------------------------------------------------------------- + +void ServerObject::seeSocial (const MessageQueueSocial & socialMsg) +{ + Controller * const controller = NON_NULL (getController()); + + if (!isAuthoritative ()) + { + MessageQueueSocial * const msg = new MessageQueueSocial (socialMsg); + controller->appendMessage(CM_socialReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + return; + } + + if (getClient ()) + { + ServerObject *sourceObject = safe_cast(NetworkIdManager::getObjectById(socialMsg.getSourceId())); + if ( sourceObject + && ( sourceObject->getCacheVersion() > 0 + || ( ObserveTracker::isObserving(*getClient(), *sourceObject) + && !PlayerObject::isIgnoring(getNetworkId(), socialMsg.getSourceId())))) + { + MessageQueueSocial * const msg = new MessageQueueSocial (socialMsg); + controller->appendMessage(CM_socialReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } +} + +//----------------------------------------------------------------------- + +bool ServerObject::serverObjectInitializeFirstTimeObject(ServerObject *cell, Transform const &transform) +{ + //This is the public interface for initializeFirstTimeObject. ::initializeFirstTimeObject has been made + //protected virtual so that we could enforce order. + + initializeFirstTimeObject(); + + // attach template scripts to this object + NOT_NULL(getScriptObject()); + getScriptObject()->initScriptInstances(); + + ServerObjectTemplate const * const newTemplate = safe_cast(getObjectTemplate()); + NOT_NULL(newTemplate); + + int count = newTemplate->getScriptsCount(); + for (int i = 0; i < count; ++i) + getScriptObject()->attachScript(newTemplate->getScripts(i), true); + + if (cell) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + if (!ContainerInterface::transferItemToCell(*cell, *this, transform, NULL, tmp)) + { + WARNING(true, ("ServerWorld::createNewObjectIntermediate tried to create a new object in a cell, but it failed.")); + return false; + } + } + else if (transform != Transform::identity) + setTransform_o2p(transform); + + getScriptObject()->setOwnerIsInitialized(); + + addObjectToConcludeList(); + + // validate the object transform + checkAndLogInvalidTransform(); + + //-- Initialize the controller + { + ServerController * const controller = safe_cast(getController()); + controller->endBaselines(); + } + + return true; +} + +//----------------------------------------------------------------------- + +void ServerObject::initializeFirstTimeObject() +{ + DEBUG_FATAL(!isAuthoritative(), ("Calling initialize on non authoritative object %s", getNetworkId().getValueString().c_str())); + setInitialized(true); + setPlacing(true); + + const ServerObjectTemplate* newTemplate = safe_cast(getObjectTemplate()); + NOT_NULL(newTemplate); + + // set up objvars - we know we are authoritative so we can get by with this + newTemplate->getObjvars(m_objVars); + + // record the crc of the pob used to create this object + PortalProperty *portalProperty = getPortalProperty(); + if (portalProperty) + m_objVars.setItem(portalPropertyCrcObjectVariableName, portalProperty->getCrc()); + + // add template equipment to this object + int i; + int count = newTemplate->getContentsCount(); + for (i = 0; i < count; ++i) + { + //Don't move this declaration of contents out of the loop or you will leak a ref. + ServerObjectTemplate::Contents contents; + newTemplate->getContents(contents, i); + if (contents.content == NULL) + { + DEBUG_WARNING(true, ("No template for contents item %d", i)); + continue; + } + if (contents.equipObject) + { + // find out where the contents go + const SlotId & slotId = SlotIdManager::findSlotId(CrcLowerString(contents.slotName.c_str())); + if (slotId != SlotId::invalid) + { + //We'll persist the contents automatically if the parent object is persisted. + ServerObject * newObject = ServerWorld::createNewObject(*(safe_cast(contents.content)), *this,slotId, false); + if (newObject == NULL) + { + DEBUG_WARNING(true, ("Can't create object from template %s",contents.content->getName())); + } + } + else + { + DEBUG_WARNING(true, ("Slot %s is not a valid slot name", contents.slotName.c_str())); + } + } + else + { + // get the object (which we assume is a volume container) in the + // desired slot + SlottedContainer * const container = ContainerInterface::getSlottedContainer(*this); + if (container != NULL) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + CachedNetworkId equippedObjectId = container->getObjectInSlot(SlotIdManager::findSlotId(CrcLowerString(contents.slotName.c_str())), tmp); + if (equippedObjectId != NetworkId::cms_invalid) + { + // put the contents in the volume container + ServerObject * equippedObject = safe_cast(equippedObjectId.getObject()); + if (equippedObject != NULL) + { + + //We'll persist the contents automatically if the parent object is persisted. + ServerObject * newObject = ServerWorld::createNewObject(*(safe_cast(contents.content)), *equippedObject,false); + if (newObject == NULL) + { + DEBUG_WARNING(true, ("Can't create object from template %s", contents.content->getName())); + } + } + else + { + DEBUG_WARNING(true, ("Object in slot %s not loaded",contents.slotName.c_str())); + } + } + else + { + DEBUG_WARNING(true, ("No object in slot %s", contents.slotName.c_str())); + } + } + else + DEBUG_WARNING(true, ("No slotted container for object")); + } + } + { + const PropertyList::iterator iEnd = m_propertyList->end(); + for (PropertyList::iterator i = m_propertyList->begin(); i != iEnd; ++i) + (*i)->initializeFirstTimeObject(); + } + + SharedObjectTemplate::GameObjectType got = + static_cast (getGameObjectType()); + if (got == SharedObjectTemplate::GOT_terminal_bazaar) + { + setLoadContents(false); + } + + //-- Assume this object wants to be altered. + scheduleForAlter(); +} + +//----------------------------------------------------------------------- + +void ServerObject::kill() +{ + Object::kill(); +} + +// ---------------------------------------------------------------------- + +/** + * Mark all the children of this object as persisted. + */ +void ServerObject::markChildrenPersisted() +{ + if (!safe_cast(getObjectTemplate())->getPersistContents()) + return; + + Container *container = ContainerInterface::getContainer(*this); + if (container) + { + for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) + { + ServerObject *containedObject = safe_cast((*containerIterator).getObject()); + if (containedObject) + { + containedObject->m_persisted=true; + containedObject->markChildrenPersisted(); + } + } + } + +} + +//----------------------------------------------------------------------- + +void ServerObject::addToWorld() +{ + if (getKill()) + return; + + if (isInWorld()) + { + DEBUG_WARNING(true, ("Calling add to world on object already in it %s", getNetworkId().getValueString().c_str())); + return; + } + updateWorldSphere(); + + Object::addToWorld(); + updateTriggerVolumes(); + + if (getScriptObject() != NULL) + getScriptObject()->setOwnerIsLoaded(); + + onAddedToWorld(); +} + +//----------------------------------------------------------------------- + +void ServerObject::onAddedToWorld() +{ + m_oldPosition = getTransform_o2w().getPosition_p(); + + // sanity check whether we should really be in the world or not + ContainedByProperty const * const containedByProperty = getContainedByProperty(); + if (containedByProperty && containedByProperty->getContainedByNetworkId().isValid()) + { + Object const * const containedByObject = containedByProperty->getContainedBy(); + if (containedByObject) + { + WARNING_DEBUG_FATAL( + !containedByObject->isInWorld(), + ( + "Tried to add object %s to the world with container %s which is not in the world.", + getDebugInformation().c_str(), + containedByObject->getDebugInformation().c_str())); + Container const * const containerProperty = ContainerInterface::getContainer(*containedByObject); + if (containerProperty) + { + WARNING_DEBUG_FATAL( + !containerProperty->isContentItemExposedWith(*this), + ( + "Tried to add object %s to the world with container %s which does not expose it.", + getDebugInformation().c_str(), + containedByObject->getDebugInformation().c_str())); + } + else + { + WARNING_DEBUG_FATAL( + true, + ( + "Tried to add object %s to the world with container %s with no container property.", + getDebugInformation().c_str(), + containedByObject->getDebugInformation().c_str())); + } + } + else + { + WARNING_DEBUG_FATAL( + true, + ( + "Tried to add object %s to the world with unresolvable container %s", + getDebugInformation().c_str(), + containedByProperty->getContainedByNetworkId().getValueString().c_str())); + } + } + + // Add networkUpdate volume + if (isInWorldCell()) + onAddedToWorldCell(); + + if (isAuthoritative()) + { + //Tell scripts we are added to world + ScriptParams params; + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_ADDED_TO_WORLD, params)); + + //remove the vendor reinitialization flag if it exists + removeObjVarItem(CommoditiesMarket::OBJVAR_VENDOR_REINITIALIZING); + } +} + +//----------------------------------------------------------------------- + +bool ServerObject::checkAndAddClientControl(Client* client) +{ + if (isPlayerControlled()) + { + CreatureObject* creature = asCreatureObject(); + if (client && creature && isInitialized() && isAuthoritative() && !isNeedingPobFixup()) + { + client->onLoadPlayer(*creature); + return true; + } + } + return false; + } + +//----------------------------------------------------------------------- + +void ServerObject::onPobFixupComplete() +{ + setNeedsPobFixup(false); + checkAndAddClientControl(GameServer::getInstance().getClient(getNetworkId())); + BuildingObject * const building = static_cast(ContainerInterface::getTopmostContainer(*this))->asBuildingObject(); + if (building) + building->gainedPlayer(*this); + +} + +//----------------------------------------------------------------------- + +void ServerObject::onClientReady(Client *c) +{ + NOT_NULL(c); + CmdSceneReady const readyMessage; + c->send(readyMessage, true); + + ScriptParams params; + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_LOGIN, params)); + + int galacticReserve = 0; + if (!getObjVars().getItem("galactic_reserve", galacticReserve)) + { + galacticReserve = 0; + } + + LOG("CustomerService", ("Money:%s logged in with %d money, %d galactic reserve", PlayerObject::getAccountDescription(getNetworkId()).c_str(), getTotalMoney(), galacticReserve)); + + if (getClient() && getClient()->isFreeTrialAccount()) + { + bool addToConcludeList = false; + + if ((m_cashBalance.get() + m_bankBalance.get()) > ConfigServerGame::getMaxFreeTrialMoney()) + { + int amountOver = (m_cashBalance.get() + m_bankBalance.get()) - ConfigServerGame::getMaxFreeTrialMoney(); + if (amountOver <= m_bankBalance.get()) + { + m_bankBalance = m_bankBalance.get() - amountOver; + LOG("CustomerService", ("Money:%s is a free trial user and logged in with too much. Deducting %d from bank.", PlayerObject::getAccountDescription(getNetworkId()).c_str(), amountOver)); + } + else + { + m_cashBalance = m_cashBalance.get() - (amountOver - m_bankBalance.get()); + LOG("CustomerService", ("Money:%s is a free trial user and logged in with too much. Deducting %d from bank and %d from cash.", PlayerObject::getAccountDescription(getNetworkId()).c_str(), m_bankBalance.get(), amountOver - m_bankBalance.get())); + m_bankBalance = 0; + } + + // sanity check - fix up any negative cash/bank balance + if (m_cashBalance.get() < 0) + m_cashBalance = 0; + + if (m_bankBalance.get() < 0) + m_bankBalance = 0; + + addToConcludeList = true; + } + + // trial accounts cannot have galactic reserve + if (galacticReserve > 0) + { + LOG("CustomerService", ("Money:%s is a free trial user and logged in with %d galactic reserve. Setting galactic reserve to 0.", PlayerObject::getAccountDescription(getNetworkId()).c_str(), galacticReserve)); + removeObjVarItem("galactic_reserve"); + PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); + if (po) + { + po->depersistGalacticReserveDeposit(); + } + + addToConcludeList = true; + } + + if (addToConcludeList) + addObjectToConcludeList(); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::onClientAboutToLoad() +{ +} + +// ---------------------------------------------------------------------- + +void ServerObject::onLoadingScreenComplete() +{ +} + +// ---------------------------------------------------------------------- + +bool ServerObject::onContainerAboutToLoseItem(ServerObject * destination, ServerObject& item, ServerObject* transferer) +{ + if (transferer && !checkBankTransfer(this, item, transferer)) + return false; + + Object *parent = ContainerInterface::getContainedByObject(*this); + if (parent && parent->asServerObject()) + return parent->asServerObject()->onContainerChildAboutToLoseItem(destination, item, transferer); + + return true; +} + +//----------------------------------------------------------------------- + +bool ServerObject::onContainerAboutToTransfer(ServerObject * destination, ServerObject* transferer) +{ + UNREF(destination); + UNREF(transferer); + return true; +} + +//----------------------------------------------------------------------- + +int ServerObject::onContainerAboutToGainItem(ServerObject& item, ServerObject* transferer) +{ + if (transferer && !checkBankTransfer(this, item, transferer)) + return Container::CEC_BlockedByDestinationContainer; + + Object *parent = ContainerInterface::getContainedByObject(*this); + //disallow putting crafting stations in other crafting stations + if (transferer && parent && parent->asServerObject()) + { + SharedObjectTemplate::GameObjectType parentGot = static_cast (parent->asServerObject()->getGameObjectType()); + SharedObjectTemplate::GameObjectType itemGot = static_cast (item.getGameObjectType()); + + if (parentGot == SharedObjectTemplate::GOT_misc_crafting_station && itemGot == parentGot) + { + return Container::CEC_BlockedByDestinationContainer; + } + } + + if (parent && parent->asServerObject()) + return parent->asServerObject()->onContainerChildAboutToGainItem(item, this, transferer) ? Container::CEC_Success : Container::CEC_BlockedByDestinationContainer; + + return Container::CEC_Success; +} + +//----------------------------------------------------------------------- + +void ServerObject::onContainerLostItem(ServerObject * destination, ServerObject& item, ServerObject* transferer) +{ + Object *parent = ContainerInterface::getContainedByObject(*this); + if (parent && parent->asServerObject()) + parent->asServerObject()->onContainerChildLostItem(destination, item, this, transferer); +} + +//----------------------------------------------------------------------- + +void ServerObject::onContainerTransfer(ServerObject * destination, ServerObject* transferer) +{ + UNREF(destination); + UNREF(transferer); +} + +//----------------------------------------------------------------------- + +void ServerObject::onContainerGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) +{ + Object *parent = ContainerInterface::getContainedByObject(*this); + if (parent && parent->asServerObject()) + parent->asServerObject()->onContainerChildGainItem(item, source, transferer); + combineResourceContainers(item); +} + +//----------------------------------------------------------------------- + +void ServerObject::onContainerTransferComplete(ServerObject *oldContainer, ServerObject *newContainer) +{ + if (!isAuthoritative()) + { + WARNING_STRICT_FATAL(true, ("onContainerTransferComplete called on non auth object %s", getNetworkId().getValueString().c_str())); + return; + } + + if (newContainer) + { + //If this object is not persisted, but it placed into a container that is + // Then persist the object + if (!isPersisted() && newContainer->isPersisted() && safe_cast(newContainer->getObjectTemplate())->getPersistContents()) + persist(); + } + + DEBUG_FATAL(getCellProperty(), ("Cell object container transfer complete")); + + setTransformChanged(true); + + if ( (oldContainer && !oldContainer->asCellObject()) + || (newContainer && !newContainer->asCellObject())) + PositionUpdateTracker::flushPositionUpdate(*this); + + containerHandleUpdateProxies(oldContainer, newContainer); + + Container const * const newContainerProperty = newContainer ? ContainerInterface::getContainer(*newContainer) : 0; + bool const wasInWorld = isInWorld(); + bool const nowInWorld = !newContainer || (newContainerProperty && newContainer->isInWorld() && newContainerProperty->isContentItemExposedWith(*this)); + + containerHandleUpdateClients(oldContainer, newContainer, (wasInWorld && !nowInWorld), (!wasInWorld && nowInWorld)); + + ObserveTracker::onObjectArrangementChanged(*this); + scheduleForAlter(); + + updatePositionOnPlanetServer(true); +} + +//----------------------------------------------------------------------- + +void ServerObject::containerDepersistContents(ServerObject * oldParent, ServerObject * newParent) +{ + Container * const oldContainer = oldParent ? ContainerInterface::getContainer(*oldParent) : NULL; + Container * const newContainer = newParent ? ContainerInterface::getContainer(*newParent) : NULL; + + if (oldContainer) + oldContainer->internalItemRemoved(*this); + if (newContainer) + { + SlottedContainer * const slotContainer = dynamic_cast(newContainer); + if (slotContainer) + { + SlottedContainmentProperty* const slotted = ContainerInterface::getSlottedContainmentProperty(*this); + DEBUG_FATAL(!slotted, ("Error unpacking non slotted objects into a slotted container")); + slotContainer->depersistSlotContents(*this, -1); + slotContainer->updateArrangement(*this, -1, slotted->getCurrentArrangement()); + } + else + { + newContainer->depersistContents(*this); + } + } +} + +//----------------------------------------------------------------------- + +void ServerObject::containerHandleUpdateClients(ServerObject* oldContainer, ServerObject* newContainer, bool remFromWorld, bool addWorld) +{ + if (remFromWorld) + removeFromWorld(); + + // If we're moving in or out of the world cell, update as appropriate (adds or removes farUpdateVolume) + if (oldContainer && !newContainer && !addWorld) + onAddedToWorldCell(); + else if (newContainer && !oldContainer && !remFromWorld) + onRemovedFromWorldCell(); + + if (addWorld) + addToWorld(); + + ObserveTracker::onObjectContainerChanged(*this); + synchronizationOnContainerChange(oldContainer, newContainer); +} + +//----------------------------------------------------------------------- + +void ServerObject::createFarNetworkUpdateVolume(float const overrideVal) +{ + if (isBeingDestroyed() || isUnloading()) + { + DEBUG_REPORT_LOG(true, ("Not creating volume for object that is being destroyed\n")); + return; + } + if (m_networkUpdateFar) + { + WARNING_STRICT_FATAL(true, ("Object %s already has a far update volume", getNetworkId().getValueString().c_str())); + return; + } + + // There's no reason for a contained item to have a far network update volume + // if this object is contained by something else. + Object const *const containedByObject = ContainerInterface::getContainedByObject(*this); + if (containedByObject) + { + DEBUG_REPORT_LOG(true, ("SO::createFarNetworkUpdateVolume(): server id=[%lu],object id=[%s],container id=[%s]: skipping creation of far network update volume because item is contained.\n", + GameServer::getInstance().getProcessId(), + getNetworkId().getValueString().c_str(), + containedByObject->getNetworkId().getValueString().c_str())); + return; + } + + if (getCacheVersion() == 0) + { + const ServerObjectTemplate * myTemplate = safe_cast(getObjectTemplate()); + UNREF(myTemplate); + float const radius_far = overrideVal != 0.0f ? overrideVal : getFarNetworkUpdateRadius(); + if (radius_far > 0) + { + if (ServerWorld::isSpaceScene()) + { + DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("creating far update volume (space version) for %s (template=%s, radius=%g)\n", getNetworkId().getValueString().c_str(), myTemplate->getName(), radius_far)); + // don't make link-dead creatures visible to other people at the top level in space + if (getSendToClient() && (getClient() || !asCreatureObject())) + SpaceVisibilityManager::addObject (*this, static_cast(radius_far)); + } + else + { + DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("creating far update volume for %s (template=%s, radius=%g)\n", getNetworkId().getValueString().c_str(), myTemplate->getName(), radius_far)); + TriggerVolume * t = new NetworkTriggerVolume(*this, radius_far); + addTriggerVolume(t); + m_networkUpdateFar = t; + } + } + } +} + +//----------------------------------------------------------------------- + +void ServerObject::destroyFarNetworkUpdateVolume() +{ + if (!m_networkUpdateFar) + return; + + DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("Removing far update volume for %s\n", getNetworkId().getValueString().c_str())); + ServerWorld::removeObjectTriggerVolume(m_networkUpdateFar); + TriggerVolumeMap::iterator i = m_triggerVolumes.find(NetworkTriggerVolumeNamespace::NetworkTriggerVolumeName); + if (i == m_triggerVolumes.end() || i->second != m_networkUpdateFar) + { + WARNING_STRICT_FATAL(true, ("Called destroyFarNetworkUpdateVolume but could not find it in m_triggerVolumes")); + } + else + m_triggerVolumes.erase(i); + + delete m_networkUpdateFar; + m_networkUpdateFar = 0; +} + +//----------------------------------------------------------------------- + +bool ServerObject::isNetworkUpdateFarTriggerVolume(TriggerVolume const &triggerVolume) const +{ + return triggerVolume.isNetworkTriggerVolume(); +} + +// ---------------------------------------------------------------------- + +TriggerVolume *ServerObject::getNetworkTriggerVolume() +{ + return m_networkUpdateFar; +} + +// ---------------------------------------------------------------------- + +float ServerObject::getFarNetworkUpdateRadius() const +{ + if (ServerWorld::getSceneId() == NewbieTutorial::getSceneId()) + return 0.f; + + // Overide update radius for all scenes for all objects gloablly with config entry + int const overrideRadius = ConfigServerGame::getOverrideUpdateRadius(); + // Overide the update radius for a specific scene if the above global overide is not set + // If Scene overide is disabled in ConfigServerGame::getEnableSceneGlobalData() it will return zero + float radius = overrideRadius > 0 ? static_cast(overrideRadius) : SceneGlobalData::getUpdateRadius(ServerWorld::getSceneId()); + // Set the radius to the far update range of from the object template if it hasn't already been overiden + radius = radius > 0 ? radius : safe_cast(getObjectTemplate())->getUpdateRanges(ServerObjectTemplate::UR_far); + + if (!ServerWorld::isSpaceScene()) + { + if (ms_buildingUpdateRadiusMultiplier == 0) + setBuildingUpdateRadiusMultiplier(ConfigServerGame::getBuildingUpdateRadiusMultiplier()); + + // Potentially allow larger objects to come into range sooner if the cfg setting to do so is set + if (radius >= 127.0f && radius < 512.0f && !asCreatureObject()) + radius *= ms_buildingUpdateRadiusMultiplier; + } + return radius; +} + +// ---------------------------------------------------------------------- + +void ServerObject::onTriggerEnter(ServerObject & object, TriggerVolume & triggerVolume) +{ +} + +//----------------------------------------------------------------------- +// object is leaving this' volume +void ServerObject::onTriggerExit(ServerObject & object, TriggerVolume & triggerVolume) +{ +} + +// ---------------------------------------------------------------------- +// this object got added to a trigger volume +void ServerObject::onAddedToTriggerVolume(TriggerVolume & triggerVolume) +{ + // only CreatureObject should ever be added to a TriggerVolume + WARNING(true, ("ServerObject (%s) being added to TriggerVolume (%s) owned by (%s)", + getDebugInformation().c_str(), + triggerVolume.getName().c_str(), + triggerVolume.getOwner().getDebugInformation().c_str())); +} + +// ---------------------------------------------------------------------- +// this object got removed from a trigger volume +void ServerObject::onRemovedFromTriggerVolume(TriggerVolume & triggerVolume) +{ + // NOTE: be careful about referencing the TriggerVolume because this + // function can be called from the TriggerVolume's dtor + + // only CreatureObject should ever be added to a TriggerVolume + WARNING(true, ("ServerObject (%s) being removed from TriggerVolume (%s) owned by (%s)", + getDebugInformation().c_str(), + triggerVolume.getName().c_str(), + triggerVolume.getOwner().getDebugInformation().c_str())); +} + +// ---------------------------------------------------------------------- + +/** + * Send an object to the database process to be persisted, if it isn't already. + * After this function is called, changes to this object will be sent to the database. + */ + +bool ServerObject::persist() +{ + // Do not persist buildout objects (buildout objects have negative networkIds) + if (getNetworkId() < NetworkId::cms_invalid) + return false; + + if (isAuthoritative()) + { + ContainedByProperty *containedBy = getContainedByProperty(); + + bool const contained = containedBy && containedBy->getContainedByNetworkId().isValid(); + + if (ServerWorld::isSpaceScene()) + { + // in space, non-player objects are only allowed to persist at the origin + if (!contained && !isPlayerControlled() && getPosition_p() != Vector::zero) + { + WARNING_STRICT_FATAL(true, ("Tried to persist non-player object %s in a space scene away from the origin (not persisting).", getDebugInformation().c_str())); + return false; + } + } + else + { + WARNING_STRICT_FATAL((getPosition_w() == Vector::zero) && !contained && (getSceneId() != "universe"), ("Persisting object %s (%s) at (0,0,0)",getNetworkId().getValueString().c_str(),getTemplateName())); + } + + if (!m_persisted.get()) + { +#ifdef _DEBUG + ServerObject *parent = static_cast(ContainerInterface::getContainedByObject(*this)); + if (parent && !parent->isPersisted()) + { + WARNING(true, ("Persisting %s into %s which is not persisted!", getNetworkId().getValueString().c_str(), parent->getNetworkId().getValueString().c_str())); + } +#endif + + m_persisted = true; + + markChildrenPersisted(); + sendCreateAndBaselinesToDatabaseServer(); + + PositionUpdateTracker::sendPositionUpdate(*this); + } + + return true; + } + else + { + sendControllerMessageToAuthServer(CM_persistObject, 0); + } + + return false; +} + +// ---------------------------------------------------------------------- + +void ServerObject::removeTriggerVolume(const std::string & name) +{ + for (unsigned int i = 0; i < m_triggerVolumeInfo.size(); ++i) + { + if (m_triggerVolumeInfo[i].name == name) + { + m_triggerVolumeInfo.erase(i); + break; + } + } +} + +//----------------------------------------------------------------------- + +void ServerObject::sendControllerMessageToAuthServer(enum GameControllerMessage cm, MessageQueue::Data * msg, float value) +{ +#ifdef _DEBUG + // debug stuff done this way so it is easy to break on + if (!isInitialized() || isInEndBaselines()) + { + WARNING(isInEndBaselines(), ("sendControllerMessageToAuthServer while ending baselines: message id=(%d) from object id=[%s], template=[%s], on server id=[%d]", static_cast(cm), getNetworkId().getValueString().c_str(), getObjectTemplateName(), static_cast(GameServer::getInstance().getProcessId()))); + WARNING(!isInitialized(), ("sendControllerMessageToAuthServer while uninitialized: message id=(%d) from object id=[%s], template=[%s], on server id=[%d]", static_cast(cm), getNetworkId().getValueString().c_str(), getObjectTemplateName(), static_cast(GameServer::getInstance().getProcessId()))); + } +#endif + + Controller * controller = getController(); + if(controller) + { + controller->appendMessage(cm, value, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + } + else + { + DEBUG_WARNING(true, ("No controller for sendControllerMessageToAuthServer")); + delete msg; + } +} + +//----------------------------------------------------------------------- + +bool ServerObject::getSendToClient() const +{ + return getCacheVersion() == 0 && getLocalFlag(LocalObjectFlags::ServerObject_SendToClient); +} + +//----------------------------------------------------------------------- + +void ServerObject::sendToClientsInUpdateRange(const GameNetworkMessage & message, bool reliable, bool includeSelf) const +{ + std::set const &clients = getObservers(); + std::set::const_iterator i; + std::map > &tmpDistributionList = DistributionListStack::alloc(); + + Client const * const myClient = getClient(); + + float minDistanceSquared = 0.0f; + + if (!reliable) + { + if (m_unreliableControllerMessageSequenceNumber == 0) + { + // Send reliable + + reliable = true; + ++m_unreliableControllerMessageSequenceNumber; + } + else + { + // Send un-reliable based on distance + + switch (m_unreliableControllerMessageSequenceNumber) + { + // The server is guaranteed to send one reliable transform update per 2 seconds (8:1 ratio for unreliable/reliable) + + case 1: { minDistanceSquared = ConfigServerGame::getUpdateRange7PacketsSquared(); } break; // 7 unreliable per 2 seconds + case 2: { minDistanceSquared = ConfigServerGame::getUpdateRange3PacketsSquared(); } break; // 3 unreliable per 2 seconds + case 3: { minDistanceSquared = ConfigServerGame::getUpdateRange5PacketsSquared(); } break; // 5 unreliable per 2 seconds + case 4: { minDistanceSquared = ConfigServerGame::getUpdateRange1PacketsSquared(); } break; // 1 unreliable per 2 seconds + case 5: { minDistanceSquared = ConfigServerGame::getUpdateRange4PacketsSquared(); } break; // 4 unreliable per 2 seconds + case 6: { minDistanceSquared = ConfigServerGame::getUpdateRange2PacketsSquared(); } break; // 2 unreliable per 2 seconds + case 7: { minDistanceSquared = ConfigServerGame::getUpdateRange6PacketsSquared(); } break; // 6 unreliable per 2 seconds + default: + { + DEBUG_WARNING(true, ("All cases should be handled for the sequence numbers: %d", m_unreliableControllerMessageSequenceNumber)); + } + + } + + if (m_unreliableControllerMessageSequenceNumber >= 7) + { + m_unreliableControllerMessageSequenceNumber = 0; + } + else + { + ++m_unreliableControllerMessageSequenceNumber; + } + } + } + + // need to do special handling for CM_combatSpam controller + // message to determine if the client should get the message + bool isCombatSpamMessage = false; + NetworkId combatSpamAttacker, combatSpamDefender; + Vector combatSpamAttackerPosition_w, combatSpamDefenderPosition_w; + if (!clients.empty()) + { + static unsigned long int const controllerMessageCrc = MessageDispatch::MessageBase::makeMessageTypeFromString("ObjControllerMessage"); + if (controllerMessageCrc == message.getType()) + { + ObjControllerMessage const & ocm = static_cast(message); + if (ocm.getMessage() == CM_combatSpam) + { + MessageQueueCombatSpam const * mqcs = static_cast(ocm.getData()); + + if (mqcs) + { + isCombatSpamMessage = true; + combatSpamAttacker = mqcs->m_attacker; + combatSpamAttackerPosition_w = mqcs->m_attackerPosition_w; + combatSpamDefender = mqcs->m_defender; + combatSpamDefenderPosition_w = mqcs->m_defenderPosition_w; + } + } + } + } + + for (i = clients.begin(); i != clients.end(); ++i) + { + // build connection list + Client * const c = (*i); + + if (isCombatSpamMessage && !c->shouldReceiveCombatSpam(combatSpamAttacker, combatSpamAttackerPosition_w, combatSpamDefender, combatSpamDefenderPosition_w)) + continue; + + if (!reliable) + { + // if it's time to try to send to this client + // because it is close enough, add it to the + // target list, otherwise continue looking + // through clients. + + ServerObject * const obj = c->getCharacterObject(); + + if (obj != NULL) + { + if ( (ConfigServerGame::getSkipUnreliableTransformsForOtherCells() && obj->getAttachedTo() != getAttachedTo()) + || (obj->getPosition_w().magnitudeBetweenSquared(getPosition_w()) > minDistanceSquared) + || (!CellProperty::areAdjacent(getParentCell(), obj->getParentCell()))) + { + // Throw out this un-reliable packet due to distance + + continue; + } + } + } + + if(includeSelf || ( (!includeSelf) && c != myClient) ) + { + ConnectionServerConnection * const n = c->getConnection(); + if (n) + tmpDistributionList[n].push_back(c->getCharacterObjectId()); + } + } + + for (std::map >::const_iterator connIter = tmpDistributionList.begin(); connIter != tmpDistributionList.end(); ++connIter) + { + GameClientMessage const msg((*connIter).second, reliable, message); + (*connIter).first->send(msg, reliable); + } + + DistributionListStack::release(); +} + +//----------------------------------------------------------------------- + +void ServerObject::sendToSpecifiedClients(const GameNetworkMessage & message, bool reliable, const std::vector & clients) +{ + for (std::vector::const_iterator i = clients.begin(); i != clients.end(); ++i) + { + ServerObject * o = safe_cast(NetworkIdManager::getObjectById(*i)); + if (o != NULL && o->getClient() != NULL) + o->getClient()->send(message, reliable); + } +} + +//----------------------------------------------------------------------- + +void ServerObject::appendMessage(int const message, float const value, uint32 const flags) +{ + Controller * const co = getController(); + if (co) + co->appendMessage(message, value, flags); + else + DEBUG_REPORT_LOG(true, ("ServerObject::appendMessage: %s called without a controller.\n", getDebugInformation().c_str())); +} + +//----------------------------------------------------------------------- + +void ServerObject::appendMessage(int const message, float const value, MessageQueue::Data * const data, uint32 const flags) +{ + Controller * const co = getController(); + if (co) + co->appendMessage(message, 0.0f, data, flags); + else + DEBUG_REPORT_LOG(true, ("ServerObject::appendMessage: %s called without a controller.\n", getDebugInformation().c_str())); +} + +//----------------------------------------------------------------------- + +void ServerObject::forwardServerObjectSpecificBaselines() const +{ +} + +//----------------------------------------------------------------------- + +void ServerObject::sendObjectSpecificBaselinesToClient(Client const &) const +{ +} + +//----------------------------------------------------------------------- + +BaselinesMessage * ServerObject::createSharedBaselinesMessage() const +{ + return new BaselinesMessage(getNetworkId(), getObjectType(), m_sharedPackage, BaselinesMessage::BASELINES_SHARED); +} + +//----------------------------------------------------------------------- + +BaselinesMessage * ServerObject::createSharedNpBaselinesMessage() const +{ + return new BaselinesMessage(getNetworkId(), getObjectType(), m_sharedPackage_np, BaselinesMessage::BASELINES_SHARED_NP); +} + +//----------------------------------------------------------------------- + +void ServerObject::setAuthority() +{ + // We make sure to send out deltas before setting authority, so that we don't push out deltas at the + // end of the frame which were intended to be nonauthoritative. + if (isInitialized()) + sendDeltasForSelfAndContents(); + + DEBUG_REPORT_LOG(ConfigServerGame::getLogObservers(), ("Called setAuthority on %s\n", getNetworkId().getValueString().c_str())); + + Container * const container = ContainerInterface::getContainer(*this); + if (container) + { + std::vector idList; + idList.reserve(container->getNumberOfItems()); + for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) + idList.push_back(*containerIterator); + + for (std::vector::iterator i = idList.begin(); i != idList.end(); ++i) + { + ServerObject * const containedObject = safe_cast(i->getObject()); + if (containedObject) + containedObject->setAuthority(); + } + } + + safe_cast(getController())->setAuthoritative(true); + + if (getScriptObject()) + getScriptObject()->setOwnerIsAuthoritative(true, GameServer::getInstance().getProcessId()); + + setAuthServerProcessId(GameServer::getInstance().getProcessId()); + + if (isInitialized()) + updatePositionOnPlanetServer(true); + + if (isAuthoritative() && (!isPlayerControlled() || getClient()) && getObjVars().hasItem("teleportFixup")) + TeleportFixupHandler::add(*this); + + // Update loadWith so we don't depend on a stale value for objects that + // drop authority and regain it later without unloading. + setLoadWith(ContainerInterface::getLoadWithContainerId(*this)); + + virtualOnSetAuthority(); + scheduleForAlter(); + if (!m_messageTos.empty()) + MessageToQueue::getInstance().addToScheduler(*this, m_messageTos.begin()->second.getCallTime()); + + if (isPlayerControlled()) + { + // Make sure Central knows the right sceneId for the player + GenericValueTypeMessage > > const msg( + "SetSceneForPlayer", + std::make_pair( + getNetworkId(), + std::make_pair(ServerWorld::getSceneId(), false))); + + GameServer::getInstance().sendToCentralServer(msg); + + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); + if ((iterFind != connectedCharacterLfgData.end()) && (iterFind->second.locationPlanet != ServerWorld::getSceneId())) + ServerUniverse::setConnectedCharacterPlanetData(getNetworkId(), ServerWorld::getSceneId()); + } + + // When a top level object or an object whose contiaining object is + // authoritative gets to this point, all its contents have been + // made authoritative, so it is now safe to trigger appropriate objects + // to notify them of gaining authority. + ServerObject * const containingObject = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (!containingObject || containingObject->isAuthoritative()) + triggerMadeAuthoritative(); +} + +//----------------------------------------------------------------------- + +void ServerObject::virtualOnSetClient() +{ + if (getObjVars().hasItem("teleportFixup")) + TeleportFixupHandler::add(*this); + + if (m_pendingSyncUi) + { + for (std::vector::const_iterator i = m_pendingSyncUi->begin(); i != m_pendingSyncUi->end(); ++i) + { + ServerObject *uiObject = safe_cast(NetworkIdManager::getObjectById(*i)); + if (uiObject && uiObject->getSynchronizedUi()) + uiObject->addSynchronizedUiClient(*this); + } + delete m_pendingSyncUi; + m_pendingSyncUi = 0; + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::setClient(Client &newClient) +{ + m_client = &newClient; + + virtualOnSetClient(); + + safe_cast(getController())->onClientReady(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::clearClient() +{ + if (m_client) + { + safe_cast(getController())->onClientLost(); + m_client = 0; + } +} + +//----------------------------------------------------------------------- + +void ServerObject::setCacheVersion(const int c) +{ + if (isAuthoritative()) + { + bool const becomingUncached = c == 0 && m_cacheVersion.get() != 0; + + if (becomingUncached) + ObserveTracker::onObjectDestroyed(*this, false); + + m_cacheVersion.set(c); + if (c == 0) + { + Container* container = ContainerInterface::getContainer(*this); + if (container) + { + for (ContainerIterator i = container->begin(); i != container->end(); ++i) + { + ServerObject *containedObject = safe_cast((*i).getObject()); + if (containedObject && containedObject->getCacheVersion() != 0) + containedObject->setCacheVersion(0); + } + } + + if (becomingUncached && isInWorld() && !ContainerInterface::getContainedByObject(*this)) + createFarNetworkUpdateVolume(); + } + } + else + { + sendControllerMessageToAuthServer(CM_setCacheVersion, new MessageQueueGenericValueType(c)); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::setDefaultAlterTime(float time) +{ + // if the server is running in build mode, always alter, so that designers' changes + // will be made even if there are no players around + if (ConfigServerGame::getBuildoutAreaEditingEnabled() && time > AlterResult::cms_alterQuickly) + time = AlterResult::cms_alterQuickly; + m_defaultAlterTime = time; +} + +// ---------------------------------------------------------------------- +// CellProperty::addObject_w calls around this function (it calls Object::setParentCell directly) +// to ensure that server-side objects send cellChanged notifications correctly. + +void ServerObject::setParentCell(CellProperty * newCell) +{ + // Uninitialized or proxy objects can set the parent cell directly + + if (!isInitialized() || !isAuthoritative()) + { + Object::setParentCell(newCell); + return; + } + + // Everything else has to go through ContainerInterface + + Transform oldTransform = getTransform_o2p(); + + bool result = false; + + CellProperty * oldCell = getParentCell(); + + if(oldCell == NULL) oldCell = CellProperty::getWorldCellProperty(); + if(newCell == NULL) newCell = CellProperty::getWorldCellProperty(); + + // ---------- + + if(oldCell == newCell) + { + // Cells are the same - nothing to do + } + if(newCell == CellProperty::getWorldCellProperty()) + { + // Object was in a cell and is moving to the world, transfer from cell container to world + + Object * oldCellObject = &oldCell->getOwner(); + + Transform oldCellTransform = oldCellObject->getTransform_o2w(); + + Transform newTransform; + + newTransform.multiply(oldCellTransform,oldTransform); + + Container::ContainerErrorCode tmp = Container::CEC_Success; + result = ContainerInterface::transferItemToWorld(*this, newTransform, NULL, tmp); + + DEBUG_REPORT_LOG(!result, ("Object %s (id=%s) transfer to world was denied via ContainerInterface::transferItemToWorld()\n", getObjectTemplateName(), getNetworkId().getValueString().c_str())); + } + else + { + // Object is moving to a different cell + + Object * newCellObject = &newCell->getOwner(); + + ServerObject * newCellServerObject = safe_cast(newCellObject); + + Container::ContainerErrorCode tmp = Container::CEC_Success; + result = ContainerInterface::transferItemToCell(*newCellServerObject, *this, NULL, tmp); + + DEBUG_REPORT_LOG(!result, ("Object %s (id=%s) transfer to cell (id=%s) was denied via ContainerInterface::transferItemToCell()\n", getObjectTemplateName(), getNetworkId().getValueString().c_str(), newCellObject->getNetworkId().getValueString().c_str())); + } + + // ---------- + + if(!result) + { + // A failed transfer may have mucked up the transform, so restore it now. + + setTransform_o2p(oldTransform); + } +} + +//----------------------------------------------------------------------- + +NetworkId const &ServerObject::getOwnerId() const +{ + return NetworkId::cms_invalid; +} + +//----------------------------------------------------------------------- + +bool ServerObject::isOwner(NetworkId const &, Client const *client) const +{ + return client && client->isGod(); +} + +//----------------------------------------------------------------------- + +void ServerObject::setOwnerId(NetworkId const &) +{ +} + +//----------------------------------------------------------------------- + +/** + * Rename an object. + * @param newName The new name for the object + * You cannot rename a player-controlled object using this function. + * @see PlayerCreationManagerServer::renamePlayer() + */ + +void ServerObject::setObjectName(const Unicode::String &newName) +{ + if(isAuthoritative()) + { + if (isPlayerControlled()) + { + DEBUG_WARNING(true, ("You cannot set the name of a player controlled object directly. Name:<%s>", Unicode::wideToNarrow(newName).c_str())); + return; + } + + std::string UTF8String = Unicode::wideToUTF8(newName); + if (UTF8String.length() > 127) + { + DEBUG_WARNING(true, ("Tried to set object %s's name to something too long (truncating). [%s]", getNetworkId().getValueString().c_str(), UTF8String.c_str())); + m_objectName = Unicode::utf8ToWide(UTF8String.substr(0, 127)); + } + else + m_objectName = newName; + + if (newName[0] == '@') + { + StringId id(Unicode::wideToNarrow(newName)); + setObjectNameStringId(id); + setObjectName(Unicode::emptyString); + } + } + else + { + sendControllerMessageToAuthServer(CM_setObjectName, new MessageQueueGenericValueType(newName)); + } +} + +//----------------------------------------------------------------- + +void ServerObject::setObjectNameStringId (const StringId & id) +{ + if(isAuthoritative()) + { + m_nameStringId = id; + } + else + { + sendControllerMessageToAuthServer(CM_setObjectNameStringId, new MessageQueueGenericValueType(id)); + } +} + +//---------------------------------------------------------------------- + +void ServerObject::setSceneIdOnThisAndContents (const std::string & sceneId) +{ + setSceneId(sceneId); + Container *container = ContainerInterface::getContainer(*this); + if (container) + { + for (ContainerIterator containerIterator = container->begin(); containerIterator != container->end(); ++containerIterator) + { + ServerObject *containedObject = safe_cast((*containerIterator).getObject()); + if (containedObject) + { + containedObject->setSceneIdOnThisAndContents(sceneId); + } + } + } +} + +//---------------------------------------------------------------------- + +void ServerObject::speakText(NetworkId const &target, uint32 chatType, uint32 mood, uint32 flags, Unicode::String const &speech, int language, Unicode::String const &oob) +{ + if (speech.empty()) + { + return; + } + + if (chatType > 16384 || mood > 16384 || flags > 16384) + { + WARNING (true, ("ChatType, Mood, or Flags are out of 16 bit range. %d, %d, %d", chatType, mood, flags)); + return; + } + + const bool isTypePrivate = SpatialChatManager::isPrivate (chatType); + if (isTypePrivate) + flags |= MessageQueueSpatialChat::F_isPrivate; + + const uint16 volume = SpatialChatManager::getVolume (chatType); + + MessageQueueSpatialChat const chatMessage( + getNetworkId(), + target, + speech, + volume, + static_cast(chatType), + static_cast(mood), + flags, + language, + oob); + speakText(chatMessage); +} + +//----------------------------------------------------------------------- + +void ServerObject::speakText(MessageQueueSpatialChat const &spatialChat) +{ + if (!isAuthoritative ()) + { + Controller * const controller = getController(); + NOT_NULL (controller); + + MessageQueueSpatialChat * msg = new MessageQueueSpatialChat (spatialChat); + controller->appendMessage(CM_spatialChatSend, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + return; + } + + if (m_scriptObject) + { + ScriptParams params; + params.addParam(spatialChat.getText ()); + if (m_scriptObject->trigAllScripts(Scripting::TRIG_SPEAKING, params) != SCRIPT_CONTINUE) + { + LOG("ScriptInvestigation", ("Chat could not speak for %s because scripts said not to", getNetworkId().getValueString().c_str())); + return; + } + } + + const float distance = static_cast(spatialChat.getVolume ()); + const uint32 flags = spatialChat.getFlags(); + const bool isPrivate = (flags & MessageQueueSpatialChat::F_isPrivate) != 0; + const bool isTargetOnly = (flags & MessageQueueSpatialChat::F_targetOnly) != 0; + const bool isTargetGroupOnly = (flags & MessageQueueSpatialChat::F_targetGroupOnly) != 0; + const bool isTargetAndSourceGroup = (flags & MessageQueueSpatialChat::F_targetAndSourceGroup) != 0; + + const NetworkId & chatTargetId = spatialChat.getTargetId (); + const NetworkId & chatSourceId = spatialChat.getSourceId (); + + typedef std::vector ServerObjectVector; + ServerObjectVector results; + ServerWorld::getSpatialChatListeners(*this, distance, results); + + const ServerObject * const chatTarget = safe_cast(NetworkIdManager::getObjectById (chatTargetId)); + const CreatureObject * const chatTargetCreature = chatTarget ? chatTarget->asCreatureObject () : 0; + int const chatMessageIndex = ChatLogManager::getNextMessageIndex(); + + const ServerObject * const chatSource = safe_cast(NetworkIdManager::getObjectById (chatSourceId)); + const CreatureObject * const chatSourceCreature = chatSource ? chatSource->asCreatureObject () : 0; + + for(ServerObjectVector::iterator i = results.begin(); i != results.end(); ++i) + { + ServerObject * const target = NON_NULL (*i); + + const NetworkId & targetId = target->getNetworkId (); + + //-- see if the target is valid for the flags + if ((spatialChat.getFlags() & MessageQueueSpatialChat::F_skipTarget) != 0 && target->getNetworkId() == spatialChat.getTargetId()) + continue; + if ((spatialChat.getFlags() & MessageQueueSpatialChat::F_skipSource) != 0 && target->getNetworkId() == spatialChat.getSourceId()) + continue; + + if (isTargetAndSourceGroup) + { + const CreatureObject * const targetCreature = target->asCreatureObject (); + if (!targetCreature) + { + continue; + } + + const GroupObject * const chatSourceGroup = chatSourceCreature ? chatSourceCreature->getGroup () : 0; + const GroupObject * const chatTargetGroup = chatTargetCreature ? chatTargetCreature->getGroup () : 0; + const GroupObject * const targetGroup = targetCreature ? targetCreature->getGroup () : 0; + + //continue if targetCreature is not in a group with the chat source or chat target + if (targetId != chatTargetId && targetId != chatSourceId) + { + if (!targetGroup || (targetGroup != chatSourceGroup && targetGroup != chatTargetGroup)) + { + continue; + } + } + + } + else if (isTargetGroupOnly) + { + if (!chatTargetCreature) + continue; + + if (targetId != chatTargetId) + { + const CreatureObject * const targetCreature = target->asCreatureObject (); + if (!targetCreature || !targetCreature->getGroup() || targetCreature->getGroup () != chatTargetCreature->getGroup ()) + continue; + } + } + else if (isTargetOnly) + { + if (targetId != chatTargetId) + continue; + } + + if (isPrivate) + { + if (targetId == chatTargetId || getNetworkId () == chatTargetId || getNetworkId () == chatSourceId) + { + //-- don't send text to ourselves if we are an NPC + if (isPlayerControlled () || chatSourceId != getNetworkId ()) + { + target->hearText(*this, spatialChat, chatMessageIndex); + } + } + else + { + const MessageQueueSpatialChat noTextMsg (spatialChat.getSourceId (), + spatialChat.getTargetId (), + Unicode::emptyString, + spatialChat.getVolume (), + spatialChat.getChatType (), + spatialChat.getMoodType (), + spatialChat.getFlags (), + spatialChat.getLanguage (), + Unicode::emptyString); + + target->hearText(*this, noTextMsg, chatMessageIndex); + } + } + else + { + target->hearText(*this, spatialChat, chatMessageIndex); + } + } +} + +//----------------------------------------------------------------------- + +void ServerObject::hearText(ServerObject const &source, MessageQueueSpatialChat const &spatialChat, int chatMessageIndex) +{ + Controller * const controller = NON_NULL (getController()); + if (!isAuthoritative()) + { + MessageQueueSpatialChat * const msg = new MessageQueueSpatialChat (spatialChat); + controller->appendMessage(CM_spatialChatReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + return; + } + + if (m_scriptObject) + { + ScriptParams params; + params.addParam(spatialChat.getSourceId()); + params.addParam(spatialChat.getText()); + if (!m_scriptObject->trigAllScripts(Scripting::TRIG_HEAR_SPEECH_STRING, params)) + return; + } + + if (getClient ()) + { + if ( source.getCacheVersion() > 0 + || ( ObserveTracker::isObserving(*getClient(), source) + && !PlayerObject::isIgnoring(getNetworkId(), spatialChat.getSourceId()))) + { + // Log the chat a player hears + + CreatureObject * const creatureObject = asCreatureObject(); + + if (creatureObject != NULL) + { + PlayerObject * const playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + + if (playerObject != NULL) + { + ChatAvatarId playerChatAvatarId(Chat::constructChatAvatarId(source)); + Unicode::String playerName(Unicode::narrowToWide(playerChatAvatarId.getFullName())); + + std::string chatTypeName; + + if (spatialChat.getChatType() == 0) + { + chatTypeName = "spatial"; + } + else + { + if (!SpatialChatManager::getChatNameByType(spatialChat.getChatType(), chatTypeName)) + { + chatTypeName = "error"; + } + } + + ChatLogManager::logChat(playerName, Unicode::emptyString, spatialChat.getText(), Unicode::narrowToWide(chatTypeName), chatMessageIndex, Os::getRealSystemTime()); + + playerObject->logChat(chatMessageIndex); + } + } + + MessageQueueSpatialChat * const msg = new MessageQueueSpatialChat (spatialChat); + controller->appendMessage(CM_spatialChatReceive, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } +} + +//---------------------------------------------------------------------- + +void ServerObject::performSocial (const NetworkId & target, uint32 socialType, bool animationOk, bool textOk) +{ + const MessageQueueSocial socialMsg (CachedNetworkId (*this), CachedNetworkId (target), socialType, animationOk, textOk); + performSocial (socialMsg); +} + +//---------------------------------------------------------------------- + +void ServerObject::performSocial (const MessageQueueSocial & socialMsg) +{ + // a permanently squelched player cannot do any emote + PlayerObject * p = PlayerCreatureController::getPlayerObject(asCreatureObject()); + if (p && (p->getSecondsUntilUnsquelched() < 0)) + { + return; + } + + if (!isAuthoritative ()) + { + Controller *const controller = NON_NULL (getController()); + + MessageQueueSocial * const msg = new MessageQueueSocial (socialMsg); + controller->appendMessage(CM_socialSend, 0, msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + return; + } + + // todo: this needs to have a better value sometime + static const float distance = 50.0f; + + const Vector & pos_w = getPosition_w (); + typedef std::vector ServerObjectVector; + ServerObjectVector results; + ServerWorld::findObjectsInRange (pos_w, distance, results); + + + bool triggerOk = false; + std::string socialTypeName; + triggerOk = SocialsManager::getSocialNameByType (socialMsg.getSocialType(), socialTypeName); + Unicode::String unicodeSocialTypeName(Unicode::narrowToWide(socialTypeName)); + + // allow scripts to prevent the player from performing the emote + ScriptParams params; + + if (getScriptObject() != NULL) + { + params.addParam(unicodeSocialTypeName); + if (getScriptObject()->trigAllScripts(Scripting::TRIG_PERFORM_EMOTE, params) != SCRIPT_CONTINUE) + return; + params.clear(); + } + + if (triggerOk) + { + params.addParam(getNetworkId()); + params.addParam(unicodeSocialTypeName); + } + + static const float trigger_range = 4.0f; + + for (ServerObjectVector::const_iterator it = results.begin(); it != results.end(); ++it) + { + ServerObject * const target = *it; + NOT_NULL (target); + + if (triggerOk && this != target) + { + const float target_trigger_range_sqr = sqr (trigger_range + target->getSphereExtent ().getRadius ()); + const float distance_sqr = pos_w.magnitudeBetweenSquared (target->getPosition_w ()); + + if (distance_sqr < target_trigger_range_sqr) + IGNORE_RETURN(target->getScriptObject()->trigAllScripts(Scripting::TRIG_SAW_EMOTE, params)); + } + + (*it)->seeSocial (socialMsg); + } +} + +//---------------------------------------------------------------------- + +void ServerObject::performCombatSpam (const MessageQueueCombatSpam & spamMsg, bool sendToSelf, bool sendToTarget, bool sendToBystanders) +{ + if (!isAuthoritative ()) + { + WARNING_STRICT_FATAL (true, ("Do not call performCombatSpam on non-authoritative objects")); + return; + } + + if (sendToSelf && !sendToBystanders) + seeCombatSpam (spamMsg); + + if (sendToTarget && !sendToBystanders) + { + ServerObject * const target = safe_cast(NetworkIdManager::getObjectById(spamMsg.m_defender)); + if (target) { + if (target->getNetworkId() != spamMsg.m_attacker) { + target->seeCombatSpam (spamMsg); + } + } else { + WARNING_STRICT_FATAL (!sendToSelf && !sendToBystanders, ("null target_obj in commandFuncCombatSpam, when sendToTarget was set true")); + } + } + + if (sendToBystanders) + { + Controller *const controller = NON_NULL (getController()); + controller->appendMessage (CM_combatSpam, 0, new MessageQueueCombatSpam(spamMsg), GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); + } +} + +// --------------------------------------------------------------------- + +void ServerObject::teleportObject(Vector const &position_w, NetworkId const &targetContainer, std::string const &targetCellName, Vector const &position_p, std::string const &scriptCallback, bool forceLoadScreen) +{ + Vector destPosition_w(position_w); + + // clamp destination if in space + if ( ServerWorld::isSpaceScene() + && ( std::abs(position_w.x) > 8000.f + || std::abs(position_w.y) > 8000.f + || std::abs(position_w.z) > 8000.f)) + { + WARNING(true, ("Tried to warp object %s outside of space zone boundaries (%g,%g,%g)", getDebugInformation().c_str(), position_w.x, position_w.y, position_w.z)); + destPosition_w.set( + clamp(-8000.f, position_w.x, 8000.f), + clamp(-8000.f, position_w.y, 8000.f), + clamp(-8000.f, position_w.z, 8000.f)); + } + + + + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_teleportObject, new MessageQueueTeleportObject(destPosition_w, targetContainer, targetCellName, position_p, scriptCallback)); + return; + } + + // make a copy of the destination position, as it might change if we are + // warping to a cloning facility + Vector finalPosition_p(position_p); + + bool doWarp = forceLoadScreen; + bool ignoreContainer = true; + + Client * const client = m_client; + std::vector > containedClients; + getContainedClients(*this, containedClients); + + ServerObject *targetContainerObject = 0; + if (targetContainer != NetworkId::cms_invalid) + { + ignoreContainer = false; + targetContainerObject = safe_cast(NetworkIdManager::getObjectById(targetContainer)); + if (targetContainerObject && !targetCellName.empty()) + { + PortalProperty *portalProp = targetContainerObject->getPortalProperty(); + targetContainerObject = 0; // clear in case we have a building that doesn't have the cell + if (portalProp != NULL) + { + CellProperty *cellProp = portalProp->getCell(targetCellName.c_str()); + if (cellProp != NULL) + targetContainerObject = safe_cast(&(cellProp->getOwner())); + } + if (!targetContainerObject) + { + WARNING(true, ("Tried to teleport to nonexistant cell '%s' of building %s.", targetCellName.c_str(), targetContainer.getValueString().c_str())); + ignoreContainer = true; + } + } + } + + Vector const oldPosition_w(NON_NULL(ContainerInterface::getTopmostContainer(*this))->getPosition_w()); + if ( destPosition_w.magnitudeBetweenSquared(oldPosition_w) >= sqr(ConfigServerGame::getMaxTeleportDistanceWithoutSceneWarp()) + || ( targetContainer != NetworkId::cms_invalid + && ( !targetContainerObject + || ( getClient() + && !ObserveTracker::isObserving(*getClient(), *targetContainerObject))))) + doWarp = true; + + if (doWarp && !containedClients.empty()) + { + for (std::vector >::const_iterator i = containedClients.begin(); i != containedClients.end(); ++i) + { + Client * const containedClient = (*i).getPointer(); + if (containedClient) + { + ServerObject * const characterObject = containedClient->getCharacterObject(); + if (characterObject) + characterObject->onClientAboutToLoad(); + containedClient->clearControlledObjects(); + } + } + } + + bool moveNeeded = true; + if (!ignoreContainer && targetContainer != NetworkId::cms_invalid) + { + if (!doWarp && targetContainerObject && targetContainerObject->isAuthoritative()) + { + // allow the destination container to change the warp position + float yaw = getObjectFrameK_p().theta(); + const ServerObject * targetObject = safe_cast( + ContainerInterface::getTopmostContainer(*targetContainerObject)); + if (targetObject && targetObject->isAuthoritative()) + targetObject->changeTeleportDestination(finalPosition_p, yaw); + + // teleporting to a container on this server + if (targetContainerObject->asCellObject()) + { + Transform worldToCell; + worldToCell.invert(targetContainerObject->getTransform_o2w()); + Transform objectToCell; + objectToCell.multiply(worldToCell, getTransform_o2w()); + objectToCell.setPosition_p(finalPosition_p); + yaw -= getObjectFrameK_p().theta(); + if (yaw != 0.0f) + { + objectToCell.yaw_l(yaw); + objectToCell.reorthonormalize(); + } + safe_cast(getController())->teleport(objectToCell, targetContainerObject); + } + else + { + if (isPlayerControlled()) + { + WARNING(true, ("Tried to use ServerObject::teleportObject to teleport a player controlled object into a non-cell container!")); + return; + } + + Container::ContainerErrorCode err = Container::CEC_Success; + ContainerInterface::transferItemToGeneralContainer(*targetContainerObject, *this, 0, err, false); + } + + moveNeeded = false; + } + else + { + // container is on a different server - flag to move us into the container as soon as we change authority + setInteriorTeleportDestination(targetContainer, targetCellName, position_p); + } + } + + //-- setup the script callback + if (!scriptCallback.empty()) + setTeleportScriptCallback(scriptCallback); + + if (moveNeeded) + { + // Moves the object. If the new area is on a different server, the PlanetServer will change our authority. + + // What we really want to check here is whether we want to use the ServerController's teleport + // if a player has logged out, but we still have them loaded in game, their client will be null, + // but we still want to use the ServerController's teleport method + // so, we check against the player creature controller and player ship controller as well + ServerController * controller = safe_cast(getController()); + if (controller && (client || dynamic_cast(controller) || dynamic_cast(controller))) + { + Transform newTransform(getTransform_o2w()); + newTransform.setPosition_p(destPosition_w); + controller->teleport(newTransform, 0); + } + else + { + if (ContainerInterface::getContainedByObject(*this)) + { + Transform newTransform(getTransform_o2w()); + newTransform.setPosition_p(destPosition_w); + Container::ContainerErrorCode err = Container::CEC_Success; + ContainerInterface::transferItemToWorld(*this, newTransform, 0, err); + } + else + setPosition_p(destPosition_w); + } + } + + if (doWarp && !containedClients.empty()) + { + for (std::vector >::const_iterator i = containedClients.begin(); i != containedClients.end(); ++i) + { + Client * const containedClient = (*i).getPointer(); + if (containedClient) + { + ServerObject * const so = NON_NULL(safe_cast(NetworkIdManager::getObjectById(containedClient->getCharacterObjectId()))); + CreatureObject * const primaryControlledCreature = NON_NULL(so->asCreatureObject()); + containedClient->assumeControl(*primaryControlledCreature); + } + } + } + + CollisionWorld::objectWarped(this); + + if (isAuthoritative() && (!isPlayerControlled() || getClient()) && getObjVars().hasItem("teleportFixup")) + TeleportFixupHandler::add(*this); +} + +// ---------------------------------------------------------------------- + +void ServerObject::changeTeleportDestination(Vector &, float &) const +{ +} + +// ---------------------------------------------------------------------- + +void ServerObject::updatePositionOnPlanetServer(bool forceUpdate) +{ + PROFILER_AUTO_BLOCK_DEFINE("updatePositionOnPlanetServer"); + // In space, only send the forced updates + if (isAuthoritative() && isInitialized() && (forceUpdate || !ServerWorld::isSpaceScene())) + updatePlanetServerInternal(forceUpdate); +} + +//---------------------------------------------------------------------- + +void ServerObject::updatePlanetServerInternal(bool) const +{ +} + +//---------------------------------------------------------------------- + +/** +* Attempts to create a synchronized ui object. If the synchronized ui object +* does not exist, its creation is attempted via createSynchronizedUi. The default implementation +* of createSynchronizedUi returns null, and renders this method a no-op. +*/ +void ServerObject::addSynchronizedUi(const std::vector & clients) +{ + if (!m_synchronizedUi.getPointer()) + m_synchronizedUi = createSynchronizedUi (); + + if (m_synchronizedUi.getPointer()) + { + for (std::vector::const_iterator i = clients.begin(); i != clients.end(); ++i) + { + ServerObject * client = safe_cast( + NetworkIdManager::getObjectById(*i)); + if (client != NULL) + { + if (client->getClient() != NULL) + m_synchronizedUi->addClientObject (*client); + else + { + client->addPendingSynchronizedUi(*this); + } + } + else + { + WARNING(true, ("Object %s tried to add non-existant client %s to its sync ui", + getNetworkId().getValueString().c_str(), i->getValueString().c_str())); + } + } + scheduleForAlter(); + } +} + +//---------------------------------------------------------------------- + +/** +* Attempts to add a client to the synchronized ui object. If the synchronized ui object +* does not exist, its creation is attempted via createSynchronizedUi. The default implementation +* of createSynchronizedUi returns null, and renders this method a no-op. +* +*/ +void ServerObject::addSynchronizedUiClient(ServerObject & client) +{ + if (isAuthoritative()) + { + if (!m_synchronizedUi.getPointer()) + m_synchronizedUi = createSynchronizedUi (); + + if (!m_synchronizedUi.getPointer()) + return; + + m_synchronizedUi->addClientObject (client); + scheduleForAlter(); + } + else + { + WARNING_STRICT_FATAL(true, ("Non-authoritative object %s is being asked to create a synchronizedUi for client %s", + getNetworkId().getValueString().c_str(), client.getNetworkId().getValueString().c_str())); + } +} + +//---------------------------------------------------------------------- + +void ServerObject::removeSynchronizedUiClient(const NetworkId & clientId) +{ + if (!m_synchronizedUi.getPointer()) + return; + + WARNING(!isAuthoritative(), ("ServerObject::removeSynchronizedUiClient being called on non-authoritative object %s for client %s", + getNetworkId().getValueString().c_str(), clientId.getValueString().c_str())); + + m_synchronizedUi->removeClientObject (clientId); + + if (m_synchronizedUi->getNumClients () == 0) + { + delete m_synchronizedUi.getPointer(); + } + scheduleForAlter(); +} + +//---------------------------------------------------------------------- + +/** +* Subclasses implement this if they have an appropriate synchronized ui object. +* Base class implementation returns null. +*/ +ServerSynchronizedUi * ServerObject::createSynchronizedUi () +{ + return 0; +} + +//---------------------------------------------------------------------- + +/** + * Adds a object to the list of objects that have a synchronized ui and are + * waiting for this object to have a client attached. + * + * @param uiObject the object with the synchronized ui + */ +void ServerObject::addPendingSynchronizedUi(const ServerObject & uiObject) +{ + if (getClient() != NULL) + { + WARNING(true, ("ServerObject::addPendingSynchronizedUi called on object %s that already has a client", getNetworkId().getValueString().c_str())); + return; + } + + if (m_pendingSyncUi == NULL) + m_pendingSyncUi = new std::vector; + m_pendingSyncUi->push_back(uiObject.getNetworkId()); +} + +//---------------------------------------------------------------------- + +void ServerObject::setPlayerControlled(bool newValue) +{ + if(isAuthoritative()) + { + m_playerControlled=newValue; + if (newValue) + setDefaultAlterTime(0); + else + setDefaultAlterTime(AlterResult::cms_keepNoAlter); + } + else + { + sendControllerMessageToAuthServer(CM_setPlayerControlled, new MessageQueueGenericValueType(newValue)); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::internalAdjustBankBalance(int const amount, bool makeRoom) +{ + if ((amount > 0) && ((amount + m_bankBalance.get()) > ConfigServerGame::getMaxMoney()) && makeRoom && isAuthoritative()) + { + PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); + if (po && po->isAuthoritative()) + { + int attempt = 0; + do + { + int amountToMove = amount + m_bankBalance.get() - ConfigServerGame::getMaxMoney(); + if (amountToMove > m_bankBalance.get()) + { + amountToMove = m_bankBalance.get(); + } + + if (amountToMove <= 0) + break; + + if ((amountToMove + m_cashBalance.get()) > ConfigServerGame::getMaxMoney()) + { + // not enough room in cash, see if there's still room in galactic reserve + int8 const galacticReserve = po->getGalacticReserveDeposit(); + if (static_cast(galacticReserve) < ConfigServerGame::getMaxGalacticReserveDepositBillion()) + { + // transfer 1 billion into galactic reserve, and try again, if necessary + po->depositToGalacticReserve(true); + + // failed to transfer to galactic reserve, don't try again + if (galacticReserve == po->getGalacticReserveDeposit()) + { + break; + } + } + else + { + // no more room in galactic reserve, move as much as possible into cash + amountToMove = ConfigServerGame::getMaxMoney() - m_cashBalance.get(); + if (amountToMove > m_bankBalance.get()) + { + amountToMove = m_bankBalance.get(); + } + + if (amountToMove > 0) + { + withdrawCashFromBank(amountToMove); + } + + break; + } + } + else + { + if (amountToMove > 0) + { + withdrawCashFromBank(amountToMove); + } + + break; + } + + ++attempt; + + } while (((amount + m_bankBalance.get()) > ConfigServerGame::getMaxMoney()) && (attempt < 2)); + } + } + + m_bankBalance = m_bankBalance.get() + amount; + if (m_bankBalance.get() > ConfigServerGame::getMaxMoney()) + { + LOG("CustomerService",("SuspectedCheaterChannel: %s has %i credits in the bank.", PlayerObject::getAccountDescription(this).c_str(), m_bankBalance.get())); + m_bankBalance = ConfigServerGame::getMaxMoney(); + } + + if (getClient() && getClient()->isFreeTrialAccount() + && (m_cashBalance.get() + m_bankBalance.get()) > ConfigServerGame::getMaxFreeTrialMoney()) + { + LOG("CustomerService",("FreeTrial: %s has exceeded max free trial balance of %d from a bank transfer amount of %d. Money lost: %d.",PlayerObject::getAccountDescription(this).c_str(), ConfigServerGame::getMaxFreeTrialMoney(), amount, m_cashBalance.get() + m_bankBalance.get() - ConfigServerGame::getMaxFreeTrialMoney())); + m_bankBalance = ConfigServerGame::getMaxFreeTrialMoney() - m_cashBalance.get(); + ProsePackage prosePackage; + prosePackage.stringId = StringId("ui_trade", "err_max_free_trial_money"); + prosePackage.digitInteger = ConfigServerGame::getMaxFreeTrialMoney(); + Chat::sendSystemMessage(*this, prosePackage); + } + + // sanity check - fix up any player character negative cash/bank balance + if ((m_cashBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) + m_cashBalance = 0; + + if ((m_bankBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) + m_bankBalance = 0; + + addObjectToConcludeList(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::internalAdjustCashBalance(int const amount, bool makeRoom) +{ + if ((amount > 0) && ((amount + m_cashBalance.get()) > ConfigServerGame::getMaxMoney()) && makeRoom && isAuthoritative()) + { + PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); + if (po && po->isAuthoritative()) + { + int attempt = 0; + do + { + int amountToMove = amount + m_cashBalance.get() - ConfigServerGame::getMaxMoney(); + if (amountToMove > m_cashBalance.get()) + { + amountToMove = m_cashBalance.get(); + } + + if (amountToMove <= 0) + break; + + if ((amountToMove + m_bankBalance.get()) > ConfigServerGame::getMaxMoney()) + { + // not enough room in bank, see if there's still room in galactic reserve + int8 const galacticReserve = po->getGalacticReserveDeposit(); + if (static_cast(galacticReserve) < ConfigServerGame::getMaxGalacticReserveDepositBillion()) + { + // transfer 1 billion into galactic reserve, and try again, if necessary + po->depositToGalacticReserve(true); + + // failed to transfer to galactic reserve, don't try again + if (galacticReserve == po->getGalacticReserveDeposit()) + { + break; + } + } + else + { + // no more room in galactic reserve, move as much as possible into bank + amountToMove = ConfigServerGame::getMaxMoney() - m_bankBalance.get(); + if (amountToMove > m_cashBalance.get()) + { + amountToMove = m_cashBalance.get(); + } + + if (amountToMove > 0) + { + depositCashToBank(amountToMove); + } + + break; + } + } + else + { + if (amountToMove > 0) + { + depositCashToBank(amountToMove); + } + + break; + } + + ++attempt; + + } while (((amount + m_cashBalance.get()) > ConfigServerGame::getMaxMoney()) && (attempt < 2)); + } + } + + m_cashBalance = m_cashBalance.get() + amount; + if (m_cashBalance.get() > ConfigServerGame::getMaxMoney()) + { + LOG("CustomerService",("SuspectedCheaterChannel: %s has %i credits cash.",PlayerObject::getAccountDescription(this).c_str(), m_cashBalance.get())); + m_cashBalance = ConfigServerGame::getMaxMoney(); + } + + if (getClient() && getClient()->isFreeTrialAccount() + && (m_cashBalance.get() + m_bankBalance.get()) > ConfigServerGame::getMaxFreeTrialMoney()) + { + LOG("CustomerService",("FreeTrial: %s has exceeded max free trial balance of %d from a cash transfer amount of %d. Money lost: %d.",PlayerObject::getAccountDescription(this).c_str(), ConfigServerGame::getMaxFreeTrialMoney(), amount, m_cashBalance.get() + m_bankBalance.get() - ConfigServerGame::getMaxFreeTrialMoney())); + m_cashBalance = ConfigServerGame::getMaxFreeTrialMoney() - m_bankBalance.get(); + ProsePackage prosePackage; + prosePackage.stringId = StringId("ui_trade", "err_max_free_trial_money"); + prosePackage.digitInteger = ConfigServerGame::getMaxFreeTrialMoney(); + Chat::sendSystemMessage(*this, prosePackage); + } + + // sanity check - fix up any player character negative cash/bank balance + if ((m_cashBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) + m_cashBalance = 0; + + if ((m_bankBalance.get() < 0) && PlayerCreatureController::getPlayerObject(asCreatureObject())) + m_bankBalance = 0; + + addObjectToConcludeList(); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::transferCashTo(const NetworkId &target, int amount, const NetworkId &transactionId) +{ + if (amount <= 0) + { + DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); + return false; + } + + if (isAuthoritative()) + { + if (amount > ConfigServerGame::getMaxMoneyTransfer()) + { + DEBUG_REPORT_LOG(true,("Tried to transfer too much cash. Source object %s, target %s, amount %i", + getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); + return false; + } + + int sourceBalance=getCashBalance(); + if (sourceBalance < amount) + { + DEBUG_REPORT_LOG(true,("Tried to transfer too much cash. Source object %s, target %s, amount %i", + getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); + return false; + } + internalAdjustCashBalance(-amount, true); + + // send persistent message to add money to target. + char buffer[100]; + snprintf(buffer,100,"%i",amount); + MessageToQueue::getInstance().sendMessageToC(target, "C++FinishCashTransfer", buffer, 0, true); + + LOG("CustomerService", ("Money: cash transfer from %s to %s, amount %i, total(from) %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(),PlayerObject::getAccountDescription(target).c_str(),amount, getTotalMoney())); + + return true; + } + else + { + //TODO: handle multi-server banking + DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); + return false; + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::transferBankCreditsTo(const NetworkId &target, int amount, const NetworkId &transactionId) +{ + if (amount <= 0) + { + DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); + return false; + } + + + if (isAuthoritative()) + { + if (amount > ConfigServerGame::getMaxMoneyTransfer()) + { + DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", + getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); + return false; + } + + int sourceBalance=getBankBalance(); + if (sourceBalance < amount) + { + DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", + getNetworkId().getValueString().c_str(),target.getValueString().c_str(),amount)); + return false; + } + internalAdjustBankBalance(-amount, true); + + // send persistent message to add money to target. + char buffer[100]; + snprintf(buffer,100,"%i",amount); + MessageToQueue::getInstance().sendMessageToC(target, "C++FinishBankTransfer", buffer, 0, true); + + LOG("CustomerService", ("Money: bank transfer from %s to %s, amount %i, total(from) %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(),PlayerObject::getAccountDescription(target).c_str(),amount, getTotalMoney())); + + return true; + } + else + { + //TODO: handle multi-server banking + DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); + return false; + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::transferBankCreditsTo(const std::string &target, int amount, const NetworkId &transactionId) +{ + if (amount <= 0) + { + DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); + return false; + } + + if (isAuthoritative()) + { + // allow transfers to/from the commodities escrow account or galactic reserve to bypass + // the max transfer limit because commodities item can be sold/bought for more than the + // transfer limit and the galactic reserve transfers 1 billion credits at a time + if ((target != CommoditiesMarket::getCommoditiesNamedEscrowAccount()) && (target != std::string("galactic_reserve"))) + { + if (amount > ConfigServerGame::getMaxMoneyTransfer()) + { + DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", + getNetworkId().getValueString().c_str(),target.c_str(),amount)); + return false; + } + } + + int sourceBalance=getBankBalance(); + if (sourceBalance < amount) + { + DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", + getNetworkId().getValueString().c_str(),target.c_str(),amount)); + return false; + } + internalAdjustBankBalance(-amount, true); + + LOG("CustomerService", ("Money: bank transfer from %s to named account %s, amount %i, total %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(),target.c_str(), amount, getTotalMoney())); + + return true; + } + else + { + //TODO: handle multi-server banking + DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); + return false; + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::transferBankCreditsFrom(const std::string &target, int amount, const NetworkId &transactionId) +{ + if (amount <= 0) + { + DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); + return false; + } + + if (isAuthoritative()) + { + // allow transfers to/from the commodities escrow account or galactic reserve to bypass + // the max transfer limit because commodities item can be sold/bought for more than the + // transfer limit and the galactic reserve transfers 1 billion credits at a time + if ((target != CommoditiesMarket::getCommoditiesNamedEscrowAccount()) && (target != std::string("galactic_reserve"))) + { + if (amount > ConfigServerGame::getMaxMoneyTransfer()) + { + DEBUG_REPORT_LOG(true,("Tried to transfer too many bank credits. Source object %s, target %s, amount %i", + getNetworkId().getValueString().c_str(),target.c_str(),amount)); + return false; + } + } + + internalAdjustBankBalance(amount, true); + + LOG("CustomerService", ("Money: bank transfer from named account %s to %s, amount %i, total %i", target.c_str(),PlayerObject::getAccountDescription(getNetworkId()).c_str(), amount, getTotalMoney())); + + return true; + } + else + { + //TODO: handle multi-server banking + DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); + return false; + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::withdrawCashFromBank(int amount, const NetworkId &transactionId) +{ + if (amount <= 0) + { + DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); + return false; + } + if (isAuthoritative()) + { + // adjust amount so it won't overflow the cash limit + if ((getCashBalance() + amount) > ConfigServerGame::getMaxMoney()) + { + amount = ConfigServerGame::getMaxMoney() - getCashBalance(); + } + + if (amount > 0) + { + int bankBalance=getBankBalance(); + + if (bankBalance < amount) + { + DEBUG_REPORT_LOG(true,("Object %s tried to bounce a check. Bank balance %i, requested %i.\n",getNetworkId().getValueString().c_str(),bankBalance,amount)); + return false; + } + + internalAdjustBankBalance(-amount, false); + internalAdjustCashBalance(amount, false); + + LOG("CustomerService", ("Money: cash withdraw from bank by %s, amount %i, total %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(), amount, getTotalMoney())); + } + + return true; + } + else + { + //TODO: handle multi-server banking + DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); + return false; + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::depositCashToBank(int amount, const NetworkId &transactionId) +{ + if (amount <= 0) + { + DEBUG_REPORT_LOG(true, ("Attempting to transfer 0 or negative money on object %s, amount %d\n", getNetworkId().getValueString().c_str(), amount)); + return false; + } + + if (isAuthoritative()) + { + // adjust amount so it won't overflow the bank limit + if ((getBankBalance() + amount) > ConfigServerGame::getMaxMoney()) + { + amount = ConfigServerGame::getMaxMoney() - getBankBalance(); + } + + if (amount > 0) + { + int cashBalance=getCashBalance(); + + if (cashBalance < amount) + { + DEBUG_REPORT_LOG(true,("Object %s tried to deposit %i credits, but only has %i credits\n",getNetworkId().getValueString().c_str(),amount,cashBalance)); + return false; + } + + internalAdjustCashBalance(-amount, false); + internalAdjustBankBalance(amount, false); + + LOG("CustomerService", ("Money: cash deposit to bank by %s, amount %i, total %i", PlayerObject::getAccountDescription(getNetworkId()).c_str(), amount, getTotalMoney())); + } + + return true; + } + else + { + //TODO: handle multi-server banking + DEBUG_FATAL(true,("Banking across game servers is not yet implemented.\n")); + return false; + } +} + +// ---------------------------------------------------------------------- + +char const *ServerObject::getTemplateName() const +{ + return getObjectTemplate()->getName(); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::getHyperspaceOnCreate () const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setHyperspaceOnCreate (bool const hyperspaceOnCreate) +{ + setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnCreate, hyperspaceOnCreate); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::getHyperspaceOnDestroy () const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setHyperspaceOnDestroy (bool const hyperspaceOnDestroy) +{ + setLocalFlag(LocalObjectFlags::ServerObject_HyperspaceOnDestruct, hyperspaceOnDestroy); +} + +// ---------------------------------------------------------------------- + +std::string const ServerObject::getPackedObjVars(std::string const &prefix) const +{ + std::vector buf; + for (DynamicVariableList::MapType::const_iterator i = getObjVars().begin(); i != getObjVars().end(); ++i) + { + if (!(*i).first.compare(0, prefix.size(), prefix)) + { + appendPackedObjVarField(buf, (*i).first.c_str()); + appendPackedObjVarField(buf, (*i).second.getType()); + appendPackedObjVarField(buf, Unicode::wideToNarrow((*i).second.getPackedValueString()).c_str()); + } + } + appendPackedObjVarField(buf, "$"); + return std::string(buf.begin(), buf.end()); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::setPackedObjVars(std::string const &packedVarString) + { + unsigned int offset = 0; + + while (offset < packedVarString.size()) + { + std::string name; + offset = getPackedObjVarField(packedVarString, offset, name); + if (name == "$") + return true; + int typeId; + offset = getPackedObjVarField(packedVarString, offset, typeId); + std::string valueString; + offset = getPackedObjVarField(packedVarString, offset, valueString); + DynamicVariable value; + value.load(0, typeId, Unicode::narrowToWide(valueString)); + setObjVarItem(name, value); +} + return false; +} + +// ---------------------------------------------------------------------- + +#ifdef _WIN32 +#define atoll(a) _atoi64(a) +#endif + +// ---------------------------------------------------------------------- + +std::string ServerObject::debugGetMessageToList() const +{ + unsigned long const now = ServerClock::getInstance().getGameTimeSeconds(); + std::string result; + time_t const timeNow = ::time(NULL); + for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) + { + char temp[256]; + + if (i->second.getCallTime() > now) + { + snprintf(temp,sizeof(temp)-1,"%s: %s [call time = %lu (%s) (%s) (%s), persisted = %s, recurring = %i]\n",i->second.getMessageId().getValueString().c_str(), i->second.getMethod().c_str(), i->second.getCallTime(), CalendarTime::convertSecondsToDHMS(static_cast(i->second.getCallTime() - now)).c_str(), CalendarTime::convertEpochToTimeStringGMT(i->second.getCallTime() - now + timeNow).c_str(), CalendarTime::convertEpochToTimeStringLocal(i->second.getCallTime() - now + timeNow).c_str(), (i->second.getPersisted() ? "true" : "false"), i->second.getRecurringTime()); + } + else + { + snprintf(temp,sizeof(temp)-1,"%s: %s [call time = %lu, persisted = %s, recurring = %i]\n",i->second.getMessageId().getValueString().c_str(), i->second.getMethod().c_str(), i->second.getCallTime(), (i->second.getPersisted() ? "true" : "false"), i->second.getRecurringTime()); + } + + temp[sizeof(temp)-1]='\0'; + result += temp; + } + return result; +} + +// ---------------------------------------------------------------------- + +/** + * Go through the list of messageTos and handle any whose time has been + * reached. + * @param effectiveMessageToTime The current Server Clock, for the purpose of MessageTos + * @return The delivery time of the next message, or 0 if there are no more messages + */ + +unsigned long ServerObject::processQueuedMessageTos(unsigned long effectiveMessageToTime) +{ + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::processQueuedMessageTos"); + + if (isAuthoritative()) + { + int handledMessageCount = 0; + unsigned long startTime = Clock::timeMs(); + while (!m_messageTos.empty() && m_messageTos.begin()->second.getCallTime() <= effectiveMessageToTime) + { + ++handledMessageCount; + if ((ConfigServerGame::getMaxMessageTosPerObjectPerFrame() !=0 ) && + (handledMessageCount > ConfigServerGame::getMaxMessageTosPerObjectPerFrame())) + { + std::string nextTenMessages; + { + int count = 1; + for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator iter = m_messageTos.begin(); ((iter != m_messageTos.end()) && (count <= 10)); ++iter, ++count) + { + nextTenMessages += iter->second.getMethod(); + nextTenMessages += ", "; + } + } + + WARNING(true,("MessageTo Backlog: object %s had more than %i messages to be handled in one frame. Remaining %d messages will be delayed until next frame. Next ten messages are (%s).", getNetworkId().getValueString().c_str(), ConfigServerGame::getMaxMessageTosPerObjectPerFrame(), m_messageTos.size(), nextTenMessages.c_str())); + MessageToQueue::getInstance().incrementBackloggedObjectCount(); + break; + } + if ((ConfigServerGame::getMaxMessageToTimePerObjectPerFrame() != 0) && + (static_cast(Clock::timeMs() - startTime) > ConfigServerGame::getMaxMessageToTimePerObjectPerFrame())) + { + WARNING(true,("MessageTo Backlog: object %s spent more than %i ms processing messages. Remaining %d messages will be delayed until next frame.", getNetworkId().getValueString().c_str(), ConfigServerGame::getMaxMessageToTimePerObjectPerFrame(), m_messageTos.size())); + MessageToQueue::getInstance().incrementBackloggedObjectCount(); + break; + } + + Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator message = m_messageTos.begin(); + + // if the message is going to be recurring, create a + // new messageTo to reschedule the recurring message + MessageToPayload * copyOfRecurringMessage = NULL; + if (message->second.getRecurringTime() > 0) + { + copyOfRecurringMessage = new MessageToPayload( + getNetworkId(), + message->second.getMessageId(), + message->second.getMethod(), + message->second.getPackedDataVector(), + ServerClock::getInstance().getGameTimeSeconds() + static_cast(message->second.getRecurringTime()), + false, + message->second.getDeliveryType(), + NetworkId::cms_invalid, + "", + message->second.getRecurringTime()); + } + + // set sentinel to prevent this message from being removed + // from m_messageTos while it is being handled + s_currentMessageToBeingHandled = message->first; + handleMessageTo(message->second); + + // remove message that just got handled + IGNORE_RETURN(m_messageTos.erase(s_currentMessageToBeingHandled)); + + s_currentMessageToBeingHandled = std::make_pair(std::make_pair(0, 0), MessageToId::cms_invalid); + + // Reschedule the recurring message, if necessary + if (copyOfRecurringMessage) + { + deliverMessageTo(*copyOfRecurringMessage); + delete copyOfRecurringMessage; + } + } + + // Make sure object will handle messages again when the next message is due + if (!m_messageTos.empty()) + return m_messageTos.begin()->second.getCallTime(); + else + return 0; + } + else + return 0; +} + +// ---------------------------------------------------------------------- + +void ServerObject::handleMessageTo(MessageToPayload const & message) +{ + if (message.getDeliveryType() == MessageToPayload::DT_c) + { + handleCMessageTo(message); + } + else if (message.getDeliveryType() == MessageToPayload::DT_java) + { + GameScriptObject *scriptObj=getScriptObject(); + if (scriptObj) + { + if (!scriptObj->handleMessage(message.getMethod(), message.getPackedDataVector())) + { + WARNING_STRICT_FATAL(true, ("ServerObject::handleMessageTo, message %s to object %s - script function was not called!", + message.getMethod().c_str(), message.getNetworkId().getValueString().c_str())); + } + } + else + { + WARNING_STRICT_FATAL(true, ("ServerObject::handleMessageTo, message %s to object %s - object does not have a ScriptObject attached!", + message.getMethod().c_str(), message.getNetworkId().getValueString().c_str())); + } + } + else + WARNING_STRICT_FATAL(true,("Called ServerObject::handleMessageTo with a message that had an unrecognized delivery type. Message is %s, delivery type is %i", message.getMethod().c_str(), message.getDeliveryType())); + + if (message.getPersisted()) + { + MessageToAckMessage const reply(message.getMessageId()); + GameServer::getInstance().sendToDatabaseServer(reply); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::handleCMessageTo(const MessageToPayload &message) +{ + std::vector const &packedData = message.getPackedDataVector(); + + if (message.getMethod() == "C++ForceAlter") + { + scheduleForAlter(); + } + else if (message.getMethod() == "C++RenameCharacter") + { + //TODO: resolve Unicode issues with messageto's + m_objectName=Unicode::narrowToWide(std::string(packedData.begin(), packedData.end())); + + // rename has been completed, remove the objvar so the system won't think there's a pending rename request + Unicode::String previousRenameName; + if (getObjVars().getItem("renameCharacterRequest.requestNewName", previousRenameName) && (previousRenameName == m_objectName.get())) + removeObjVarItem("renameCharacterRequest.requestNewName"); + + // if character is connected, update the client (character selection) with the new name + Client * const client = getClient(); + if (client) + { + GenericValueTypeMessage, Unicode::String> > const characterNameChanged("CharacterNameChanged", std::make_pair(std::make_pair(GameServer::getInstance().getClusterName(), getNetworkId()), m_objectName.get())); + client->send(characterNameChanged, true); + } + } + else if (message.getMethod() == "C++FinishBankTransfer") + { + std::string packedDataString(packedData.begin(), packedData.end()); + int m_amount=strtoul(packedDataString.c_str(), 0, 10); + DEBUG_FATAL(m_amount < 0,("C++FinishBankTransaction had a negative amount. This message should always have a positive amount.\n")); + internalAdjustBankBalance(m_amount, true); + } + // transfers money from a named account to the bank + else if( message.getMethod() == "C++FromNamedAccountToBank") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + //DEBUG_WARNING(true, ("Processing C++FromNamedAccountToBank. Params = '%s' MessageId=%Ld", params, message.getMessageId().getValue() )); + char *splitPos = strstr(params, " "); + if( splitPos) + { + *splitPos = 0; + std::string const named_account(params); + int const amount = atoi(splitPos+1); + DEBUG_FATAL(amount < 0,("C++FromNamedAccountToBank had a negative amount. This message should always have a positive amount.\n")); + transferBankCreditsFrom(named_account, amount); + } + delete [] params; + } + else if (message.getMethod() == "C++FinishCashTransfer") + { + std::string packedDataString(packedData.begin(), packedData.end()); + int m_amount=strtoul(packedDataString.c_str(), 0, 10); + DEBUG_FATAL(m_amount < 0,("C++FinishCashTransaction had a negative amount. This message should always have a positive amount.\n")); + internalAdjustCashBalance(m_amount, true); + } + else if (message.getMethod() == "C++ModifyCash") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + char *splitPos = strstr(params, " "); + if (splitPos) + { + *splitPos = 0; + NetworkId recipient(atoll(params)); + int amount = atoi(splitPos+1); + transferCashTo(recipient, amount); + } + delete [] params; + } + else if (message.getMethod() == "C++ModifyBank") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + char *splitPos = strstr(params, " "); + if (splitPos) + { + *splitPos = 0; + NetworkId recipient(atoll(params)); + int amount = atoi(splitPos+1); + transferBankCreditsTo(recipient, amount); + } + delete [] params; + } + else if (message.getMethod() == "C++DestroySelf") + { + permanentlyDestroy(DeleteReasons::Script); + } + else if (message.getMethod() == "C++VendorStatusChange") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + int status = atoi(params); + CommoditiesMarket::vendorStatusChange(getNetworkId(), status); + delete [] params; + } + else if (message.getMethod() == "C++Unstick") + { + CreatureObject* creatureObject = asCreatureObject(); + if (creatureObject && creatureObject->isInWorld()) + { + PlayerObject * p = PlayerCreatureController::getPlayerObject(creatureObject); + if (p && p->getIsUnsticking()) + { + //Receive positional information with this unstick message. If you change + //the format of this positional information, you must also change it in the sender in CommandCppFuncs.cpp + Vector position = getPosition_p(); + char buf[255]; + snprintf(buf, sizeof(buf), "%f:%f", position.x, position.z); + buf[sizeof(buf) - 1] = '\0'; + + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + + if (strcmp(buf, params) == 0) + { + //handle unstick + static MessageDispatch::Emitter e; + Chat::sendSystemMessageSimple(*this, SharedStringIds::unstick_request_complete, NULL); + RequestUnstick r; + r.setClientId(getNetworkId()); + e.emitMessage(r); + p->setIsUnsticking(false); + } + delete [] params; + } + } + } + else if (message.getMethod() == "C++WaitForPatrolPreload") + { + WARNING(true, ("Non-creature object %s received a C++WaitForPatrolPreload message", + getNetworkId().getValueString().c_str())); + MessageToQueue::cancelRecurringMessageTo(getNetworkId(), "C++WaitForPatrolPreload"); + } + else if (message.getMethod() == "CancelRecurringMessageTo") + { + std::string const & methodName = message.getDataAsString(); + for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) + { + if ((i->second.getRecurringTime() != 0) && (i->second.getMethod() == methodName) && (i->first != s_currentMessageToBeingHandled)) + { + IGNORE_RETURN(m_messageTos.erase(i)); + break; + } + } + } + else if (message.getMethod() == "C++updateObserversCount") + { + std::string const & buffer = message.getDataAsString(); + if (!buffer.empty()) + { + int count = atoi(buffer.c_str()); + updateObserversCount(count); + } + } + else if (message.getMethod() == "C++addBroadcastListener") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + char *splitPos = strstr(params, " "); + if (splitPos) + { + *splitPos = 0; + addBroadcastListener(std::string(params), NetworkId(std::string(splitPos+1))); + } + delete [] params; + } + else if (message.getMethod() == "C++removeBroadcastListener") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + char *splitPos = strstr(params, " "); + if (splitPos) + { + *splitPos = 0; + removeBroadcastListener(std::string(params), NetworkId(std::string(splitPos+1))); + } + delete [] params; + } + else if (message.getMethod() == "C++removeBroadcastListenerAllMessage") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + removeBroadcastListener(NetworkId(std::string(params))); + delete [] params; + } + else if (message.getMethod() == "C++listenToBroadcastMessage") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + char *splitPos = strstr(params, " "); + if (splitPos) + { + *splitPos = 0; + listenToBroadcastMessage(std::string(params), NetworkId(std::string(splitPos+1))); + } + delete [] params; + } + else if (message.getMethod() == "C++stopListeningToBroadcastMessage") + { + char *params = new char[packedData.size()+1]; + memcpy(params, &(*packedData.begin()), packedData.size()); + params[packedData.size()] = 0; + char *splitPos = strstr(params, " "); + if (splitPos) + { + *splitPos = 0; + stopListeningToBroadcastMessage(std::string(params), NetworkId(std::string(splitPos+1))); + } + delete [] params; + } + else if (message.getMethod() == "C++stopListeningToAllBroadcastMessage") + { + stopListeningToAllBroadcastMessages(); + } + else if (message.getMethod() == "C++AdjustAccountFeatureIdResponse") + { + if (!packedData.empty()) + { + Archive::ByteStream bs; + bs.put(reinterpret_cast(&packedData[0]), static_cast(packedData.size())); + + Archive::ReadIterator ri = bs.begin(); + AdjustAccountFeatureIdResponse const msg(ri); + + if (msg.getTargetPlayer() == getNetworkId()) + { + if (msg.getResultCode() == RESULT_SUCCESS) + { + Client * client = getClient(); + if (client) + { + if (msg.getGameCode() == PlatformGameCode::SWG) + { + // request an updated list of feature id + AccountFeatureIdRequest const req(NetworkId::cms_invalid, GameServer::getInstance().getProcessId(), msg.getTargetPlayer(), msg.getTargetStationId(), msg.getGameCode(), AccountFeatureIdRequest::RR_Reload); + client->sendToConnectionServer(req); + + // let player know that the reward was successfully traded in + if (VeteranRewardManager::isTradeInRewardFeatureId(msg.getFeatureId()) && !msg.getTargetPlayerDescription().empty() && msg.getTargetItem().isValid() && !msg.getTargetItemDescription().empty()) + Chat::sendSystemMessage(*this, StringId("veteran_new", "trade_in_success"), Unicode::emptyString); + } + else if (msg.getGameCode() == PlatformGameCode::SWGTCG) + { + // let player know that the card was successfully redeemed + Chat::sendSystemMessage(*this, StringId("veteran_new", "redeem_tcg_card_success"), Unicode::emptyString); + } + } + } + else if (msg.getGameCode() == PlatformGameCode::SWGTCG) + { + Client * client = getClient(); + if (client) + { + // let player know that the card failed to redeem + Chat::sendSystemMessage(*this, StringId("veteran_new", "redeem_tcg_card_failure"), Unicode::emptyString); + } + } + else if ((msg.getGameCode() == PlatformGameCode::SWG) && VeteranRewardManager::isTradeInRewardFeatureId(msg.getFeatureId()) && !msg.getTargetPlayerDescription().empty() && msg.getTargetItem().isValid() && !msg.getTargetItemDescription().empty()) + { + Client * client = getClient(); + if (client) + { + // let player know that the reward trade in failed + Chat::sendSystemMessage(*this, StringId("veteran_new", "trade_in_failure"), Unicode::emptyString); + } + } + } + + if (msg.getRequestingPlayer() == getNetworkId()) + { + if (msg.getResultCode() == RESULT_SUCCESS) + { + if (msg.getResultCameFromSession()) + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("feature Id (%lu) on account (%lu) has been adjusted from (%d) to (%d); session/Platform reported successful result code (%u, %s:%s)", msg.getFeatureId(), msg.getTargetStationId(), msg.getOldValue(), msg.getNewValue(), msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str()), getClient()); + else + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("feature Id (%lu) on account (%lu) has been adjusted from (%d) to (%d)", msg.getFeatureId(), msg.getTargetStationId(), msg.getOldValue(), msg.getNewValue()), getClient()); + } + else + { + if (msg.getResultCameFromSession()) + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request to adjust feature Id for account (%lu) failed with error code (%u, %s:%s)", msg.getTargetStationId(), msg.getResultCode(), msg.getSessionResultString().c_str(), msg.getSessionResultText().c_str()), getClient()); + else + ConsoleMgr::broadcastString(FormattedString<1024>().sprintf("request to adjust feature Id for account (%lu) failed", msg.getTargetStationId()), getClient()); + } + } + + if (msg.getTargetItem() == getNetworkId()) + { + if (msg.getGameCode() == PlatformGameCode::SWGTCG) + VeteranRewardManager::handleTcgRedemptionResponse(*this, msg); + else if ((msg.getGameCode() == PlatformGameCode::SWG) && VeteranRewardManager::isTradeInRewardFeatureId(msg.getFeatureId()) && !msg.getTargetPlayerDescription().empty() && !msg.getTargetItemDescription().empty()) + VeteranRewardManager::handleTradeInResponse(*this, msg); + } + } + } + else if (message.getMethod() == "C++kickPlayerCtsCompletedOrInProgress") + { + LOG("CustomerService",("Login: dropping %s because of CTS completed or in progress", PlayerObject::getAccountDescription(this).c_str())); + + KickPlayer const kickMessage(getNetworkId(), "CTS completed or in progress"); + GameServer::getInstance().sendToConnectionServers(kickMessage); + GameServer::getInstance().dropClient(getNetworkId(), true); + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::handleTeleportFixup(bool force) +{ + if (getObjVars().hasItem("teleportFixup")) + { + LOG("TeleportFixup", ("Teleport fixup called for %s\n", getNetworkId().getValueString().c_str())); + if (getObjVars().hasItem("teleportFixup.x")) + { + // Ignore the container portion of a teleport fixup if we are already contained + if (!ContainerInterface::getContainedByObject(*this)) + { + ServerObject *container = 0; + NetworkId destContainer; + std::string destCellName; + Vector destPosition_p; + + getObjVars().getItem("teleportFixup.x", destPosition_p.x); + getObjVars().getItem("teleportFixup.y", destPosition_p.y); + getObjVars().getItem("teleportFixup.z", destPosition_p.z); + getObjVars().getItem("teleportFixup.container", destContainer); + + + if (getObjVars().getItem("teleportFixup.cellname", destCellName)) + { + ServerObject * const destBuilding = safe_cast(NetworkIdManager::getObjectById(destContainer)); + if (destBuilding) + { + PortalProperty * const portalProp = destBuilding->getPortalProperty(); + if (portalProp) + { + CellProperty * const cellProp = portalProp->getCell(destCellName.c_str()); + if (cellProp) + container = safe_cast(&(cellProp->getOwner())); + } + } + } + else + container = safe_cast(NetworkIdManager::getObjectById(destContainer)); + + if (container) + { + // allow the destination container to change the warp position + float yaw = 0.0f; + ServerObject * const topmost = safe_cast(ContainerInterface::getTopmostContainer(*container)); + if (topmost && topmost->isAuthoritative()) + topmost->changeTeleportDestination(destPosition_p, yaw); + + Transform t; + t.setPosition_p(destPosition_p); + yaw -= getObjectFrameK_p().theta(); + if (yaw != 0.0f) + { + t.yaw_l(yaw); + t.reorthonormalize(); + } + LOG("TeleportFixup", ("TeleportFixup from (%g,%g,%g) in world to (%g,%g,%g) in %s\n", + getPosition_w().x, getPosition_w().y, getPosition_w().z, + t.getPosition_p().x, t.getPosition_p().y, t.getPosition_p().z, + container->getNetworkId().getValueString().c_str())); + safe_cast(getController())->teleport(t, container); + } + else if (destContainer != NetworkId::cms_invalid && !force) + { + LOG("TeleportFixup", ("Failing teleport fixup because object %s is in a null dest container and force was passed in\n", getNetworkId().getValueString().c_str())); + return false; // going to a container and it wasn't loaded, defer + } + } + else + LOG("TeleportFixup", ("Ignoring teleport fixup because object %s is already contained by %s\n", getNetworkId().getValueString().c_str(), ContainerInterface::getContainedByObject(*this)->getNetworkId().getValueString().c_str())); + } + + // Teleporting may cause us to become nonauthoritative here, and if so we should not clear the fixup, so it is + // reapplied on the new auth server. + if (!isAuthoritative()) + return true; + + std::string scriptCallback; + if (getObjVars().getItem("teleportFixup.callback", scriptCallback)) + { + DEBUG_REPORT_LOG(true, ("Player warp making callback %s\n", scriptCallback.c_str())); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), scriptCallback, std::vector(), 0, true); + } + + LOG("TeleportFixup", ("Removing teleport fixup objvars for object %s\n", getNetworkId().getValueString().c_str())); + removeObjVarItem("teleportFixup"); + } + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Sets customization data for this object. + * + * @param customName name of the customization parameter + * @param value value to set the customization to + */ +void ServerObject::customize(const std::string & customName, int value) +{ + if(isAuthoritative()) + { + CustomizationDataProperty *const cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); + if (cdProperty != NULL) + { + CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); + if (customizationData != NULL) + { + RangedIntCustomizationVariable * variable = dynamic_cast< + RangedIntCustomizationVariable*>(customizationData->findVariable( + customName)); + if (variable != NULL) + variable->setValue(value); + else + { + DEBUG_WARNING(true, ("ServerObject::customize() tried to access var [%s] as ranged int, but not right type.", customName.c_str())); + } + //-- release local references + customizationData->release(); + } + else + { + // this shouldn't happen + DEBUG_WARNING(true, ("CustomizationDataProperty returned NULL CustomizationData on fetch.")); + } + } + else + { + // this shouldn't happen + DEBUG_WARNING(true, ("ServerObject::customize() object does not have customization property")); + } + } + else + { + sendControllerMessageToAuthServer(CM_customize, new MessageQueueGenericValueType >(std::make_pair(customName, value))); + } +} // ServerObject::customize + +// ---------------------------------------------------------------------- + +bool ServerObject::isInWorldCell() const +{ + return isInWorld() && (ContainerInterface::getTopmostContainer(*this) == this); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::canDestroy() const +{ + if (isPlayerControlled()) + return false; + const Container * container = ContainerInterface::getContainer(*this); + if (container) + { + //Check contents to make sure they can be destroyed. + ContainerConstIterator i = container->begin(); + for (; i != container->end(); ++i) + { + const ServerObject* child = safe_cast((*i).getObject()); + if (child && !child->canDestroy()) + { + DEBUG_REPORT_LOG(true, ("Tried to delete object %s but could not delete child %s\n", getNetworkId().getValueString().c_str(), child->getNetworkId().getValueString().c_str())); + return false; + } + } + } + + return true; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::permanentlyDestroy(DeleteReasons::Enumerator reason) +{ + // prevent recursion + if (isBeingDestroyed()) + return true; + + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_permanentlyDestroy, new MessageQueueGenericValueType(reason)); + return false; + } + + if (!canDestroy()) + { + return false; + } + + // can't destroy an initialized vendor unless the commodities server is up because + // there is commodities server data that *MUST* be removed when the vendor is + // destroyed, or else the commodities server will think the player has more + // vendors than he actually has + if ( isVendor() && getObjVars().hasItem("vendor_initialized") && !CommoditiesMarket::isCommoditiesServerAvailable() ) + { + return false; + } + + BuildingObject* buildingObject = asBuildingObject(); + const bool houseDestroyedByScript = (reason == DeleteReasons::Script && buildingObject && buildingObject->isPlayerPlaced()); + + // tell scripts we want to destroy the object + if (getScriptObject() != NULL && !m_calledTriggerDestroy) + { + m_calledTriggerDestroy = true; + ScriptParams params; + if (getScriptObject()->trigAllScripts(Scripting::TRIG_DESTROY, params) == SCRIPT_OVERRIDE) + { + if(reason != DeleteReasons::God) + { + m_calledTriggerDestroy = false; + return false; + } + } + } + + if (isAuthoritative() && (getScriptObject() != NULL) && !m_calledTriggerRemovingFromWorld) + { + ScriptParams params; + m_calledTriggerRemovingFromWorld = true; + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_REMOVING_FROM_WORLD, params)); + } + + setBeingDestroyed(true); + + if (isInBazaarOrVendor()) + { + CommoditiesMarket::auctionCancel(getOwnerId(), getNetworkId().getValue()); + } + + // need to remove all the items from the Commodities Market + // TODO: how to remove an item that might get deleted from a vendor's inventory without the vendor being deleted? (GM deleting and item for instance) + // TODO PROBLEM: contents of vendors aren't guaranteed to be loaded + if ( isVendor() ) + { + ServerObject *inv = getBazaarContainer(); + NetworkId playerOwnerId; + getObjVars().getItem("vendor_owner", playerOwnerId); + if( inv && playerOwnerId.getValue()>0 ) + { + // if this was an uninitialized vendor, remove objvar from owner + ServerObject *owner = dynamic_cast(NetworkIdManager::getObjectById(playerOwnerId)); + if (owner) + { + NetworkId notInitalizedVendor; + if (owner->getObjVars().getItem("vendor_not_initialized", notInitalizedVendor)) + { + if (notInitalizedVendor == Object::getNetworkId()) + { + owner->removeObjVarItem("vendor_not_initialized"); + } + } + } + CommoditiesMarket::destroyVendorMarket(playerOwnerId, *inv); + } + } + + if (isPersisted()) + { + sendDeleteToDatabase(*this, houseDestroyedByScript ? DeleteReasons::House : reason); + ServerObject const * const oldContainer = safe_cast(ContainerInterface::getContainedByObject(*this)); + LOG("CustomerService",("Deletion: %s in container: %s deleted from game. Reason: %s", ServerObject::getLogDescription(this).c_str(), oldContainer ? ServerObject::getLogDescription(oldContainer).c_str() : "none", describeDeleteReason(static_cast(reason)).c_str())); + int childReason = DeleteReasons::ContainerDeleted; + if (houseDestroyedByScript) + childReason = DeleteReasons::House; + flagChildObjectsForDeletion(*this, childReason); + } + + // grab the proxy list prior to removing it from the container, because it's about to lose its proxy list + ProxyList const &proxyList = getExposedProxyList(); + if (!proxyList.empty()) + { + ServerMessageForwarding::begin(std::vector(proxyList.begin(), proxyList.end())); + + UnloadObjectMessage const unloadMessage(getNetworkId()); + ServerMessageForwarding::send(unloadMessage); + + ServerMessageForwarding::end(); + } + + onPermanentlyDestroyed(); + unload(); + + //-- Ensure state is set to initialized (i.e. have received end baselines or + // created on this server). This is required so that the AlterScheduler + // can accept the Object. If changing initialization state, warn about it here. + if (!isInitialized()) + { + DEBUG_WARNING(true, ("ServerObject::permanentlyDestroy(): object is not initialized, setting to initialized to allow submission to alter scheduler for delete. id=[%s],template=[%s].", getNetworkId().getValueString().c_str(), getObjectTemplateName())); + setInitialized(true); + } + + //-- Ensure this object gets altered next frame so that kill() can take effect. + AlterScheduler::submitForAlter(*this); + + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Allows an object to do pre-deletion cleanup. + */ +void ServerObject::onRemovingFromWorld() +{ + // If we're being removed from the world, we may need to remove ourselves from the parent container list. + if (isAuthoritative() && isPlayerControlled() && isUnloading()) + { + Object * const parent = ContainerInterface::getContainedByObject(*this); + if (parent) + { + Container * const container = parent->getCellProperty(); + if (container) + { + container->internalItemRemoved(*this); + } + } + } + + if (m_networkUpdateFar) + onRemovedFromWorldCell(); + + destroyTriggerVolumes(); +} + +// ---------------------------------------------------------------------- +/* Why would I unload something? + * - It might be a player character logging out + * - Or the planet server might be telling me to unload an object */ +// ---------------------------------------------------------------------- + +void ServerObject::unload() +{ + scheduleForAlter(); + addObjectToConcludeList(); + + // prevent recursion + if (isUnloading()) + { + kill(); + return; + } + + setUnloading(true); + + DEBUG_REPORT_LOG(ConfigServerGame::getLogObjectLoading(), ("Unloading object (%s : %s)\n", getObjectTemplateName(), getNetworkId().getValueString().c_str())); + + // If the object has a client, uncontrol it. When the primary controlled + // object is unloaded, this prevents us from sending destroys to ourself, + if (getClient()) + getClient()->removeControlledObject(*this); + + synchronizationOnUnload(); + + if (isAuthoritative()) + { + ScriptParams params; + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_UNLOADED_FROM_MEMORY, params)); + } + + kill(); + + // if this object is in a slot in a slotted container, immediately remove + // it from the slot, because another object may be immediately put into + // the slot before this object is eventually destroyed and removed from the container + Object * const containedBy = ContainerInterface::getContainedByObject(*this); + if (containedBy) + { + Container * const container = ContainerInterface::getContainer(*containedBy); + SlottedContainer * const slotContainer = dynamic_cast(container); + if (slotContainer) + slotContainer->removeItemFromSlotOnly(*this); + } +} + +// ---------------------------------------------------------------------- + +/** + * Unload the object, and tell the database to move it to a specified player + */ +void ServerObject::moveToPlayerAndUnload(const NetworkId &player) +{ + GenericValueTypeMessage > const moveToPlayerMessage( + "MoveToPlayer", + std::make_pair(getNetworkId(), player)); + GameServer::getInstance().sendToDatabaseServer(moveToPlayerMessage); + + unload(); +} + + +// ---------------------------------------------------------------------- + +/** + * Unload the object, and tell the database to move it to a specified player's bank + */ +void ServerObject::moveToPlayerBankAndUnload(const NetworkId &player) +{ + GenericValueTypeMessage > const moveToPlayerMessage( + "MoveToPlayerBankMessage", + std::make_pair(getNetworkId(), player)); + GameServer::getInstance().sendToDatabaseServer(moveToPlayerMessage); + + unload(); +} + +// ---------------------------------------------------------------------- + +/** + * Unload the object, and tell the database to move it to a specified player's bank + */ +void ServerObject::moveToPlayerDatapadAndUnload(const NetworkId &player, int maxDepth) +{ + GenericValueTypeMessage, int> > const moveToPlayerMessage( + "MoveToPlayerDatapadMessage", + std::make_pair(std::make_pair(getNetworkId(), player), maxDepth)); + GameServer::getInstance().sendToDatabaseServer(moveToPlayerMessage); + + unload(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::onPermanentlyDestroyed() +{ + IGNORE_RETURN(ContainerInterface::onObjectDestroy(*this)); +} + +// ------------------------------------------------------------------------------------------ + + +/** + * Request to load a specific object contained by this object. + * (This object must be a demand-load container, i.e. m_loadContents==false.) + */ + +void ServerObject::loadContainedObjectFromDB(const NetworkId &oid) const +{ + LoadContainedObjectMessage const msg(getNetworkId(), oid); + GameServer::getInstance().sendToDatabaseServer(msg); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::areContentsLoaded() const +{ + return m_contentsLoaded.get(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::loadAllContentsFromDB() const +{ + if (m_contentsLoaded.get() || m_contentsRequested.get()) + { + DEBUG_REPORT_LOG(true,("Ignoring LoadAllContentsFromDB for object %s because they are already loaded\n",getNetworkId().getValueString().c_str())); + return; + } + + DEBUG_REPORT_LOG(true,("LoadAllContentsFromDB, object %s\n",getNetworkId().getValueString().c_str())); + + if (m_loadContents.get()) + WARNING_STRICT_FATAL(true,("Requested loading contents of container %s, but the container is not a demand-load container.",getNetworkId().getValueString().c_str())); + else + { + m_contentsRequested = true; + LoadContentsMessage const msg(getNetworkId()); + GameServer::getInstance().sendToDatabaseServer(msg); + } +} + +//---------------------------------------------------------------------- + +void ServerObject::setLoadContents(bool loadContents) +{ + if (isAuthoritative()) + { + m_loadContents = loadContents; + } + else + { + // this function should probably never be called on a proxy object + WARNING_STRICT_FATAL(true,("Setting loadContent across game servers is not allowed.")); + } +} + +//---------------------------------------------------------------------- + +void ServerObject::unloadPersistedContents() +{ + if (!areContentsLoaded()) + { + return; + } + + Container *container = ContainerInterface::getContainer(*this); + if (container) + { + for (ContainerIterator j = container->begin(); j != container->end(); ++j) + { + ServerObject * obj = safe_cast((*j).getObject()); + if (obj && obj->isPersisted()) + { + obj->unload(); + } + } + m_contentsLoaded = false; + m_contentsRequested = false; + } +} + +//---------------------------------------------------------------------- + +const Unicode::String ServerObject::getAssignedObjectFirstName () const +{ + const Unicode::String & name = m_objectName.get (); + // split off the last name from toName + std::string::size_type spacePos = name.find(' '); + if (spacePos != std::string::npos) + return name.substr(0, spacePos); + + return name; +} + +//---------------------------------------------------------------------- + +/** + * This function is used to obtain a client-displayable name regardless of whether + * the object has an assigned name or string id. + */ + +const Unicode::String ServerObject::getEncodedObjectName () const +{ + static const Unicode::String at (1, '@'); + + if (!m_objectName.get ().empty ()) + return m_objectName.get (); + else + return at + Unicode::narrowToWide (m_nameStringId.get().getCanonicalRepresentation ()); +} + +// ---------------------------------------------------------------------- + +/** + * Do a money transfer and send the reply to a script + * @param target Target of the money transfer + * @param replyTo Object that wants the reply message (this object does not need to be involved in the transaction) + * @param successCallback Script method on the object to call on success. + * @param failCallback Script method on the object to call on failure. + * @param packedDictionary Dictionary to be passed to the script (packed into a string) + */ +void ServerObject::scriptTransferCashTo(const NetworkId &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) +{ + if (isAuthoritative()) + { + bool result = transferCashTo(target, amount); + if (result) + { + if (!successCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); + } + else + { + if (!failCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); + } + } + else + { + MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_cashTransfer, target, "", amount, replyTo, successCallback, failCallback, packedDictionary); + Controller *const controller = getController(); + NOT_NULL(controller); + controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +// ---------------------------------------------------------------------- + +/** + * Do a money transfer and send the reply to a script + * @param target Target of the money transfer + * @param replyTo Object that wants the reply message (this object does not need to be involved in the transaction) + * @param successCallback Script method on the object to call on success. + * @param failCallback Script method on the object to call on failure. + * @param packedDictionary Dictionary to be passed to the script (packed into a string) + */ +void ServerObject::scriptTransferBankCreditsTo(const NetworkId &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) +{ + if (isAuthoritative()) + { + bool result = transferBankCreditsTo(target, amount); + if (result) + { + if (!successCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); + } + else + { + if (!failCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); + } + } + else + { + MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankTransfer, target, "", amount, replyTo, successCallback, failCallback, packedDictionary); + Controller *const controller = getController(); + NOT_NULL(controller); + controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::scriptWithdrawCashFromBank(int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) +{ + if (isAuthoritative()) + { + bool result = withdrawCashFromBank(amount); + if (result) + { + if (!successCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); + } + else + { + if (!failCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); + } + } + else + { + MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankWithdrawal, NetworkId::cms_invalid, "", amount, replyTo, successCallback, failCallback, packedDictionary); + Controller *const controller = getController(); + NOT_NULL(controller); + controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::scriptDepositCashToBank(int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) +{ + if (isAuthoritative()) + { + bool result = depositCashToBank(amount); + if (result) + { + if (!successCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); + } + else + { + if (!failCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); + } + } + else + { + MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankDeposit, NetworkId::cms_invalid, "", amount, replyTo, successCallback, failCallback, packedDictionary); + Controller *const controller = getController(); + NOT_NULL(controller); + controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +// ---------------------------------------------------------------------- + +/** + * Do a money transfer and send the reply to a script + * @param target Target of the money transfer + * @param replyTo Object that wants the reply message (this object does not need to be involved in the transaction) + * @param successCallback Script method on the object to call on success. + * @param failCallback Script method on the object to call on failure. + * @param packedDictionary Dictionary to be passed to the script (packed into a string) + */ +void ServerObject::scriptTransferBankCreditsTo(const std::string &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) +{ + if (isAuthoritative()) + { + bool result = transferBankCreditsTo(target, amount); + if (result) + { + if (!successCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); + } + else + { + if (!failCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); + } + } + else + { + MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankTransferToNamedAccount, NetworkId::cms_invalid, target, amount, replyTo, successCallback, failCallback, packedDictionary); + Controller *const controller = getController(); + NOT_NULL(controller); + controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::scriptTransferBankCreditsFrom(const std::string &target, int amount, const NetworkId &replyTo, const std::string &successCallback, const std::string &failCallback, const std::vector &packedDictionary) +{ + if (isAuthoritative()) + { + bool result = transferBankCreditsFrom(target, amount); + if (result) + { + if (!successCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,successCallback,packedDictionary,0,true); + } + else + { + if (!failCallback.empty()) + MessageToQueue::getInstance().sendMessageToJava(replyTo,failCallback,packedDictionary,0,true); + } + } + else + { + MessageQueueScriptTransferMoney *msg = new MessageQueueScriptTransferMoney(MessageQueueScriptTransferMoney::TT_bankTransferFromNamedAccount, NetworkId::cms_invalid, target, amount, replyTo, successCallback, failCallback, packedDictionary); + Controller *const controller = getController(); + NOT_NULL(controller); + controller->appendMessage(CM_scriptTransferMoney,0,msg, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_AUTH_SERVER); + } +} + +//---------------------------------------------------------------------- + +void ServerObject::getAttributes(const NetworkId & playerId, AttributeVector &data) const +{ + getAttributes (data); + + if (!isAuthoritative()) + { + DEBUG_WARNING (true, ("ServerObject::getAttributes invoked on non-auth object %s", getNetworkId ().getValueString ().c_str ())); + return; + } + + GameScriptObject * const gso = const_cast(getScriptObject()); + + if (gso->hasTrigger (Scripting::TRIG_GET_ATTRIBS)) + { + const CreatureObject * player = safe_cast(ServerWorld::findObjectByNetworkId(playerId)); + int MAX_ATTRIBS = 80; + if(player) + { + if(player->getClient()) + { + if(player->getClient()->isGod()) + { + MAX_ATTRIBS = 2000; + } + } + } + + // allow scripts to add attribute data to the vector + static std::vector names (MAX_ATTRIBS, static_cast(0)); + static std::vector attribs (MAX_ATTRIBS, static_cast(0)); + + //-- clear the vectors + names.clear (); + attribs.clear (); + names.resize (MAX_ATTRIBS, static_cast(0)); + attribs.resize (MAX_ATTRIBS, static_cast(0)); + + ScriptParams params; + params.addParam (playerId); + params.addParam (names); + params.addParam (attribs); + + NOT_NULL (gso); + + IGNORE_RETURN(gso->trigAllScripts(Scripting::TRIG_GET_ATTRIBS, params)); + + const std::vector & newNames = params.getStringArrayParam (1); + const std::vector & newAttribs = params.getUnicodeArrayParam (2); + + // copy the returned strings to data + for (int i = 0; i < MAX_ATTRIBS; ++i) + { + const char * const newName = newNames [i]; + const Unicode::String * const newAttrib = newAttribs [i]; + + if (newName && *newName && newAttrib && !newAttrib->empty ()) + { + data.push_back (std::make_pair (std::string (newName), *newAttrib)); + } + else + break; + } + + // if the requestor is a gm, add objvars and scriptvars + // to result data (ignore max attribs as well!) + + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::getAttributes(AttributeVector &) const +{ +} + +// ---------------------------------------------------------------------- + +/** + * Return all the standard attributes for an item, plus special + * auction-specific attributes. + * + * May eventually make this into a virtual function if we add more to it. + */ +void ServerObject::getAttributesForAuction(AttributeVector &data) const +{ + static const std::string attributeClientSharedTemplateName("ClientSharedTemplateName"); + static const std::string attributeAppearanceData("AppearanceData"); + + DEBUG_FATAL(strlen(getClientSharedTemplateName()) > 1000,("Client shared template name was more than 1000 characters long, too long to save.")); + + getAttributes(NetworkId::cms_invalid,data); + data.push_back(std::make_pair(attributeClientSharedTemplateName, Unicode::narrowToWide(getClientSharedTemplateName()))); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::alwaysSendReliableTransform() const +{ + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Called when a request to load a contained object has been completed. + * + * Two Important Notes: + * 1) This is called in response to loadContainedObjectFromDB. It is not + * called in response to loadAllContentsFromDB + * 2) There is no guarantee the requested object exists. If the object + * id was wrong or the object wasn't in the container, it will not + * have been loaded. + */ +void ServerObject::onContainedObjectLoaded(NetworkId const &oid) +{ + CommoditiesMarket::checkPendingLoads(oid); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isBazaarTerminal() const +{ + SharedObjectTemplate::GameObjectType got = + static_cast (getGameObjectType()); + return (got == SharedObjectTemplate::GOT_terminal_bazaar); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isVendor() const +{ + const TangibleObject *tangibleObject = asTangibleObject(); + if (tangibleObject) + { + return tangibleObject->hasCondition(ServerTangibleObjectTemplate::C_vendor); + } + return false; +} + +// ---------------------------------------------------------------------- + +void ServerObject::makeVendor() +{ + CreatureObject *creatureObject = asCreatureObject(); + if (creatureObject) + { + const char* s_inventoryTemplate = "object/tangible/inventory/vendor_inventory.iff"; + std::set inventoryObservers; + ServerObject *inventory = creatureObject->getInventory(); + if (inventory) + { + // if there's already a vendor inventory on the creature, + // then it means this creature is already a vendor; we + // don't want to destroy that vendor inventory and create + // another vendor inventory, because the vendor inventory + // is already registered with the commodities server and + // may have items in it, and deleting the vendor inventory + // would cause those items to be orphaned; + + // doing what we are doing here will cause the existing + // vendor inventory to be registered with the commodities + // server again, but it won't hurt, and it covers the + // recovery case where if for some reason the first + // registration failed, we will try the registration again + if(strcmp(inventory->getTemplateName(), s_inventoryTemplate) == 0) + { + LOG("CustomerService", ("vendor: Calling makeVendor() for vendor (%s) who already has a vendor inventory object (%s)", getDebugInformation().c_str(), inventory->getDebugInformation().c_str())); + return; + } + + // make a copy of the current inventory observers + inventoryObservers = inventory->getObservers(); + + // destroy the existing inventory + LOG("CustomerService", ("vendor: makeVendor() for vendor (%s), destroying existing inventory object (%s)", getDebugInformation().c_str(), inventory->getDebugInformation().c_str())); + + inventory->permanentlyDestroy(DeleteReasons::Replaced); + } + const SlotId invenSlot = SlotIdManager::findSlotId(ConstCharCrcLowerString("inventory")); + ServerObject *vendorInventory = ServerWorld::createNewObject(std::string(s_inventoryTemplate), *this, invenSlot, true); + if (vendorInventory) + { + LOG("CustomerService", ("vendor: makeVendor() for vendor (%s), created vendor inventory object (%s)", getDebugInformation().c_str(), vendorInventory->getDebugInformation().c_str())); + + vendorInventory->setLoadContents(false); + + // make sure that the new inventory object has + // the same observers as the old inventory object + ObserveTracker::onMakeVendorInventory(*vendorInventory, inventoryObservers); + } + else + { + LOG("CustomerService", ("vendor: makeVendor() for vendor (%s), failed to create vendor inventory object", getDebugInformation().c_str())); + } + } + else + { + setLoadContents(false); + } +} + +// ---------------------------------------------------------------------- + +ServerObject *ServerObject::getBazaarContainer() +{ + CreatureObject *creatureObject = asCreatureObject(); + if (creatureObject) + { + return creatureObject->getInventory(); + } + else + { + return this; + } +} + + +// ---------------------------------------------------------------------- + +const ServerObject *ServerObject::getBazaarContainer() const +{ + const CreatureObject *creatureObject = asCreatureObject(); + if (creatureObject) + { + return creatureObject->getInventory(); + } + else + { + return this; + } +} + +// ---------------------------------------------------------------------- + +/** + * Called when a request to load a contained object has been completed. + * + * Two Important Notes: + * 1) This is called in response to loadAllContentsFromDB. It is not + * called in response to loadContainedObjectFromDB + * 2) There is no guarantee the container now contains any objects. + * If there were no contained objects in the database, the container + * will be empty. + */ +void ServerObject::onAllContentsLoaded() +{ + GameServer::removePendingLoadRequest(getNetworkId()); + + m_contentsLoaded=true; + if (getObjVars().hasItem(CommoditiesMarket::OBJVAR_VENDOR_REINITIALIZING)) + { + //vendor is re-initializing + setLoadContents( false ); + CommoditiesMarket::reinitializeVendorContents(*this); + } + else if (getObjVars().hasItem(OBJVAR_STRUCTURE_PLAYER_PACK)) + { + //Get player initiating load + NetworkId playerId; + + if (getObjVars().getItem(OBJVAR_STRUCTURE_PLAYER_PACK, playerId)) + { + bool failed = true; + + if (isAuthoritative()) + { + ServerObject *player = NULL; + if ((player = getServerObject(playerId)) != NULL) + { + //Tell scripts we are loaded + ScriptParams params; + params.addParam( getNetworkId() ); + IGNORE_RETURN(player->getScriptObject()->trigAllScripts(Scripting::TRIG_BUILDING_CONTENTS_LOADED, params)); + failed = false; + } + } + + if (failed) + { + // fail pack-up as authority lost on player - notify script + MessageToQueue::getInstance().sendMessageToJava(playerId, "handleFailedStructurePackup", std::vector(), 0, false); + } + } + + //remove the vendor reinitialization flag if it exists + removeObjVarItem(OBJVAR_STRUCTURE_PLAYER_PACK); + } + else + { + ServerObject const * const containedBy = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (containedBy) + { + Client * const client = containedBy->getClient(); + if (client) + { + CreatureObject const * const containedByCreature = containedBy->asCreatureObject(); + if (containedByCreature && containedByCreature->getBankContainer() == this) + { + if (containedBy->getLoadCTSBank()) + { + LOG("CustomerService", ("CharacterTransfer: serverObject has LoadCTSBank flag set, sending ReplyBankCTSLoaded message")); + GenericValueTypeMessage setFromCTSLoadBank("ReplyBankCTSLoaded", containedBy->getNetworkId()); + client->sendToConnectionServer(setFromCTSLoadBank); + } + else + client->openContainer(*this, 0, std::string()); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::immediateLogoutAllowed() +{ + return true; +} + +// ---------------------------------------------------------------------- + +void ServerObject::disconnect() +{ + if (!isAuthoritative()) + sendControllerMessageToAuthServer(CM_disconnect, 0); + else if (getClient()) + GameServer::getInstance().dropClient(getNetworkId()); +} + +// ---------------------------------------------------------------------- + +void ServerObject::handleDisconnect(bool immediate) +{ + if (isPlayerControlled()) + { + // client has disconnected, log pertinent information about the play session + CreatureObject * const creatureObject = asCreatureObject(); + PlayerObject * playerObject = NULL; + if (creatureObject) + { + playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if (playerObject && (playerObject->getSessionStartPlayTime() != 0)) + { + char buffer[128]; + std::string logText; + + // leading delimiter + logText += "|"; + + // character name + logText += Unicode::wideToNarrow(getObjectName()); + logText += "|"; + + // character id + logText += getNetworkId().getValueString(); + logText += "|"; + + // character birth date + // get the base date of Jan 1st, 2001 + struct tm baseTimeData; + baseTimeData.tm_hour = 0; + baseTimeData.tm_isdst = 0; + baseTimeData.tm_mday = 1; + baseTimeData.tm_min = 0; + baseTimeData.tm_mon = 0; + baseTimeData.tm_sec = 0; + baseTimeData.tm_wday = 0; + baseTimeData.tm_yday = 0; + baseTimeData.tm_year = 101; + time_t baseTime = mktime(&baseTimeData); + + // the birth date is the number of days since Jan 1st, 2001 + baseTime += static_cast(playerObject->getBornDate() * 60 * 60 * 24); + + struct tm * birthDateTimeData = gmtime(&baseTime); + + snprintf(buffer, sizeof(buffer)-1, "%d%02d%02d", (birthDateTimeData->tm_year + 1900), (birthDateTimeData->tm_mon + 1), birthDateTimeData->tm_mday); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // station id + snprintf(buffer, sizeof(buffer)-1, "%lu", playerObject->getStationId()); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // session play time + logText += CalendarTime::convertSecondsToHMS(static_cast(playerObject->getSessionPlayTimeDuration())); + logText += "|"; + + // session active play time + logText += CalendarTime::convertSecondsToHMS(static_cast(playerObject->getSessionActivePlayTimeDuration())); + logText += "|"; + + // session activity + snprintf(buffer, sizeof(buffer)-1, "%lu", playerObject->getSessionActivity()); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // scene name + logText += ServerWorld::getSceneId(); + logText += "|"; + + // container id (0 if in world cell) + Object const * const container = ContainerInterface::getContainedByObject(*this); + snprintf(buffer, sizeof(buffer)-1, "%s", (container ? container->getNetworkId().getValueString().c_str() : "0")); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // x,y,z in container + Vector const posContainer = getPosition_p(); + snprintf(buffer, sizeof(buffer)-1, "%d %d %d", static_cast(posContainer.x), static_cast(posContainer.y), static_cast(posContainer.z)); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // x,y,z in world + Vector const posWorld = getPosition_w(); + snprintf(buffer, sizeof(buffer)-1, "%d %d %d", static_cast(posWorld.x), static_cast(posWorld.y), static_cast(posWorld.z)); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // profession + logText += playerObject->getSkillTemplate(); + logText += "|"; + + // level + snprintf(buffer, sizeof(buffer)-1, "%d", creatureObject->getLevel()); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // current quest id + snprintf(buffer, sizeof(buffer)-1, "%lu", playerObject->getCurrentQuest()); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + logText += "|"; + + // current quest name + if (playerObject->getCurrentQuest() != 0) + { + logText += QuestManager::getQuestName(playerObject->getCurrentQuest()); + } + else + { + logText += "none"; + } + logText += "|"; + + // xp + bool hasLoggedFirstXp = false; + std::map const & xp = playerObject->getExperiencePoints(); + for (std::map::const_iterator iter = xp.begin(); iter != xp.end(); ++iter) + { + if (iter->second == 0) + continue; + + if (hasLoggedFirstXp) + logText += ","; + + logText += iter->first; + logText += "="; + + snprintf(buffer, sizeof(buffer)-1, "%d", iter->second); + buffer[sizeof(buffer)-1] = '\0'; + logText += buffer; + + hasLoggedFirstXp = true; + } + logText += "|"; + + // log it + LOG("CustomerService", ("Logout:%s", logText.c_str())); + + // clear the session play time info + playerObject->setSessionPlayTimeInfo(0, 0, 0); + + // clear the session activity info + playerObject->clearSessionActivity(); + } + } + + if (!immediate && !immediateLogoutAllowed()) + LogoutTracker::add(getNetworkId()); + else + { + virtualOnLogout(); + + if (ConfigServerGame::getLogoutTriggerEnabled()) + { + ScriptParams params; + getScriptObject()->trigAllScripts(Scripting::TRIG_LOGOUT, params); + } + + Client * const client = getClient(); + if (client) + { + LogoutMessage const logoutMessage; + client->send(logoutMessage, true); + } + + PositionUpdateTracker::flushPositionUpdate(*this); + LogoutTracker::addPendingSave(this); + + // get rid of the proxies + clearProxyList(); + + // if we're inside a container, it's the topmost parent that contains our proxy + // list, so the above clearProxyList() call will not get rid of the proxies + synchronizationOnUnload(); + + // don't allow anyone to continue observing this object (and associated PlayerObject) + if (playerObject) + ObserveTracker::onObjectDestroyed(*playerObject, false); + + ObserveTracker::onObjectDestroyed(*this, false); + + // remove from world and/or container as necessary but keep containment information available + if (isInWorld()) + removeFromWorld(); + else + WARNING(getTriggerVolumeEntered() && !getTriggerVolumeEntered()->empty(), ("ServerObject::handleDisconnect called for (%s) which is not in the world but is contained in one or more trigger volumes", getDebugInformation().c_str())); + + // the object should have been removed from all TriggerVolumes + // (from removeFromWorld() above) by now, but as a safety measure, + // we'll do a final check and remove the object from any + // TriggerVolumes that it is still in + if (getTriggerVolumeEntered()) + { + std::set const triggerVolumeEntered = *(getTriggerVolumeEntered()); + for (std::set::const_iterator i = triggerVolumeEntered.begin(); i != triggerVolumeEntered.end(); ++i) + { + WARNING(true, ("Object (%s) added to LogoutTracker but hasn't been removed from TriggerVolume (%s) owned by (%s)", + getDebugInformation().c_str(), + (*i)->getName().c_str(), + (*i)->getOwner().getDebugInformation().c_str())); + + (*i)->removeObject(*this); + } + } + + Object *containerObject = ContainerInterface::getContainedByObject(*this); + if (containerObject) + { + NON_NULL(ContainerInterface::getContainer(*containerObject))->internalItemRemoved(*this); + + // if the character was in a building, tell the building it has lost + // the player so the building demand load/unload system can work correctly + Object *buildingObj = ContainerInterface::getTopmostContainer(*containerObject); + if (buildingObj && buildingObj->isAuthoritative() && buildingObj->asServerObject() && buildingObj->asServerObject()->asBuildingObject()) + buildingObj->asServerObject()->asBuildingObject()->lostPlayer(*this); + } + + // remove all sui pages for character + ServerUIManager::onPlayerLogout(getNetworkId()); + } + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::setAttributeAttained(int attribute) +{ + BitArray tmp(m_attributesAttained.get()); + tmp.setBit(attribute); + m_attributesAttained = tmp; +} + +// ---------------------------------------------------------------------- + +void ServerObject::clearAttributeAttained(int attribute) +{ + BitArray tmp(m_attributesAttained.get()); + tmp.clearBit(attribute); + m_attributesAttained = tmp; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::hasAttributeAttained(int attribute) const +{ + return m_attributesAttained.get().testBit(attribute); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setAttributeInterested(int attribute) +{ + BitArray tmp(m_attributesInterested.get()); + tmp.setBit(attribute); + m_attributesInterested = tmp; +} + +// ---------------------------------------------------------------------- + +void ServerObject::clearAttributeInterested(int attribute) +{ + BitArray tmp(m_attributesInterested.get()); + tmp.clearBit(attribute); + m_attributesInterested = tmp; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::hasAttributeInterest(int attribute) const +{ + return m_attributesInterested.get().testBit(attribute); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isInterested(const ServerObject &rhs) const +{ + return m_attributesInterested.get().matchAnyBit(rhs.m_attributesAttained.get()); +} + +// ---------------------------------------------------------------------- + +std::string ServerObject::getItemLog() const +{ + return getNetworkId().getValueString() + ' ' + Unicode::wideToNarrow(getObjectName()); +} + +// ---------------------------------------------------------------------- + +void ServerObject::checkAndLogInvalidTransform() const +{ + Transform const &transform_o2p = getTransform_o2p(); + bool const isValid = transform_o2p.validate(true); + + if (!isValid) + { + Object const *const container = ContainerInterface::getContainedByObject(*this); + Vector const position = transform_o2p.getPosition_p(); + Vector const containerPosition = container ? container->getTransform_o2w().getPosition_p() : Vector::zero; + + WARNING(!isValid, + ("transform is invalid for object id=[%s], object template name=[%s], server id=[%d], server scene id=[%s], position=[%.2f,%.2f,%.2f], container id=[%s], container position=[%.2f,%.2f,%.2f]", + getNetworkId().getValueString().c_str(), + getObjectTemplateName(), + static_cast(GameServer::getInstance().getProcessId()), + ServerWorld::getSceneId().c_str(), + position.x, + position.y, + position.z, + container ? container->getNetworkId().getValueString().c_str() : "", + containerPosition.x, + containerPosition.y, + containerPosition.z + )); + } +} + +// ---------------------------------------------------------------------- + +ServerObject * ServerObject::combineResourceContainers(ServerObject &item) +{ + if (isVendor() || isBazaarTerminal() || isInBazaarOrVendor() ) + { + //Do not combine resources on vendors or bazaars, as they need + //to remain separate to sell separately. + return &item; + } + + ServerObject * returnedItem = &item; + typedef std::vector SimilarContainers; + static SimilarContainers similarContainers; + + if (item.getObjectType() == ServerResourceContainerObjectTemplate::ServerResourceContainerObjectTemplate_tag) + { + ResourceContainerObject *resourceContainerObject = safe_cast(&item); + + if (resourceContainerObject != NULL) + { + // If this is a container, see if it contains another resource container of the same type + + Container *container = ContainerInterface::getContainer(*this); + + if (container != NULL) + { + ContainerIterator iterContainer = container->begin(); + + for (; iterContainer != container->end(); ++iterContainer) + { + Object *containedObject = NetworkIdManager::getObjectById(*iterContainer); + + // Make sure the contained item is not the item we are gaining and that + // the item is a resource container + + if ((containedObject != &item) && + (containedObject != NULL) && + (containedObject->getObjectType() == ServerResourceContainerObjectTemplate::ServerResourceContainerObjectTemplate_tag)) + { + ResourceContainerObject *containedResourceContainerObject = safe_cast(containedObject); + + if ((containedResourceContainerObject != NULL) && + (resourceContainerObject->getResourceType() == containedResourceContainerObject->getResourceType())) + { + // This is a container of similar type, if it is not full, save it to the list + + int const quantity = containedResourceContainerObject->getQuantity(); + int const maxQuantity = containedResourceContainerObject->getMaxQuantity(); + + if (quantity != maxQuantity) + { + similarContainers.push_back(containedResourceContainerObject); + } + } + } + } + } + } + + // Combine the resources as much as possible + + bool done = false; + int resourcesLeftToAdd = resourceContainerObject->getQuantity(); + + while (!done) + { + // Find the most full container + + SimilarContainers::iterator iterSimilarContainers = similarContainers.begin(); + SimilarContainers::iterator fullestContainer = similarContainers.end(); + + for (; iterSimilarContainers != similarContainers.end(); ++iterSimilarContainers) + { + if (fullestContainer == similarContainers.end()) + { + fullestContainer = iterSimilarContainers; + } + else + { + int const currentQuantity = (*iterSimilarContainers)->getQuantity(); + int const fullestQuantity = (*fullestContainer)->getQuantity(); + + if (currentQuantity > fullestQuantity) + { + fullestContainer = iterSimilarContainers; + } + } + } + + // Add as much as we can to the fullest container + + if (fullestContainer != similarContainers.end()) + { + int const fullestQuantity = (*fullestContainer)->getQuantity(); + int const fullestMaxQuantity = (*fullestContainer)->getMaxQuantity(); + int const amountToAdd = std::min(resourcesLeftToAdd, fullestMaxQuantity - fullestQuantity); + + // Add the amount to the fullest container + + ResourceContainerObject *sourceObj = resourceContainerObject; + ResourceContainerObject *destObj = *fullestContainer; + + if (sourceObj && destObj && (amountToAdd > 0)) + { + sourceObj->transferTo(*destObj, amountToAdd); + if (sourceObj->isBeingDestroyed()) + returnedItem = destObj; + } + + resourcesLeftToAdd -= amountToAdd; + + // Remove this container from the list + + similarContainers.erase(fullestContainer); + } + else + { + // There are no more containers to combine to, so we are done + + done = true; + } + + if (resourcesLeftToAdd <= 0) + { + // If there is no more resources left to combine, then we are done + + done = true; + } + } + + similarContainers.clear(); + } + return returnedItem; +} + +// ---------------------------------------------------------------------- + +/** + * Determines if this object is contained by another object. + * + * @param container the object that might contain this one + * @param includeContents if true, return true if one of the container's contents contains us + * + * @return true if we are contained by the container (or its contents) + */ +bool ServerObject::isContainedBy(const ServerObject & container, bool includeContents) const +{ + // we actually check what we are contained by instead of checking the + // container's contents + const Object * test = ContainerInterface::getContainedByObject(*this); + if (test == &container) + { + // our container is the desired container + return true; + } + else if (test != NULL && test != this && includeContents) + { + // our container isn't the desired container, see if it is contained + return safe_cast(test)->isContainedBy(container, true); + } + return false; +} + +// ---------------------------------------------------------------------- + +void ServerObject::concludeScriptVars() +{ + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::concludeScriptVars"); + GameScriptObject::packAllScriptVarDeltas(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::scheduleForAlter() +{ + // ServerObjects do not recurse into containers, so are always responsible for scheduling themselves directly. + if (isInitialized()) + { +// DEBUG_REPORT_LOG(true, ("[aitest] Scheduling %s for alter\n", getNetworkId().getValueString().c_str())); + AlterScheduler::submitForAlter(*this); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::onAddedToWorldCell() +{ + createFarNetworkUpdateVolume(); + virtualOnAddedToWorldCell(); + updatePositionOnPlanetServer(true); +} + + +// ---------------------------------------------------------------------- + +void ServerObject::virtualOnAddedToWorldCell() +{ +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::onRemovedFromWorldCell() +{ + virtualOnRemovedFromWorldCell(); +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::virtualOnRemovedFromWorldCell() +{ + destroyFarNetworkUpdateVolume(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::virtualOnSetAuthority() +{ +} + +// ---------------------------------------------------------------------- + +void ServerObject::virtualOnReleaseAuthority() +{ +} + +// ---------------------------------------------------------------------- + +void ServerObject::virtualOnLogout() +{ +} + +//------------------------------------------------------------------------------------------ + +bool ServerObject::wantSawAttackTriggers() const +{ + return false; +} + +// ---------------------------------------------------------------------- + +void ServerObject::setTeleportScriptCallback(std::string const &scriptCallback) +{ + setObjVarItem("teleportFixup.callback", scriptCallback); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setInteriorTeleportDestination(NetworkId const &destContainerId, std::string const &destCellName, Vector const &destPosition_p) +{ + LOG("TeleportFixup", ("Setting interior telerport destination for %s: into %f %f %f %s %s\n", getNetworkId().getValueString().c_str(), destPosition_p.x, destPosition_p.y, destPosition_p.z, destCellName.c_str(), destContainerId.getValueString().c_str())); + removeObjVarItem("teleportFixup"); + setObjVarItem("teleportFixup.x", destPosition_p.x); + setObjVarItem("teleportFixup.y", destPosition_p.y); + setObjVarItem("teleportFixup.z", destPosition_p.z); + setObjVarItem("teleportFixup.container", destContainerId); + if (!destCellName.empty()) + setObjVarItem("teleportFixup.cellname", destCellName); +} + +// ---------------------------------------------------------------------- + +Vector const &ServerObject::getTriggerPosition() const +{ + return m_oldPosition; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::getTransformChanged() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_TransformChanged); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setTransformChanged(bool c) +{ + setLocalFlag(LocalObjectFlags::ServerObject_TransformChanged, c); + if (c) + { + addObjectToConcludeList(); + if (isAuthoritative() && isPersisted()) + PositionUpdateTracker::positionChanged(*this); + } +} + +// ---------------------------------------------------------------------- + +bool ServerObject::onContainerChildAboutToLoseItem(ServerObject * destination, ServerObject& item, ServerObject* transferer) +{ + if (transferer && !checkBankTransfer(this, item, transferer)) + return false; + + Object * const parent = ContainerInterface::getContainedByObject(*this); + if (parent && parent->asServerObject()) + return parent->asServerObject()->onContainerChildAboutToLoseItem(destination, item, transferer); + + return true; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::onContainerChildAboutToGainItem(ServerObject& item, ServerObject* destination, ServerObject* transferer) +{ + if (transferer && !checkBankTransfer(this, item, transferer)) + return false; + + Object * const parent = ContainerInterface::getContainedByObject(*this); + if (parent && parent->asServerObject()) + return parent->asServerObject()->onContainerChildAboutToGainItem(item, destination, transferer); + + return true; +} + +// ---------------------------------------------------------------------- + +void ServerObject::onContainerChildLostItem(ServerObject * destination, ServerObject& item, ServerObject* source, ServerObject* transferer) +{ + Object * const parent = ContainerInterface::getContainedByObject(*this); + if (parent && parent->asServerObject()) + parent->asServerObject()->onContainerChildLostItem(destination, item, source, transferer); +} + +// ---------------------------------------------------------------------- + +void ServerObject::onContainerChildGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) +{ + Object * const parent = ContainerInterface::getContainedByObject(*this); + if (parent && parent->asServerObject()) + parent->asServerObject()->onContainerChildGainItem(item, source, transferer); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setLoadCTSBank(bool isForCTS) +{ + m_loadCTSBank = isForCTS; +} + +// ---------------------------------------------------------------------- + +void ServerObject::setLoadCTSPackedHouses(bool isForCTS) +{ + m_loadCTSPackedHouses = isForCTS; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::getLoadCTSBank() const +{ + return m_loadCTSBank; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::getLoadCTSPackedHouses() const +{ + return m_loadCTSPackedHouses; +} + +// ---------------------------------------------------------------------- + +void ServerObject::packedHouseLoaded() +{ + // see if we have the objvar + if (getLoadCTSPackedHouses()) + { + if (getObjVars().hasItem("cts.packed_house_count")) + { + int count = 0; + if (getObjVars().getItem("cts.packed_house_count", count)) + { + --count; + if (count <= 0) + { + LOG("CustomerService", ("CharacterTransfer: all houses loaded, responding to connection server.")); + removeObjVarItem("cts.packed_house_count"); + + // tell the connection server. + Client * client = getClient(); + if (client && client->getConnection()) + { + GenericValueTypeMessage loadedMsg("PackedHousesLoaded", getNetworkId()); + client->getConnection()->send(loadedMsg, true); + } + } + else + { + LOG("CustomerService", ("CharacterTransfer: packed house is loaded, but we expect %d more.", count)); + setObjVarItem("cts.packed_house_count", count); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::setLoadWith(const NetworkId& id) +{ + m_loadWith = id; +} + +//----------------------------------------------------------------------- + +std::string ServerObject::getLogDescription(const NetworkId & id) +{ + std::string const result = getLogDescription(safe_cast(NetworkIdManager::getObjectById(id))); + if (result.empty()) + return id.getValueString(); + return result; +} + +//----------------------------------------------------------------------- + +std::string ServerObject::getLogDescription(const ServerObject * source) +{ + std::string desc = ""; + if(source) + { + desc += "NonPlayerObject "; + desc += Unicode::wideToNarrow(source->getObjectName()); + desc += "("; + desc += source->getNetworkId().getValueString(); + desc += ") "; + desc += source->getObjectTemplateName(); + } + return desc; +} + +//---------------------------------------------------------------------- + +void ServerObject::retrieveStoredObjectAttributes (AttributeVector & av) const +{ + typedef stdvector::fwd UnicodeStringVector; + + static UnicodeStringVector kv; + static UnicodeStringVector vv; + + kv.clear (); + vv.clear (); + + getObjVars ().getItem (objvar_item_attribute_keys, kv); + getObjVars ().getItem (objvar_item_attribute_values, vv); + + if (kv.size () == vv.size ()) + { + const size_t size = vv.size (); + + av.reserve (av.size () + kv.size ()); + + for (size_t i = 0; i < size; ++i) + { + const std::string & key = Unicode::wideToNarrow (kv [i]); + const Unicode::String & value = vv [i]; + + av.push_back (std::make_pair (key, value)); + } + } +} + +//---------------------------------------------------------------------- + +void ServerObject::storeObjectAttributes (const ServerObject & prototype) +{ + typedef stdvector::fwd UnicodeStringVector; + + static UnicodeStringVector kv; + static UnicodeStringVector vv; + static AttributeVector av; + + av.clear (); + kv.clear (); + vv.clear (); + + prototype.getAttributes (NetworkId::cms_invalid, av); + + kv.reserve (av.size()); + vv.reserve (av.size()); + + for (AttributeVector::const_iterator it = av.begin (); it != av.end (); ++it) + { + const std::string & key = (*it).first; + const Unicode::String & value = (*it).second; + + kv.push_back (Unicode::narrowToWide (key)); + vv.push_back (value); + } + + setObjVarItem (objvar_item_attribute_keys, kv); + setObjVarItem (objvar_item_attribute_values, vv); +} + +//---------------------------------------------------------------------- + +void ServerObject::clearStoredObjectAttributes () +{ + m_objVars.removeItemByName (objvar_item_attribute_keys); + m_objVars.removeItemByName (objvar_item_attribute_values); +} + +//---------------------------------------------------------------------- + +void ServerObject::replaceStoredObjectAttribute(Unicode::String const & attribute, Unicode::String const & value) +{ + typedef stdvector::fwd UnicodeStringVector; + + static UnicodeStringVector kv; + static UnicodeStringVector vv; + + kv.clear (); + vv.clear (); + + getObjVars ().getItem (objvar_item_attribute_keys, kv); + getObjVars ().getItem (objvar_item_attribute_values, vv); + + if (kv.size () == vv.size ()) + { + const size_t size = vv.size (); + for (size_t i = 0; i < size; ++i) + { + if (kv [i] == attribute) + { + vv [i] = value; + setObjVarItem (objvar_item_attribute_values, vv); + + break; + } + } + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::setInitialized(bool initialized) +{ + setLocalFlag(LocalObjectFlags::ServerObject_Initialized, initialized); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setBeingDestroyed(bool beingDestroyed) +{ + setLocalFlag(LocalObjectFlags::ServerObject_BeingDestroyed, beingDestroyed); + + // set corresponding flag in script + if (beingDestroyed && isAuthoritative() && getScriptObject()) + getScriptObject()->setOwnerDestroyed(); + + // stop listening to broadcast messages + if (beingDestroyed && isAuthoritative()) + stopListeningToAllBroadcastMessages(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setPlacing(bool placing) +{ + setLocalFlag(LocalObjectFlags::ServerObject_Placing, placing); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setUnloading(bool unloading) +{ + setLocalFlag(LocalObjectFlags::ServerObject_Unloading, unloading); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setGoingToConclude(bool goingToConclude) +{ + setLocalFlag(LocalObjectFlags::ServerObject_GoingToConclude, goingToConclude); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setInEndBaselines(bool inEndBaselines) +{ + setLocalFlag(LocalObjectFlags::ServerObject_InEndBaselines, inEndBaselines); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setNeedsPobFixup(bool needsFixup) +{ + setLocalFlag(LocalObjectFlags::ServerObject_NeedsPobFixup, needsFixup); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isInitialized() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_Initialized); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isPlacing() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_Placing); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isUnloading() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_Unloading); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isBeingDestroyed() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_BeingDestroyed); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isGoingToConclude() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_GoingToConclude); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isInEndBaselines() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_InEndBaselines); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isNeedingPobFixup() const +{ + return getLocalFlag(LocalObjectFlags::ServerObject_NeedsPobFixup); +} + +// ---------------------------------------------------------------------- + +float ServerObject::getLocationReservationRadius() const +{ + return getSharedTemplate() ? getSharedTemplate()->getLocationReservationRadius() : 0.f; +} + +// ---------------------------------------------------------------------- + +void ServerObject::sendDirtyObjectMenuNotification() +{ + if (getLocalFlag(LocalObjectFlags::ServerObject_DirtyObjectMenuSent)) + return; + setLocalFlag(LocalObjectFlags::ServerObject_DirtyObjectMenuSent, true); + + Controller * const controller = getController(); + if (controller) + controller->appendMessage(CM_objectMenuDirty, 0, NULL, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); +} + +// ---------------------------------------------------------------------- + +void ServerObject::sendDirtyAttributesNotification() +{ + if (getLocalFlag(LocalObjectFlags::ServerObject_DirtyAttributesSent)) + return; + setLocalFlag(LocalObjectFlags::ServerObject_DirtyAttributesSent, true); + + Controller * const controller = getController(); + if (controller) + controller->appendMessage(CM_attributesDirty, 0, NULL, GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_ALL_CLIENT); +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::setBuildingUpdateRadiusMultiplier(float m) +{ + if (m <= 0) + { + ms_buildingUpdateRadiusMultiplier = 1.0f; + DEBUG_WARNING(true, ("Building Update Radius Multiplier was set to a value (%f) <= 0", m)); + } + else + ms_buildingUpdateRadiusMultiplier = m; + +} + +// ---------------------------------------------------------------------- + +void ServerObject::triggerMadeAuthoritative() +{ + std::vector trigObjs; + getPlayerControlledContents(*this, trigObjs); + for (std::vector::const_iterator i = trigObjs.begin(); i != trigObjs.end(); ++i) + { + ServerObject *trigObj = safe_cast((*i).getObject()); + if (trigObj && trigObj->isAuthoritative()) + { + ScriptParams params; + IGNORE_RETURN(trigObj->getScriptObject()->trigAllScripts(Scripting::TRIG_MADE_AUTHORITATIVE, params)); + } + } +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::setLayer(TerrainGenerator::Layer* layer) +{ + LayerProperty * layerProperty = NULL; + Property * property = getProperty(LayerProperty::getClassPropertyId()); + if (property != NULL) + layerProperty = safe_cast(property); + else + layerProperty = new LayerProperty(*this); + + layerProperty->setLayer(layer); + if (property == NULL) + { + addProperty(*layerProperty, true); + ObjectTracker::addRunTimeRule(); + addNotification (ServerObjectTerrainModificationNotification::getInstance ()); + } +} + +//------------------------------------------------------------------------------------------ + +TerrainGenerator::Layer* ServerObject::getLayer() const +{ + const Property * property = getProperty(LayerProperty::getClassPropertyId()); + if (property != NULL) + { + const LayerProperty * layerProperty = safe_cast(property); + return layerProperty->getLayer(); + } + return NULL; +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const +{ + if(name == "complexity") + { + m_complexity.pack(target); + } + else if(name == "bankBalance") + { + m_bankBalance.pack(target); + } +} + +//------------------------------------------------------------------------------------------ + +void ServerObject::setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source) +{ + Archive::ReadIterator ri(source); + if(name == "complexity") + { + m_complexity.unpackDelta(ri); + } + else if(name == "bankBalance") + { + m_bankBalance.unpackDelta(ri); + } + addObjectToConcludeList(); +} + +// ---------------------------------------------------------------------- + +/** + * Deliver a MessageTo to this object. If the object is not + * authoritative, send the message to the authoritative server. + * If the MessageTo's time has expired, handle it. If not, enqueue it + * for later. + */ +void ServerObject::deliverMessageTo(MessageToPayload & message) +{ + PROFILER_AUTO_BLOCK_DEFINE("ServerObject::deliverMessageTo"); + + if (message.getRecurringTime() != 0) + { + // Recurring messages can have only one instance each. Ignore + // this message if there is already a recurring one with the same method name. + for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) + { + if ((i->second.getRecurringTime() != 0) && (i->second.getMethod() == message.getMethod())) + return; + } + } + + if (isAuthoritative()) + { + if (message.getCallTime() <= MessageToQueue::getInstance().getEffectiveMessageToTime()) + { + // Message is already due, handle it right away + handleMessageTo(message); + } + else + { + if (isPersisted() && message.getGuaranteed() && !message.getPersisted()) + { + // Message is guaranteed. Since it's being delayed, make sure the DB saves it + // in case of a server crash + message.setPersisted(true); + MessageToMessage const msg(message, GameServer::getInstance().getProcessId()); + GameServer::getInstance().sendToDatabaseServer(msg); + } + if (m_messageTos.empty() || message.getCallTime() < m_messageTos.begin()->second.getCallTime()) + MessageToQueue::getInstance().addToScheduler(*this, message.getCallTime()); + pushMessageTo(message); + } + } + else + { + message.addBounceServer(GameServer::getInstance().getProcessId()); + ServerMessageForwarding::begin(getAuthServerProcessId()); + ServerMessageForwarding::send(MessageToMessage(message, GameServer::getInstance().getProcessId())); + ServerMessageForwarding::end(); + } +} + +// ---------------------------------------------------------------------- + +/** + * Add a MessageTo to the sorted vector of pending messages + * + * Does a binary search to find the appropriate insertion point. + */ +void ServerObject::pushMessageTo(MessageToPayload const & newMessage) +{ + m_messageTos.set(std::make_pair(std::make_pair(newMessage.getCallTime(), newMessage.getCounterMessageToPayload()), newMessage.getMessageId()), newMessage); +} + +// ---------------------------------------------------------------------- + +int ServerObject::cancelMessageTo(std::string const & messageName) +{ + int removeCount; + + if (isAuthoritative()) + { + removeCount = 0; + + for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end();) + { + if ((i->second.getMethod() == messageName) && (i->first != s_currentMessageToBeingHandled)) + { + i = m_messageTos.erase(i); + ++removeCount; + } + else + ++i; + } + } + else + { + sendControllerMessageToAuthServer( + CM_cancelMessageTo, + new MessageQueueGenericValueType(messageName)); + + // -1 means request has been forward to authoritative server for processing + removeCount = -1; + } + + return removeCount; +} + +// ---------------------------------------------------------------------- + +int ServerObject::cancelMessageToByMessageId(NetworkId const & messageId) +{ + int removeCount; + + if (isAuthoritative()) + { + removeCount = 0; + + for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end();) + { + if ((i->second.getMessageId() == messageId) && (i->first != s_currentMessageToBeingHandled)) + { + i = m_messageTos.erase(i); + ++removeCount; + break; + } + else + ++i; + } + } + else + { + sendControllerMessageToAuthServer( + CM_cancelMessageTo, + new MessageQueueGenericValueType(messageId.getValueString())); + + // -1 means request has been forward to authoritative server for processing + removeCount = -1; + } + + return removeCount; +} + +// ---------------------------------------------------------------------- +// returns the number of seconds until the messageTo fires, which *CAN* be 0 +// returns -1 if object doesn't have the messageTo +int ServerObject::timeUntilMessageTo(std::string const & messageName) const +{ + for (Archive::AutoDeltaMap, MessageToId>, MessageToPayload>::const_iterator i=m_messageTos.begin(); i!=m_messageTos.end(); ++i) + { + if (i->second.getMethod() == messageName) + { + if ((i->first != s_currentMessageToBeingHandled) || (i->second.getRecurringTime() > 0)) + { + unsigned long const now = ServerClock::getInstance().getGameTimeSeconds(); + unsigned long const callTime = i->second.getCallTime(); + if (callTime > now) + return static_cast(callTime - now); + + return 0; + } + } + } + + return -1; // doesn't have the messageTo +} + +// ---------------------------------------------------------------------- + +/** + * Sets the root node for a patrol path node. + * + * @param root the root node + * + * NOTE: Does not work multiserver! + */ +void ServerObject::setPatrolPathRoot(const ServerObject & root) +{ + if (!isAuthoritative()) + { + WARNING(true, ("ServerObject::setPatrolPathRoot called on non-authoritative object %s for %s", + getNetworkId().getValueString().c_str(), root.getNetworkId().getValueString().c_str())); + return; + } + + // make sure we aren't already a root node + Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); + if (p != NULL) + { + if (root.getNetworkId() != getNetworkId()) + { + WARNING(true, ("ServerObject::setPatrolPathRoot trying to set root node %s on node %s that is already a root", + root.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); + } + return; + } + + // see if we are going to be the root node + if (root.getNetworkId() == getNetworkId()) + { + p = new PatrolPathRootProperty(*this); + addProperty(*p, true); + } + else + { + // add the root node to our node list + p = getProperty(PatrolPathNodeProperty::getClassPropertyId()); + if (p == NULL) + { + p = new PatrolPathNodeProperty(*this); + addProperty(*p, true); + } + else if (safe_cast(p)->hasRoot(root)) + return; + safe_cast(p)->addRoot(root); + + if (!root.isPatrolPathRoot()) + { + // the root has not been set up, do it now + WARNING(true, ("ServerObject::setPatrolPathRoot for node %s: root node %s was not initialized, doing it now (THIS SHOULD NEVER HAPPEN)", + getNetworkId().getValueString().c_str(), root.getNetworkId().getValueString().c_str())); + const_cast(root).setPatrolPathRoot(root); + } + } + + // we need to add any players in range to our path observer count + TriggerVolume * triggerVolume = getNetworkTriggerVolume(); + if (triggerVolume != NULL) + { + TriggerVolume::ContentsSet const & contents = triggerVolume->getContents(); + for (TriggerVolume::ContentsSet::const_iterator i = contents.begin(); i != contents.end(); ++i) + { + if (*i != NULL) + { + Client * client = (*i)->getClient(); + if (client != NULL) + { + if (!ObserveTracker::isObserving(*client, *this)) + ObserveTracker::onClientEnteredNetworkTriggerVolume(*client, *triggerVolume); + else + { + // note: we call addPatrolPathObserver() on the root instead of us so + // that we don't update the count of any paths we already belong to + const_cast(root).addPatrolPathObserver(); + } + } + } + } + } +} // ServerObject::setPatrolPathRoot + +// ---------------------------------------------------------------------- + +/** + * Returns the root node for a patrol path node. + * + * @return the root node, or NULL if this isn't a patrol path node + */ +const std::set & ServerObject::getPatrolPathRoots() const +{ +static const std::set noRoots; + + const Property * p = getProperty(PatrolPathNodeProperty::getClassPropertyId()); + if (p != NULL) + { + return safe_cast(p)->getRoots(); + } + return noRoots; +} // ServerObject::getPatrolPathRoot + +// ---------------------------------------------------------------------- + +/** + * Adds an object that is moving along a patrol path where this object is the + * root node. If our path goes from being unobserved to observed, all the objects + * using this path will be scheduled for alter. + * + * @param ai the object that's on our path + * + * NOTE: Does not work multiserver! + */ +void ServerObject::addPatrolPathingObject(const ServerObject & ai) +{ + if (!isAuthoritative()) + { + WARNING(true, ("ServerObject::addPatrolPathingObject called on non-authoritative object %s for %s", + getNetworkId().getValueString().c_str(), ai.getNetworkId().getValueString().c_str())); + return; + } + + Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); + if (p != NULL) + { + safe_cast(p)->addPatrollingObject(ai); + DEBUG_REPORT_LOG(true, ("[patrolpath] add patrol ai %s to root %s\n", + ai.getNetworkId().getValueString().c_str(), + getNetworkId().getValueString().c_str())); + } + else + { + // if we are not a root, try to add the ai to our root (but only do so if we have + // one root) + DEBUG_WARNING(true, ("ServerObject::addPatrolPathingObject trying to add an ai %s to a non-root path node %s, going to use our root", + ai.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); + const std::set & roots = getPatrolPathRoots(); + if (roots.size() == 1) + { + ServerObject * root = safe_cast(roots.begin()->getObject()); + if (root != NULL) + root->addPatrolPathingObject(ai); + } + else + { + WARNING(true, ("ServerObject::addPatrolPathingObject trying to add an ai %s to a non-root path node %s which has muliple roots.", + ai.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); + } + } +} // ServerObject::addPatrolPathingObject + +// ---------------------------------------------------------------------- + +/** + * Removes an object that is moving along our patrol path. + * + * @param ai the object to remove + * + * NOTE: Does not work multiserver! + */ +void ServerObject::removePatrolPathingObject(const ServerObject & ai) +{ + if (!isAuthoritative()) + { + WARNING(true, ("ServerObject::removePatrolPathingObject called on non-authoritative object %s for %s", + getNetworkId().getValueString().c_str(), ai.getNetworkId().getValueString().c_str())); + return; + } + + Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); + if (p != NULL) + { + safe_cast(p)->removePatrollingObject(ai); + DEBUG_REPORT_LOG(true, ("[patrolpath] remove patrol ai %s from root %s\n", + ai.getNetworkId().getValueString().c_str(), + getNetworkId().getValueString().c_str())); + } + else + { + // if we are not a root, try to remove the ai to our root (but only do so if we have + // one root) + const std::set & roots = getPatrolPathRoots(); + if (roots.size() == 1) + { + ServerObject * root = safe_cast(roots.begin()->getObject()); + if (root != NULL) + root->removePatrolPathingObject(ai); + } + else + { + WARNING(true, ("ServerObject::removePatrolPathingObject trying to remove an ai %s from a non-root path node %s which has muliple roots.", + ai.getNetworkId().getValueString().c_str(), getNetworkId().getValueString().c_str())); + } + } +} // ServerObject::removePatrolPathingObject + +// ---------------------------------------------------------------------- + +/** + * Increments the observer count for this patrol path. If this is the first observer, + * schedules any patrolling objects for alter. + * + * NOTE: Does not work multiserver! + */ +void ServerObject::addPatrolPathObserver() +{ + if (!isAuthoritative()) + { + WARNING(true, ("ServerObject::addPatrolPathObserver called on non-authoritative object %s", + getNetworkId().getValueString().c_str())); + return; + } + + // if we are a root node, increment our observer count + Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); + if (p != NULL) + { + PatrolPathRootProperty * pprp = safe_cast(p); + pprp->incrementObserverCount(); + DEBUG_REPORT_LOG(true, ("[patrolpath] add observer to %s, count = %d\n", + getNetworkId().getValueString().c_str(), pprp->getObserverCount())); + if (pprp->getObserverCount() == 1) + { + // we need to wake up hibernating ai + const std::set > & ai = pprp->getPatrollingObjects(); + for (std::set >::const_iterator i = ai.begin(); i != ai.end(); ++i) + { + if (*i != NULL) + { + const ServerObject * ai = *i; + if (ai->getController()->asCreatureController() != NULL) + { + const CreatureController * controller = ai->getController()->asCreatureController(); + if (controller->getHibernate()) + { + DEBUG_REPORT_LOG(true, ("[patrolpath] path root %s waking up ai %s", + getNetworkId().getValueString().c_str(), + ai->getNetworkId().getValueString().c_str())); + const_cast(ai)->scheduleForAlter(); + } + } + } + } + } + } + else + { + // increment the count of the root nodes of any paths we belong to + const std::set & roots = getPatrolPathRoots(); + for (std::set::const_iterator i = roots.begin(); i != roots.end(); ++i) + { + ServerObject * root = safe_cast(i->getObject()); + if (root != NULL) + { + root->addPatrolPathObserver(); + } + } + } +} // ServerObject::addPatrolPathObserver + +// ---------------------------------------------------------------------- + +/** + * Decrements the observer count for this patrol path. + * + * NOTE: Does not work multiserver! + */ +void ServerObject::removePatrolPathObserver() +{ + if (!isAuthoritative()) + { + WARNING(true, ("ServerObject::removePatrolPathObserver called on non-authoritative object %s", + getNetworkId().getValueString().c_str())); + return; + } + + // if we are a root node, decrement our observer count + Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); + if (p != NULL) + { + PatrolPathRootProperty * pprp = safe_cast(p); + pprp->decrementObserverCount(); + DEBUG_REPORT_LOG(true, ("[patrolpath] remove observer from %s, count = %d\n", + getNetworkId().getValueString().c_str(), pprp->getObserverCount())); + if (pprp->getObserverCount() < 0) + { + WARNING(true, ("ServerObject::removePatrolPathObserver %s has negative patrol path observer count of %d", + getNetworkId().getValueString().c_str(), pprp->getObserverCount())); + } + } + else + { + // decrement the count of the root nodes of any paths we belong to + const std::set & roots = getPatrolPathRoots(); + for (std::set::const_iterator i = roots.begin(); i != roots.end(); ++i) + { + ServerObject * root = safe_cast(i->getObject()); + if (root != NULL) + { + root->removePatrolPathObserver(); + } + } + } +} // ServerObject::removePatrolPathObserver + +// ---------------------------------------------------------------------- + +/** + * Returns the number of observers of this patrol path. If this node connects to multiple + * roots, we will return the total for all paths it connects to. + * + * @return the observer count + */ +int ServerObject::getPatrolPathObservers() const +{ + int observers = 0; + + const Property * p = getProperty(PatrolPathRootProperty::getClassPropertyId()); + if (p != NULL) + { + observers = safe_cast(p)->getObserverCount(); + } + else + { + const std::set & roots = getPatrolPathRoots(); + for (std::set::const_iterator i = roots.begin(); i != roots.end(); ++i) + { + const ServerObject * root = safe_cast(i->getObject()); + if (root != NULL && root->isPatrolPathRoot()) + { + observers += root->getPatrolPathObservers(); + } + } + } + return observers; +} // ServerObject::getPatrolPathObservers + +// ---------------------------------------------------------------------- + +bool ServerObject::isPatrolPathNode() const +{ + return (getProperty(PatrolPathNodeProperty::getClassPropertyId()) != NULL) || isPatrolPathRoot(); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::isPatrolPathRoot() const +{ + return getProperty(PatrolPathRootProperty::getClassPropertyId()) != NULL; +} + +// ---------------------------------------------------------------------- + +bool ServerObject::hasAttributeCaching() const +{ + // rls - if attribute caching breaks for an object, you can disable + // caching by returning false here. + return true; +} + +// ---------------------------------------------------------------------- + +int ServerObject::getAttributeRevision() const +{ + return m_objVars.getRevision(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setAttributeRevisionDirty() +{ + m_objVars.updateRevision(); +} + +// ---------------------------------------------------------------------- + +bool ServerObject::getIncludeInBuildout() const +{ + return m_includeInBuildout.get(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::setIncludeInBuildout( bool value ) +{ + m_includeInBuildout = value; +} + +// ---------------------------------------------------------------------- + +void ServerObject::setDescriptionStringId(const StringId & id) +{ + m_descriptionStringId.set(id); +} + +// ---------------------------------------------------------------------- + +StringId const & ServerObject::getDescriptionStringId() +{ + return m_descriptionStringId.get(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::addBroadcastListener(std::string const & messageName, NetworkId const & listener) +{ + if (!isAuthoritative()) + return; + + m_broadcastListeners.insert(std::make_pair(messageName, listener)); +} + +// ---------------------------------------------------------------------- + +void ServerObject::removeBroadcastListener(std::string const & messageName, NetworkId const & listener) +{ + if (!isAuthoritative()) + return; + + IGNORE_RETURN(m_broadcastListeners.erase(std::make_pair(messageName, listener))); +} + +// ---------------------------------------------------------------------- + +void ServerObject::removeBroadcastListener(NetworkId const & listener) +{ + if (!isAuthoritative()) + return; + + for (BroadcastMap::const_iterator iter = m_broadcastListeners.begin(); iter != m_broadcastListeners.end();) + { + if (iter->second == listener) + { + // AutoDeltaSet's erase() will increment iter to point to the next item + m_broadcastListeners.erase(iter); + } + else + { + ++iter; + } + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::addBroadcastBroadcaster(std::string const & messageName, NetworkId const & broadcaster) +{ + if (!isAuthoritative()) + return; + + m_broadcastBroadcasters.insert(std::make_pair(messageName, broadcaster)); +} + +// ---------------------------------------------------------------------- + +void ServerObject::removeBroadcastBroadcaster(std::string const & messageName, NetworkId const & broadcaster) +{ + if (!isAuthoritative()) + return; + + IGNORE_RETURN(m_broadcastBroadcasters.erase(std::make_pair(messageName, broadcaster))); +} + +// ---------------------------------------------------------------------- + +void ServerObject::removeBroadcastAllBroadcasters() +{ + if (!isAuthoritative()) + return; + + m_broadcastBroadcasters.clear(); +} + +// ---------------------------------------------------------------------- + +void ServerObject::listenToBroadcastMessage(std::string const & messageName, NetworkId const & broadcaster) +{ + if (messageName.empty() || !broadcaster.isValid()) + return; + + if (!isAuthoritative()) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), broadcaster.getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++listenToBroadcastMessage", buffer, 0, false); + } + else + { + // need to send a message to the broadcaster if the broadcaster is not on this game server + ServerObject * objBroadcaster = ServerWorld::findObjectByNetworkId(broadcaster); + if (objBroadcaster && objBroadcaster->isAuthoritative()) + { + // tell broadcaster that I want to listen + objBroadcaster->addBroadcastListener(messageName, getNetworkId()); + } + else + { + char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), getNetworkId().getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + MessageToQueue::getInstance().sendMessageToC(broadcaster, "C++addBroadcastListener", buffer, 0, false); + } + + // this object is now listening to the broadcaster + // @TODO: technically, we should have the remote broadcaster + // send a message back confirming that this object has + // been added to the broadcaster's listener list before + // we mark this object as listening to the broadcaster + addBroadcastBroadcaster(messageName, broadcaster); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::stopListeningToBroadcastMessage(std::string const & messageName, NetworkId const & broadcaster) +{ + if (messageName.empty() || !broadcaster.isValid()) + return; + + if (!isAuthoritative()) + { + char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), broadcaster.getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++stopListeningToBroadcastMessage", buffer, 0, false); + } + else + { + // need to send a message to the broadcaster if the broadcaster is not on this game server + ServerObject * objBroadcaster = ServerWorld::findObjectByNetworkId(broadcaster); + if (objBroadcaster && objBroadcaster->isAuthoritative()) + { + // tell broadcaster that I no longer want to listen + objBroadcaster->removeBroadcastListener(messageName, getNetworkId()); + } + else + { + char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s %s", messageName.c_str(), getNetworkId().getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + MessageToQueue::getInstance().sendMessageToC(broadcaster, "C++removeBroadcastListener", buffer, 0, false); + } + + // this object is no longer listening to the broadcaster + // @TODO: technically, we should have the remote broadcaster + // send a message back confirming that this object has + // been removed from the broadcaster's listener list before + // we mark this object as no longer listening to the broadcaster + removeBroadcastBroadcaster(messageName, broadcaster); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::stopListeningToAllBroadcastMessages() +{ + if (!isAuthoritative()) + { + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++stopListeningToAllBroadcastMessage", "", 0, false); + } + else + { + // build list of all broadcasters this object is currently listening to + std::unordered_set broadcasters; + for (BroadcastMap::const_iterator iter = m_broadcastBroadcasters.begin(); iter != m_broadcastBroadcasters.end(); ++iter) + IGNORE_RETURN(broadcasters.insert(iter->second)); + + for (std::unordered_set::const_iterator iter2 = broadcasters.begin(); iter2 != broadcasters.end(); ++iter2) + { + // need to send a message to the broadcaster if the broadcaster is not on this game server + ServerObject * objBroadcaster = ServerWorld::findObjectByNetworkId(*iter2); + if (objBroadcaster && objBroadcaster->isAuthoritative()) + { + // tell broadcaster that I no longer want to listen + objBroadcaster->removeBroadcastListener(getNetworkId()); + } + else + { + char buffer[128]; + snprintf(buffer, sizeof(buffer)-1, "%s", getNetworkId().getValueString().c_str()); + buffer[sizeof(buffer)-1] = '\0'; + MessageToQueue::getInstance().sendMessageToC(*iter2, "C++removeBroadcastListenerAllMessage", buffer, 0, false); + } + } + + // this object is no longer listening to any broadcasters + // @TODO: technically, we should have the remote broadcaster + // send a message back confirming that this object has + // been removed from the broadcaster's listener list before + // we mark this object as no longer listening to the broadcaster + removeBroadcastAllBroadcasters(); + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::addObserver(Client * client) +{ + std::pair::const_iterator, bool> result = m_observers.insert(client); + + if (result.second) + { + if (isAuthoritative()) + { + m_observersCount = m_observersCount.get() + 1; + } + else + { + sendControllerMessageToAuthServer(CM_updateObserversCount, new MessageQueueGenericValueType(1)); + } + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::removeObserver(Client * client) +{ + int erased = m_observers.erase(client); + + if (erased > 0) + { + if (isAuthoritative()) + { + m_observersCount = m_observersCount.get() - erased; + if (m_observersCount.get() < 0) + { + WARNING(true, ("ServerObject::removeObserver for object %s has observer count of %d", getNetworkId().getValueString().c_str(), m_observersCount.get())); + m_observersCount = 0; + } + } + else + { + sendControllerMessageToAuthServer(CM_updateObserversCount, new MessageQueueGenericValueType(-erased)); + } + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::clearObservers() +{ + int erased = m_observers.size(); + m_observers.clear(); + + if (erased > 0) + { + if (isAuthoritative()) + { + m_observersCount = m_observersCount.get() - erased; + if (m_observersCount.get() < 0) + { + WARNING(true, ("ServerObject::clearObservers for object %s has observer count of %d", getNetworkId().getValueString().c_str(), m_observersCount.get())); + m_observersCount = 0; + } + } + else + { + // if we aren't being deleted, send a controller message, otherwise send a messageTo + if (!getKill()) + sendControllerMessageToAuthServer(CM_updateObserversCount, new MessageQueueGenericValueType(-erased)); + else + { + char buffer[32]; + _itoa(-erased, buffer, 10); + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), "C++updateObserversCount", buffer, 0, false); + } + } + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::clearObserversCount() +{ + if (isAuthoritative()) + { + m_observersCount = 0; + } +} + +// ---------------------------------------------------------------------- + +void ServerObject::updateObserversCount(int delta) +{ + if (isAuthoritative()) + { + m_observersCount = m_observersCount.get() + delta; + if (m_observersCount.get() < 0) + { + WARNING(m_observersCount.get() < 0, ("ServerObject::updateObserversCount for object %s has observer count of %d", getNetworkId().getValueString().c_str(), m_observersCount.get())); + m_observersCount = 0; + } + } +} + +// ---------------------------------------------------------------------- + +/** + * Do nothing; this function is base virtual function so that creatures can go + * in and out of hibernation when observed. + */ +void ServerObject::observersCountChanged() +{ +} + +// ====================================================================== + +namespace Archive +{ + void put(Archive::ByteStream &target, TriggerVolumeInfo const &source) + { + put(target, source.name); + put(target, source.radius); + put(target, source.isPromiscuous); + } + + void get(Archive::ReadIterator &source, TriggerVolumeInfo &target) + { + get(source, target.name); + get(source, target.radius); + get(source, target.isPromiscuous); + } +} + +// ====================================================================== + diff --git a/src/engine/server/library/serverGame/src/shared/object/ServerObject.h b/src/engine/server/library/serverGame/src/shared/object/ServerObject.h index e20e0e8ef..32192ce36 100644 --- a/src/engine/server/library/serverGame/src/shared/object/ServerObject.h +++ b/src/engine/server/library/serverGame/src/shared/object/ServerObject.h @@ -297,7 +297,7 @@ public: bool isInEndBaselines() const; bool isNeedingPobFixup() const; bool permanentlyDestroy (DeleteReasons::Enumerator reason); - virtual void persist (); + virtual bool persist (); virtual void onRemovingFromWorld (); virtual void unload (); void moveToPlayerAndUnload (const NetworkId &player); diff --git a/src/engine/server/library/serverGame/src/shared/object/ShipObject_Components.cpp b/src/engine/server/library/serverGame/src/shared/object/ShipObject_Components.cpp index 7e2358dc5..ec75f19bd 100644 --- a/src/engine/server/library/serverGame/src/shared/object/ShipObject_Components.cpp +++ b/src/engine/server/library/serverGame/src/shared/object/ShipObject_Components.cpp @@ -1,3422 +1,3422 @@ -//====================================================================== -// -// ShipObject_Components.cpp -// copyright (c) 2004 Sony Online Entertainment -// -//====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/ShipObject_Components.h" - -#include "UnicodeUtils.h" -#include "serverGame/Chat.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/MissileManager.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/ResourceTypeObject.h" -#include "serverGame/ServerObjectTemplate.h" -#include "serverGame/ServerResourceClassObject.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/ShipComponentDataEngine.h" -#include "serverGame/ShipComponentDataManager.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptFunctionTable.h" -#include "serverScript/ScriptParameters.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/Timer.h" -#include "sharedGame/SharedStringIds.h" -#include "sharedGame/ShipChassis.h" -#include "sharedGame/ShipChassisSlot.h" -#include "sharedGame/ShipChassisSlotType.h" -#include "sharedGame/ShipComponentAttachmentManager.h" -#include "sharedGame/ShipComponentData.h" -#include "sharedGame/ShipComponentDescriptor.h" -#include "sharedGame/ShipComponentFlags.h" -#include "sharedGame/ShipComponentWeaponManager.h" -#include "sharedGame/ShipTurretManager.h" -#include "sharedLog/Log.h" -#include "sharedObject/Appearance.h" -#include "sharedObject/AppearanceTemplate.h" -#include "sharedObject/AppearanceTemplateList.h" -#include "sharedObject/Hardpoint.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedObject/PortalProperty.h" -#include "sharedObject/PortalPropertyTemplate.h" -#include "sharedObject/VolumeContainer.h" - - -// ====================================================================== - -namespace ShipObjectNamespace -{ - ConstCharCrcString const s_turretPitchHardpoint("turretpitch1"); -} -using namespace ShipObjectNamespace; - -// ====================================================================== - -uint32 ShipObject::getChassisType () const -{ - return m_chassisType.get (); -} - -//---------------------------------------------------------------------- - -/** - * Returns [0.0, 1.0] relating to the hitpoints of the chassis and all installed components - * 1.0 == pristine, 0.0 == totally broken (though there are other rules to determine if a ship is flyable) - */ -float ShipObject::getOverallHealth() const -{ - float total = 0.0f; - int numComponents = 0; - if(getMaximumChassisHitPoints() > 0.0) - { - total += getCurrentChassisHitPoints() / getMaximumChassisHitPoints(); - ++numComponents; - } - - for(int i = ShipChassisSlotType::SCST_first; i != ShipChassisSlotType::SCST_num_types; ++i) - { - if(isSlotInstalled(i)) - { - if(getComponentHitpointsMaximum(i) > 0.0f) - { - total += getComponentHitpointsCurrent(i) / getComponentHitpointsMaximum(i); - ++numComponents; - } - } - } - - if(numComponents <= 0) - return 0.0f; - else - return clamp(0.0f, total / numComponents, 1.0f); -} - -//---------------------------------------------------------------------- - -float ShipObject::getOverallHealthWithShieldsAndArmor() const -{ - int numberObjectsToWeight = 0; - - float total = getOverallHealth(); - ++numberObjectsToWeight; - - float const shieldHitpointsFrontMaximum = getShieldHitpointsFrontMaximum(); - if (shieldHitpointsFrontMaximum != 0.0) - { - total += getShieldHitpointsFrontCurrent() / shieldHitpointsFrontMaximum; - ++numberObjectsToWeight; - } - - float const shieldHitpointsBackMaximum = getShieldHitpointsBackMaximum(); - if (shieldHitpointsBackMaximum != 0.0) - { - total += getShieldHitpointsBackCurrent() / shieldHitpointsBackMaximum; - ++numberObjectsToWeight; - } - - float const componentArmorHitpointsMaximum0 = getComponentArmorHitpointsMaximum(ShipChassisSlotType::SCST_armor_0); - if (componentArmorHitpointsMaximum0 != 0.0) - { - total += getComponentArmorHitpointsCurrent(ShipChassisSlotType::SCST_armor_0) / componentArmorHitpointsMaximum0; - ++numberObjectsToWeight; - } - - float const componentArmorHitpointsMaximum1 = getComponentArmorHitpointsMaximum(ShipChassisSlotType::SCST_armor_1); - if (componentArmorHitpointsMaximum1 != 0.0) - { - total += getComponentArmorHitpointsCurrent(ShipChassisSlotType::SCST_armor_1) / componentArmorHitpointsMaximum1; - ++numberObjectsToWeight; - } - - return clamp(0.0f, total / static_cast(numberObjectsToWeight), 1.0f); -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentArmorHitpointsMaximum (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentArmorHitpointsMaximum.find (chassisSlot); - if (it != m_componentArmorHitpointsMaximum.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentArmorHitpointsCurrent (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentArmorHitpointsCurrent.find (chassisSlot); - if (it != m_componentArmorHitpointsCurrent.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentEfficiencyGeneral (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentEfficiencyGeneral.find (chassisSlot); - if (it != m_componentEfficiencyGeneral.end ()) - return (*it).second; - return 1.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentEfficiencyEnergy (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentEfficiencyEnergy.find (chassisSlot); - if (it != m_componentEfficiencyEnergy.end ()) - return (*it).second; - return 1.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentEnergyMaintenanceRequirement (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentEnergyMaintenanceRequirement.find (chassisSlot); - if (it != m_componentEnergyMaintenanceRequirement.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentMass (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentMass.find (chassisSlot); - if (it != m_componentMass.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -uint32 ShipObject::getComponentCrc (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentCrc.find (chassisSlot); - if (it != m_componentCrc.end ()) - return (*it).second; - return 0; -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentHitpointsCurrent (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentHitpointsCurrent.find (chassisSlot); - if (it != m_componentHitpointsCurrent.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getComponentHitpointsMaximum (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentHitpointsMaximum.find (chassisSlot); - if (it != m_componentHitpointsMaximum.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -int ShipObject::getComponentFlags (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentFlags.find (chassisSlot); - if (it != m_componentFlags.end ()) - return (*it).second; - return 0; -} - -//---------------------------------------------------------------------- - -Unicode::String const &ShipObject::getComponentName(int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentNames.find (chassisSlot); - if (it != m_componentNames.end() && !(*it).second.empty()) - return (*it).second; - - return Unicode::emptyString; -} - -//---------------------------------------------------------------------- - -NetworkId const &ShipObject::getComponentCreator(int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_componentCreators.find (chassisSlot); - if (it != m_componentCreators.end()) - return (*it).second; - - return NetworkId::cms_invalid; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponDamageMaximum (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponDamageMaximum.find (chassisSlot); - if (it != m_weaponDamageMaximum.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponDamageMinimum (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponDamageMinimum.find (chassisSlot); - if (it != m_weaponDamageMinimum.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponEffectivenessShields (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponEffectivenessShields.find (chassisSlot); - if (it != m_weaponEffectivenessShields.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponEffectivenessArmor (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponEffectivenessArmor.find (chassisSlot); - if (it != m_weaponEffectivenessArmor.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponEnergyPerShot (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponEnergyPerShot.find (chassisSlot); - if (it != m_weaponEnergyPerShot.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponActualEnergyPerShot(int chassisSlot) const -{ - float const weaponEfficiencyEnergy = std::max(0.1f, getComponentEfficiencyEnergy(chassisSlot)); - return getWeaponEnergyPerShot(chassisSlot) / weaponEfficiencyEnergy; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponRefireRate (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponRefireRate.find (chassisSlot); - if (it != m_weaponRefireRate.end ()) - return (*it).second; - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponActualRefireRate (int chassisSlot) const -{ - if (!isSlotInstalled(chassisSlot)) - return 0.0f; - - float const eff = clamp(0.1f, getWeaponEfficiencyRefireRate(chassisSlot), 10.0f); - return getWeaponRefireRate(chassisSlot) / eff; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponEfficiencyRefireRate (int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponEfficiencyRefireRate.find (chassisSlot); - if (it != m_weaponEfficiencyRefireRate.end ()) - return (*it).second; - return 1.0f; -} - -//---------------------------------------------------------------------- - -int ShipObject::getWeaponAmmoCurrent(int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoCurrent.find (chassisSlot); - if (it != m_weaponAmmoCurrent.end ()) - return (*it).second; - return 0; -} - -//---------------------------------------------------------------------- - -int ShipObject::getWeaponAmmoMaximum(int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoMaximum.find (chassisSlot); - if (it != m_weaponAmmoMaximum.end ()) - return (*it).second; - return 0; -} - -//---------------------------------------------------------------------- - -uint32 ShipObject::getWeaponAmmoType(int chassisSlot) const -{ - Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoType.find (chassisSlot); - if (it != m_weaponAmmoType.end ()) - return (*it).second; - return 0; -} - -//---------------------------------------------------------------------- - -float ShipObject::getShieldHitpointsFrontCurrent () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) - return m_shieldHitpointsFrontCurrent.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getShieldHitpointsFrontMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) - return m_shieldHitpointsFrontMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getShieldHitpointsBackCurrent () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) - return m_shieldHitpointsBackCurrent.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getShieldHitpointsBackMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) - return m_shieldHitpointsBackMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getShieldRechargeRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) - return m_shieldRechargeRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getCapacitorEnergyCurrent () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) - return m_capacitorEnergyCurrent.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getCapacitorEnergyMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) - return m_capacitorEnergyMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getCapacitorEnergyEffectiveMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor) && isComponentFunctional(ShipChassisSlotType::SCST_capacitor)) - return m_capacitorEnergyMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getCapacitorEnergyRechargeRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) - return m_capacitorEnergyRechargeRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineAccelerationRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineAccelerationRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineDecelerationRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineDecelerationRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEnginePitchAccelerationRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_enginePitchAccelerationRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineYawAccelerationRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineYawAccelerationRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineRollAccelerationRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineRollAccelerationRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEnginePitchRateMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_enginePitchRateMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineYawRateMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineYawRateMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineRollRateMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineRollRateMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineSpeedMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineSpeedMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineSpeedRotationFactorMaximum() const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineSpeedRotationFactorMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineSpeedRotationFactorMinimum() const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineSpeedRotationFactorMinimum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getEngineSpeedRotationFactorOptimal() const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - return m_engineSpeedRotationFactorOptimal.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getReactorEnergyGenerationRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_reactor)) - return m_reactorEnergyGenerationRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getBoosterEnergyCurrent () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) - return m_boosterEnergyCurrent.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getBoosterEnergyMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) - return m_boosterEnergyMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getBoosterEnergyRechargeRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) - return m_boosterEnergyRechargeRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getBoosterEnergyConsumptionRate () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) - return m_boosterEnergyConsumptionRate.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getBoosterAcceleration () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) - return m_boosterAcceleration.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getBoosterSpeedMaximum () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) - return m_boosterSpeedMaximum.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -float ShipObject::getDroidInterfaceCommandSpeed () const -{ - if (isSlotInstalled (ShipChassisSlotType::SCST_droid_interface)) - return m_droidInterfaceCommandSpeed.get (); - return 0.0f; -} - -//---------------------------------------------------------------------- - -bool ShipObject::hasSlot (int chassisSlot) const -{ - ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); - return shipChassis && shipChassis->getSlot (static_cast(chassisSlot)); -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentArmorHitpointsMaximum (int chassisSlot, float componentArmorHitpointsMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentArmorHitpointsMaximum () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentArmorHitpointsMaximum () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_componentArmorHitpointsMaximum.set (chassisSlot, componentArmorHitpointsMaximum); - //-- force update of current hitpoints - IGNORE_RETURN(setComponentArmorHitpointsCurrent (chassisSlot, getComponentArmorHitpointsCurrent (chassisSlot))); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentArmorHitpointsCurrent (int chassisSlot, float componentArmorHitpointsCurrent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentArmorHitpointsCurrent () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentArmorHitpointsCurrent () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - componentArmorHitpointsCurrent = std::min (getComponentArmorHitpointsMaximum (chassisSlot), componentArmorHitpointsCurrent); - m_componentArmorHitpointsCurrent.set (chassisSlot, componentArmorHitpointsCurrent); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentEfficiencyGeneral (int chassisSlot, float componentEfficiencyGeneral) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEfficiencyGeneral () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentEfficiencyGeneral () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - componentEfficiencyGeneral = clamp (0.1f, componentEfficiencyGeneral, 10.0f); - m_componentEfficiencyGeneral.set (chassisSlot, componentEfficiencyGeneral); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentEfficiencyEnergy (int chassisSlot, float componentEfficiencyEnergy) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEfficiencyEnergy () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentEfficiencyEnergy () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - componentEfficiencyEnergy = clamp (0.1f, componentEfficiencyEnergy, 10.0f); - m_componentEfficiencyEnergy.set (chassisSlot, componentEfficiencyEnergy); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentEnergyMaintenanceRequirement (int chassisSlot, float componentEnergyMaintenanceRequirement) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEnergyMaintenanceRequirement () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentEnergyMaintenanceRequirement () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_componentEnergyMaintenanceRequirement.set (chassisSlot, componentEnergyMaintenanceRequirement); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentMass (int chassisSlot, float componentMass) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentMass () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentMass () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_componentMass.set (chassisSlot, componentMass); - - internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); - return true; -} - -//---------------------------------------------------------------------- - -/** -* Setting a component template crc to zero removes the component -*/ - -void ShipObject::setComponentCrc (int chassisSlot, uint32 componentCrc) -{ - if (componentCrc == 0) - { - IGNORE_RETURN (m_componentArmorHitpointsMaximum.erase (chassisSlot)); - IGNORE_RETURN (m_componentArmorHitpointsCurrent.erase (chassisSlot)); - IGNORE_RETURN (m_componentEfficiencyGeneral.erase (chassisSlot)); - IGNORE_RETURN (m_componentEfficiencyEnergy.erase (chassisSlot)); - IGNORE_RETURN (m_componentEnergyMaintenanceRequirement.erase (chassisSlot)); - IGNORE_RETURN (m_componentMass.erase (chassisSlot)); - IGNORE_RETURN (m_componentCrc.erase (chassisSlot)); - IGNORE_RETURN (m_componentCrcForClient.erase (chassisSlot)); - IGNORE_RETURN (m_componentHitpointsCurrent.erase (chassisSlot)); - IGNORE_RETURN (m_componentHitpointsMaximum.erase (chassisSlot)); - IGNORE_RETURN (m_componentFlags.erase (chassisSlot)); - IGNORE_RETURN (m_componentNames.erase (chassisSlot)); - IGNORE_RETURN (m_weaponDamageMaximum.erase (chassisSlot)); - IGNORE_RETURN (m_weaponDamageMinimum.erase (chassisSlot)); - IGNORE_RETURN (m_weaponEffectivenessShields.erase (chassisSlot)); - IGNORE_RETURN (m_weaponEffectivenessArmor.erase (chassisSlot)); - IGNORE_RETURN (m_weaponEnergyPerShot.erase (chassisSlot)); - IGNORE_RETURN (m_weaponRefireRate.erase (chassisSlot)); - IGNORE_RETURN (m_componentCreators.erase (chassisSlot)); - - internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); - } - else - { - m_componentCrc.set (chassisSlot, componentCrc); - m_componentCrcForClient.set (chassisSlot, componentCrc); - - //-- all components start out at low power so script gets the first power up pulse - IGNORE_RETURN(setComponentLowPower (chassisSlot, true)); - - internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); - } - - if (ShipChassisSlotType::isWeaponChassisSlot(static_cast(chassisSlot))) - { - // Cache the turret positions - { - int const weaponIndex = ShipChassisSlotType::getWeaponIndex(static_cast(chassisSlot)); - - if (ShipTurretManager::isTurret(getChassisType(), weaponIndex)) - { - m_turretWeaponIndices->setBit(weaponIndex); - } - else - { - m_turretWeaponIndices->clearBit(weaponIndex); - } - } - - // Cache for the fastest projectile weapon speed - { - m_fastestWeaponProjectileSpeed = 0.0f; - - for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex) - { - if (isProjectile(weaponIndex)) - { - m_fastestWeaponProjectileSpeed = std::max(m_fastestWeaponProjectileSpeed, getWeaponProjectileSpeed(weaponIndex)); - } - } - } - } -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentHitpointsCurrent (int chassisSlot, float componentHitpointsCurrent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentHitpointsCurrent () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentHitpointsCurrent () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - float const maxHp = getComponentHitpointsMaximum(chassisSlot); - - componentHitpointsCurrent = std::min (maxHp, componentHitpointsCurrent); - m_componentHitpointsCurrent.set (chassisSlot, componentHitpointsCurrent); - - bool const isDemolished = isComponentDemolished(chassisSlot); - - if (componentHitpointsCurrent <= 0.0f && maxHp > 0.0f && !isDemolished) - IGNORE_RETURN(setComponentDemolished(chassisSlot, true)); - else if (isDemolished) - IGNORE_RETURN(setComponentDemolished(chassisSlot, false)); - - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentHitpointsMaximum (int chassisSlot, float componentHitpointsMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentHitpointsMaximum () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentHitpointsMaximum () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_componentHitpointsMaximum.set (chassisSlot, componentHitpointsMaximum); - IGNORE_RETURN(setComponentHitpointsCurrent (chassisSlot, getComponentHitpointsCurrent (chassisSlot))); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentFlags (int chassisSlot, int componentFlags) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentFlags () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentFlags () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_componentFlags.set (chassisSlot, componentFlags); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentName(int chassisSlot, Unicode::String const & componentName) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentName () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentName () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_componentNames.set (chassisSlot, componentName); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentCreator(int chassisSlot, NetworkId const & componentCreator) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentName () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentCreator () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - if (componentCreator != NetworkId::cms_invalid) - m_componentCreators.set (chassisSlot, componentCreator); - else - m_componentCreators.erase(chassisSlot); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentDisabled (int chassisSlot, bool componentDisabled) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentDisabled () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentDisabled () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - int const flags = getComponentFlags (chassisSlot); - - if (componentDisabled) - { - IGNORE_RETURN(setComponentFlags(chassisSlot, flags | static_cast(ShipComponentFlags::F_disabled))); - IGNORE_RETURN(setComponentLowPower(chassisSlot, true)); - IGNORE_RETURN(setComponentActive(chassisSlot, false)); - } - else - { - IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_disabled))); - IGNORE_RETURN(setComponentDisabledNeedsPower(chassisSlot, false)); - } - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentDisabledNeedsPower(int chassisSlot, bool componentDisabledNeedsPower) -{ - FATAL(isInitialized() && !isAuthoritative(), ("ShipObject::setComponentDisabledNeedsPower() called on non-auth object.")); - if (!isSlotInstalled(chassisSlot)) - { - WARNING(true, ("ShipObject::setComponentDisabledNeedsPower() called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - int const flags = getComponentFlags(chassisSlot); - - if (componentDisabledNeedsPower) - IGNORE_RETURN(setComponentFlags(chassisSlot, flags | static_cast(ShipComponentFlags::F_disabledNeedsPower))); - else - IGNORE_RETURN(setComponentFlags(chassisSlot, flags & ~static_cast(ShipComponentFlags::F_disabledNeedsPower))); - - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentLowPower (int chassisSlot, bool componentLowPower) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentLowPower () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentLowPower () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - int const flags = getComponentFlags (chassisSlot); - - if (componentLowPower) - IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_lowPower))); - else - IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_lowPower))); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentActive (int chassisSlot, bool componentActive) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentActive() called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentActive() called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - int const flags = getComponentFlags (chassisSlot); - - if (componentActive) - IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_active))); - else - IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_active))); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setComponentDemolished(int chassisSlot, bool const componentDemolished) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentDemolished() called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setComponentDemolished() called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - int const flags = getComponentFlags (chassisSlot); - - if (componentDemolished) - IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_demolished))); - else - IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_demolished))); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponDamageMaximum (int chassisSlot, float weaponDamageMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponDamageMaximum () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponDamageMaximum () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponDamageMaximum.set (chassisSlot, weaponDamageMaximum); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponDamageMinimum (int chassisSlot, float weaponDamageMinimum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponDamageMinimum () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponDamageMinimum () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponDamageMinimum.set (chassisSlot, weaponDamageMinimum); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponEffectivenessShields (int chassisSlot, float weaponEffectivenessShields) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEffectivenessShields () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponEffectivenessShields () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponEffectivenessShields.set (chassisSlot, weaponEffectivenessShields); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponEffectivenessArmor (int chassisSlot, float weaponEffectivenessArmor) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEffectivenessArmor () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponEffectivenessArmor () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponEffectivenessArmor.set (chassisSlot, weaponEffectivenessArmor); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponEnergyPerShot (int chassisSlot, float weaponEnergyPerShot) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEnergyPerShot () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponEnergyPerShot () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponEnergyPerShot.set (chassisSlot, weaponEnergyPerShot); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponRefireRate (int chassisSlot, float weaponRefireRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponRefireRate () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponRefireRate () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponRefireRate.set (chassisSlot, weaponRefireRate); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponEfficiencyRefireRate (int chassisSlot, float weaponEfficiencyRefireRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEfficiencyRefireRate () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponEfficiencyRefireRate () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponEfficiencyRefireRate.set (chassisSlot, weaponEfficiencyRefireRate); - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Set a weapon's refire timer to have the specified percentage of its time - * already elapsed. For example, 0.25 will prevent the weapon from firing - * again until 75% of its regular refire time has elapsed. This setting - * applies to the next shot only; future shots will use the regular refire rate. - */ -void ShipObject::setWeaponRefireTimerPercent(int weaponIndex, float refireTimerPercent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponRefireTimerPercent () called on non-auth object.")); - m_weaponRefireTimers[weaponIndex].setElapsedTime(refireTimerPercent * getWeaponActualRefireRate(static_cast(ShipChassisSlotType::SCST_weapon_first) + weaponIndex)); -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponAmmoCurrent(int chassisSlot, int weaponAmmoCurrent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponAmmoCurrent () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponAmmoCurrent.set (chassisSlot, weaponAmmoCurrent); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponAmmoMaximum(int chassisSlot, int weaponAmmoMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponAmmoMaximum () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponAmmoMaximum.set (chassisSlot, weaponAmmoMaximum); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setWeaponAmmoType(int chassisSlot, uint32 weaponAmmoType) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::setWeaponAmmoType () called on slot [%d] with nothing installed.", chassisSlot)); - return false; - } - - m_weaponAmmoType.set (chassisSlot, weaponAmmoType); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setShieldHitpointsFrontCurrent (float shieldHitpointsCurrent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsFrontCurrent () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) - { - WARNING (true, ("ShipObject::setShieldHitpointsFrontCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); - return false; - } - - shieldHitpointsCurrent = std::min (getShieldHitpointsFrontMaximum (), shieldHitpointsCurrent); - m_shieldHitpointsFrontCurrent.set (shieldHitpointsCurrent); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setShieldHitpointsFrontMaximum (float shieldHitpointsMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsFrontMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) - { - WARNING (true, ("ShipObject::setShieldHitpointsFrontMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); - return false; - } - - m_shieldHitpointsFrontMaximum.set (shieldHitpointsMaximum); - IGNORE_RETURN(setShieldHitpointsFrontCurrent (getShieldHitpointsFrontCurrent ())); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setShieldHitpointsBackCurrent (float shieldHitpointsCurrent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsBackCurrent () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) - { - WARNING (true, ("ShipObject::setShieldHitpointsBackCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); - return false; - } - - shieldHitpointsCurrent = std::min (getShieldHitpointsBackMaximum (), shieldHitpointsCurrent); - m_shieldHitpointsBackCurrent.set (shieldHitpointsCurrent); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setShieldHitpointsBackMaximum (float shieldHitpointsMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsBackMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) - { - WARNING (true, ("ShipObject::setShieldHitpointsBackMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); - return false; - } - - m_shieldHitpointsBackMaximum.set (shieldHitpointsMaximum); - IGNORE_RETURN(setShieldHitpointsBackCurrent (getShieldHitpointsBackCurrent ())); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setShieldRechargeRate (float shieldRechargeRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldRechargeRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) - { - WARNING (true, ("ShipObject::setShieldRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); - return false; - } - - m_shieldRechargeRate.set (shieldRechargeRate); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setCapacitorEnergyCurrent (float capacitorEnergyCurrent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyCurrent () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) - { - WARNING (true, ("ShipObject::setCapacitorEnergyCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); - return false; - } - - float const capacitorEnergyMaximum = getCapacitorEnergyEffectiveMaximum () * getComponentEfficiencyGeneral(ShipChassisSlotType::SCST_capacitor); - capacitorEnergyCurrent = std::min (capacitorEnergyMaximum, capacitorEnergyCurrent); - m_capacitorEnergyCurrent = capacitorEnergyCurrent; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setCapacitorEnergyMaximum (float capacitorEnergyMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) - { - WARNING (true, ("ShipObject::setCapacitorEnergyMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); - return false; - } - - m_capacitorEnergyMaximum = capacitorEnergyMaximum; - IGNORE_RETURN(setCapacitorEnergyCurrent (getCapacitorEnergyCurrent ())); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setCapacitorEnergyRechargeRate (float capacitorEnergyRechargeRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyRechargeRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) - { - WARNING (true, ("ShipObject::setCapacitorEnergyRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); - return false; - } - - m_capacitorEnergyRechargeRate = capacitorEnergyRechargeRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineAccelerationRate (float engineAccelerationRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineAccelerationRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineAccelerationRate = engineAccelerationRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineDecelerationRate (float engineDecelerationRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineDecelerationRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineDecelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineDecelerationRate = engineDecelerationRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEnginePitchAccelerationRate (float enginePitchAccelerationRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEnginePitchAccelerationRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEnginePitchAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_enginePitchAccelerationRate = enginePitchAccelerationRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineYawAccelerationRate (float engineYawAccelerationRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineYawAccelerationRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineYawAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineYawAccelerationRate = engineYawAccelerationRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineRollAccelerationRate (float engineRollAccelerationRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineRollAccelerationRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineRollAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineRollAccelerationRate = engineRollAccelerationRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEnginePitchRateMaximum (float enginePitchRateMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEnginePitchRateMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEnginePitchRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_enginePitchRateMaximum = enginePitchRateMaximum; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineYawRateMaximum (float engineYawRateMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineYawRateMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineYawRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineYawRateMaximum = engineYawRateMaximum; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineRollRateMaximum (float engineRollRateMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineRollRateMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineRollRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineRollRateMaximum = engineRollRateMaximum; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineSpeedMaximum (float engineSpeedMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineSpeedMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineSpeedMaximum = engineSpeedMaximum; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineSpeedRotationFactorMaximum(float engineSpeedRotationFactor) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineSpeedRotationFactorMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineSpeedRotationFactorMaximum = engineSpeedRotationFactor; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineSpeedRotationFactorMinimum(float engineSpeedRotationFactorMin) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorMinimum() called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineSpeedRotationFactorMinimum() called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineSpeedRotationFactorMinimum = engineSpeedRotationFactorMin; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setEngineSpeedRotationFactorOptimal(float engineSpeedRotationFactorOptimal) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorOptimal() called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) - { - WARNING (true, ("ShipObject::setEngineSpeedRotationFactorOptimal() called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); - return false; - } - - m_engineSpeedRotationFactorOptimal = engineSpeedRotationFactorOptimal; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setReactorEnergyGenerationRate (float reactorEnergyGenerationRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setReactorEnergyGenerationRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_reactor))) - { - WARNING (true, ("ShipObject::setReactorEnergyGenerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_reactor))); - return false; - } - - m_reactorEnergyGenerationRate = reactorEnergyGenerationRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setBoosterEnergyCurrent (float boosterEnergyCurrent) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyCurrent () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) - { - WARNING (true, ("ShipObject::setBoosterEnergyCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); - return false; - } - - boosterEnergyCurrent = std::min (getBoosterEnergyMaximum (), boosterEnergyCurrent); - m_boosterEnergyCurrent = boosterEnergyCurrent; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setBoosterEnergyMaximum (float boosterEnergyMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) - { - WARNING (true, ("ShipObject::setBoosterEnergyMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); - return false; - } - - m_boosterEnergyMaximum = boosterEnergyMaximum; - IGNORE_RETURN(setBoosterEnergyCurrent (getBoosterEnergyCurrent ())); - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setBoosterEnergyRechargeRate (float boosterEnergyRechargeRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyRechargeRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) - { - WARNING (true, ("ShipObject::setBoosterEnergyRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); - return false; - } - - m_boosterEnergyRechargeRate = boosterEnergyRechargeRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setBoosterEnergyConsumptionRate (float boosterEnergyConsumptionRate) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyConsumptionRate () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) - { - WARNING (true, ("ShipObject::setBoosterEnergyConsumptionRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); - return false; - } - - m_boosterEnergyConsumptionRate = boosterEnergyConsumptionRate; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setBoosterAcceleration (float boosterAcceleration) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterAcceleration () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) - { - WARNING (true, ("ShipObject::setBoosterAcceleration () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); - return false; - } - - m_boosterAcceleration = boosterAcceleration; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setBoosterSpeedMaximum (float boosterSpeedMaximum) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterSpeedMaximum () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) - { - WARNING (true, ("ShipObject::setBoosterSpeedMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); - return false; - } - - m_boosterSpeedMaximum = boosterSpeedMaximum; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::setDroidInterfaceCommandSpeed (float droidInterfaceCommandSpeed) -{ - FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setDroidInterfaceCommandSpeed () called on non-auth object.")); - if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_droid_interface))) - { - WARNING (true, ("ShipObject::setDroidInterfaceCommandSpeed () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_droid_interface))); - return false; - } - - m_droidInterfaceCommandSpeed = droidInterfaceCommandSpeed; - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::canInstallComponent (int chassisSlot, TangibleObject const & component) const -{ - ShipComponentData const * const shipComponentData = ShipComponentDataManager::create (component); - if (!shipComponentData) - { - WARNING (true, ("ShipObject::canInstallComponent failed for [%s] because a ShipComponentData could not be constructed.", component.getNetworkId ().getValueString ().c_str ())); - return false; - } - - if (chassisSlot < static_cast(ShipChassisSlotType::SCST_first) || - chassisSlot >= static_cast(ShipChassisSlotType::SCST_num_types)) - { - WARNING (true, ("ShipObject::canInstallComponent failed for [%s] because a chassisSlot was invalid.", component.getNetworkId ().getValueString ().c_str ())); - return false; - } - - ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); - if (shipChassis) - { - int effectiveCompatibilitySlot = chassisSlot; - // weapon slots beyond 7 wrap back to slot 0 for the purposes of compatibility checking on captial ships - if (isCapitalShip() && chassisSlot >= ShipChassisSlotType::SCST_num_explicit_types && chassisSlot <= ShipChassisSlotType::SCST_weapon_last) - effectiveCompatibilitySlot = ShipChassisSlotType::SCST_weapon_first+((chassisSlot-ShipChassisSlotType::SCST_weapon_first)&7); - - ShipChassisSlot const * const slot = shipChassis->getSlot (static_cast(effectiveCompatibilitySlot)); - - if (slot != NULL) - { - if (slot->canAcceptComponent (shipComponentData->getDescriptor ())) - { - //-- check for mass availability - float const massAvailable = getChassisComponentMassMaximum() - getChassisComponentMassCurrent(); - return massAvailable >= shipComponentData->m_mass; - } - } - } - - return false; -} - -//---------------------------------------------------------------------- - -/** -* This function destroys the component -*/ - -bool ShipObject::installComponent (NetworkId const & installerId, int chassisSlot, TangibleObject & component) -{ - if (!canInstallComponent (chassisSlot, component)) - { - WARNING (true, ("ShipObject::installComponent failed for [%s] because the component can't go here.", component.getNetworkId ().getValueString ().c_str ())); - return false; - } - - if (isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::installComponent failed for [%s] because the slot is occupied.", component.getNetworkId ().getValueString ().c_str ())); - return false; - } - - ShipComponentData const * const shipComponentData = ShipComponentDataManager::create (component); - if (!shipComponentData) - { - WARNING (true, ("ShipObject::installComponent failed for [%s] because a ShipComponentData could not be constructed.", component.getNetworkId ().getValueString ().c_str ())); - return false; - } - - if(getScriptObject()) - { - ScriptParams p; - p.addParam(installerId); - p.addParam(component.getNetworkId ()); - p.addParam(chassisSlot); - - if (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_INSTALLING, p) == SCRIPT_OVERRIDE) - return false; - } - - shipComponentData->writeDataToShip (chassisSlot, *this); - - LOG( - "CustomerService", - ( - "ShipComponents: %s (%s), [%s]: added to %s (%s) by %s", - Unicode::wideToNarrow(component.getObjectName()).c_str(), - component.getNetworkId().getValueString().c_str(), - component.getObjectTemplateName(), - Unicode::wideToNarrow(getObjectName()).c_str(), - getNetworkId().getValueString().c_str(), - PlayerObject::getAccountDescription(getOwnerId()).c_str())); - - IGNORE_RETURN (component.permanentlyDestroy (DeleteReasons::Consumed)); - - if(getScriptObject()) - { - ScriptParams p; - p.addParam(installerId); - p.addParam (chassisSlot); - - IGNORE_RETURN (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_INSTALLED, p)); - } - - return true; -} - -//---------------------------------------------------------------------- - -void ShipObject::purgeComponent (int chassisSlot) -{ - IGNORE_RETURN (internalUninstallComponent (NetworkId::cms_invalid, chassisSlot, NULL)); -} - -//---------------------------------------------------------------------- - -TangibleObject * ShipObject::internalUninstallComponent (NetworkId const & uninstallerId, int chassisSlot, ServerObject * containerTarget, bool allowOverload) -{ - if (!isSlotInstalled (chassisSlot)) - { - WARNING (true, ("ShipObject::internalUninstallComponent failed... no component installed in slot")); - return NULL; - } - - ShipComponentData * const shipComponentData = createShipComponentData (chassisSlot); - - if (shipComponentData == NULL) - { - WARNING (true, ("ShipObject::internalUninstallComponent failed null data")); - delete shipComponentData; - return NULL; - } - - if(getScriptObject()) - { - ScriptParams p; - p.addParam(uninstallerId); - p.addParam (chassisSlot); - p.addParam (containerTarget ? containerTarget->getNetworkId () : NetworkId::cms_invalid); - - if (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_UNINSTALLING, p) == SCRIPT_OVERRIDE) - return NULL; - } - - TangibleObject * tangible = 0; - - if (containerTarget) - { - uint32 const objectTemplateCrc = shipComponentData->getDescriptor ().getObjectTemplateCrc (); - - ServerObject * obj = 0; - if (allowOverload) - { - - VolumeContainer * volContainer = ContainerInterface::getVolumeContainer(*containerTarget); - if (volContainer == NULL) - return 0; - - int oldCapacity = volContainer->debugDoNotUseSetCapacity(-1); - - obj = ServerWorld::createNewObject(objectTemplateCrc, *containerTarget, true, true); - - volContainer->debugDoNotUseSetCapacity(oldCapacity); - volContainer->recalculateVolume(); - } - else - { - obj = safe_cast(ServerWorld::createNewObject (objectTemplateCrc, *containerTarget, true)); - } - - if (obj == NULL) - { - WARNING (true, ("ShipObject::internalUninstallComponent failed for slot [%d] because ServerWorld could not create an object for [%d], or container is full", chassisSlot, objectTemplateCrc)); - delete shipComponentData; - return NULL; - } - - tangible = obj->asTangibleObject (); - - if (tangible == NULL) - { - WARNING (true, ("ShipObject::internalUninstallComponent failed for slot [%d] because object template [%d] is not tangible", chassisSlot, objectTemplateCrc)); - delete shipComponentData; - IGNORE_RETURN (obj->permanentlyDestroy (DeleteReasons::SetupFailed)); - return NULL; - } - - shipComponentData->writeDataToComponent (*tangible); - - LOG( - "CustomerService", - ( - "ShipComponents: %s (%s), [%s]: removed from %s (%s) by %s", - Unicode::wideToNarrow(tangible->getObjectName()).c_str(), - tangible->getNetworkId().getValueString().c_str(), - tangible->getObjectTemplateName(), - Unicode::wideToNarrow(getObjectName()).c_str(), - getNetworkId().getValueString().c_str(), - PlayerObject::getAccountDescription(getOwnerId()).c_str())); - } - - switch (chassisSlot) - { - case ShipChassisSlotType::SCST_reactor: - IGNORE_RETURN(setReactorEnergyGenerationRate (0.0f)); - break; - case ShipChassisSlotType::SCST_engine: - IGNORE_RETURN(setEngineAccelerationRate (0.0f)); - IGNORE_RETURN(setEngineDecelerationRate (0.0f)); - IGNORE_RETURN(setEnginePitchAccelerationRate (0.0f)); - IGNORE_RETURN(setEngineYawAccelerationRate (0.0f)); - IGNORE_RETURN(setEngineRollAccelerationRate (0.0f)); - IGNORE_RETURN(setEnginePitchRateMaximum (0.0f)); - IGNORE_RETURN(setEngineYawRateMaximum (0.0f)); - IGNORE_RETURN(setEngineRollRateMaximum (0.0f)); - IGNORE_RETURN(setEngineSpeedMaximum (0.0f)); - break; - - case ShipChassisSlotType::SCST_capacitor: - IGNORE_RETURN(setCapacitorEnergyCurrent (0.0f)); - IGNORE_RETURN(setCapacitorEnergyMaximum (0.0f)); - IGNORE_RETURN(setCapacitorEnergyRechargeRate (0.0f)); - break; - - case ShipChassisSlotType::SCST_shield_0: - IGNORE_RETURN(setShieldHitpointsFrontCurrent (0.0f)); - IGNORE_RETURN(setShieldHitpointsFrontMaximum (0.0f)); - IGNORE_RETURN(setShieldHitpointsBackCurrent (0.0f)); - IGNORE_RETURN(setShieldHitpointsBackMaximum (0.0f)); - IGNORE_RETURN(setShieldRechargeRate (0.0f)); - break; - - case ShipChassisSlotType::SCST_booster: - IGNORE_RETURN(setBoosterEnergyCurrent (0.0f)); - IGNORE_RETURN(setBoosterEnergyMaximum (0.0f)); - IGNORE_RETURN(setBoosterEnergyRechargeRate (0.0f)); - IGNORE_RETURN(setBoosterEnergyConsumptionRate (0.0f)); - IGNORE_RETURN(setBoosterAcceleration (0.0f)); - IGNORE_RETURN(setBoosterSpeedMaximum (0.0f)); - break; - - case ShipChassisSlotType::SCST_droid_interface: - IGNORE_RETURN(setDroidInterfaceCommandSpeed (0.0f)); - break; - - case ShipChassisSlotType::SCST_cargo_hold: - { - m_cargoHoldContents.clear(); - setCargoHoldContentsCurrent(0); - setCargoHoldContentsMaximum(0); - } - break; - - default: - break; - } - - setComponentCrc (chassisSlot, 0); - - delete shipComponentData; - - if(getScriptObject()) - { - ScriptParams p; - p.addParam(uninstallerId); - p.addParam (tangible ? tangible->getNetworkId () : NetworkId::cms_invalid); - p.addParam (chassisSlot); - p.addParam (containerTarget ? containerTarget->getNetworkId () : NetworkId::cms_invalid); - - IGNORE_RETURN (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_UNINSTALLED, p)); - } - - return tangible; -} - -//---------------------------------------------------------------------- - -TangibleObject * ShipObject::uninstallComponent (NetworkId const & uninstallerId, int chassisSlot, ServerObject & containerTarget, bool allowOverload) -{ - return internalUninstallComponent (uninstallerId, chassisSlot, &containerTarget, allowOverload); -} - -//---------------------------------------------------------------------- - -bool ShipObject::installComponentFromData(int chassisSlot, ShipComponentData const & shipComponentData) -{ - ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); - if (shipChassis == NULL) - { - WARNING (true, ("Ship [%s] chassis [%d] is invalid for installing component [%s]", - getNetworkId().getValueString().c_str(), - static_cast(getChassisType ()), - shipComponentData.getDescriptor().getName().getString())); - return false; - } - - if (isSlotInstalled (chassisSlot)) - { - WARNING (true, ("Ship [%s] chassis [%s] slot [%s] is already filled, cannot install [%s]", - getNetworkId().getValueString().c_str(), - shipChassis->getName().getString(), - ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), - shipComponentData.getDescriptor().getName().getString())); - - return false; - } - - int effectiveCompatibilitySlot = chassisSlot; - // weapon slots beyond 7 wrap back to slot 0 for the purposes of compatibility checking on captial ships - if (isCapitalShip() && chassisSlot >= ShipChassisSlotType::SCST_num_explicit_types && chassisSlot <= ShipChassisSlotType::SCST_weapon_last) - effectiveCompatibilitySlot = ShipChassisSlotType::SCST_weapon_first+((chassisSlot-ShipChassisSlotType::SCST_weapon_first)&7); - - ShipChassisSlot const * const slot = shipChassis->getSlot (static_cast(effectiveCompatibilitySlot)); - if (slot == NULL) - { - WARNING (true, ("Ship [%s] chassis [%s] does not support slot [%s] for installing component [%s]", - getNetworkId().getValueString().c_str(), - shipChassis->getName().getString(), - ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), - shipComponentData.getDescriptor().getName().getString())); - return false; - } - - if (!slot->canAcceptComponent(shipComponentData.getDescriptor())) - { - WARNING (true, ("Component [%s], compat [%s] cannot be installed in ship [%s] chassis [%s], slot [%s], compats [%s].", - shipComponentData.getDescriptor().getName().getString(), - shipComponentData.getDescriptor().getCompatibility().getString(), - getNetworkId().getValueString().c_str(), - shipChassis->getName().getString(), - ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), - slot->getCompatibilityString().c_str())); - return false; - } - - shipComponentData.writeDataToShip (chassisSlot, *this); - - return true; -} - -//---------------------------------------------------------------------- - -bool ShipObject::pseudoInstallComponent(int chassisSlot, uint32 componentCrc) -{ - ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc (componentCrc); - if (shipComponentDescriptor == NULL) - { - WARNING (true, ("Invalid component name")); - return false; - } - - ShipComponentData * const shipComponentData = ShipComponentDataManager::create (*shipComponentDescriptor); - - if (shipComponentData == NULL) - { - WARNING(true, ("ShipObject::pseudoInstallComponent invalid descriptor")); - return false; - } - - bool const retval = installComponentFromData(chassisSlot, *shipComponentData); - - delete shipComponentData; - - return retval; -} - -//---------------------------------------------------------------------- - -ShipComponentData * ShipObject::createShipComponentData (int chassisSlot) const -{ - ShipComponentDescriptor const * shipComponentDescriptor = NULL; - - uint32 const componentCrc = getComponentCrc (chassisSlot); - if (componentCrc) - { - shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc (componentCrc); - if (shipComponentDescriptor == NULL) - { - WARNING (true, ("ShipObject::createShipComponentData failed for slot [%d] because component crc [%d] could not map to a component descriptor", chassisSlot, componentCrc)); - return NULL; - } - } - else - return NULL; - - ShipComponentData * const shipComponentData = ShipComponentDataManager::create (*shipComponentDescriptor); - if (shipComponentData == NULL) - { - WARNING (true, ("ShipObject::createShipComponentData failed for slot [%d] ship Component data could not be constructed", chassisSlot)); - delete(shipComponentData); - return NULL; - } - - if (!shipComponentData->readDataFromShip (chassisSlot, *this)) - WARNING (true, ("ShipObject::createShipComponentData failed for read data from the ship")); - - return shipComponentData; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isSlotInstalled (int chassisSlot) const -{ - return getComponentCrc (chassisSlot) != 0; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isBoosterInstalled() const -{ - return isSlotInstalled(ShipChassisSlotType::SCST_booster); -} - -//---------------------------------------------------------------------- - -bool ShipObject::isBoosterActive() const -{ - if (isBoosterInstalled()) - { - return isComponentActive(ShipChassisSlotType::SCST_booster); - } - - return false; -} - -// ---------------------------------------------------------------------- - -void ShipObject::setBoosterActive(bool const active) -{ - if (isSlotInstalled(ShipChassisSlotType::SCST_booster)) - IGNORE_RETURN(setComponentActive(ShipChassisSlotType::SCST_booster, active)); -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualAccelerationRate () const -{ - float rate = 0.0f; - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - { - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - rate = getEngineAccelerationRate () * efficiency; - } - - if (isSlotInstalled (ShipChassisSlotType::SCST_booster) && isBoosterActive () && isComponentFunctional(ShipChassisSlotType::SCST_booster)) - { - float const boosterEfficiency = computeActualComponentEfficiencyGeneral (ShipChassisSlotType::SCST_booster); - rate += getBoosterAcceleration () * boosterEfficiency; - } - - //-- @todo: divide rate by mass - - rate = rate * m_movementPercent; - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualDecelerationRate () const -{ - float rate = 0.0f; - - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - rate = getEngineDecelerationRate () * efficiency; - else - rate = getShipDataEngine().m_engineDecelerationRate; - - //-- @todo: divide rate by mass - - rate = rate * m_movementPercent; - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeSpeedRotationFactor() const -{ - //-- compute rotational factor - float const engineSpeedRotationFactorBaseMax = getEngineSpeedRotationFactorMaximum(); - float const engineSpeedRotationFactorBaseMin = getEngineSpeedRotationFactorMinimum(); - float const engineSpeedRotationFactorOptimal = getEngineSpeedRotationFactorOptimal(); - - float const speedMax = getShipActualSpeedMaximum(); - float const speedCur = getCurrentSpeed(); - float const speedPercent = (speedMax > 0.0f) ? (speedCur / speedMax) : 0.0f; - float engineSpeedRotationFactor = 1.0f; - - if (speedPercent < engineSpeedRotationFactorOptimal || engineSpeedRotationFactorOptimal >= 1.0f) - { - float const speedPercentToOptimal = speedPercent / engineSpeedRotationFactorOptimal; - engineSpeedRotationFactor = linearInterpolate(engineSpeedRotationFactorBaseMin, 1.0f, speedPercentToOptimal); - } - else - { - float const speedPercentFromOptimal = (speedPercent - engineSpeedRotationFactorOptimal) / (1.0f - engineSpeedRotationFactorOptimal); - engineSpeedRotationFactor = linearInterpolate(1.0f, engineSpeedRotationFactorBaseMax, speedPercentFromOptimal); - } - - // snap to discreet values, to avoid constant change - return floorf((engineSpeedRotationFactor * 10.f) + 0.5f) / 10.f; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualPitchAccelerationRate () const -{ - //float rate = 0.0f; - // - //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - // - //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - //{ - // rate = getEnginePitchAccelerationRate () * efficiency; - // - // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) - // { - // //-- player ships are allowed to stop spinning - // if (isPlayerShip()) - // rate *= 0.5f; - // else - // rate = 0.0f; - // } - //} - float rate = 0.0f; - - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - rate = getEnginePitchAccelerationRate () * efficiency; - else - rate = getShipDataEngine().m_enginePitchAccelerationRate; - - //-- @todo: divide rate by rotational inertia - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualYawAccelerationRate () const -{ - //float rate = 0.0f; - // - //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - // - //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - //{ - // rate = getEngineYawAccelerationRate () * efficiency; - // - // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) - // { - // //-- player ships are allowed to stop spinning - // if (isPlayerShip()) - // rate *= 0.5f; - // else - // rate = 0.0f; - // } - //} - float rate = 0.0f; - - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - rate = getEngineYawAccelerationRate () * efficiency; - else - rate = getShipDataEngine().m_engineYawAccelerationRate; - - //-- @todo: divide rate by rotational inertia - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualRollAccelerationRate () const -{ - //float rate = 0.0f; - // - //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - // - //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - //{ - // rate = getEngineRollAccelerationRate () * efficiency; - // - // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) - // { - // //-- player ships are allowed to stop spinning - // if (isPlayerShip()) - // rate *= 0.5f; - // else - // rate = 0.0f; - // } - //} - - float rate = 0.0f; - - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - rate = getEngineRollAccelerationRate () * efficiency; - else - rate = getShipDataEngine().m_engineRollAccelerationRate; - - //-- @todo: divide rate by rotational inertia - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualPitchRateMaximum () const -{ - //float rate = 0.0f; - // - //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - // - //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - //{ - // rate = getEnginePitchRateMaximum () * efficiency; - // - // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) - // { - // //-- player ships have zero max rotation rates so the ship will come to a stop - // if (isPlayerShip()) - // rate = 0.0f; - // } - //} - float rate = 0.0f; - - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - rate = getEnginePitchRateMaximum () * efficiency; - - rate *= computeSpeedRotationFactor(); - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualYawRateMaximum () const -{ - //float rate = 0.0f; - // - //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - // - //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - //{ - // rate = getEngineYawRateMaximum () * efficiency; - // - // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) - // { - // //-- player ships have zero max rotation rates so the ship will come to a stop - // if (isPlayerShip()) - // rate = 0.0f; - // } - //} - float rate = 0.0f; - - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - rate = getEngineYawRateMaximum () * efficiency; - - rate *= computeSpeedRotationFactor(); - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualRollRateMaximum () const -{ - //float rate = 0.0f; - // - //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - // - //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) - //{ - // rate = getEngineRollRateMaximum () * efficiency; - // - // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) - // { - // //-- player ships have zero max rotation rates so the ship will come to a stop - // if (isPlayerShip()) - // rate = 0.0f; - // } - //} - float rate = 0.0f; - - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - rate = getEngineRollRateMaximum () * efficiency; - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeShipActualSpeedMaximum () const -{ - float rate = 0.0f; - - if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) - { - float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); - rate = getEngineSpeedMaximum () * efficiency; - } - - if (isSlotInstalled(ShipChassisSlotType::SCST_booster) && isBoosterActive() && isComponentFunctional(ShipChassisSlotType::SCST_booster)) - rate += getBoosterSpeedMaximum () * computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_booster); - - if (hasWings() && hasCondition(TangibleObject::C_wingsOpened)) - { - ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc(getChassisType()); - if (NULL != shipChassis) - { - float const wingOpenSpeedFactor = shipChassis->getWingOpenSpeedFactor(); - rate *= wingOpenSpeedFactor; - } - } - - rate *= m_chassisSpeedMaximumModifier.get(); - - rate = std::min(512.0f, rate * m_movementPercent); - - return rate; -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualAccelerationRate () const -{ - return m_shipActualAccelerationRate.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualDecelerationRate () const -{ - return m_shipActualDecelerationRate.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualPitchAccelerationRate () const -{ - return m_shipActualPitchAccelerationRate.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualYawAccelerationRate () const -{ - return m_shipActualYawAccelerationRate.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualRollAccelerationRate () const -{ - return m_shipActualRollAccelerationRate.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualPitchRateMaximum () const -{ - return m_shipActualPitchRateMaximum.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualYawRateMaximum () const -{ - return m_shipActualYawRateMaximum.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualRollRateMaximum () const -{ - return m_shipActualRollRateMaximum.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualYprRateMaximum() const -{ - return std::max(std::max(m_shipActualPitchRateMaximum.get(), m_shipActualYawRateMaximum.get()), m_shipActualRollRateMaximum.get()); -} - -//---------------------------------------------------------------------- - -float ShipObject::getShipActualSpeedMaximum () const -{ - return m_shipActualSpeedMaximum.get(); -} - -//---------------------------------------------------------------------- - -bool ShipObject::isComponentDisabled (int chassisSlot) const -{ - return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_disabled)) != 0; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isComponentDisabledNeedsPower(int chassisSlot) const -{ - return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_disabledNeedsPower)) != 0; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isComponentLowPower (int chassisSlot) const -{ - return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_lowPower)) != 0; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isComponentActive(int chassisSlot) const -{ - return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_active)) != 0; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isComponentDemolished(int chassisSlot) const -{ - return (getComponentFlags(chassisSlot) & ShipComponentFlags::F_demolished) != 0; -} - -//---------------------------------------------------------------------- - -void ShipObject::handlePowerPulse (float timeElapsedSecs) -{ - PROFILER_AUTO_BLOCK_DEFINE("ShipObject::handlePowerPulse"); - - DEBUG_FATAL (!isAuthoritative(), ("ShipObject::handlePowerPulse called on non-auth ship object")); - - //-- handle componentized power system - - ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); - if (!shipChassis) - return; - - CreatureObject * const pilot = getPilot(); - - float powerGenerated = 0.0f; - - if (isSlotInstalled (static_cast(ShipChassisSlotType::SCST_reactor)) && isComponentFunctional(ShipChassisSlotType::SCST_reactor)) - { - powerGenerated = getReactorEnergyGenerationRate () * computeActualComponentEfficiencyGeneral (static_cast(ShipChassisSlotType::SCST_reactor)) * timeElapsedSecs; - powerGenerated += (powerGenerated * m_nebulaEffectReactor); - powerGenerated = std::max (0.0f, powerGenerated); - } - - //-- discharge the capacitor if it is disabled (because the power logic below is skipped for disabled components) - if (isSlotInstalled(ShipChassisSlotType::SCST_capacitor) && !isComponentFunctional(ShipChassisSlotType::SCST_capacitor)) - IGNORE_RETURN(setCapacitorEnergyCurrent(0.0f)); - - for (int i = static_cast(ShipChassisSlotType::SCST_first); i < static_cast(ShipChassisSlotType::SCST_num_types); ++i) - { - ShipChassisSlotType::Type const slotType = shipChassis->getSlotPowerPriority (i); - if (slotType == ShipChassisSlotType::SCST_num_types || slotType == ShipChassisSlotType::SCST_reactor) - continue; - - int const slotIndex = static_cast(slotType); - - if (!isSlotInstalled (slotIndex)) - continue; - - if (isComponentDemolished(slotIndex)) - continue; - - if (isComponentDisabled(slotIndex)) - { - if (!isComponentDisabledNeedsPower(slotIndex)) - continue; - } - - float const baseComponentEnergyRequired = getComponentEnergyMaintenanceRequirement (slotIndex) * timeElapsedSecs; - - float oo_componentEfficiencyEnergy = getComponentEfficiencyEnergy (slotIndex); - if (oo_componentEfficiencyEnergy > 0.0f) - oo_componentEfficiencyEnergy = RECIP (oo_componentEfficiencyEnergy); - - float const energyRequired = baseComponentEnergyRequired * oo_componentEfficiencyEnergy; - - //-- first consume the base energy requirement for the component - - float energyInsufficiencyPercent = 0.0f; - - //-- insufficient power - if (energyRequired > powerGenerated) - { - if(getScriptObject()) - { - ScriptParams p; - p.addParam (slotIndex); - p.addParam (energyRequired); - p.addParam (powerGenerated); - - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_POWER_INSUFFICIENT, p)); - - //-- script has for some reason removed the component, stop processing it - if (!isSlotInstalled(slotIndex)) - continue; - } - - //-- energy req cannot be zero - energyInsufficiencyPercent = 1.0f - powerGenerated / energyRequired; - IGNORE_RETURN(setComponentLowPower (slotIndex, true)); - } - //-- sufficient power - else - { - if (isComponentLowPower (slotIndex)) - { - if(getScriptObject()) - { - ScriptParams p; - p.addParam (slotIndex); - p.addParam (energyRequired); - - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_POWER_SUFFICIENT, p)); - - //-- script has for some reason removed the component, stop processing it - if (!isSlotInstalled(slotIndex)) - continue; - } - - IGNORE_RETURN(setComponentLowPower (slotIndex, false)); - } - } - - powerGenerated = std::max (0.0f, powerGenerated - energyRequired); - - //-- - if (isComponentDisabled(slotIndex)) - continue; - - float const efficiencyGeneral = computeActualComponentEfficiencyGeneral(slotIndex); - - switch (slotType) - { - //-- - //-- recharge or decay the shields - //-- - - case ShipChassisSlotType::SCST_shield_0: - { - float const hpFrontCurrent = getShieldHitpointsFrontCurrent (); - float const hpFrontMaximum = getShieldHitpointsFrontMaximum (); - float const hpBackCurrent = getShieldHitpointsBackCurrent (); - float const hpBackMaximum = getShieldHitpointsBackMaximum (); - - //-- recharge the shields - if (!isComponentLowPower(slotIndex)) - { - float shieldRechargeRateHps = getShieldRechargeRate () * efficiencyGeneral * timeElapsedSecs; - shieldRechargeRateHps += (shieldRechargeRateHps * m_nebulaEffectShields); - - if (shieldRechargeRateHps > 0.0f) - { - float const hpFrontNeeded = std::max (0.0f, std::min (hpFrontMaximum - hpFrontCurrent, shieldRechargeRateHps)); - float const hpBackNeeded = std::max (0.0f, std::min (hpBackMaximum - hpBackCurrent, shieldRechargeRateHps)); - - if (hpFrontNeeded > 0.0f || hpBackNeeded > 0.0f) - { - if (hpFrontNeeded) - IGNORE_RETURN(setShieldHitpointsFrontCurrent(hpFrontCurrent + hpFrontNeeded)); - if (hpBackNeeded) - IGNORE_RETURN(setShieldHitpointsBackCurrent(hpBackCurrent + hpBackNeeded)); - } - } - } - //-- decay the shields to some percentage - else if (energyInsufficiencyPercent > 0.0f) - { - float const shieldDecayRateHps = std::max (1.0f, (getShieldRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); - - float const minShieldsFront = (1.0f - energyInsufficiencyPercent) * getShieldHitpointsFrontMaximum(); - float const minShieldsBack = (1.0f - energyInsufficiencyPercent) * getShieldHitpointsBackMaximum(); - - if (hpFrontCurrent > minShieldsFront) - IGNORE_RETURN(setShieldHitpointsFrontCurrent(std::max(minShieldsFront, hpFrontCurrent - shieldDecayRateHps))); - if (hpBackCurrent > minShieldsBack) - IGNORE_RETURN(setShieldHitpointsBackCurrent(std::max(minShieldsFront, hpBackCurrent - shieldDecayRateHps))); - } - } - break; - - //-- - //-- recharge or decay the capacitor - //-- - - case ShipChassisSlotType::SCST_capacitor: - { - float capacitorEnergyCurrent = getCapacitorEnergyCurrent (); - float const capacitorEnergyMaximum = getCapacitorEnergyEffectiveMaximum () * getComponentEfficiencyGeneral(ShipChassisSlotType::SCST_capacitor); - - //-- the efficiency might cause the current charge to exceed the max - if (capacitorEnergyCurrent > capacitorEnergyMaximum) - { - IGNORE_RETURN(setCapacitorEnergyCurrent (capacitorEnergyMaximum)); - capacitorEnergyCurrent = getCapacitorEnergyCurrent (); - } - - //-- recharge the capacitor - if (!isComponentLowPower(slotIndex)) - { - float const rechargeRate = getCapacitorEnergyRechargeRate () * efficiencyGeneral * timeElapsedSecs; - float const capacitorEnergyRechargeNeeded = std::min (capacitorEnergyMaximum - capacitorEnergyCurrent, rechargeRate); - - if (capacitorEnergyRechargeNeeded > 0.0f) - { - IGNORE_RETURN(setCapacitorEnergyCurrent (capacitorEnergyCurrent + capacitorEnergyRechargeNeeded)); - } - } - //-- decay the capacitors to some percentage - else if (energyInsufficiencyPercent > 0.0f) - { - float const decayRate = std::max (1.0f, (getCapacitorEnergyRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); - - float const minLevel = (1.0f - energyInsufficiencyPercent) * getCapacitorEnergyEffectiveMaximum(); - - if (capacitorEnergyCurrent > minLevel) - IGNORE_RETURN(setCapacitorEnergyCurrent (std::max(minLevel, capacitorEnergyCurrent - decayRate))); - } - } - break; - - //-- - //-- recharge or decay the booster - //-- - - case ShipChassisSlotType::SCST_booster: - { - float boosterEnergyCurrent = getBoosterEnergyCurrent(); - - if (isBoosterActive()) - { - float const boosterEnergyUsed = (getBoosterEnergyConsumptionRate() * timeElapsedSecs) * oo_componentEfficiencyEnergy; - - IGNORE_RETURN(setBoosterEnergyCurrent(std::max(0.0f, boosterEnergyCurrent - boosterEnergyUsed))); - boosterEnergyCurrent = getBoosterEnergyCurrent(); - - //-- when the booster runs out of energy, kill it - if (boosterEnergyCurrent <= 0.0f) - { - IGNORE_RETURN(setComponentActive(ShipChassisSlotType::SCST_booster, false)); - if (pilot != NULL) - Chat::sendSystemMessage(*pilot, SharedStringIds::booster_energy_depleted, Unicode::emptyString); - - restartBoosterTimer(); - } - break; - } - - float const boosterEnergyMaximum = getBoosterEnergyMaximum (); - - //recharge the booster - if (!isComponentLowPower(slotIndex)) - { - float const rechargeRate = getBoosterEnergyRechargeRate () * efficiencyGeneral * timeElapsedSecs; - float const boosterEnergyRechargeNeeded = std::min (boosterEnergyMaximum - boosterEnergyCurrent, rechargeRate); - - if (boosterEnergyRechargeNeeded > 0.0f) - { - - float const boosterEnergyRequired = boosterEnergyRechargeNeeded * oo_componentEfficiencyEnergy; - - IGNORE_RETURN(setBoosterEnergyCurrent (boosterEnergyCurrent + boosterEnergyRequired)); - } - } - //-- decay the boosters to some percentage - else if (energyInsufficiencyPercent > 0.0f) - { - float const decayRate = std::max (1.0f, (getBoosterEnergyRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); - - float const minLevel = (1.0f - energyInsufficiencyPercent) * getBoosterEnergyMaximum(); - - if (boosterEnergyCurrent > minLevel) - IGNORE_RETURN(setBoosterEnergyCurrent (std::max(minLevel, boosterEnergyCurrent - decayRate))); - } - } - break; - - default: - break; - - } //lint !e788 //switch cases not used - } -} - -//---------------------------------------------------------------------- - -int ShipObject::getProjectileIndexForWeapon(int const weaponIndex) const -{ - if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) - return -1; - - ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); - - uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); - if (componentCrc == 0) - return -1; - - return ShipComponentWeaponManager::getProjectileIndex(componentCrc); -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponRange(int weaponIndex) const -{ - if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) - return 0.0f; - - ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); - - uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); - if (componentCrc == 0) - return 0.0f; - - float range = 0.0f; - - if (ShipComponentWeaponManager::isMissile(componentCrc)) - { - int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); - range = MissileManager::getInstance().getRangeByMissileType(missileTypeId); - } - else - { - range = ShipComponentWeaponManager::getRange(componentCrc); - } - - return range; -} - -//---------------------------------------------------------------------- - -float ShipObject::getWeaponProjectileSpeed(int weaponIndex) const -{ - if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) - return 0.0f; - - ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); - - uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); - if (componentCrc == 0) - return 0.0f; - - float speed = 0.0f; - - if (ShipComponentWeaponManager::isMissile(componentCrc)) - { - int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); - speed = MissileManager::getInstance().getSpeedByMissileType(missileTypeId); - } - else - { - speed = ShipComponentWeaponManager::getProjectileSpeed(componentCrc); - } - - return speed; -} -//---------------------------------------------------------------------- - -float ShipObject::computeWeaponProjectileTimeToLive(int weaponIndex) const -{ - if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) - return 0.0f; - - ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); - - uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); - if (componentCrc == 0) - return 0.0f; - - float timeToLive = 0.0f; - - if (ShipComponentWeaponManager::isMissile(componentCrc)) - { - int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); - timeToLive = MissileManager::getInstance().getMaxTimeByMissileType(missileTypeId); - } - else - { - float const range = ShipComponentWeaponManager::getRange(componentCrc); - float const projectileSpeed = ShipComponentWeaponManager::getProjectileSpeed(componentCrc); - timeToLive = (projectileSpeed <= 0.0f) ? 0.0f : range / projectileSpeed; - } - - return timeToLive; -} - -//---------------------------------------------------------------------- - -float ShipObject::computeActualComponentEfficiencyGeneral(int chassisType) const -{ - float efficiency = getComponentEfficiencyGeneral(chassisType); - float nebulaEffect = 0.0f; - - switch (chassisType) - { - case ShipChassisSlotType::SCST_engine: - nebulaEffect = m_nebulaEffectEngine; - break; - case ShipChassisSlotType::SCST_reactor: - nebulaEffect = m_nebulaEffectReactor; - break; - case ShipChassisSlotType::SCST_shield_0: - nebulaEffect = m_nebulaEffectShields; - break; - default: - break; - } - - efficiency = clamp(0.1f, efficiency + nebulaEffect, 10.0f); - return efficiency; -} - -//---------------------------------------------------------------------- - -void ShipObject::setSlotTargetable(ShipChassisSlotType::Type slot) -{ - BitArray tmp(m_targetableSlotBitfield.get()); - tmp.setBit(slot); - m_targetableSlotBitfield = tmp; -} - -//---------------------------------------------------------------------- - -void ShipObject::clearSlotTargetable(ShipChassisSlotType::Type slot) -{ - BitArray tmp(m_targetableSlotBitfield.get()); - tmp.clearBit(slot); - m_targetableSlotBitfield = tmp; -} - -//---------------------------------------------------------------------- - -bool ShipObject::getSlotTargetable(ShipChassisSlotType::Type slot) const -{ - return m_targetableSlotBitfield.get().testBit(slot); -} - -//---------------------------------------------------------------------- - -bool ShipObject::isValidTargetableSlot (ShipChassisSlotType::Type slot) const -{ - if(getSlotTargetable(slot)) - { - if(isSlotInstalled(slot)) - { - if(isComponentFunctional(slot)) - { - return true; - } - } - } - return false; -} - -//---------------------------------------------------------------------- - -void ShipObject::setPilotLookAtTargetSlot(ShipChassisSlotType::Type slot) -{ - if(isAuthoritative() && isValidTargetableSlot(slot)) - { - m_pilotLookAtTargetSlot.set(slot); - } -} - -//---------------------------------------------------------------------- - -void ShipObject::setTurretTarget(int weaponIndex, CachedNetworkId const & target) -{ - if (isAuthoritative()) - { - DEBUG_FATAL(!isTurret(weaponIndex), ("Assigning a target(%s) to a weaponIndex(%d) that is not a turret", target.getValueString().c_str(), weaponIndex)); - - if (!target.isValid()) - IGNORE_RETURN(m_turretTargets.erase(weaponIndex)); - else - m_turretTargets[weaponIndex] = target; - } -} - -//---------------------------------------------------------------------- - -CachedNetworkId const & ShipObject::getTurretTarget(int weaponIndex) const -{ - if (isAuthoritative()) - { - DEBUG_FATAL(!isTurret(weaponIndex), ("Requesting the target of an weaponIndex(%d) that is not a turret", weaponIndex)); - - std::map::const_iterator const it = m_turretTargets.find(weaponIndex); - if (it != m_turretTargets.end()) - return (*it).second; - } - return CachedNetworkId::cms_cachedInvalid; -} - -//---------------------------------------------------------------------- - -Transform const ShipObject::getTurretTransform(int weaponIndex) const -{ - int const chassisSlot = static_cast(ShipChassisSlotType::SCST_weapon_0) + weaponIndex; - uint32 const componentCrc = getComponentCrc(chassisSlot); - - if (componentCrc != 0) - { - AppearanceTemplate const * exteriorAppearanceTemplate = 0; - - PortalProperty const * const portalProperty = getPortalProperty(); - if (portalProperty) - { - char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); - if (exteriorAppearanceName) - exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); - } - else - { - Appearance const * const appearance = getAppearance(); - if (appearance) - exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); - } - - if (exteriorAppearanceTemplate) - { - ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); - if (!attachments.empty()) - { - ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *attachments.begin(); - int const turretYawHardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); - WARNING(turretYawHardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); - if (turretYawHardpointIndex != -1) - { - Hardpoint const &turretYawHardpoint = exteriorAppearanceTemplate->getHardpoint(turretYawHardpointIndex); - // we now need to find a weapon hardpoint on this attachment - SharedObjectTemplate const * const objectTemplate = safe_cast(ObjectTemplateList::fetch(templateHardpointPair.first)); - if (objectTemplate) - { - AppearanceTemplate const * const appearanceTemplate = AppearanceTemplateList::fetch(objectTemplate->getAppearanceFilename().c_str()); - if (appearanceTemplate) - { - int const turretPitchHardpointIndex = appearanceTemplate->getHardpointIndex(s_turretPitchHardpoint, true); - if (turretPitchHardpointIndex != -1) - { - Hardpoint const &turretPitchHardpoint = appearanceTemplate->getHardpoint(turretPitchHardpointIndex); - return getTransform_o2p().rotateTranslate_l2p(turretYawHardpoint.getTransform().rotateTranslate_l2p(turretPitchHardpoint.getTransform())); - } - } - } - // we couldn't find a turret pitch hardpoint, so the turret yaw hardpoint is for the object which pitches also - return getTransform_o2p().rotateTranslate_l2p(turretYawHardpoint.getTransform()); - } - } - } - } - - // we couldn't find an attachment hardpoint, so assume we fire forward from the ship center - return getTransform_o2p(); -} - -//---------------------------------------------------------------------- - -bool ShipObject::isMissile(int const weaponIndex) const -{ - bool ismissile = false; - - if(weaponIndex >= 0 && weaponIndex < ShipChassisSlotType::cms_numWeaponIndices) - { - int const chassisSlot = static_cast(ShipChassisSlotType::SCST_weapon_first) + weaponIndex; - uint32 const componentCrc = getComponentCrc(chassisSlot); - if (componentCrc != 0) - { - ismissile = ShipComponentWeaponManager::isMissile(componentCrc); - } - } - - return ismissile; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isTurret(int const weaponIndex) const -{ - DEBUG_FATAL(!ShipChassisSlotType::isWeaponIndex(weaponIndex), ("weaponIndex(%d) is out of range [0...%d]", weaponIndex, ShipChassisSlotType::cms_numWeaponIndices - 1)); - - return m_turretWeaponIndices->testBit(weaponIndex); -} - -//---------------------------------------------------------------------- - -bool ShipObject::isCountermeasure(int const weaponIndex) const -{ - ShipChassisSlotType::Type const shipChassisSlotType = static_cast(static_cast(ShipChassisSlotType::SCST_weapon_0) + weaponIndex); - if (isSlotInstalled(shipChassisSlotType)) - { - uint32 const componentCrc = getComponentCrc(shipChassisSlotType); - return ShipComponentWeaponManager::isCountermeasure(componentCrc); - } - return false; -} - -//---------------------------------------------------------------------- - -bool ShipObject::isProjectile(int const weaponIndex) const -{ - bool missile = isMissile(weaponIndex); - bool turret = isTurret(weaponIndex); - bool countermeasure = isCountermeasure(weaponIndex); - - return (!missile && !turret && !countermeasure); -} - -//---------------------------------------------------------------------- - -float ShipObject::computeChassisComponentMassCurrent() const -{ - float massCurrent = 0.0f; - - for (int chassisSlot = static_cast(ShipChassisSlotType::SCST_first); chassisSlot < static_cast(ShipChassisSlotType::SCST_num_types); ++chassisSlot) - { - if (!isSlotInstalled (chassisSlot)) - continue; - - massCurrent += getComponentMass(chassisSlot); - } - - return massCurrent; -} - -//---------------------------------------------------------------------- - -float ShipObject::getChassisComponentMassMaximum() const -{ - return m_chassisComponentMassMaximum.get(); -} - -//---------------------------------------------------------------------- - -float ShipObject::getChassisComponentMassCurrent() const -{ - return m_chassisComponentMassCurrent.get(); -} - -//---------------------------------------------------------------------- - -void ShipObject::setChassisComponentMassMaximum(float massMaximum) -{ - m_chassisComponentMassMaximum.set(massMaximum); -} - -//---------------------------------------------------------------------- - -void ShipObject::internalSetChassisComponentMassCurrent(float massCurrent) -{ - m_chassisComponentMassCurrent.set(massCurrent); -} - -// ---------------------------------------------------------------------- - -/** - * Check whether a turret can fire towards a particular location without - * exceeding its rotation limits. - */ -bool ShipObject::canTurretFireTowardsLocation_p(int weaponIndex, Vector const & targetLocation_p) const -{ - Transform turretTransform_o2p(getTurretTransform(weaponIndex)); - - uint32 const chassisCrc = getChassisType(); - float const minYaw = ShipTurretManager::getTurretMinYaw(chassisCrc, weaponIndex); - float const maxYaw = ShipTurretManager::getTurretMaxYaw(chassisCrc, weaponIndex); - float const minPitch = ShipTurretManager::getTurretMinPitch(chassisCrc, weaponIndex); - float const maxPitch = ShipTurretManager::getTurretMaxPitch(chassisCrc, weaponIndex); - - Vector const turretToTarget = turretTransform_o2p.rotateTranslate_p2l(targetLocation_p); - - float yaw=turretToTarget.theta(); - float pitch=turretToTarget.phi(); - - // if yaw and pitch are limited for this turret, check that the desired yaw/pitch is within the range - - if ((maxYaw-minYaw)+0.001 < PI_TIMES_2) - if (yaw > maxYaw || yaw < minYaw) - return false; - - if ((maxPitch-minPitch)+0.001 < PI_TIMES_2) - if (pitch > maxPitch || pitch < minPitch) - return false; - - return true; -} - -// ---------------------------------------------------------------------- - -/** - * Given a position on the ship, figure out which targettable chassis slot covers - * that position. Used to determine which component a projectile hit. - */ -int ShipObject::findTargetChassisSlotByPosition(Vector const & position_o) const -{ - DEBUG_FATAL(!isCapitalShip(),("Programmer bug: findChassisSlotByPosition() should only be called on capital ships")); - - AppearanceTemplate const * exteriorAppearanceTemplate = 0; - - PortalProperty const * const portalProperty = getPortalProperty(); - if (portalProperty) - { - char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); - if (exteriorAppearanceName) - exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); - } - else - { - Appearance const * const appearance = getAppearance(); - if (appearance) - exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); - } - NOT_NULL(exteriorAppearanceTemplate); - if (!exteriorAppearanceTemplate) //lint !e774 only always false in debug mode - return ShipChassisSlotType::SCST_invalid; - - ShipChassisSlotType::Type closestSlot = ShipChassisSlotType::SCST_invalid; - float closestDistance = 0.0f; - - for (int chassisSlotIterator = static_cast(ShipChassisSlotType::SCST_first); chassisSlotIterator != static_cast(ShipChassisSlotType::SCST_num_types); ++chassisSlotIterator) - { - ShipChassisSlotType::Type chassisSlot = static_cast(chassisSlotIterator); - uint32 const componentCrc = getComponentCrc(chassisSlot); - - //DEBUG_REPORT_LOG(componentCrc != 0 && !getSlotTargetable(chassisSlot),("Skipping slot %i because it is not targettable\n",chassisSlot)); - - if (componentCrc != 0 && getSlotTargetable(chassisSlot)) - { - float hitRange = ShipComponentAttachmentManager::getComponentHitRange(getChassisType(), componentCrc, chassisSlot); - { - // First look at regular attachments - ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); - for (ShipComponentAttachmentManager::TemplateHardpointPairVector::const_iterator i=attachments.begin(); i!=attachments.end(); ++i) - { - ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *i; - - int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); - WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); - if (hardpointIndex != -1) - { - Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); - Transform const & transform_o = hardpoint.getTransform(); - float const distanceSquared = (position_o - transform_o.getPosition_p()).magnitudeSquared(); - - if (distanceSquared < sqr(hitRange) && - ((closestSlot == ShipChassisSlotType::SCST_invalid) || (distanceSquared < closestDistance))) - { - closestSlot = chassisSlot; - closestDistance = distanceSquared; - } - } - } - } - { - // Second look at "extra" hardpoints (hardpoints that exist for the sake of targeting only - ShipComponentAttachmentManager::HardpointVector const &extraHardpoints = ShipComponentAttachmentManager::getExtraHardpointsForComponent(getChassisType(), componentCrc, chassisSlot); - for (ShipComponentAttachmentManager::HardpointVector::const_iterator i=extraHardpoints.begin(); i!=extraHardpoints.end(); ++i) - { - int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(*i, true); - WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), (*i).getString())); - if (hardpointIndex != -1) - { - Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); - Transform const & transform_o = hardpoint.getTransform(); - float const distanceSquared = (position_o - transform_o.getPosition_p()).magnitudeSquared(); - - if (distanceSquared < sqr(hitRange) && - ((closestSlot == ShipChassisSlotType::SCST_invalid) || (distanceSquared < closestDistance))) - { - closestSlot = chassisSlot; - closestDistance = distanceSquared; - } - } - } - } - } - } - return closestSlot; -} - -// ---------------------------------------------------------------------- - -void ShipObject::findTransformsForComponent(int const chassisSlot, std::vector & transforms) const -{ - transforms.clear(); - AppearanceTemplate const * const exteriorAppearanceTemplate = getExteriorAppearance(); - if (!exteriorAppearanceTemplate) - return; - uint32 const componentCrc = getComponentCrc(chassisSlot); - - { - // First look at regular attachments - ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); - for (ShipComponentAttachmentManager::TemplateHardpointPairVector::const_iterator i=attachments.begin(); i!=attachments.end(); ++i) - { - ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *i; - - int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); - WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); - if (hardpointIndex != -1) - { - Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); - Transform const & transform_o = hardpoint.getTransform(); - transforms.push_back(transform_o); - } - } - } - - { - // Second look at "extra" hardpoints (hardpoints that exist for the sake of targeting only - ShipComponentAttachmentManager::HardpointVector const &extraHardpoints = ShipComponentAttachmentManager::getExtraHardpointsForComponent(getChassisType(), componentCrc, chassisSlot); - for (ShipComponentAttachmentManager::HardpointVector::const_iterator i=extraHardpoints.begin(); i!=extraHardpoints.end(); ++i) - { - int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(*i, true); - WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), (*i).getString())); - if (hardpointIndex != -1) - { - Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); - Transform const & transform_o = hardpoint.getTransform(); - transforms.push_back(transform_o); - } - } - } -} - -// ---------------------------------------------------------------------- - -AppearanceTemplate const * ShipObject::getExteriorAppearance() const -{ - AppearanceTemplate const * exteriorAppearanceTemplate = 0; - - PortalProperty const * const portalProperty = getPortalProperty(); - if (portalProperty) - { - char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); - if (exteriorAppearanceName) - exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); - } - else - { - Appearance const * const appearance = getAppearance(); - if (appearance) - exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); - } - NOT_NULL(exteriorAppearanceTemplate); - return exteriorAppearanceTemplate; -} - -// ---------------------------------------------------------------------- - -float ShipObject::getFastestWeaponProjectileSpeed() const -{ - return m_fastestWeaponProjectileSpeed; -} - -//---------------------------------------------------------------------- - -int ShipObject::getCargoHoldContentsMaximum() const -{ - return m_cargoHoldContentsMaximum.get(); -} - -//---------------------------------------------------------------------- - -bool ShipObject::setCargoHoldContentsMaximum(int contents) -{ - if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) - { - m_cargoHoldContentsMaximum = contents; - setCargoHoldContentsCurrent(getCargoHoldContentsCurrent()); - return true; - } - - return false; -} - -//---------------------------------------------------------------------- - -int ShipObject::getCargoHoldContentsCurrent() const -{ - return m_cargoHoldContentsCurrent.get(); -} - -//---------------------------------------------------------------------- - -bool ShipObject::setCargoHoldContentsCurrent(int contents) -{ - if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) - { - int const maximum = getCargoHoldContentsMaximum(); - m_cargoHoldContentsCurrent = std::min(contents, maximum); - return true; - } - - return false; -} - -//---------------------------------------------------------------------- - -ShipObject::NetworkIdIntMap const & ShipObject::getCargoHoldContents() const -{ - return m_cargoHoldContents.getMap(); -} - -//---------------------------------------------------------------------- - -void ShipObject::setCargoHoldContents(NetworkIdIntMap const & contents) -{ - if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) - { - m_cargoHoldContents.clear(); - - NetworkIdIntMap::const_iterator const end = contents.end(); - for (NetworkIdIntMap::const_iterator it = contents.begin(); it != end; ++it) - { - m_cargoHoldContents.insert(it->first, it->second); - } - - setCargoHoldContentsCurrent(computeCargoHoldContentsCurrent()); - } -} - -//---------------------------------------------------------------------- - -void ShipObject::setCargoHoldContent(NetworkId const & resourceTypeId, int amount) -{ - if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) - { - if (amount <= 0) - { - m_cargoHoldContents.erase(resourceTypeId); - m_cargoHoldContentsResourceTypeInfo.erase(resourceTypeId); - } - else - { - ResourceTypeObject const * const resourceTypeObject = ServerUniverse::getInstance().getResourceTypeById(resourceTypeId); - if (NULL == ServerUniverse::getInstance().getResourceTypeById(resourceTypeId)) - { - WARNING(true, ("ShipObject::setCargoHoldContent invalid resource type [%s]", resourceTypeId.getValueString().c_str())); - return; - } - - bool alreadyHasThisResource = getCargoHoldContent(resourceTypeId) > 0; - - if (!alreadyHasThisResource) - { - m_cargoHoldContentsResourceTypeInfo.set( - resourceTypeId, - ResourceTypeInfoPair(Unicode::narrowToWide(resourceTypeObject->getResourceName()), resourceTypeObject->getParentClass().getResourceClassName())); - } - - m_cargoHoldContents.set(resourceTypeId, amount); - - } - - setCargoHoldContentsCurrent(computeCargoHoldContentsCurrent()); - } -} - -//---------------------------------------------------------------------- - -int ShipObject::getCargoHoldContent(NetworkId const & resourceTypeId) const -{ - if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) - { - NetworkIdIntMap::const_iterator const it = m_cargoHoldContents.find(resourceTypeId); - if (it != m_cargoHoldContents.end()) - { - return (*it).second; - } - } - - return 0; -} - -//---------------------------------------------------------------------- - -int ShipObject::computeCargoHoldContentsCurrent() const -{ - int total = 0; - NetworkIdIntMap::const_iterator const end = m_cargoHoldContents.end(); - for (NetworkIdIntMap::const_iterator it = m_cargoHoldContents.begin(); it != end; ++it) - { - total += (*it).second; - } - - return total; -} - -//====================================================================== +//====================================================================== +// +// ShipObject_Components.cpp +// copyright (c) 2004 Sony Online Entertainment +// +//====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/ShipObject_Components.h" + +#include "UnicodeUtils.h" +#include "serverGame/Chat.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/MissileManager.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/ResourceTypeObject.h" +#include "serverGame/ServerObjectTemplate.h" +#include "serverGame/ServerResourceClassObject.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/ShipComponentDataEngine.h" +#include "serverGame/ShipComponentDataManager.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptFunctionTable.h" +#include "serverScript/ScriptParameters.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/Timer.h" +#include "sharedGame/SharedStringIds.h" +#include "sharedGame/ShipChassis.h" +#include "sharedGame/ShipChassisSlot.h" +#include "sharedGame/ShipChassisSlotType.h" +#include "sharedGame/ShipComponentAttachmentManager.h" +#include "sharedGame/ShipComponentData.h" +#include "sharedGame/ShipComponentDescriptor.h" +#include "sharedGame/ShipComponentFlags.h" +#include "sharedGame/ShipComponentWeaponManager.h" +#include "sharedGame/ShipTurretManager.h" +#include "sharedLog/Log.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/Hardpoint.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/PortalProperty.h" +#include "sharedObject/PortalPropertyTemplate.h" +#include "sharedObject/VolumeContainer.h" + + +// ====================================================================== + +namespace ShipObjectNamespace +{ + ConstCharCrcString const s_turretPitchHardpoint("turretpitch1"); +} +using namespace ShipObjectNamespace; + +// ====================================================================== + +uint32 ShipObject::getChassisType () const +{ + return m_chassisType.get (); +} + +//---------------------------------------------------------------------- + +/** + * Returns [0.0, 1.0] relating to the hitpoints of the chassis and all installed components + * 1.0 == pristine, 0.0 == totally broken (though there are other rules to determine if a ship is flyable) + */ +float ShipObject::getOverallHealth() const +{ + float total = 0.0f; + int numComponents = 0; + if(getMaximumChassisHitPoints() > 0.0) + { + total += getCurrentChassisHitPoints() / getMaximumChassisHitPoints(); + ++numComponents; + } + + for(int i = ShipChassisSlotType::SCST_first; i != ShipChassisSlotType::SCST_num_types; ++i) + { + if(isSlotInstalled(i)) + { + if(getComponentHitpointsMaximum(i) > 0.0f) + { + total += getComponentHitpointsCurrent(i) / getComponentHitpointsMaximum(i); + ++numComponents; + } + } + } + + if(numComponents <= 0) + return 0.0f; + else + return clamp(0.0f, total / numComponents, 1.0f); +} + +//---------------------------------------------------------------------- + +float ShipObject::getOverallHealthWithShieldsAndArmor() const +{ + int numberObjectsToWeight = 0; + + float total = getOverallHealth(); + ++numberObjectsToWeight; + + float const shieldHitpointsFrontMaximum = getShieldHitpointsFrontMaximum(); + if (shieldHitpointsFrontMaximum != 0.0) + { + total += getShieldHitpointsFrontCurrent() / shieldHitpointsFrontMaximum; + ++numberObjectsToWeight; + } + + float const shieldHitpointsBackMaximum = getShieldHitpointsBackMaximum(); + if (shieldHitpointsBackMaximum != 0.0) + { + total += getShieldHitpointsBackCurrent() / shieldHitpointsBackMaximum; + ++numberObjectsToWeight; + } + + float const componentArmorHitpointsMaximum0 = getComponentArmorHitpointsMaximum(ShipChassisSlotType::SCST_armor_0); + if (componentArmorHitpointsMaximum0 != 0.0) + { + total += getComponentArmorHitpointsCurrent(ShipChassisSlotType::SCST_armor_0) / componentArmorHitpointsMaximum0; + ++numberObjectsToWeight; + } + + float const componentArmorHitpointsMaximum1 = getComponentArmorHitpointsMaximum(ShipChassisSlotType::SCST_armor_1); + if (componentArmorHitpointsMaximum1 != 0.0) + { + total += getComponentArmorHitpointsCurrent(ShipChassisSlotType::SCST_armor_1) / componentArmorHitpointsMaximum1; + ++numberObjectsToWeight; + } + + return clamp(0.0f, total / static_cast(numberObjectsToWeight), 1.0f); +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentArmorHitpointsMaximum (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentArmorHitpointsMaximum.find (chassisSlot); + if (it != m_componentArmorHitpointsMaximum.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentArmorHitpointsCurrent (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentArmorHitpointsCurrent.find (chassisSlot); + if (it != m_componentArmorHitpointsCurrent.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentEfficiencyGeneral (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentEfficiencyGeneral.find (chassisSlot); + if (it != m_componentEfficiencyGeneral.end ()) + return (*it).second; + return 1.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentEfficiencyEnergy (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentEfficiencyEnergy.find (chassisSlot); + if (it != m_componentEfficiencyEnergy.end ()) + return (*it).second; + return 1.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentEnergyMaintenanceRequirement (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentEnergyMaintenanceRequirement.find (chassisSlot); + if (it != m_componentEnergyMaintenanceRequirement.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentMass (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentMass.find (chassisSlot); + if (it != m_componentMass.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +uint32 ShipObject::getComponentCrc (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentCrc.find (chassisSlot); + if (it != m_componentCrc.end ()) + return (*it).second; + return 0; +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentHitpointsCurrent (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentHitpointsCurrent.find (chassisSlot); + if (it != m_componentHitpointsCurrent.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getComponentHitpointsMaximum (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentHitpointsMaximum.find (chassisSlot); + if (it != m_componentHitpointsMaximum.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +int ShipObject::getComponentFlags (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentFlags.find (chassisSlot); + if (it != m_componentFlags.end ()) + return (*it).second; + return 0; +} + +//---------------------------------------------------------------------- + +Unicode::String const &ShipObject::getComponentName(int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentNames.find (chassisSlot); + if (it != m_componentNames.end() && !(*it).second.empty()) + return (*it).second; + + return Unicode::emptyString; +} + +//---------------------------------------------------------------------- + +NetworkId const &ShipObject::getComponentCreator(int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_componentCreators.find (chassisSlot); + if (it != m_componentCreators.end()) + return (*it).second; + + return NetworkId::cms_invalid; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponDamageMaximum (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponDamageMaximum.find (chassisSlot); + if (it != m_weaponDamageMaximum.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponDamageMinimum (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponDamageMinimum.find (chassisSlot); + if (it != m_weaponDamageMinimum.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponEffectivenessShields (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponEffectivenessShields.find (chassisSlot); + if (it != m_weaponEffectivenessShields.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponEffectivenessArmor (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponEffectivenessArmor.find (chassisSlot); + if (it != m_weaponEffectivenessArmor.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponEnergyPerShot (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponEnergyPerShot.find (chassisSlot); + if (it != m_weaponEnergyPerShot.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponActualEnergyPerShot(int chassisSlot) const +{ + float const weaponEfficiencyEnergy = std::max(0.1f, getComponentEfficiencyEnergy(chassisSlot)); + return getWeaponEnergyPerShot(chassisSlot) / weaponEfficiencyEnergy; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponRefireRate (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponRefireRate.find (chassisSlot); + if (it != m_weaponRefireRate.end ()) + return (*it).second; + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponActualRefireRate (int chassisSlot) const +{ + if (!isSlotInstalled(chassisSlot)) + return 0.0f; + + float const eff = clamp(0.1f, getWeaponEfficiencyRefireRate(chassisSlot), 10.0f); + return getWeaponRefireRate(chassisSlot) / eff; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponEfficiencyRefireRate (int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponEfficiencyRefireRate.find (chassisSlot); + if (it != m_weaponEfficiencyRefireRate.end ()) + return (*it).second; + return 1.0f; +} + +//---------------------------------------------------------------------- + +int ShipObject::getWeaponAmmoCurrent(int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoCurrent.find (chassisSlot); + if (it != m_weaponAmmoCurrent.end ()) + return (*it).second; + return 0; +} + +//---------------------------------------------------------------------- + +int ShipObject::getWeaponAmmoMaximum(int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoMaximum.find (chassisSlot); + if (it != m_weaponAmmoMaximum.end ()) + return (*it).second; + return 0; +} + +//---------------------------------------------------------------------- + +uint32 ShipObject::getWeaponAmmoType(int chassisSlot) const +{ + Archive::AutoDeltaMap::const_iterator const it = m_weaponAmmoType.find (chassisSlot); + if (it != m_weaponAmmoType.end ()) + return (*it).second; + return 0; +} + +//---------------------------------------------------------------------- + +float ShipObject::getShieldHitpointsFrontCurrent () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) + return m_shieldHitpointsFrontCurrent.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getShieldHitpointsFrontMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) + return m_shieldHitpointsFrontMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getShieldHitpointsBackCurrent () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) + return m_shieldHitpointsBackCurrent.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getShieldHitpointsBackMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) + return m_shieldHitpointsBackMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getShieldRechargeRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_shield_0)) + return m_shieldRechargeRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getCapacitorEnergyCurrent () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) + return m_capacitorEnergyCurrent.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getCapacitorEnergyMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) + return m_capacitorEnergyMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getCapacitorEnergyEffectiveMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor) && isComponentFunctional(ShipChassisSlotType::SCST_capacitor)) + return m_capacitorEnergyMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getCapacitorEnergyRechargeRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_capacitor)) + return m_capacitorEnergyRechargeRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineAccelerationRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineAccelerationRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineDecelerationRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineDecelerationRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEnginePitchAccelerationRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_enginePitchAccelerationRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineYawAccelerationRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineYawAccelerationRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineRollAccelerationRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineRollAccelerationRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEnginePitchRateMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_enginePitchRateMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineYawRateMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineYawRateMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineRollRateMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineRollRateMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineSpeedMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineSpeedMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineSpeedRotationFactorMaximum() const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineSpeedRotationFactorMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineSpeedRotationFactorMinimum() const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineSpeedRotationFactorMinimum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getEngineSpeedRotationFactorOptimal() const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + return m_engineSpeedRotationFactorOptimal.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getReactorEnergyGenerationRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_reactor)) + return m_reactorEnergyGenerationRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getBoosterEnergyCurrent () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) + return m_boosterEnergyCurrent.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getBoosterEnergyMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) + return m_boosterEnergyMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getBoosterEnergyRechargeRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) + return m_boosterEnergyRechargeRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getBoosterEnergyConsumptionRate () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) + return m_boosterEnergyConsumptionRate.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getBoosterAcceleration () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) + return m_boosterAcceleration.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getBoosterSpeedMaximum () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_booster)) + return m_boosterSpeedMaximum.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +float ShipObject::getDroidInterfaceCommandSpeed () const +{ + if (isSlotInstalled (ShipChassisSlotType::SCST_droid_interface)) + return m_droidInterfaceCommandSpeed.get (); + return 0.0f; +} + +//---------------------------------------------------------------------- + +bool ShipObject::hasSlot (int chassisSlot) const +{ + ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); + return shipChassis && shipChassis->getSlot (static_cast(chassisSlot)); +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentArmorHitpointsMaximum (int chassisSlot, float componentArmorHitpointsMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentArmorHitpointsMaximum () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentArmorHitpointsMaximum () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_componentArmorHitpointsMaximum.set (chassisSlot, componentArmorHitpointsMaximum); + //-- force update of current hitpoints + IGNORE_RETURN(setComponentArmorHitpointsCurrent (chassisSlot, getComponentArmorHitpointsCurrent (chassisSlot))); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentArmorHitpointsCurrent (int chassisSlot, float componentArmorHitpointsCurrent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentArmorHitpointsCurrent () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentArmorHitpointsCurrent () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + componentArmorHitpointsCurrent = std::min (getComponentArmorHitpointsMaximum (chassisSlot), componentArmorHitpointsCurrent); + m_componentArmorHitpointsCurrent.set (chassisSlot, componentArmorHitpointsCurrent); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentEfficiencyGeneral (int chassisSlot, float componentEfficiencyGeneral) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEfficiencyGeneral () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentEfficiencyGeneral () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + componentEfficiencyGeneral = clamp (0.1f, componentEfficiencyGeneral, 10.0f); + m_componentEfficiencyGeneral.set (chassisSlot, componentEfficiencyGeneral); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentEfficiencyEnergy (int chassisSlot, float componentEfficiencyEnergy) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEfficiencyEnergy () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentEfficiencyEnergy () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + componentEfficiencyEnergy = clamp (0.1f, componentEfficiencyEnergy, 10.0f); + m_componentEfficiencyEnergy.set (chassisSlot, componentEfficiencyEnergy); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentEnergyMaintenanceRequirement (int chassisSlot, float componentEnergyMaintenanceRequirement) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentEnergyMaintenanceRequirement () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentEnergyMaintenanceRequirement () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_componentEnergyMaintenanceRequirement.set (chassisSlot, componentEnergyMaintenanceRequirement); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentMass (int chassisSlot, float componentMass) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentMass () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentMass () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_componentMass.set (chassisSlot, componentMass); + + internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); + return true; +} + +//---------------------------------------------------------------------- + +/** +* Setting a component template crc to zero removes the component +*/ + +void ShipObject::setComponentCrc (int chassisSlot, uint32 componentCrc) +{ + if (componentCrc == 0) + { + IGNORE_RETURN (m_componentArmorHitpointsMaximum.erase (chassisSlot)); + IGNORE_RETURN (m_componentArmorHitpointsCurrent.erase (chassisSlot)); + IGNORE_RETURN (m_componentEfficiencyGeneral.erase (chassisSlot)); + IGNORE_RETURN (m_componentEfficiencyEnergy.erase (chassisSlot)); + IGNORE_RETURN (m_componentEnergyMaintenanceRequirement.erase (chassisSlot)); + IGNORE_RETURN (m_componentMass.erase (chassisSlot)); + IGNORE_RETURN (m_componentCrc.erase (chassisSlot)); + IGNORE_RETURN (m_componentCrcForClient.erase (chassisSlot)); + IGNORE_RETURN (m_componentHitpointsCurrent.erase (chassisSlot)); + IGNORE_RETURN (m_componentHitpointsMaximum.erase (chassisSlot)); + IGNORE_RETURN (m_componentFlags.erase (chassisSlot)); + IGNORE_RETURN (m_componentNames.erase (chassisSlot)); + IGNORE_RETURN (m_weaponDamageMaximum.erase (chassisSlot)); + IGNORE_RETURN (m_weaponDamageMinimum.erase (chassisSlot)); + IGNORE_RETURN (m_weaponEffectivenessShields.erase (chassisSlot)); + IGNORE_RETURN (m_weaponEffectivenessArmor.erase (chassisSlot)); + IGNORE_RETURN (m_weaponEnergyPerShot.erase (chassisSlot)); + IGNORE_RETURN (m_weaponRefireRate.erase (chassisSlot)); + IGNORE_RETURN (m_componentCreators.erase (chassisSlot)); + + internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); + } + else + { + m_componentCrc.set (chassisSlot, componentCrc); + m_componentCrcForClient.set (chassisSlot, componentCrc); + + //-- all components start out at low power so script gets the first power up pulse + IGNORE_RETURN(setComponentLowPower (chassisSlot, true)); + + internalSetChassisComponentMassCurrent(computeChassisComponentMassCurrent()); + } + + if (ShipChassisSlotType::isWeaponChassisSlot(static_cast(chassisSlot))) + { + // Cache the turret positions + { + int const weaponIndex = ShipChassisSlotType::getWeaponIndex(static_cast(chassisSlot)); + + if (ShipTurretManager::isTurret(getChassisType(), weaponIndex)) + { + m_turretWeaponIndices->setBit(weaponIndex); + } + else + { + m_turretWeaponIndices->clearBit(weaponIndex); + } + } + + // Cache for the fastest projectile weapon speed + { + m_fastestWeaponProjectileSpeed = 0.0f; + + for (int weaponIndex = 0; weaponIndex < ShipChassisSlotType::cms_numWeaponIndices; ++weaponIndex) + { + if (isProjectile(weaponIndex)) + { + m_fastestWeaponProjectileSpeed = std::max(m_fastestWeaponProjectileSpeed, getWeaponProjectileSpeed(weaponIndex)); + } + } + } + } +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentHitpointsCurrent (int chassisSlot, float componentHitpointsCurrent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentHitpointsCurrent () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentHitpointsCurrent () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + float const maxHp = getComponentHitpointsMaximum(chassisSlot); + + componentHitpointsCurrent = std::min (maxHp, componentHitpointsCurrent); + m_componentHitpointsCurrent.set (chassisSlot, componentHitpointsCurrent); + + bool const isDemolished = isComponentDemolished(chassisSlot); + + if (componentHitpointsCurrent <= 0.0f && maxHp > 0.0f && !isDemolished) + IGNORE_RETURN(setComponentDemolished(chassisSlot, true)); + else if (isDemolished) + IGNORE_RETURN(setComponentDemolished(chassisSlot, false)); + + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentHitpointsMaximum (int chassisSlot, float componentHitpointsMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentHitpointsMaximum () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentHitpointsMaximum () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_componentHitpointsMaximum.set (chassisSlot, componentHitpointsMaximum); + IGNORE_RETURN(setComponentHitpointsCurrent (chassisSlot, getComponentHitpointsCurrent (chassisSlot))); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentFlags (int chassisSlot, int componentFlags) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentFlags () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentFlags () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_componentFlags.set (chassisSlot, componentFlags); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentName(int chassisSlot, Unicode::String const & componentName) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentName () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentName () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_componentNames.set (chassisSlot, componentName); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentCreator(int chassisSlot, NetworkId const & componentCreator) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentName () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentCreator () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + if (componentCreator != NetworkId::cms_invalid) + m_componentCreators.set (chassisSlot, componentCreator); + else + m_componentCreators.erase(chassisSlot); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentDisabled (int chassisSlot, bool componentDisabled) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentDisabled () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentDisabled () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + int const flags = getComponentFlags (chassisSlot); + + if (componentDisabled) + { + IGNORE_RETURN(setComponentFlags(chassisSlot, flags | static_cast(ShipComponentFlags::F_disabled))); + IGNORE_RETURN(setComponentLowPower(chassisSlot, true)); + IGNORE_RETURN(setComponentActive(chassisSlot, false)); + } + else + { + IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_disabled))); + IGNORE_RETURN(setComponentDisabledNeedsPower(chassisSlot, false)); + } + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentDisabledNeedsPower(int chassisSlot, bool componentDisabledNeedsPower) +{ + FATAL(isInitialized() && !isAuthoritative(), ("ShipObject::setComponentDisabledNeedsPower() called on non-auth object.")); + if (!isSlotInstalled(chassisSlot)) + { + WARNING(true, ("ShipObject::setComponentDisabledNeedsPower() called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + int const flags = getComponentFlags(chassisSlot); + + if (componentDisabledNeedsPower) + IGNORE_RETURN(setComponentFlags(chassisSlot, flags | static_cast(ShipComponentFlags::F_disabledNeedsPower))); + else + IGNORE_RETURN(setComponentFlags(chassisSlot, flags & ~static_cast(ShipComponentFlags::F_disabledNeedsPower))); + + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentLowPower (int chassisSlot, bool componentLowPower) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentLowPower () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentLowPower () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + int const flags = getComponentFlags (chassisSlot); + + if (componentLowPower) + IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_lowPower))); + else + IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_lowPower))); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentActive (int chassisSlot, bool componentActive) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentActive() called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentActive() called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + int const flags = getComponentFlags (chassisSlot); + + if (componentActive) + IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_active))); + else + IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_active))); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setComponentDemolished(int chassisSlot, bool const componentDemolished) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setComponentDemolished() called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setComponentDemolished() called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + int const flags = getComponentFlags (chassisSlot); + + if (componentDemolished) + IGNORE_RETURN(setComponentFlags (chassisSlot, flags | static_cast(ShipComponentFlags::F_demolished))); + else + IGNORE_RETURN(setComponentFlags (chassisSlot, flags & ~static_cast(ShipComponentFlags::F_demolished))); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponDamageMaximum (int chassisSlot, float weaponDamageMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponDamageMaximum () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponDamageMaximum () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponDamageMaximum.set (chassisSlot, weaponDamageMaximum); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponDamageMinimum (int chassisSlot, float weaponDamageMinimum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponDamageMinimum () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponDamageMinimum () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponDamageMinimum.set (chassisSlot, weaponDamageMinimum); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponEffectivenessShields (int chassisSlot, float weaponEffectivenessShields) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEffectivenessShields () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponEffectivenessShields () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponEffectivenessShields.set (chassisSlot, weaponEffectivenessShields); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponEffectivenessArmor (int chassisSlot, float weaponEffectivenessArmor) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEffectivenessArmor () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponEffectivenessArmor () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponEffectivenessArmor.set (chassisSlot, weaponEffectivenessArmor); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponEnergyPerShot (int chassisSlot, float weaponEnergyPerShot) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEnergyPerShot () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponEnergyPerShot () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponEnergyPerShot.set (chassisSlot, weaponEnergyPerShot); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponRefireRate (int chassisSlot, float weaponRefireRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponRefireRate () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponRefireRate () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponRefireRate.set (chassisSlot, weaponRefireRate); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponEfficiencyRefireRate (int chassisSlot, float weaponEfficiencyRefireRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponEfficiencyRefireRate () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponEfficiencyRefireRate () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponEfficiencyRefireRate.set (chassisSlot, weaponEfficiencyRefireRate); + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Set a weapon's refire timer to have the specified percentage of its time + * already elapsed. For example, 0.25 will prevent the weapon from firing + * again until 75% of its regular refire time has elapsed. This setting + * applies to the next shot only; future shots will use the regular refire rate. + */ +void ShipObject::setWeaponRefireTimerPercent(int weaponIndex, float refireTimerPercent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponRefireTimerPercent () called on non-auth object.")); + m_weaponRefireTimers[weaponIndex].setElapsedTime(refireTimerPercent * getWeaponActualRefireRate(static_cast(ShipChassisSlotType::SCST_weapon_first) + weaponIndex)); +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponAmmoCurrent(int chassisSlot, int weaponAmmoCurrent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponAmmoCurrent () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponAmmoCurrent.set (chassisSlot, weaponAmmoCurrent); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponAmmoMaximum(int chassisSlot, int weaponAmmoMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponAmmoMaximum () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponAmmoMaximum.set (chassisSlot, weaponAmmoMaximum); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setWeaponAmmoType(int chassisSlot, uint32 weaponAmmoType) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setWeaponProjectileSpeed () called on non-auth object.")); + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::setWeaponAmmoType () called on slot [%d] with nothing installed.", chassisSlot)); + return false; + } + + m_weaponAmmoType.set (chassisSlot, weaponAmmoType); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setShieldHitpointsFrontCurrent (float shieldHitpointsCurrent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsFrontCurrent () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) + { + WARNING (true, ("ShipObject::setShieldHitpointsFrontCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); + return false; + } + + shieldHitpointsCurrent = std::min (getShieldHitpointsFrontMaximum (), shieldHitpointsCurrent); + m_shieldHitpointsFrontCurrent.set (shieldHitpointsCurrent); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setShieldHitpointsFrontMaximum (float shieldHitpointsMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsFrontMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) + { + WARNING (true, ("ShipObject::setShieldHitpointsFrontMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); + return false; + } + + m_shieldHitpointsFrontMaximum.set (shieldHitpointsMaximum); + IGNORE_RETURN(setShieldHitpointsFrontCurrent (getShieldHitpointsFrontCurrent ())); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setShieldHitpointsBackCurrent (float shieldHitpointsCurrent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsBackCurrent () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) + { + WARNING (true, ("ShipObject::setShieldHitpointsBackCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); + return false; + } + + shieldHitpointsCurrent = std::min (getShieldHitpointsBackMaximum (), shieldHitpointsCurrent); + m_shieldHitpointsBackCurrent.set (shieldHitpointsCurrent); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setShieldHitpointsBackMaximum (float shieldHitpointsMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldHitpointsBackMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) + { + WARNING (true, ("ShipObject::setShieldHitpointsBackMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); + return false; + } + + m_shieldHitpointsBackMaximum.set (shieldHitpointsMaximum); + IGNORE_RETURN(setShieldHitpointsBackCurrent (getShieldHitpointsBackCurrent ())); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setShieldRechargeRate (float shieldRechargeRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setShieldRechargeRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_shield_0))) + { + WARNING (true, ("ShipObject::setShieldRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_shield_0))); + return false; + } + + m_shieldRechargeRate.set (shieldRechargeRate); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setCapacitorEnergyCurrent (float capacitorEnergyCurrent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyCurrent () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) + { + WARNING (true, ("ShipObject::setCapacitorEnergyCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); + return false; + } + + float const capacitorEnergyMaximum = getCapacitorEnergyEffectiveMaximum () * getComponentEfficiencyGeneral(ShipChassisSlotType::SCST_capacitor); + capacitorEnergyCurrent = std::min (capacitorEnergyMaximum, capacitorEnergyCurrent); + m_capacitorEnergyCurrent = capacitorEnergyCurrent; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setCapacitorEnergyMaximum (float capacitorEnergyMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) + { + WARNING (true, ("ShipObject::setCapacitorEnergyMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); + return false; + } + + m_capacitorEnergyMaximum = capacitorEnergyMaximum; + IGNORE_RETURN(setCapacitorEnergyCurrent (getCapacitorEnergyCurrent ())); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setCapacitorEnergyRechargeRate (float capacitorEnergyRechargeRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setCapacitorEnergyRechargeRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_capacitor))) + { + WARNING (true, ("ShipObject::setCapacitorEnergyRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_capacitor))); + return false; + } + + m_capacitorEnergyRechargeRate = capacitorEnergyRechargeRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineAccelerationRate (float engineAccelerationRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineAccelerationRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineAccelerationRate = engineAccelerationRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineDecelerationRate (float engineDecelerationRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineDecelerationRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineDecelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineDecelerationRate = engineDecelerationRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEnginePitchAccelerationRate (float enginePitchAccelerationRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEnginePitchAccelerationRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEnginePitchAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_enginePitchAccelerationRate = enginePitchAccelerationRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineYawAccelerationRate (float engineYawAccelerationRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineYawAccelerationRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineYawAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineYawAccelerationRate = engineYawAccelerationRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineRollAccelerationRate (float engineRollAccelerationRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineRollAccelerationRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineRollAccelerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineRollAccelerationRate = engineRollAccelerationRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEnginePitchRateMaximum (float enginePitchRateMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEnginePitchRateMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEnginePitchRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_enginePitchRateMaximum = enginePitchRateMaximum; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineYawRateMaximum (float engineYawRateMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineYawRateMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineYawRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineYawRateMaximum = engineYawRateMaximum; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineRollRateMaximum (float engineRollRateMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineRollRateMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineRollRateMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineRollRateMaximum = engineRollRateMaximum; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineSpeedMaximum (float engineSpeedMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineSpeedMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineSpeedMaximum = engineSpeedMaximum; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineSpeedRotationFactorMaximum(float engineSpeedRotationFactor) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineSpeedRotationFactorMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineSpeedRotationFactorMaximum = engineSpeedRotationFactor; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineSpeedRotationFactorMinimum(float engineSpeedRotationFactorMin) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorMinimum() called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineSpeedRotationFactorMinimum() called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineSpeedRotationFactorMinimum = engineSpeedRotationFactorMin; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setEngineSpeedRotationFactorOptimal(float engineSpeedRotationFactorOptimal) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setEngineSpeedRotationFactorOptimal() called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_engine))) + { + WARNING (true, ("ShipObject::setEngineSpeedRotationFactorOptimal() called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_engine))); + return false; + } + + m_engineSpeedRotationFactorOptimal = engineSpeedRotationFactorOptimal; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setReactorEnergyGenerationRate (float reactorEnergyGenerationRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setReactorEnergyGenerationRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_reactor))) + { + WARNING (true, ("ShipObject::setReactorEnergyGenerationRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_reactor))); + return false; + } + + m_reactorEnergyGenerationRate = reactorEnergyGenerationRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setBoosterEnergyCurrent (float boosterEnergyCurrent) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyCurrent () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) + { + WARNING (true, ("ShipObject::setBoosterEnergyCurrent () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); + return false; + } + + boosterEnergyCurrent = std::min (getBoosterEnergyMaximum (), boosterEnergyCurrent); + m_boosterEnergyCurrent = boosterEnergyCurrent; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setBoosterEnergyMaximum (float boosterEnergyMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) + { + WARNING (true, ("ShipObject::setBoosterEnergyMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); + return false; + } + + m_boosterEnergyMaximum = boosterEnergyMaximum; + IGNORE_RETURN(setBoosterEnergyCurrent (getBoosterEnergyCurrent ())); + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setBoosterEnergyRechargeRate (float boosterEnergyRechargeRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyRechargeRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) + { + WARNING (true, ("ShipObject::setBoosterEnergyRechargeRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); + return false; + } + + m_boosterEnergyRechargeRate = boosterEnergyRechargeRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setBoosterEnergyConsumptionRate (float boosterEnergyConsumptionRate) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterEnergyConsumptionRate () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) + { + WARNING (true, ("ShipObject::setBoosterEnergyConsumptionRate () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); + return false; + } + + m_boosterEnergyConsumptionRate = boosterEnergyConsumptionRate; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setBoosterAcceleration (float boosterAcceleration) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterAcceleration () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) + { + WARNING (true, ("ShipObject::setBoosterAcceleration () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); + return false; + } + + m_boosterAcceleration = boosterAcceleration; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setBoosterSpeedMaximum (float boosterSpeedMaximum) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setBoosterSpeedMaximum () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_booster))) + { + WARNING (true, ("ShipObject::setBoosterSpeedMaximum () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_booster))); + return false; + } + + m_boosterSpeedMaximum = boosterSpeedMaximum; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::setDroidInterfaceCommandSpeed (float droidInterfaceCommandSpeed) +{ + FATAL (isInitialized () && !isAuthoritative (), ("ShipObject::setDroidInterfaceCommandSpeed () called on non-auth object.")); + if (!isSlotInstalled (static_cast(ShipChassisSlotType::SCST_droid_interface))) + { + WARNING (true, ("ShipObject::setDroidInterfaceCommandSpeed () called on slot [%d] with nothing installed.", static_cast(ShipChassisSlotType::SCST_droid_interface))); + return false; + } + + m_droidInterfaceCommandSpeed = droidInterfaceCommandSpeed; + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::canInstallComponent (int chassisSlot, TangibleObject const & component) const +{ + ShipComponentData const * const shipComponentData = ShipComponentDataManager::create (component); + if (!shipComponentData) + { + WARNING (true, ("ShipObject::canInstallComponent failed for [%s] because a ShipComponentData could not be constructed.", component.getNetworkId ().getValueString ().c_str ())); + return false; + } + + if (chassisSlot < static_cast(ShipChassisSlotType::SCST_first) || + chassisSlot >= static_cast(ShipChassisSlotType::SCST_num_types)) + { + WARNING (true, ("ShipObject::canInstallComponent failed for [%s] because a chassisSlot was invalid.", component.getNetworkId ().getValueString ().c_str ())); + return false; + } + + ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); + if (shipChassis) + { + int effectiveCompatibilitySlot = chassisSlot; + // weapon slots beyond 7 wrap back to slot 0 for the purposes of compatibility checking on captial ships + if (isCapitalShip() && chassisSlot >= ShipChassisSlotType::SCST_num_explicit_types && chassisSlot <= ShipChassisSlotType::SCST_weapon_last) + effectiveCompatibilitySlot = ShipChassisSlotType::SCST_weapon_first+((chassisSlot-ShipChassisSlotType::SCST_weapon_first)&7); + + ShipChassisSlot const * const slot = shipChassis->getSlot (static_cast(effectiveCompatibilitySlot)); + + if (slot != NULL) + { + if (slot->canAcceptComponent (shipComponentData->getDescriptor ())) + { + //-- check for mass availability + float const massAvailable = getChassisComponentMassMaximum() - getChassisComponentMassCurrent(); + return massAvailable >= shipComponentData->m_mass; + } + } + } + + return false; +} + +//---------------------------------------------------------------------- + +/** +* This function destroys the component +*/ + +bool ShipObject::installComponent (NetworkId const & installerId, int chassisSlot, TangibleObject & component) +{ + if (!canInstallComponent (chassisSlot, component)) + { + WARNING (true, ("ShipObject::installComponent failed for [%s] because the component can't go here.", component.getNetworkId ().getValueString ().c_str ())); + return false; + } + + if (isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::installComponent failed for [%s] because the slot is occupied.", component.getNetworkId ().getValueString ().c_str ())); + return false; + } + + ShipComponentData const * const shipComponentData = ShipComponentDataManager::create (component); + if (!shipComponentData) + { + WARNING (true, ("ShipObject::installComponent failed for [%s] because a ShipComponentData could not be constructed.", component.getNetworkId ().getValueString ().c_str ())); + return false; + } + + if(getScriptObject()) + { + ScriptParams p; + p.addParam(installerId); + p.addParam(component.getNetworkId ()); + p.addParam(chassisSlot); + + if (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_INSTALLING, p) == SCRIPT_OVERRIDE) + return false; + } + + shipComponentData->writeDataToShip (chassisSlot, *this); + + LOG( + "CustomerService", + ( + "ShipComponents: %s (%s), [%s]: added to %s (%s) by %s", + Unicode::wideToNarrow(component.getObjectName()).c_str(), + component.getNetworkId().getValueString().c_str(), + component.getObjectTemplateName(), + Unicode::wideToNarrow(getObjectName()).c_str(), + getNetworkId().getValueString().c_str(), + PlayerObject::getAccountDescription(getOwnerId()).c_str())); + + IGNORE_RETURN (component.permanentlyDestroy (DeleteReasons::Consumed)); + + if(getScriptObject()) + { + ScriptParams p; + p.addParam(installerId); + p.addParam (chassisSlot); + + IGNORE_RETURN (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_INSTALLED, p)); + } + + return true; +} + +//---------------------------------------------------------------------- + +void ShipObject::purgeComponent (int chassisSlot) +{ + IGNORE_RETURN (internalUninstallComponent (NetworkId::cms_invalid, chassisSlot, NULL)); +} + +//---------------------------------------------------------------------- + +TangibleObject * ShipObject::internalUninstallComponent (NetworkId const & uninstallerId, int chassisSlot, ServerObject * containerTarget, bool allowOverload) +{ + if (!isSlotInstalled (chassisSlot)) + { + WARNING (true, ("ShipObject::internalUninstallComponent failed... no component installed in slot")); + return NULL; + } + + ShipComponentData * const shipComponentData = createShipComponentData (chassisSlot); + + if (shipComponentData == NULL) + { + WARNING (true, ("ShipObject::internalUninstallComponent failed null data")); + delete shipComponentData; + return NULL; + } + + if(getScriptObject()) + { + ScriptParams p; + p.addParam(uninstallerId); + p.addParam (chassisSlot); + p.addParam (containerTarget ? containerTarget->getNetworkId () : NetworkId::cms_invalid); + + if (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_UNINSTALLING, p) == SCRIPT_OVERRIDE) + return NULL; + } + + TangibleObject * tangible = 0; + + if (containerTarget) + { + uint32 const objectTemplateCrc = shipComponentData->getDescriptor ().getObjectTemplateCrc (); + + ServerObject * obj = 0; + if (allowOverload) + { + + VolumeContainer * volContainer = ContainerInterface::getVolumeContainer(*containerTarget); + if (volContainer == NULL) + return 0; + + int oldCapacity = volContainer->debugDoNotUseSetCapacity(-1); + + obj = ServerWorld::createNewObject(objectTemplateCrc, *containerTarget, true, true); + + volContainer->debugDoNotUseSetCapacity(oldCapacity); + volContainer->recalculateVolume(); + } + else + { + obj = safe_cast(ServerWorld::createNewObject (objectTemplateCrc, *containerTarget, true)); + } + + if (obj == NULL) + { + WARNING (true, ("ShipObject::internalUninstallComponent failed for slot [%d] because ServerWorld could not create an object for [%d], or container is full", chassisSlot, objectTemplateCrc)); + delete shipComponentData; + return NULL; + } + + tangible = obj->asTangibleObject (); + + if (tangible == NULL) + { + WARNING (true, ("ShipObject::internalUninstallComponent failed for slot [%d] because object template [%d] is not tangible", chassisSlot, objectTemplateCrc)); + delete shipComponentData; + IGNORE_RETURN (obj->permanentlyDestroy (DeleteReasons::SetupFailed)); + return NULL; + } + + shipComponentData->writeDataToComponent (*tangible); + + LOG( + "CustomerService", + ( + "ShipComponents: %s (%s), [%s]: removed from %s (%s) by %s", + Unicode::wideToNarrow(tangible->getObjectName()).c_str(), + tangible->getNetworkId().getValueString().c_str(), + tangible->getObjectTemplateName(), + Unicode::wideToNarrow(getObjectName()).c_str(), + getNetworkId().getValueString().c_str(), + PlayerObject::getAccountDescription(getOwnerId()).c_str())); + } + + switch (chassisSlot) + { + case ShipChassisSlotType::SCST_reactor: + IGNORE_RETURN(setReactorEnergyGenerationRate (0.0f)); + break; + case ShipChassisSlotType::SCST_engine: + IGNORE_RETURN(setEngineAccelerationRate (0.0f)); + IGNORE_RETURN(setEngineDecelerationRate (0.0f)); + IGNORE_RETURN(setEnginePitchAccelerationRate (0.0f)); + IGNORE_RETURN(setEngineYawAccelerationRate (0.0f)); + IGNORE_RETURN(setEngineRollAccelerationRate (0.0f)); + IGNORE_RETURN(setEnginePitchRateMaximum (0.0f)); + IGNORE_RETURN(setEngineYawRateMaximum (0.0f)); + IGNORE_RETURN(setEngineRollRateMaximum (0.0f)); + IGNORE_RETURN(setEngineSpeedMaximum (0.0f)); + break; + + case ShipChassisSlotType::SCST_capacitor: + IGNORE_RETURN(setCapacitorEnergyCurrent (0.0f)); + IGNORE_RETURN(setCapacitorEnergyMaximum (0.0f)); + IGNORE_RETURN(setCapacitorEnergyRechargeRate (0.0f)); + break; + + case ShipChassisSlotType::SCST_shield_0: + IGNORE_RETURN(setShieldHitpointsFrontCurrent (0.0f)); + IGNORE_RETURN(setShieldHitpointsFrontMaximum (0.0f)); + IGNORE_RETURN(setShieldHitpointsBackCurrent (0.0f)); + IGNORE_RETURN(setShieldHitpointsBackMaximum (0.0f)); + IGNORE_RETURN(setShieldRechargeRate (0.0f)); + break; + + case ShipChassisSlotType::SCST_booster: + IGNORE_RETURN(setBoosterEnergyCurrent (0.0f)); + IGNORE_RETURN(setBoosterEnergyMaximum (0.0f)); + IGNORE_RETURN(setBoosterEnergyRechargeRate (0.0f)); + IGNORE_RETURN(setBoosterEnergyConsumptionRate (0.0f)); + IGNORE_RETURN(setBoosterAcceleration (0.0f)); + IGNORE_RETURN(setBoosterSpeedMaximum (0.0f)); + break; + + case ShipChassisSlotType::SCST_droid_interface: + IGNORE_RETURN(setDroidInterfaceCommandSpeed (0.0f)); + break; + + case ShipChassisSlotType::SCST_cargo_hold: + { + m_cargoHoldContents.clear(); + setCargoHoldContentsCurrent(0); + setCargoHoldContentsMaximum(0); + } + break; + + default: + break; + } + + setComponentCrc (chassisSlot, 0); + + delete shipComponentData; + + if(getScriptObject()) + { + ScriptParams p; + p.addParam(uninstallerId); + p.addParam (tangible ? tangible->getNetworkId () : NetworkId::cms_invalid); + p.addParam (chassisSlot); + p.addParam (containerTarget ? containerTarget->getNetworkId () : NetworkId::cms_invalid); + + IGNORE_RETURN (getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_UNINSTALLED, p)); + } + + return tangible; +} + +//---------------------------------------------------------------------- + +TangibleObject * ShipObject::uninstallComponent (NetworkId const & uninstallerId, int chassisSlot, ServerObject & containerTarget, bool allowOverload) +{ + return internalUninstallComponent (uninstallerId, chassisSlot, &containerTarget, allowOverload); +} + +//---------------------------------------------------------------------- + +bool ShipObject::installComponentFromData(int chassisSlot, ShipComponentData const & shipComponentData) +{ + ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); + if (shipChassis == NULL) + { + WARNING (true, ("Ship [%s] chassis [%d] is invalid for installing component [%s]", + getNetworkId().getValueString().c_str(), + static_cast(getChassisType ()), + shipComponentData.getDescriptor().getName().getString())); + return false; + } + + if (isSlotInstalled (chassisSlot)) + { + WARNING (true, ("Ship [%s] chassis [%s] slot [%s] is already filled, cannot install [%s]", + getNetworkId().getValueString().c_str(), + shipChassis->getName().getString(), + ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), + shipComponentData.getDescriptor().getName().getString())); + + return false; + } + + int effectiveCompatibilitySlot = chassisSlot; + // weapon slots beyond 7 wrap back to slot 0 for the purposes of compatibility checking on captial ships + if (isCapitalShip() && chassisSlot >= ShipChassisSlotType::SCST_num_explicit_types && chassisSlot <= ShipChassisSlotType::SCST_weapon_last) + effectiveCompatibilitySlot = ShipChassisSlotType::SCST_weapon_first+((chassisSlot-ShipChassisSlotType::SCST_weapon_first)&7); + + ShipChassisSlot const * const slot = shipChassis->getSlot (static_cast(effectiveCompatibilitySlot)); + if (slot == NULL) + { + WARNING (true, ("Ship [%s] chassis [%s] does not support slot [%s] for installing component [%s]", + getNetworkId().getValueString().c_str(), + shipChassis->getName().getString(), + ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), + shipComponentData.getDescriptor().getName().getString())); + return false; + } + + if (!slot->canAcceptComponent(shipComponentData.getDescriptor())) + { + WARNING (true, ("Component [%s], compat [%s] cannot be installed in ship [%s] chassis [%s], slot [%s], compats [%s].", + shipComponentData.getDescriptor().getName().getString(), + shipComponentData.getDescriptor().getCompatibility().getString(), + getNetworkId().getValueString().c_str(), + shipChassis->getName().getString(), + ShipChassisSlotType::getNameFromType(static_cast(chassisSlot)).c_str(), + slot->getCompatibilityString().c_str())); + return false; + } + + shipComponentData.writeDataToShip (chassisSlot, *this); + + return true; +} + +//---------------------------------------------------------------------- + +bool ShipObject::pseudoInstallComponent(int chassisSlot, uint32 componentCrc) +{ + ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc (componentCrc); + if (shipComponentDescriptor == NULL) + { + WARNING (true, ("Invalid component name")); + return false; + } + + ShipComponentData * const shipComponentData = ShipComponentDataManager::create (*shipComponentDescriptor); + + if (shipComponentData == NULL) + { + WARNING(true, ("ShipObject::pseudoInstallComponent invalid descriptor")); + return false; + } + + bool const retval = installComponentFromData(chassisSlot, *shipComponentData); + + delete shipComponentData; + + return retval; +} + +//---------------------------------------------------------------------- + +ShipComponentData * ShipObject::createShipComponentData (int chassisSlot) const +{ + ShipComponentDescriptor const * shipComponentDescriptor = NULL; + + uint32 const componentCrc = getComponentCrc (chassisSlot); + if (componentCrc) + { + shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc (componentCrc); + if (shipComponentDescriptor == NULL) + { + WARNING (true, ("ShipObject::createShipComponentData failed for slot [%d] because component crc [%d] could not map to a component descriptor", chassisSlot, componentCrc)); + return NULL; + } + } + else + return NULL; + + ShipComponentData * const shipComponentData = ShipComponentDataManager::create (*shipComponentDescriptor); + if (shipComponentData == NULL) + { + WARNING (true, ("ShipObject::createShipComponentData failed for slot [%d] ship Component data could not be constructed", chassisSlot)); + delete(shipComponentData); + return NULL; + } + + if (!shipComponentData->readDataFromShip (chassisSlot, *this)) + WARNING (true, ("ShipObject::createShipComponentData failed for read data from the ship")); + + return shipComponentData; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isSlotInstalled (int chassisSlot) const +{ + return getComponentCrc (chassisSlot) != 0; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isBoosterInstalled() const +{ + return isSlotInstalled(ShipChassisSlotType::SCST_booster); +} + +//---------------------------------------------------------------------- + +bool ShipObject::isBoosterActive() const +{ + if (isBoosterInstalled()) + { + return isComponentActive(ShipChassisSlotType::SCST_booster); + } + + return false; +} + +// ---------------------------------------------------------------------- + +void ShipObject::setBoosterActive(bool const active) +{ + if (isSlotInstalled(ShipChassisSlotType::SCST_booster)) + IGNORE_RETURN(setComponentActive(ShipChassisSlotType::SCST_booster, active)); +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualAccelerationRate () const +{ + float rate = 0.0f; + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + { + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + rate = getEngineAccelerationRate () * efficiency; + } + + if (isSlotInstalled (ShipChassisSlotType::SCST_booster) && isBoosterActive () && isComponentFunctional(ShipChassisSlotType::SCST_booster)) + { + float const boosterEfficiency = computeActualComponentEfficiencyGeneral (ShipChassisSlotType::SCST_booster); + rate += getBoosterAcceleration () * boosterEfficiency; + } + + //-- @todo: divide rate by mass + + rate = rate * m_movementPercent; + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualDecelerationRate () const +{ + float rate = 0.0f; + + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + rate = getEngineDecelerationRate () * efficiency; + else + rate = getShipDataEngine().m_engineDecelerationRate; + + //-- @todo: divide rate by mass + + rate = rate * m_movementPercent; + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeSpeedRotationFactor() const +{ + //-- compute rotational factor + float const engineSpeedRotationFactorBaseMax = getEngineSpeedRotationFactorMaximum(); + float const engineSpeedRotationFactorBaseMin = getEngineSpeedRotationFactorMinimum(); + float const engineSpeedRotationFactorOptimal = getEngineSpeedRotationFactorOptimal(); + + float const speedMax = getShipActualSpeedMaximum(); + float const speedCur = getCurrentSpeed(); + float const speedPercent = (speedMax > 0.0f) ? (speedCur / speedMax) : 0.0f; + float engineSpeedRotationFactor = 1.0f; + + if (speedPercent < engineSpeedRotationFactorOptimal || engineSpeedRotationFactorOptimal >= 1.0f) + { + float const speedPercentToOptimal = speedPercent / engineSpeedRotationFactorOptimal; + engineSpeedRotationFactor = linearInterpolate(engineSpeedRotationFactorBaseMin, 1.0f, speedPercentToOptimal); + } + else + { + float const speedPercentFromOptimal = (speedPercent - engineSpeedRotationFactorOptimal) / (1.0f - engineSpeedRotationFactorOptimal); + engineSpeedRotationFactor = linearInterpolate(1.0f, engineSpeedRotationFactorBaseMax, speedPercentFromOptimal); + } + + // snap to discreet values, to avoid constant change + return floorf((engineSpeedRotationFactor * 10.f) + 0.5f) / 10.f; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualPitchAccelerationRate () const +{ + //float rate = 0.0f; + // + //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + // + //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + //{ + // rate = getEnginePitchAccelerationRate () * efficiency; + // + // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) + // { + // //-- player ships are allowed to stop spinning + // if (isPlayerShip()) + // rate *= 0.5f; + // else + // rate = 0.0f; + // } + //} + float rate = 0.0f; + + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + rate = getEnginePitchAccelerationRate () * efficiency; + else + rate = getShipDataEngine().m_enginePitchAccelerationRate; + + //-- @todo: divide rate by rotational inertia + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualYawAccelerationRate () const +{ + //float rate = 0.0f; + // + //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + // + //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + //{ + // rate = getEngineYawAccelerationRate () * efficiency; + // + // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) + // { + // //-- player ships are allowed to stop spinning + // if (isPlayerShip()) + // rate *= 0.5f; + // else + // rate = 0.0f; + // } + //} + float rate = 0.0f; + + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + rate = getEngineYawAccelerationRate () * efficiency; + else + rate = getShipDataEngine().m_engineYawAccelerationRate; + + //-- @todo: divide rate by rotational inertia + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualRollAccelerationRate () const +{ + //float rate = 0.0f; + // + //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + // + //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + //{ + // rate = getEngineRollAccelerationRate () * efficiency; + // + // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) + // { + // //-- player ships are allowed to stop spinning + // if (isPlayerShip()) + // rate *= 0.5f; + // else + // rate = 0.0f; + // } + //} + + float rate = 0.0f; + + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + rate = getEngineRollAccelerationRate () * efficiency; + else + rate = getShipDataEngine().m_engineRollAccelerationRate; + + //-- @todo: divide rate by rotational inertia + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualPitchRateMaximum () const +{ + //float rate = 0.0f; + // + //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + // + //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + //{ + // rate = getEnginePitchRateMaximum () * efficiency; + // + // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) + // { + // //-- player ships have zero max rotation rates so the ship will come to a stop + // if (isPlayerShip()) + // rate = 0.0f; + // } + //} + float rate = 0.0f; + + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + rate = getEnginePitchRateMaximum () * efficiency; + + rate *= computeSpeedRotationFactor(); + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualYawRateMaximum () const +{ + //float rate = 0.0f; + // + //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + // + //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + //{ + // rate = getEngineYawRateMaximum () * efficiency; + // + // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) + // { + // //-- player ships have zero max rotation rates so the ship will come to a stop + // if (isPlayerShip()) + // rate = 0.0f; + // } + //} + float rate = 0.0f; + + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + rate = getEngineYawRateMaximum () * efficiency; + + rate *= computeSpeedRotationFactor(); + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualRollRateMaximum () const +{ + //float rate = 0.0f; + // + //float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + // + //if (isSlotInstalled (ShipChassisSlotType::SCST_engine)) + //{ + // rate = getEngineRollRateMaximum () * efficiency; + // + // if (isComponentDisabled(ShipChassisSlotType::SCST_engine)) + // { + // //-- player ships have zero max rotation rates so the ship will come to a stop + // if (isPlayerShip()) + // rate = 0.0f; + // } + //} + float rate = 0.0f; + + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + rate = getEngineRollRateMaximum () * efficiency; + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeShipActualSpeedMaximum () const +{ + float rate = 0.0f; + + if (isSlotInstalled (ShipChassisSlotType::SCST_engine) && isComponentFunctional(ShipChassisSlotType::SCST_engine)) + { + float const efficiency = computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_engine); + rate = getEngineSpeedMaximum () * efficiency; + } + + if (isSlotInstalled(ShipChassisSlotType::SCST_booster) && isBoosterActive() && isComponentFunctional(ShipChassisSlotType::SCST_booster)) + rate += getBoosterSpeedMaximum () * computeActualComponentEfficiencyGeneral(ShipChassisSlotType::SCST_booster); + + if (hasWings() && hasCondition(TangibleObject::C_wingsOpened)) + { + ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc(getChassisType()); + if (NULL != shipChassis) + { + float const wingOpenSpeedFactor = shipChassis->getWingOpenSpeedFactor(); + rate *= wingOpenSpeedFactor; + } + } + + rate *= m_chassisSpeedMaximumModifier.get(); + + rate = std::min(512.0f, rate * m_movementPercent); + + return rate; +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualAccelerationRate () const +{ + return m_shipActualAccelerationRate.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualDecelerationRate () const +{ + return m_shipActualDecelerationRate.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualPitchAccelerationRate () const +{ + return m_shipActualPitchAccelerationRate.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualYawAccelerationRate () const +{ + return m_shipActualYawAccelerationRate.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualRollAccelerationRate () const +{ + return m_shipActualRollAccelerationRate.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualPitchRateMaximum () const +{ + return m_shipActualPitchRateMaximum.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualYawRateMaximum () const +{ + return m_shipActualYawRateMaximum.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualRollRateMaximum () const +{ + return m_shipActualRollRateMaximum.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualYprRateMaximum() const +{ + return std::max(std::max(m_shipActualPitchRateMaximum.get(), m_shipActualYawRateMaximum.get()), m_shipActualRollRateMaximum.get()); +} + +//---------------------------------------------------------------------- + +float ShipObject::getShipActualSpeedMaximum () const +{ + return m_shipActualSpeedMaximum.get(); +} + +//---------------------------------------------------------------------- + +bool ShipObject::isComponentDisabled (int chassisSlot) const +{ + return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_disabled)) != 0; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isComponentDisabledNeedsPower(int chassisSlot) const +{ + return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_disabledNeedsPower)) != 0; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isComponentLowPower (int chassisSlot) const +{ + return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_lowPower)) != 0; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isComponentActive(int chassisSlot) const +{ + return (getComponentFlags (chassisSlot) & static_cast(ShipComponentFlags::F_active)) != 0; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isComponentDemolished(int chassisSlot) const +{ + return (getComponentFlags(chassisSlot) & ShipComponentFlags::F_demolished) != 0; +} + +//---------------------------------------------------------------------- + +void ShipObject::handlePowerPulse (float timeElapsedSecs) +{ + PROFILER_AUTO_BLOCK_DEFINE("ShipObject::handlePowerPulse"); + + DEBUG_FATAL (!isAuthoritative(), ("ShipObject::handlePowerPulse called on non-auth ship object")); + + //-- handle componentized power system + + ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (getChassisType ()); + if (!shipChassis) + return; + + CreatureObject * const pilot = getPilot(); + + float powerGenerated = 0.0f; + + if (isSlotInstalled (static_cast(ShipChassisSlotType::SCST_reactor)) && isComponentFunctional(ShipChassisSlotType::SCST_reactor)) + { + powerGenerated = getReactorEnergyGenerationRate () * computeActualComponentEfficiencyGeneral (static_cast(ShipChassisSlotType::SCST_reactor)) * timeElapsedSecs; + powerGenerated += (powerGenerated * m_nebulaEffectReactor); + powerGenerated = std::max (0.0f, powerGenerated); + } + + //-- discharge the capacitor if it is disabled (because the power logic below is skipped for disabled components) + if (isSlotInstalled(ShipChassisSlotType::SCST_capacitor) && !isComponentFunctional(ShipChassisSlotType::SCST_capacitor)) + IGNORE_RETURN(setCapacitorEnergyCurrent(0.0f)); + + for (int i = static_cast(ShipChassisSlotType::SCST_first); i < static_cast(ShipChassisSlotType::SCST_num_types); ++i) + { + ShipChassisSlotType::Type const slotType = shipChassis->getSlotPowerPriority (i); + if (slotType == ShipChassisSlotType::SCST_num_types || slotType == ShipChassisSlotType::SCST_reactor) + continue; + + int const slotIndex = static_cast(slotType); + + if (!isSlotInstalled (slotIndex)) + continue; + + if (isComponentDemolished(slotIndex)) + continue; + + if (isComponentDisabled(slotIndex)) + { + if (!isComponentDisabledNeedsPower(slotIndex)) + continue; + } + + float const baseComponentEnergyRequired = getComponentEnergyMaintenanceRequirement (slotIndex) * timeElapsedSecs; + + float oo_componentEfficiencyEnergy = getComponentEfficiencyEnergy (slotIndex); + if (oo_componentEfficiencyEnergy > 0.0f) + oo_componentEfficiencyEnergy = RECIP (oo_componentEfficiencyEnergy); + + float const energyRequired = baseComponentEnergyRequired * oo_componentEfficiencyEnergy; + + //-- first consume the base energy requirement for the component + + float energyInsufficiencyPercent = 0.0f; + + //-- insufficient power + if (energyRequired > powerGenerated) + { + if(getScriptObject()) + { + ScriptParams p; + p.addParam (slotIndex); + p.addParam (energyRequired); + p.addParam (powerGenerated); + + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_POWER_INSUFFICIENT, p)); + + //-- script has for some reason removed the component, stop processing it + if (!isSlotInstalled(slotIndex)) + continue; + } + + //-- energy req cannot be zero + energyInsufficiencyPercent = 1.0f - powerGenerated / energyRequired; + IGNORE_RETURN(setComponentLowPower (slotIndex, true)); + } + //-- sufficient power + else + { + if (isComponentLowPower (slotIndex)) + { + if(getScriptObject()) + { + ScriptParams p; + p.addParam (slotIndex); + p.addParam (energyRequired); + + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SHIP_COMPONENT_POWER_SUFFICIENT, p)); + + //-- script has for some reason removed the component, stop processing it + if (!isSlotInstalled(slotIndex)) + continue; + } + + IGNORE_RETURN(setComponentLowPower (slotIndex, false)); + } + } + + powerGenerated = std::max (0.0f, powerGenerated - energyRequired); + + //-- + if (isComponentDisabled(slotIndex)) + continue; + + float const efficiencyGeneral = computeActualComponentEfficiencyGeneral(slotIndex); + + switch (slotType) + { + //-- + //-- recharge or decay the shields + //-- + + case ShipChassisSlotType::SCST_shield_0: + { + float const hpFrontCurrent = getShieldHitpointsFrontCurrent (); + float const hpFrontMaximum = getShieldHitpointsFrontMaximum (); + float const hpBackCurrent = getShieldHitpointsBackCurrent (); + float const hpBackMaximum = getShieldHitpointsBackMaximum (); + + //-- recharge the shields + if (!isComponentLowPower(slotIndex)) + { + float shieldRechargeRateHps = getShieldRechargeRate () * efficiencyGeneral * timeElapsedSecs; + shieldRechargeRateHps += (shieldRechargeRateHps * m_nebulaEffectShields); + + if (shieldRechargeRateHps > 0.0f) + { + float const hpFrontNeeded = std::max (0.0f, std::min (hpFrontMaximum - hpFrontCurrent, shieldRechargeRateHps)); + float const hpBackNeeded = std::max (0.0f, std::min (hpBackMaximum - hpBackCurrent, shieldRechargeRateHps)); + + if (hpFrontNeeded > 0.0f || hpBackNeeded > 0.0f) + { + if (hpFrontNeeded) + IGNORE_RETURN(setShieldHitpointsFrontCurrent(hpFrontCurrent + hpFrontNeeded)); + if (hpBackNeeded) + IGNORE_RETURN(setShieldHitpointsBackCurrent(hpBackCurrent + hpBackNeeded)); + } + } + } + //-- decay the shields to some percentage + else if (energyInsufficiencyPercent > 0.0f) + { + float const shieldDecayRateHps = std::max (1.0f, (getShieldRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); + + float const minShieldsFront = (1.0f - energyInsufficiencyPercent) * getShieldHitpointsFrontMaximum(); + float const minShieldsBack = (1.0f - energyInsufficiencyPercent) * getShieldHitpointsBackMaximum(); + + if (hpFrontCurrent > minShieldsFront) + IGNORE_RETURN(setShieldHitpointsFrontCurrent(std::max(minShieldsFront, hpFrontCurrent - shieldDecayRateHps))); + if (hpBackCurrent > minShieldsBack) + IGNORE_RETURN(setShieldHitpointsBackCurrent(std::max(minShieldsFront, hpBackCurrent - shieldDecayRateHps))); + } + } + break; + + //-- + //-- recharge or decay the capacitor + //-- + + case ShipChassisSlotType::SCST_capacitor: + { + float capacitorEnergyCurrent = getCapacitorEnergyCurrent (); + float const capacitorEnergyMaximum = getCapacitorEnergyEffectiveMaximum () * getComponentEfficiencyGeneral(ShipChassisSlotType::SCST_capacitor); + + //-- the efficiency might cause the current charge to exceed the max + if (capacitorEnergyCurrent > capacitorEnergyMaximum) + { + IGNORE_RETURN(setCapacitorEnergyCurrent (capacitorEnergyMaximum)); + capacitorEnergyCurrent = getCapacitorEnergyCurrent (); + } + + //-- recharge the capacitor + if (!isComponentLowPower(slotIndex)) + { + float const rechargeRate = getCapacitorEnergyRechargeRate () * efficiencyGeneral * timeElapsedSecs; + float const capacitorEnergyRechargeNeeded = std::min (capacitorEnergyMaximum - capacitorEnergyCurrent, rechargeRate); + + if (capacitorEnergyRechargeNeeded > 0.0f) + { + IGNORE_RETURN(setCapacitorEnergyCurrent (capacitorEnergyCurrent + capacitorEnergyRechargeNeeded)); + } + } + //-- decay the capacitors to some percentage + else if (energyInsufficiencyPercent > 0.0f) + { + float const decayRate = std::max (1.0f, (getCapacitorEnergyRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); + + float const minLevel = (1.0f - energyInsufficiencyPercent) * getCapacitorEnergyEffectiveMaximum(); + + if (capacitorEnergyCurrent > minLevel) + IGNORE_RETURN(setCapacitorEnergyCurrent (std::max(minLevel, capacitorEnergyCurrent - decayRate))); + } + } + break; + + //-- + //-- recharge or decay the booster + //-- + + case ShipChassisSlotType::SCST_booster: + { + float boosterEnergyCurrent = getBoosterEnergyCurrent(); + + if (isBoosterActive()) + { + float const boosterEnergyUsed = (getBoosterEnergyConsumptionRate() * timeElapsedSecs) * oo_componentEfficiencyEnergy; + + IGNORE_RETURN(setBoosterEnergyCurrent(std::max(0.0f, boosterEnergyCurrent - boosterEnergyUsed))); + boosterEnergyCurrent = getBoosterEnergyCurrent(); + + //-- when the booster runs out of energy, kill it + if (boosterEnergyCurrent <= 0.0f) + { + IGNORE_RETURN(setComponentActive(ShipChassisSlotType::SCST_booster, false)); + if (pilot != NULL) + Chat::sendSystemMessage(*pilot, SharedStringIds::booster_energy_depleted, Unicode::emptyString); + + restartBoosterTimer(); + } + break; + } + + float const boosterEnergyMaximum = getBoosterEnergyMaximum (); + + //recharge the booster + if (!isComponentLowPower(slotIndex)) + { + float const rechargeRate = getBoosterEnergyRechargeRate () * efficiencyGeneral * timeElapsedSecs; + float const boosterEnergyRechargeNeeded = std::min (boosterEnergyMaximum - boosterEnergyCurrent, rechargeRate); + + if (boosterEnergyRechargeNeeded > 0.0f) + { + + float const boosterEnergyRequired = boosterEnergyRechargeNeeded * oo_componentEfficiencyEnergy; + + IGNORE_RETURN(setBoosterEnergyCurrent (boosterEnergyCurrent + boosterEnergyRequired)); + } + } + //-- decay the boosters to some percentage + else if (energyInsufficiencyPercent > 0.0f) + { + float const decayRate = std::max (1.0f, (getBoosterEnergyRechargeRate () * timeElapsedSecs) * energyInsufficiencyPercent); + + float const minLevel = (1.0f - energyInsufficiencyPercent) * getBoosterEnergyMaximum(); + + if (boosterEnergyCurrent > minLevel) + IGNORE_RETURN(setBoosterEnergyCurrent (std::max(minLevel, boosterEnergyCurrent - decayRate))); + } + } + break; + + default: + break; + + } //lint !e788 //switch cases not used + } +} + +//---------------------------------------------------------------------- + +int ShipObject::getProjectileIndexForWeapon(int const weaponIndex) const +{ + if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) + return -1; + + ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); + + uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); + if (componentCrc == 0) + return -1; + + return ShipComponentWeaponManager::getProjectileIndex(componentCrc); +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponRange(int weaponIndex) const +{ + if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) + return 0.0f; + + ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); + + uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); + if (componentCrc == 0) + return 0.0f; + + float range = 0.0f; + + if (ShipComponentWeaponManager::isMissile(componentCrc)) + { + int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); + range = MissileManager::getInstance().getRangeByMissileType(missileTypeId); + } + else + { + range = ShipComponentWeaponManager::getRange(componentCrc); + } + + return range; +} + +//---------------------------------------------------------------------- + +float ShipObject::getWeaponProjectileSpeed(int weaponIndex) const +{ + if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) + return 0.0f; + + ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); + + uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); + if (componentCrc == 0) + return 0.0f; + + float speed = 0.0f; + + if (ShipComponentWeaponManager::isMissile(componentCrc)) + { + int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); + speed = MissileManager::getInstance().getSpeedByMissileType(missileTypeId); + } + else + { + speed = ShipComponentWeaponManager::getProjectileSpeed(componentCrc); + } + + return speed; +} +//---------------------------------------------------------------------- + +float ShipObject::computeWeaponProjectileTimeToLive(int weaponIndex) const +{ + if (weaponIndex < 0 || weaponIndex >= ShipChassisSlotType::cms_numWeaponIndices) + return 0.0f; + + ShipChassisSlotType::Type const weaponChassisSlotType = static_cast(weaponIndex + static_cast(ShipChassisSlotType::SCST_weapon_0)); + + uint32 const componentCrc = getComponentCrc(weaponChassisSlotType); + if (componentCrc == 0) + return 0.0f; + + float timeToLive = 0.0f; + + if (ShipComponentWeaponManager::isMissile(componentCrc)) + { + int const missileTypeId = static_cast(getWeaponAmmoType(weaponChassisSlotType)); + timeToLive = MissileManager::getInstance().getMaxTimeByMissileType(missileTypeId); + } + else + { + float const range = ShipComponentWeaponManager::getRange(componentCrc); + float const projectileSpeed = ShipComponentWeaponManager::getProjectileSpeed(componentCrc); + timeToLive = (projectileSpeed <= 0.0f) ? 0.0f : range / projectileSpeed; + } + + return timeToLive; +} + +//---------------------------------------------------------------------- + +float ShipObject::computeActualComponentEfficiencyGeneral(int chassisType) const +{ + float efficiency = getComponentEfficiencyGeneral(chassisType); + float nebulaEffect = 0.0f; + + switch (chassisType) + { + case ShipChassisSlotType::SCST_engine: + nebulaEffect = m_nebulaEffectEngine; + break; + case ShipChassisSlotType::SCST_reactor: + nebulaEffect = m_nebulaEffectReactor; + break; + case ShipChassisSlotType::SCST_shield_0: + nebulaEffect = m_nebulaEffectShields; + break; + default: + break; + } + + efficiency = clamp(0.1f, efficiency + nebulaEffect, 10.0f); + return efficiency; +} + +//---------------------------------------------------------------------- + +void ShipObject::setSlotTargetable(ShipChassisSlotType::Type slot) +{ + BitArray tmp(m_targetableSlotBitfield.get()); + tmp.setBit(slot); + m_targetableSlotBitfield = tmp; +} + +//---------------------------------------------------------------------- + +void ShipObject::clearSlotTargetable(ShipChassisSlotType::Type slot) +{ + BitArray tmp(m_targetableSlotBitfield.get()); + tmp.clearBit(slot); + m_targetableSlotBitfield = tmp; +} + +//---------------------------------------------------------------------- + +bool ShipObject::getSlotTargetable(ShipChassisSlotType::Type slot) const +{ + return m_targetableSlotBitfield.get().testBit(slot); +} + +//---------------------------------------------------------------------- + +bool ShipObject::isValidTargetableSlot (ShipChassisSlotType::Type slot) const +{ + if(getSlotTargetable(slot)) + { + if(isSlotInstalled(slot)) + { + if(isComponentFunctional(slot)) + { + return true; + } + } + } + return false; +} + +//---------------------------------------------------------------------- + +void ShipObject::setPilotLookAtTargetSlot(ShipChassisSlotType::Type slot) +{ + if(isAuthoritative() && isValidTargetableSlot(slot)) + { + m_pilotLookAtTargetSlot.set(slot); + } +} + +//---------------------------------------------------------------------- + +void ShipObject::setTurretTarget(int weaponIndex, CachedNetworkId const & target) +{ + if (isAuthoritative()) + { + DEBUG_FATAL(!isTurret(weaponIndex), ("Assigning a target(%s) to a weaponIndex(%d) that is not a turret", target.getValueString().c_str(), weaponIndex)); + + if (!target.isValid()) + IGNORE_RETURN(m_turretTargets.erase(weaponIndex)); + else + m_turretTargets[weaponIndex] = target; + } +} + +//---------------------------------------------------------------------- + +CachedNetworkId const & ShipObject::getTurretTarget(int weaponIndex) const +{ + if (isAuthoritative()) + { + DEBUG_FATAL(!isTurret(weaponIndex), ("Requesting the target of an weaponIndex(%d) that is not a turret", weaponIndex)); + + std::map::const_iterator const it = m_turretTargets.find(weaponIndex); + if (it != m_turretTargets.end()) + return (*it).second; + } + return CachedNetworkId::cms_cachedInvalid; +} + +//---------------------------------------------------------------------- + +Transform const ShipObject::getTurretTransform(int weaponIndex) const +{ + int const chassisSlot = static_cast(ShipChassisSlotType::SCST_weapon_0) + weaponIndex; + uint32 const componentCrc = getComponentCrc(chassisSlot); + + if (componentCrc != 0) + { + AppearanceTemplate const * exteriorAppearanceTemplate = 0; + + PortalProperty const * const portalProperty = getPortalProperty(); + if (portalProperty) + { + char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); + if (exteriorAppearanceName) + exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); + } + else + { + Appearance const * const appearance = getAppearance(); + if (appearance) + exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); + } + + if (exteriorAppearanceTemplate) + { + ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); + if (!attachments.empty()) + { + ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *attachments.begin(); + int const turretYawHardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); + WARNING(turretYawHardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); + if (turretYawHardpointIndex != -1) + { + Hardpoint const &turretYawHardpoint = exteriorAppearanceTemplate->getHardpoint(turretYawHardpointIndex); + // we now need to find a weapon hardpoint on this attachment + SharedObjectTemplate const * const objectTemplate = safe_cast(ObjectTemplateList::fetch(templateHardpointPair.first)); + if (objectTemplate) + { + AppearanceTemplate const * const appearanceTemplate = AppearanceTemplateList::fetch(objectTemplate->getAppearanceFilename().c_str()); + if (appearanceTemplate) + { + int const turretPitchHardpointIndex = appearanceTemplate->getHardpointIndex(s_turretPitchHardpoint, true); + if (turretPitchHardpointIndex != -1) + { + Hardpoint const &turretPitchHardpoint = appearanceTemplate->getHardpoint(turretPitchHardpointIndex); + return getTransform_o2p().rotateTranslate_l2p(turretYawHardpoint.getTransform().rotateTranslate_l2p(turretPitchHardpoint.getTransform())); + } + } + } + // we couldn't find a turret pitch hardpoint, so the turret yaw hardpoint is for the object which pitches also + return getTransform_o2p().rotateTranslate_l2p(turretYawHardpoint.getTransform()); + } + } + } + } + + // we couldn't find an attachment hardpoint, so assume we fire forward from the ship center + return getTransform_o2p(); +} + +//---------------------------------------------------------------------- + +bool ShipObject::isMissile(int const weaponIndex) const +{ + bool ismissile = false; + + if(weaponIndex >= 0 && weaponIndex < ShipChassisSlotType::cms_numWeaponIndices) + { + int const chassisSlot = static_cast(ShipChassisSlotType::SCST_weapon_first) + weaponIndex; + uint32 const componentCrc = getComponentCrc(chassisSlot); + if (componentCrc != 0) + { + ismissile = ShipComponentWeaponManager::isMissile(componentCrc); + } + } + + return ismissile; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isTurret(int const weaponIndex) const +{ + DEBUG_FATAL(!ShipChassisSlotType::isWeaponIndex(weaponIndex), ("weaponIndex(%d) is out of range [0...%d]", weaponIndex, ShipChassisSlotType::cms_numWeaponIndices - 1)); + + return m_turretWeaponIndices->testBit(weaponIndex); +} + +//---------------------------------------------------------------------- + +bool ShipObject::isCountermeasure(int const weaponIndex) const +{ + ShipChassisSlotType::Type const shipChassisSlotType = static_cast(static_cast(ShipChassisSlotType::SCST_weapon_0) + weaponIndex); + if (isSlotInstalled(shipChassisSlotType)) + { + uint32 const componentCrc = getComponentCrc(shipChassisSlotType); + return ShipComponentWeaponManager::isCountermeasure(componentCrc); + } + return false; +} + +//---------------------------------------------------------------------- + +bool ShipObject::isProjectile(int const weaponIndex) const +{ + bool missile = isMissile(weaponIndex); + bool turret = isTurret(weaponIndex); + bool countermeasure = isCountermeasure(weaponIndex); + + return (!missile && !turret && !countermeasure); +} + +//---------------------------------------------------------------------- + +float ShipObject::computeChassisComponentMassCurrent() const +{ + float massCurrent = 0.0f; + + for (int chassisSlot = static_cast(ShipChassisSlotType::SCST_first); chassisSlot < static_cast(ShipChassisSlotType::SCST_num_types); ++chassisSlot) + { + if (!isSlotInstalled (chassisSlot)) + continue; + + massCurrent += getComponentMass(chassisSlot); + } + + return massCurrent; +} + +//---------------------------------------------------------------------- + +float ShipObject::getChassisComponentMassMaximum() const +{ + return m_chassisComponentMassMaximum.get(); +} + +//---------------------------------------------------------------------- + +float ShipObject::getChassisComponentMassCurrent() const +{ + return m_chassisComponentMassCurrent.get(); +} + +//---------------------------------------------------------------------- + +void ShipObject::setChassisComponentMassMaximum(float massMaximum) +{ + m_chassisComponentMassMaximum.set(massMaximum); +} + +//---------------------------------------------------------------------- + +void ShipObject::internalSetChassisComponentMassCurrent(float massCurrent) +{ + m_chassisComponentMassCurrent.set(massCurrent); +} + +// ---------------------------------------------------------------------- + +/** + * Check whether a turret can fire towards a particular location without + * exceeding its rotation limits. + */ +bool ShipObject::canTurretFireTowardsLocation_p(int weaponIndex, Vector const & targetLocation_p) const +{ + Transform turretTransform_o2p(getTurretTransform(weaponIndex)); + + uint32 const chassisCrc = getChassisType(); + float const minYaw = ShipTurretManager::getTurretMinYaw(chassisCrc, weaponIndex); + float const maxYaw = ShipTurretManager::getTurretMaxYaw(chassisCrc, weaponIndex); + float const minPitch = ShipTurretManager::getTurretMinPitch(chassisCrc, weaponIndex); + float const maxPitch = ShipTurretManager::getTurretMaxPitch(chassisCrc, weaponIndex); + + Vector const turretToTarget = turretTransform_o2p.rotateTranslate_p2l(targetLocation_p); + + float yaw=turretToTarget.theta(); + float pitch=turretToTarget.phi(); + + // if yaw and pitch are limited for this turret, check that the desired yaw/pitch is within the range + + if ((maxYaw-minYaw)+0.001 < PI_TIMES_2) + if (yaw > maxYaw || yaw < minYaw) + return false; + + if ((maxPitch-minPitch)+0.001 < PI_TIMES_2) + if (pitch > maxPitch || pitch < minPitch) + return false; + + return true; +} + +// ---------------------------------------------------------------------- + +/** + * Given a position on the ship, figure out which targettable chassis slot covers + * that position. Used to determine which component a projectile hit. + */ +int ShipObject::findTargetChassisSlotByPosition(Vector const & position_o) const +{ + DEBUG_FATAL(!isCapitalShip(),("Programmer bug: findChassisSlotByPosition() should only be called on capital ships")); + + AppearanceTemplate const * exteriorAppearanceTemplate = 0; + + PortalProperty const * const portalProperty = getPortalProperty(); + if (portalProperty) + { + char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); + if (exteriorAppearanceName) + exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); + } + else + { + Appearance const * const appearance = getAppearance(); + if (appearance) + exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); + } + NOT_NULL(exteriorAppearanceTemplate); + if (!exteriorAppearanceTemplate) //lint !e774 only always false in debug mode + return ShipChassisSlotType::SCST_invalid; + + ShipChassisSlotType::Type closestSlot = ShipChassisSlotType::SCST_invalid; + float closestDistance = 0.0f; + + for (int chassisSlotIterator = static_cast(ShipChassisSlotType::SCST_first); chassisSlotIterator != static_cast(ShipChassisSlotType::SCST_num_types); ++chassisSlotIterator) + { + ShipChassisSlotType::Type chassisSlot = static_cast(chassisSlotIterator); + uint32 const componentCrc = getComponentCrc(chassisSlot); + + //DEBUG_REPORT_LOG(componentCrc != 0 && !getSlotTargetable(chassisSlot),("Skipping slot %i because it is not targettable\n",chassisSlot)); + + if (componentCrc != 0 && getSlotTargetable(chassisSlot)) + { + float hitRange = ShipComponentAttachmentManager::getComponentHitRange(getChassisType(), componentCrc, chassisSlot); + { + // First look at regular attachments + ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); + for (ShipComponentAttachmentManager::TemplateHardpointPairVector::const_iterator i=attachments.begin(); i!=attachments.end(); ++i) + { + ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *i; + + int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); + WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); + if (hardpointIndex != -1) + { + Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); + Transform const & transform_o = hardpoint.getTransform(); + float const distanceSquared = (position_o - transform_o.getPosition_p()).magnitudeSquared(); + + if (distanceSquared < sqr(hitRange) && + ((closestSlot == ShipChassisSlotType::SCST_invalid) || (distanceSquared < closestDistance))) + { + closestSlot = chassisSlot; + closestDistance = distanceSquared; + } + } + } + } + { + // Second look at "extra" hardpoints (hardpoints that exist for the sake of targeting only + ShipComponentAttachmentManager::HardpointVector const &extraHardpoints = ShipComponentAttachmentManager::getExtraHardpointsForComponent(getChassisType(), componentCrc, chassisSlot); + for (ShipComponentAttachmentManager::HardpointVector::const_iterator i=extraHardpoints.begin(); i!=extraHardpoints.end(); ++i) + { + int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(*i, true); + WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), (*i).getString())); + if (hardpointIndex != -1) + { + Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); + Transform const & transform_o = hardpoint.getTransform(); + float const distanceSquared = (position_o - transform_o.getPosition_p()).magnitudeSquared(); + + if (distanceSquared < sqr(hitRange) && + ((closestSlot == ShipChassisSlotType::SCST_invalid) || (distanceSquared < closestDistance))) + { + closestSlot = chassisSlot; + closestDistance = distanceSquared; + } + } + } + } + } + } + return closestSlot; +} + +// ---------------------------------------------------------------------- + +void ShipObject::findTransformsForComponent(int const chassisSlot, std::vector & transforms) const +{ + transforms.clear(); + AppearanceTemplate const * const exteriorAppearanceTemplate = getExteriorAppearance(); + if (!exteriorAppearanceTemplate) + return; + uint32 const componentCrc = getComponentCrc(chassisSlot); + + { + // First look at regular attachments + ShipComponentAttachmentManager::TemplateHardpointPairVector const &attachments = ShipComponentAttachmentManager::getAttachmentsForShip(getChassisType(), componentCrc, chassisSlot); + for (ShipComponentAttachmentManager::TemplateHardpointPairVector::const_iterator i=attachments.begin(); i!=attachments.end(); ++i) + { + ShipComponentAttachmentManager::TemplateHardpointPair const &templateHardpointPair = *i; + + int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(templateHardpointPair.second, true); + WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), templateHardpointPair.second.getString())); + if (hardpointIndex != -1) + { + Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); + Transform const & transform_o = hardpoint.getTransform(); + transforms.push_back(transform_o); + } + } + } + + { + // Second look at "extra" hardpoints (hardpoints that exist for the sake of targeting only + ShipComponentAttachmentManager::HardpointVector const &extraHardpoints = ShipComponentAttachmentManager::getExtraHardpointsForComponent(getChassisType(), componentCrc, chassisSlot); + for (ShipComponentAttachmentManager::HardpointVector::const_iterator i=extraHardpoints.begin(); i!=extraHardpoints.end(); ++i) + { + int const hardpointIndex = exteriorAppearanceTemplate->getHardpointIndex(*i, true); + WARNING(hardpointIndex == -1, ("Ship %s references hardpoint '%s' which could not be found.", getDebugInformation().c_str(), (*i).getString())); + if (hardpointIndex != -1) + { + Hardpoint const & hardpoint = exteriorAppearanceTemplate->getHardpoint(hardpointIndex); + Transform const & transform_o = hardpoint.getTransform(); + transforms.push_back(transform_o); + } + } + } +} + +// ---------------------------------------------------------------------- + +AppearanceTemplate const * ShipObject::getExteriorAppearance() const +{ + AppearanceTemplate const * exteriorAppearanceTemplate = 0; + + PortalProperty const * const portalProperty = getPortalProperty(); + if (portalProperty) + { + char const * const exteriorAppearanceName = portalProperty->getPortalPropertyTemplate().getExteriorAppearanceName(); + if (exteriorAppearanceName) + exteriorAppearanceTemplate = AppearanceTemplateList::fetch(exteriorAppearanceName); + } + else + { + Appearance const * const appearance = getAppearance(); + if (appearance) + exteriorAppearanceTemplate = appearance->getAppearanceTemplate(); + } + NOT_NULL(exteriorAppearanceTemplate); + return exteriorAppearanceTemplate; +} + +// ---------------------------------------------------------------------- + +float ShipObject::getFastestWeaponProjectileSpeed() const +{ + return m_fastestWeaponProjectileSpeed; +} + +//---------------------------------------------------------------------- + +int ShipObject::getCargoHoldContentsMaximum() const +{ + return m_cargoHoldContentsMaximum.get(); +} + +//---------------------------------------------------------------------- + +bool ShipObject::setCargoHoldContentsMaximum(int contents) +{ + if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) + { + m_cargoHoldContentsMaximum = contents; + setCargoHoldContentsCurrent(getCargoHoldContentsCurrent()); + return true; + } + + return false; +} + +//---------------------------------------------------------------------- + +int ShipObject::getCargoHoldContentsCurrent() const +{ + return m_cargoHoldContentsCurrent.get(); +} + +//---------------------------------------------------------------------- + +bool ShipObject::setCargoHoldContentsCurrent(int contents) +{ + if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) + { + int const maximum = getCargoHoldContentsMaximum(); + m_cargoHoldContentsCurrent = std::min(contents, maximum); + return true; + } + + return false; +} + +//---------------------------------------------------------------------- + +ShipObject::NetworkIdIntMap const & ShipObject::getCargoHoldContents() const +{ + return m_cargoHoldContents.getMap(); +} + +//---------------------------------------------------------------------- + +void ShipObject::setCargoHoldContents(NetworkIdIntMap const & contents) +{ + if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) + { + m_cargoHoldContents.clear(); + + NetworkIdIntMap::const_iterator const end = contents.end(); + for (NetworkIdIntMap::const_iterator it = contents.begin(); it != end; ++it) + { + m_cargoHoldContents.insert(it->first, it->second); + } + + setCargoHoldContentsCurrent(computeCargoHoldContentsCurrent()); + } +} + +//---------------------------------------------------------------------- + +void ShipObject::setCargoHoldContent(NetworkId const & resourceTypeId, int amount) +{ + if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) + { + if (amount <= 0) + { + m_cargoHoldContents.erase(resourceTypeId); + m_cargoHoldContentsResourceTypeInfo.erase(resourceTypeId); + } + else + { + ResourceTypeObject const * const resourceTypeObject = ServerUniverse::getInstance().getResourceTypeById(resourceTypeId); + if (NULL == ServerUniverse::getInstance().getResourceTypeById(resourceTypeId)) + { + WARNING(true, ("ShipObject::setCargoHoldContent invalid resource type [%s]", resourceTypeId.getValueString().c_str())); + return; + } + + bool alreadyHasThisResource = getCargoHoldContent(resourceTypeId) > 0; + + if (!alreadyHasThisResource) + { + m_cargoHoldContentsResourceTypeInfo.set( + resourceTypeId, + ResourceTypeInfoPair(Unicode::narrowToWide(resourceTypeObject->getResourceName()), resourceTypeObject->getParentClass().getResourceClassName())); + } + + m_cargoHoldContents.set(resourceTypeId, amount); + + } + + setCargoHoldContentsCurrent(computeCargoHoldContentsCurrent()); + } +} + +//---------------------------------------------------------------------- + +int ShipObject::getCargoHoldContent(NetworkId const & resourceTypeId) const +{ + if (isSlotInstalled(static_cast(ShipChassisSlotType::SCST_cargo_hold))) + { + NetworkIdIntMap::const_iterator const it = m_cargoHoldContents.find(resourceTypeId); + if (it != m_cargoHoldContents.end()) + { + return (*it).second; + } + } + + return 0; +} + +//---------------------------------------------------------------------- + +int ShipObject::computeCargoHoldContentsCurrent() const +{ + int total = 0; + NetworkIdIntMap::const_iterator const end = m_cargoHoldContents.end(); + for (NetworkIdIntMap::const_iterator it = m_cargoHoldContents.begin(); it != end; ++it) + { + total += (*it).second; + } + + return total; +} + +//====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/object/TangibleObject.cpp b/src/engine/server/library/serverGame/src/shared/object/TangibleObject.cpp index 255c14378..6d58c476f 100644 --- a/src/engine/server/library/serverGame/src/shared/object/TangibleObject.cpp +++ b/src/engine/server/library/serverGame/src/shared/object/TangibleObject.cpp @@ -1,6411 +1,6411 @@ -// ====================================================================== -// -// TangibleObject.cpp -// Copyright 2001, 2002 Sony Online Entertainment Inc. -// All Rights Reserved. -// -// ====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/TangibleObject.h" - -#include "SwgGameServer/CombatEngine.h" -#include "SwgGameServer/ConfigCombatEngine.h" -#include "serverGame/AiCombatPulseQueue.h" -#include "serverGame/AiCreatureController.h" -#include "serverGame/Chat.h" -#include "serverGame/CityInfo.h" -#include "serverGame/CityInterface.h" -#include "serverGame/Client.h" -#include "serverGame/CombatTracker.h" -#include "serverGame/CommandQueue.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/DraftSchematicObject.h" -#include "serverGame/GameServer.h" -#include "serverGame/GroupObject.h" -#include "serverGame/ManufactureSchematicObject.h" -#include "serverGame/MessageToQueue.h" -#include "serverGame/NameManager.h" -#include "serverGame/NetworkTriggerVolume.h" -#include "serverGame/NpcConversation.h" -#include "serverGame/ObjectTracker.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PlanetObject.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/Pvp.h" -#include "serverGame/RegionMaster.h" -#include "serverGame/RegionPvp.h" -#include "serverGame/ResourceContainerObject.h" -#include "serverGame/ResourceTypeObject.h" -#include "serverGame/ServerCollisionProperty.h" -#include "serverGame/ServerLotManagerNotification.h" -#include "serverGame/ServerMessageForwarding.h" -#include "serverGame/ServerResourceClassObject.h" -#include "serverGame/ServerSynchronizedUi.h" -#include "serverGame/ServerTangibleObjectTemplate.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/ShipComponentDataManager.h" -#include "serverGame/ShipObject.h" -#include "serverGame/TangibleController.h" -#include "serverNetworkMessages/MessageQueueCommandQueueEnqueueFwd.h" -#include "serverNetworkMessages/MessageQueueCommandQueueForceExecuteCommandFwd.h" -#include "serverNetworkMessages/MessageToPayload.h" -#include "serverNetworkMessages/UpdateObjectOnPlanetMessage.h" -#include "serverPathfinding/ServerPathfindingNotification.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptDictionary.h" -#include "serverScript/ScriptFunctionTable.h" -#include "serverScript/ScriptParameters.h" -#include "serverUtility/ServerClock.h" -#include "sharedDebug/Profiler.h" -#include "sharedFile/FileNameUtils.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/DynamicVariable.h" -#include "sharedFoundation/DynamicVariableList.h" -#include "sharedFoundation/GameControllerMessage.h" -#include "sharedFoundation/Os.h" -#include "sharedGame/Command.h" -#include "sharedGame/CraftingData.h" -#include "sharedGame/GameObjectTypes.h" -#include "sharedGame/LfgCharacterData.h" -#include "sharedGame/PvpData.h" -#include "sharedGame/SharedObjectAttributes.h" -#include "sharedGame/SharedObjectTemplate.h" -#include "sharedGame/SharedStringIds.h" -#include "sharedGame/SharedTangibleObjectTemplate.h" -#include "sharedGame/ShipComponentData.h" -#include "sharedLog/Log.h" -#include "sharedMath/PackedArgb.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/IncubatorCommitMessage.h" -#include "sharedNetworkMessages/MessageQueueCommandQueueRemove.h" -#include "sharedNetworkMessages/MessageQueueCraftIngredients.h" -#include "sharedNetworkMessages/MessageQueueGenericValueType.h" -#include "sharedNetworkMessages/MessageQueueNetworkId.h" -#include "sharedNetworkMessages/MessageQueueOpponentInfo.h" -#include "sharedNetworkMessages/MessageQueueShowFlyText.h" -#include "sharedNetworkMessages/MessageQueueShowCombatText.h" -#include "sharedNetworkMessages/MessageQueueStartNpcConversation.h" -#include "sharedNetworkMessages/MessageQueueStopNpcConversation.h" -#include "sharedNetworkMessages/ObjectChannelMessages.h" -#include "sharedNetworkMessages/UpdatePvpStatusMessage.h" -#include "sharedObject/AlterResult.h" -#include "sharedObject/AppearanceTemplateList.h" -#include "sharedObject/ContainedByProperty.h" -#include "sharedObject/Container.h" -#include "sharedObject/CustomizationData.h" -#include "sharedObject/CustomizationDataProperty.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedObject/SlotIdManager.h" -#include "sharedObject/SlottedContainer.h" -#include "sharedObject/SlottedContainmentProperty.h" -#include "sharedObject/StructureFootprint.h" -#include "sharedObject/VolumeContainer.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" - -#ifdef _DEBUG -#include "serverGame/ConsoleManager.h" -#endif - -#include -#include -#include - -#pragma warning(disable:4355) - - -namespace TangibleObjectNamespace -{ - int const s_minCombatDuration = 4; - const int NUM_DAMAGE_TYPES = 9; - - const int s_ignoreDamageTypes = - static_cast(ServerArmorTemplate::DT_environmental_heat) | - static_cast(ServerArmorTemplate::DT_environmental_cold) | - static_cast(ServerArmorTemplate::DT_environmental_acid) | - static_cast(ServerArmorTemplate::DT_environmental_electrical); - - bool isEmpty(const ServerObject& obj) - { - const Container* container = obj.getContainerProperty(); - if (container) - { - return (container->getNumberOfItems() == 0); - } - return true; - } - - std::string const s_attributeBonusNames[] = - { - "health", - "health_regen", - "action", - "action_regen", - "mind", - "mind_regen" - }; - - const char * const s_accessListScriptVar = "tangible_object.accessList"; - const char * const s_guildAccessListScriptVar = "tangible_object.guildAccessList"; - - void getCategorizedSkillModBonuses(TangibleObject const & to, std::string const & objvarName, std::map & skillModBonuses); - int getCategorizedSkillModBonus(TangibleObject const & to, std::string const & objvarName, std::string const & skillMod); -} - -//---------------------------------------------------------------------- - -void TangibleObjectNamespace::getCategorizedSkillModBonuses(TangibleObject const & to, std::string const & objvarName, std::map & skillModBonuses) -{ - DynamicVariableList::NestedList children(to.getObjVars(), objvarName); - for (DynamicVariableList::NestedList::const_iterator iterChildren = children.begin(); iterChildren != children.end(); ++iterChildren) - { - DynamicVariable::DynamicVariableType const type = iterChildren.getType(); - if (type == DynamicVariable::INT) - { - int bonus = 0; - iterChildren.getValue(bonus); - - std::string const childName = iterChildren.getName(); - std::map::iterator iterFind = skillModBonuses.find(childName); - if (iterFind != skillModBonuses.end()) - iterFind->second += bonus; - else - IGNORE_RETURN(skillModBonuses.insert(std::make_pair(childName, bonus))); - } - else if (type == DynamicVariable::LIST) - { - std::string const childFullName = objvarName + '.' + iterChildren.getName(); - getCategorizedSkillModBonuses(to, childFullName, skillModBonuses); - } - } -} - -//---------------------------------------------------------------------- - -int TangibleObjectNamespace::getCategorizedSkillModBonus(TangibleObject const & to, std::string const & objvarName, std::string const & skillMod) -{ - int totalBonus = 0; - DynamicVariableList::NestedList children(to.getObjVars(), objvarName); - for (DynamicVariableList::NestedList::const_iterator iterChildren = children.begin(); iterChildren != children.end(); ++iterChildren) - { - DynamicVariable::DynamicVariableType const type = iterChildren.getType(); - if (type == DynamicVariable::INT) - { - if (iterChildren.getName() == skillMod) - { - int bonus = 0; - iterChildren.getValue(bonus); - - totalBonus += bonus; - } - } - else if (type == DynamicVariable::LIST) - { - std::string const childFullName = objvarName + '.' + iterChildren.getName(); - totalBonus += getCategorizedSkillModBonus(to, childFullName, skillMod); - } - } - - return totalBonus; -} - -//---------------------------------------------------------------------- - -using namespace TangibleObjectNamespace; - -//======================================================================= -// class TangibleObject::CraftingToolSyncUi - -class TangibleObject::CraftingToolSyncUi : public ServerSynchronizedUi -{ -public: - CraftingToolSyncUi(TangibleObject & owner) : - ServerSynchronizedUi(owner), - m_prototype(), - m_manfSchematic(), - m_manfSchematicObserver() - { - addToUiPackage(m_prototype); - addToUiPackage(m_manfSchematic); - } - - virtual ~CraftingToolSyncUi() - { - if (!isOwnerChangingAuthority()) - { - if (m_manfSchematic.get() != CachedNetworkId::cms_cachedInvalid) - { - safe_cast(getOwner())->clearCraftingManufactureSchematic(); - } - if (m_prototype.get() != CachedNetworkId::cms_cachedInvalid) - { - safe_cast(getOwner())->clearCraftingPrototype(); - } - } - } - - const CachedNetworkId & getPrototype(void) const - { - return m_prototype.get(); - } - - void setPrototype(const CachedNetworkId & prototype) - { - m_prototype = prototype; - } - - const CachedNetworkId & getManfSchematic(void) const - { - return m_manfSchematic.get(); - } - - void setManfSchematic(const CachedNetworkId & manfSchematic, const CachedNetworkId & observer, bool deleteSchematic) - { - m_manfSchematic = manfSchematic; - m_manfSchematicObserver = observer; - } - -private: - - CraftingToolSyncUi(const CraftingToolSyncUi & src); - CraftingToolSyncUi & operator =(const CraftingToolSyncUi & src); - -private: - - Archive::AutoDeltaVariable m_prototype; - Archive::AutoDeltaVariable m_manfSchematic; - - CachedNetworkId m_manfSchematicObserver; -}; - -//======================================================================= - -static const ConstCharCrcLowerString COMMAND_GROUP_COMBAT("combat"); - -// armor objvars - also defined in armor.scriptlib -static const std::string OBJVAR_ARMOR_BASE = "armor"; -static const std::string OBJVAR_ARMOR_ENCUMBRANCE = "armorencumbrance"; -static const std::string OBJVAR_ENCUMBRANCE_SPLIT = "encumbranceSplit"; -static const std::string OBJVAR_ARMOR_LEVEL = "armorLevel"; - -// objvar to flag the object as a shield -static const std::string OBJVAR_ARMOR_SHIELD = "armor.isShield"; - -// armor datatable strings -static const std::string DATATABLE_ARMOR = "datatables/crafting/armor.iff"; -static const std::string DATATABLE_FINAL_ROW = "final"; -static const std::string DATATABLE_TYPE_COL = "type"; -static const std::string DATATABLE_MIN_ENCUMBRANCE_COL = "min_encumbrance"; -static const std::string DATATABLE_MAX_ENCUMBRANCE_COL = "max_encumbrance"; - -// bio-link objvars -static const std::string OBJVAR_BIO_LINK = "biolink"; -static const std::string OBJVAR_BIO_LINK_ID = "biolink.id"; -// This id is used for a bio-linked item that is linked to no one. -// It is safe as long as no player has id 1 (which should be a good assumption). -// Note this value is reflected in library.utils.scriptlib. -static const NetworkId PENDING_BIO_LINK_NETWORK_ID(static_cast(1)); - -// template for crafting components container -const static ConstCharCrcLowerString CRAFTING_COMPONENTS_CONTAINER = "object/tangible/crafting/crafting_components_container.iff"; - -// slots for a crafting tool -const static ConstCharCrcLowerString INGREDIENT_HOPPER_SLOT_NAME = "ingredient_hopper"; -const static ConstCharCrcLowerString MANF_OUTPUT_SLOT_NAME = "anythingnomod2"; -const static ConstCharCrcLowerString TEMP_PROTOTYPE_SLOT_NAME = "anythingnomod1"; -const static ConstCharCrcLowerString TEMP_SCHEMATIC_SLOT_NAME = "test_manf_schematic"; - -// objvars for crafting -const static std::string OBJVAR_CRAFTING_TOOL = "crafting.tool"; -const static std::string OBJVAR_CRAFTING_STATION = "crafting.station"; -const static std::string OBJVAR_CRAFTING_CRAFTER = "crafting.crafter"; -const static std::string OBJVAR_CRAFTING_COMPONENTS = "crafting.components"; -const static std::string OBJVAR_CRAFTING_SCHEMATIC = "crafting.source_schematic"; -const static std::string OBJVAR_CRAFTING_TYPE = "crafting.type"; -const static std::string OBJVAR_CRAFTING_REPAIR_TYPE = "crafting.repair_type"; -const static std::string OBJVAR_CRAFTING_PROTOTYPE_TIME = "crafting.prototypeTime"; -const static std::string OBJVAR_CRAFTING_PROTOTYPE_START_TIME = "crafting.prototypeStartTime"; -const static std::string OBJVAR_CRAFTING_PROTOTYPE_OBJECT = "crafting.prototypeObject"; -const static std::string OBJVAR_CRAFTING_PROTOTYPE_CRAFTER = "crafting.prototypeCrafter"; -const static std::string OBJVAR_CREATOR_ID = "crafting.creator.id"; -const static std::string OBJVAR_CREATOR_XP = "crafting.creator.xp"; -const static std::string OBJVAR_CREATOR_XP_TYPE = "crafting.creator.xpType"; -const static std::string OBJVAR_REPAIR_TOOL = "crafting.repair"; -const static std::string OBJVAR_CRAFTING_STATIONMOD = "crafting.stationMod"; -const static std::string OBJVAR_SKILLMOD_BONUS = "skillmod.bonus"; -const static std::string OBJVAR_CATEGORIZED_SKILLMOD_BONUS = "categorizedSkillmod.bonus"; -const static std::string OBJVAR_SKILLMOD_SOCKETS = "skillmod.sockets"; -const static std::string OBJVAR_ATTRIBUTE_BONUS = "attribute.bonus"; - -const std::string OBJVAR_COMPONENT_DATA("crafting_components"); - -// battlefield objvars -const static std::string OBJVAR_BATTLEFIELD_PARTICIPANTS = "battleDudes"; - -// no trade -static const std::string NOMOVE_SCRIPT = "item.special.nomove"; - -static const std::string OBJVAR_DECLINE_DUEL = "decline_duel"; - -const SharedObjectTemplate * TangibleObject::m_defaultSharedTemplate = NULL; - - -//----------------------------------------------------------------------- -TangibleObject::TangibleObject(const ServerTangibleObjectTemplate* newTemplate) : - ServerObject(newTemplate), - m_combatData(NULL), - m_pvpType(), - m_pvpMercenaryType(PvpType_Neutral), - m_pvpFutureType(-1), - m_pvpFaction(), - m_pvpMercenaryFaction(PvpData::getNeutralFactionId()), - m_pvpRegionCrc(), - m_pvpEnemies(), - m_damageTaken(0), - m_maxHitPoints(newTemplate->getMaxHitPoints()), - m_ownerId(NetworkId(static_cast(0))), - m_customAppearance(), - m_appearanceData(), - m_locationTargets(), - m_components(), - m_visible(true), - m_hideFromClient(false), - m_count(newTemplate->getCount()), - m_condition(newTemplate->getCondition()), - m_creatorId(NetworkId::cms_invalid), - m_sourceDraftSchematic(0), - m_hateList(), - m_hateOverTime(), - m_inCombat(false), - m_combatStartTime(0), - m_attackableOverride(false), - m_passiveReveal(), - m_passiveRevealPlayerCharacter(), - m_mapColorOverride(0), - m_accessList(), - m_guildAccessList(), - m_effectsMap(), - m_npcConversation(NULL), - m_conversations() -{ - WARNING_STRICT_FATAL(!getSharedTemplate(), ("Tried to create a TANGIBLE %s object without a shared template!\n", newTemplate->DataResource::getName())); - - m_hateList.addServerNpAutoDeltaVariables(m_serverPackage_np); - m_hateList.setOwner(this); - - m_maxHitPoints.setSourceObject(this); - m_ownerId.setSourceObject(this); - m_customAppearance.setSourceObject(this); - m_appearanceData.setSourceObject(this); - m_pvpType.setSourceObject(this); - m_pvpMercenaryType.setSourceObject(this); - m_pvpFaction.setSourceObject(this); - m_pvpMercenaryFaction.setSourceObject(this); - m_pvpRegionCrc.setSourceObject(this); - m_pvpEnemies.setSourceObject(this); - m_visible.setSourceObject(this); - m_hideFromClient.setSourceObject(this); - m_condition.setSourceObject(this); - m_inCombat.setSourceObject(this); - m_attackableOverride.setSourceObject(this); - m_passiveRevealPlayerCharacter.setSourceObject(this); - - // set to not disabled, and set invulnerable and wantSawAttack from template - int condition = m_condition.get(); - condition &= ~( ServerTangibleObjectTemplate::C_disabled - | ServerTangibleObjectTemplate::C_invulnerable - | ServerTangibleObjectTemplate::C_wantSawAttackTrigger); - if (newTemplate->getInvulnerable()) - condition |= ServerTangibleObjectTemplate::C_invulnerable; - if (newTemplate->getWantSawAttackTriggers()) - condition |= ServerTangibleObjectTemplate::C_wantSawAttackTrigger; - m_condition = condition; - - // attach trigger volumes to this object - size_t i; - size_t count = newTemplate->getTriggerVolumesCount(); - for (i = 0; i < count; ++i) - { - const TriggerVolumeData & trigger = newTemplate->getTriggerVolumes(static_cast(i)); - createTriggerVolume(trigger.getRadius(), trigger.getName(), true); //@todo : add "promiscuous param to template entry - } - - //-- initialize CustomizationDataProperty if any customization variables are declared - // for the SharedTangibleObjectTemplate. - const SharedTangibleObjectTemplate *const sharedObjectTemplate = safe_cast(getSharedTemplate()); - if (sharedObjectTemplate) - { - //-- create CustomizationDataProperty if appropriate - sharedObjectTemplate->createCustomizationDataPropertyAsNeeded(*this); - - //-- if a CustomizationDataProperty was created, attach a modification listener. - // check if the property exists - CustomizationDataProperty *cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); - - if (cdProperty) - { - // retrieve the CustomizationData instance associated with the property - CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); - NOT_NULL(customizationData); - - // attach modification callback - customizationData->registerModificationListener(customizationDataModificationCallback, this); - - // release local reference - customizationData->release(); - } - - if(ConfigServerGame::getCreateAppearances()) - { - const std::string &appearanceString = sharedObjectTemplate->getAppearanceFilename(); - if (appearanceString.size() != 0 && strstr (appearanceString.c_str (), ".apt") != 0) - { - Appearance * newAppearance = AppearanceTemplateList::createAppearance(appearanceString.c_str()); - - if(newAppearance != NULL) - { - setAppearance(newAppearance); - } - } - } - } - - // If the object is a path node, attach the pathfinding notification - - if (isWaypoint()) - { - addNotification( ServerPathfindingNotification::getInstance() ); - } - - // attach the collision property - - ServerCollisionProperty* collision = new ServerCollisionProperty(*this,getSharedTemplate()); - - addProperty(*collision); - - addMembersToPackages(); - - ObjectTracker::addTangible(); - - if(getGameObjectType() == SharedObjectTemplate::GOT_loadbeacon) - { - ServerWorld::addLoadBeacon(this); - } - - //-- add the lot manager notification - { - SharedTangibleObjectTemplate const * const sharedTangibleObjectTemplate = dynamic_cast (getSharedTemplate ()); - if (sharedTangibleObjectTemplate) - { - StructureFootprint const * const structureFootprint = sharedTangibleObjectTemplate->getStructureFootprint (); - if (structureFootprint) - addNotification (ServerLotManagerNotification::getInstance ()); - } - else - DEBUG_WARNING (true, ("TangibleObject::TangibleObject - [%s] does not have a shared tangible object template", getObjectTemplate ()->getName ())); - } -} - -//----------------------------------------------------------------------- - -TangibleObject::~TangibleObject() -{ - //-- This must be the first line in the destructor to invalidate any watchers watching this object - nullWatchers(); - - if (getSynchronizedUi() != NULL) - { - CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync != NULL) - { - if (isAuthoritative() && isCraftingTool()) - { - clearCraftingPrototype(); - clearCraftingManufactureSchematic(); - } - else - { - if (!isAuthoritative()) - { - WARNING(true, ("Tangible object %s is not authoritative " - "but has a SynchronizedUi", - getNetworkId().getValueString().c_str())); - } - if (!isCraftingTool()) - { - WARNING(true, ("Tangible object %s is not a crafting tool " - "but has a CraftingToolSyncUi", - getNetworkId().getValueString().c_str())); - } - sync->setPrototype(CachedNetworkId::cms_cachedInvalid); - sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, - CachedNetworkId::cms_cachedInvalid, true); - } - } - } - - if(getGameObjectType() == SharedObjectTemplate::GOT_loadbeacon) - { - ServerWorld::removeLoadBeacon(this); - } - - CombatTracker::removeDefender(this); - - if (m_combatData != NULL) - { - if (isAuthoritative()) - { - if (!getCombatData()->defenseData.damage.empty()) - { - WARNING(true, ("\tobject still has a non-empty damage list")); - - // look up the call stack information - const int callStackOffset = 4; - const int maxStackDepth = 64; - const int callStackSize = callStackOffset + maxStackDepth; - uint32 callStack[callStackOffset + maxStackDepth]; - DebugHelp::getCallStack(callStack, callStackOffset + maxStackDepth); - - // look up the caller's file and line - if (callStack[callStackOffset]) - { - char lib[4 * 1024] = { '\0' }; - char file[4 * 1024] = { '\0' }; - int line = 0; - REPORT_LOG(true, ("\tCall stack:")); - for (int i = callStackOffset; i < callStackSize; ++i) - { - if (callStack[i]) - { - if (DebugHelp::lookupAddress(callStack[i], lib, file, sizeof(file), line)) - REPORT_LOG(true, ("\t%s(%d) : caller %d\n", file, line, i-callStackOffset)); - else - REPORT_LOG(true, ("\tunknown(0x%08X) : caller %d\n", static_cast(callStack[i]), i-callStackOffset)); - } - } - } - } - } - - delete m_combatData; - m_combatData = NULL; - - if (!isPlayerControlled()) - ObjectTracker::removeCombatAI(); - } - - if (m_npcConversation != NULL) - { - delete m_npcConversation; - m_npcConversation = NULL; - } - - ObjectTracker::removeTangible(); -} // TangibleObject::~TangibleObject - -//----------------------------------------------------------------------- - -/** - * Initializes a newly created object. - */ -void TangibleObject::initializeFirstTimeObject() -{ - DEBUG_FATAL(!isAuthoritative(), ("Trying to initialize non auth object %s", getNetworkId().getValueString().c_str())); - - // set up armor from the template - const ServerTangibleObjectTemplate * newTemplate = safe_cast< - const ServerTangibleObjectTemplate *>(getObjectTemplate()); - if (newTemplate != NULL) - { - setInvulnerable(newTemplate->getInvulnerable()); - - if (isAuthoritative()) - { - initializeVisibility(); - - const ServerArmorTemplate * armorTemplate = newTemplate->getArmor(); - if (armorTemplate != NULL) - { - int const rating = static_cast(armorTemplate->getRating()); - if ( rating < static_cast(ServerArmorTemplate::AR_armorNone) - || rating > static_cast(ServerArmorTemplate::AR_armorHeavy)) - { - WARNING(true, ("TangibleObject::initializeFirstTimeObject trying " - "to add armor data from template %s with an invalid rating " - "of %d", armorTemplate->getName(), rating)); - } - else - { - // armor integrity replaces hitpoints - m_maxHitPoints = armorTemplate->getIntegrity(); - } - } - } - } - - // attach the combat skeleton script to this object - ServerTangibleObjectTemplate::CombatSkeleton skeleton = static_cast(getCombatSkeleton()); - const ConfigCombatEngine::SkeletonAttackMod & skeletonMod = - ConfigCombatEngine::getSkeletonAttackMod(skeleton); - if (!skeletonMod.script.empty() && skeletonMod.script[0] != '\0') - { - NOT_NULL(getScriptObject()); - getScriptObject()->attachScript(skeletonMod.script, true); - } - - handleContainerSetup(); - - ServerObject::initializeFirstTimeObject(); - - setDefaultAlterTime(AlterResult::cms_keepNoAlter); - - calcPvpableState(); - if (!isNonPvpObject()) - MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++CheckPvpRegion", std::string(), static_cast(getPvpRegionCheckTime())); -} - -//----------------------------------------------------------------------- - -/** - * Initializes a proxy object. - */ -void TangibleObject::endBaselines() -{ - ServerObject::endBaselines(); - handleContainerSetup(); - - // set the hate list owner to ensure the player object is set correctly - m_hateList.setOwner(this); - - if (isAuthoritative()) - { - // fix the load_with values if they don't match - if ( getLoadWith() != ContainerInterface::getLoadWithContainerId(*this)) - { - setLoadWith(ContainerInterface::getLoadWithContainerId(*this)); - } - - // test to flag the object as disabled - if (getDamageTaken() >= getMaxHitPoints()) - setDisabled(true); - - // pvp needs to be notified after an object is both initialized and made authoritative. - Pvp::handleAuthorityAcquire(*this); - - // this code is for legacy objects already in the database - // Don't consider virtual overrides for invulnerability in this case - if (getCacheVersion() > 0 && !TangibleObject::isInvulnerable()) - setInvulnerable(true); - - if (getObjVars().hasItem(OBJVAR_CRAFTING_SCHEMATIC)) - setCondition(C_crafted); - else - clearCondition(C_crafted); - - removeObjVarItem("debuggingLogCommandEnqueue"); - - // destroy duped TCG Set5 AT-AT Head ITV - if ((getStaticItemName() == "item_tcg_loot_reward_series5_atat_head_itv") && !getObjVars().hasItem("rewardGrantInfo")) - { - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++DestroyDupedTcg5AtAtHeadItv", - "", - 5, - false); - } - } - - calcPvpableState(); - - // check for existence of objvar to enable/disable m_logCommandEnqueue - CommandQueue * const queue = getCommandQueue(); - if (queue != NULL) - { - queue->setLogCommandEnqueue(getObjVars().hasItem("debuggingLogCommandEnqueue")); - } - - // if this is an incubator, and it contains imported resource from another - // galaxy, register the imported resource type on this game server, if it - // hasn't already been registered on this game server; this must be done - // on each game server as it receives the incubator - static const uint32 crcIncubator = CrcLowerString::calculateCrc("object/tangible/crafting/station/incubator_station.iff"); - if (getTemplateCrc() == crcIncubator) - { - DynamicVariableList const & objvars = getObjVars(); - if (objvars.hasItem("power.resourceData") && (DynamicVariable::STRING == objvars.getType("power.resourceData"))) - { - std::string resourceData; - IGNORE_RETURN(objvars.getItem("power.resourceData", resourceData)); - IGNORE_RETURN(ResourceTypeObject::addImportedResourceType(resourceData)); - } - } -} // TangibleObject::endBaselines - -//----------------------------------------------------------------------- - -void TangibleObject::onLoadedFromDatabase() -{ - ServerObject::onLoadedFromDatabase(); - - // if we are a crafting tool that is counting down a prototype, - // reactivate the counter - if (isCraftingTool() && isAuthoritative()) - { - float prototypeTime = 0; - getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME, prototypeTime); - if (prototypeTime > 0) - { - int timeLeft = getCraftingToolPrototypeTime(); - if (timeLeft < 1) - timeLeft = 1; - - NetworkId ownerId; - NetworkId prototypeId; - bool result = getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_OBJECT, - prototypeId) && getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_CRAFTER, - ownerId); - if (result) - { - ScriptParams params; - params.addParam(ownerId, "crafter"); - params.addParam(prototypeId, "prototype"); - ScriptDictionaryPtr dictionary; - getScriptObject()->makeScriptDictionary(params, dictionary); - if (dictionary.get() != NULL) - { - dictionary->serialize(); - MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), - "prototypeDone", dictionary->getSerializedData(), - timeLeft, false); - MessageToQueue::getInstance().sendMessageToC(getNetworkId(), - "C++updateCounter", "", 1, false); - } - } - } - } - - setDefaultAlterTime(AlterResult::cms_keepNoAlter); - - calcPvpableState(); - if (!isNonPvpObject()) - MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++CheckPvpRegion", std::string(), static_cast(getPvpRegionCheckTime())); - - if(isLocked()) - { - readInUserAccessListObjVars(); - readInGuildAccessListObjVars(); - } - - // Invalid Socket check. - bool checkForInvalidSockets = (GameObjectTypes::isTypeOf(getGameObjectType(), SharedObjectTemplate::GOT_clothing) || - GameObjectTypes::isTypeOf(getGameObjectType(), SharedObjectTemplate::GOT_armor) ) && isCrafted(); - if(checkForInvalidSockets) - { - std::vector< std::pair< std::string, int > > skillMods; - getSkillModBonuses(skillMods, false); - - if(skillMods.size() > 3) // 3 is the max legit amount for any 1 socket item - { - // Check all our stats, make sure they aren't over the limit for 1 socket, cross reference names with the reverse engineering datatable. - DataTable * modTable = DataTableManager::getTable("datatables/crafting/reverse_engineering_mods.iff", true); - if(!modTable) - return; - int invalidSkillCounter = 0; - // Check each skill mod against the datatable. If we don't have that skill mod in the table, then it could be a legitimate item from the older system. - for(unsigned int i = 0; i < skillMods.size(); ++i) - { - std::string skillModName = skillMods[i].first; - int row = modTable->searchColumnString(0, skillModName); - - if(row < 0) // wasn't in our table, could be legit. - continue; - - ++invalidSkillCounter; - } - - if(invalidSkillCounter <= 3) // Valid item. - return; - - // Player Name - std::string playerName = NameManager::getInstance().getPlayerFullName(getOwnerId()); - Unicode::String objName = getObjectName(); - std::string narrowObjName; - if(!objName.empty()) - narrowObjName = Unicode::wideToNarrow(objName); - // Possible invalid item. - LOG("CustomerService", ("extraSocketExploit:Reason: Invalid # of Skill mods. Item Name: [%s] OID:[%s] Shared Template Name: [%s]", - narrowObjName.empty() ? "" : narrowObjName.c_str(), getNetworkId().getValueString().c_str(), getSharedTemplateName() ? getSharedTemplateName() : "")); - LOG("CustomerService", ("extraSocketExploit:Owner OID: [%s] Owner Station ID: [%u] Owner Name: [%s]", - getOwnerId().getValueString().c_str(), NameManager::getInstance().getPlayerStationId(getOwnerId()), playerName.empty() ? "" : playerName.c_str())); - LOG("CustomerService", ("extraSocketExploit:Skill Mods are:")); - - for(unsigned int i = 0; i < skillMods.size(); ++i) - { - int row = modTable->searchColumnString(0, skillMods[i].first); - int currentValue = skillMods[i].second; - int maxValue = 0; - - if(row < 0) - { - LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[i].first.c_str(), skillMods[i].second)); - continue; - } - - int ratioValue = modTable->getIntValue(1, row); - - if(ratioValue != 0) - maxValue = 35 / ratioValue; - - if(currentValue > maxValue) - LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [%d]", skillMods[i].first.c_str(), skillMods[i].second, maxValue)); - else if(currentValue > 35) - LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [35]", skillMods[i].first.c_str(), skillMods[i].second)); - else - LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[i].first.c_str(), skillMods[i].second)); - } - } - else - { - // Check all our stats, make sure they aren't over the limit for 1 socket. - DataTable * modTable = DataTableManager::getTable("datatables/crafting/reverse_engineering_mods.iff", true); - if(!modTable) - return; - - for(unsigned int i = 0; i < skillMods.size(); ++i) - { - std::string skillModName = skillMods[i].first; - int currentValue = skillMods[i].second; - int maxValue = 0; - bool logItem = false; - - if(currentValue > 35) - logItem = true; - else - { - int row = modTable->searchColumnString(0, skillModName); - - if(row < 0) - return; - - int ratioValue = modTable->getIntValue(1, row); - - if(ratioValue != 0) - maxValue = 35 / ratioValue; - - if(currentValue > maxValue) - logItem = true; - } - - if(logItem) - { - // Player Name - std::string playerName = NameManager::getInstance().getPlayerFullName(getOwnerId()); - Unicode::String objName = getObjectName(); - std::string narrowObjName; - if(!objName.empty()) - narrowObjName = Unicode::wideToNarrow(objName); - // Possible invalid item. - LOG("CustomerService", ("extraSocketExploit:Reason: Invalid Skill mod value. Item Name: [%s] OID:[%s] Shared Template Name: [%s]", - narrowObjName.empty() ? "" : narrowObjName.c_str(), getNetworkId().getValueString().c_str(), getSharedTemplateName() ? getSharedTemplateName() : "")); - LOG("CustomerService", ("extraSocketExploit:Owner OID: [%s] Owner Station ID: [%u] Owner Name: [%s]", - getOwnerId().getValueString().c_str(), NameManager::getInstance().getPlayerStationId(getOwnerId()), playerName.empty() ? "" : playerName.c_str())); - LOG("CustomerService", ("extraSocketExploit:Skill Mods are:")); - - for(unsigned int j = 0; j < skillMods.size(); ++j) - { - - int row = modTable->searchColumnString(0, skillMods[j].first); - currentValue = skillMods[j].second; - - if(row < 0) - { - LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[j].first.c_str(), skillMods[j].second)); - continue; - } - - int ratioValue = modTable->getIntValue(1, row); - - if(ratioValue != 0) - maxValue = 35 / ratioValue; - - if(currentValue > maxValue) - LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [%d]", skillMods[j].first.c_str(), skillMods[j].second, maxValue)); - else if(currentValue > 35) - LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [35]", skillMods[j].first.c_str(), skillMods[j].second)); - else - LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[j].first.c_str(), skillMods[j].second)); - } - - return; - } - } - } - } - - // start the decay process going -} - -//----------------------------------------------------------------------- - -void TangibleObject::virtualOnSetAuthority() -{ - ServerObject::virtualOnSetAuthority(); -} - -//----------------------------------------------------------------------- - -TangibleObject * TangibleObject::getTangibleObject(NetworkId const & networkId) -{ - return asTangibleObject(NetworkIdManager::getObjectById(networkId)); -} - -//----------------------------------------------------------------------- - -TangibleObject * TangibleObject::asTangibleObject(Object * object) -{ - ServerObject * serverObject = (object != NULL) ? object->asServerObject() : NULL; - return (serverObject != NULL) ? serverObject->asTangibleObject() : NULL; -} - -//----------------------------------------------------------------------- - -TangibleObject const * TangibleObject::asTangibleObject(Object const * object) -{ - ServerObject const * serverObject = (object != NULL) ? object->asServerObject() : NULL; - return (serverObject != NULL) ? serverObject->asTangibleObject() : NULL; -} - -//----------------------------------------------------------------------- - -TangibleObject * TangibleObject::asTangibleObject() -{ - return this; -} - -// ---------------------------------------------------------------------- - -TangibleObject const * TangibleObject::asTangibleObject() const -{ - return this; -} - -// ---------------------------------------------------------------------- - -/** - * Returns a shared template if none was given for this object. - * - * @return the shared template - */ -const SharedObjectTemplate * TangibleObject::getDefaultSharedTemplate(void) const -{ -static const ConstCharCrcLowerString templateName("object/tangible/base/shared_tangible_default.iff"); - - if (m_defaultSharedTemplate == NULL) - { - m_defaultSharedTemplate = safe_cast( - ObjectTemplateList::fetch(templateName)); - WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create " - "default shared object template %s", templateName.getString())); - if (m_defaultSharedTemplate != NULL) - ExitChain::add (removeDefaultTemplate, "TangibleObject::removeDefaultTemplate"); - } - return m_defaultSharedTemplate; -} // TangibleObject::getDefaultSharedTemplate - -//----------------------------------------------------------------------- - -/** - * Cleans up the default shared template. - */ -void TangibleObject::removeDefaultTemplate(void) -{ - if (m_defaultSharedTemplate != NULL) - { - m_defaultSharedTemplate->releaseReference(); - m_defaultSharedTemplate = NULL; - } -} // TangibleObject::removeDefaultTemplate - -//----------------------------------------------------------------------- - -/** - * Returns the name of the shared template that will be sent to the client when - * this object is created. If this object has a custom appearance, that template - * name will be returned, otherwise the default name will be returned. - * - * - */ -const char * TangibleObject::getClientSharedTemplateName(void) const -{ - if (!m_customAppearance.get().empty()) - return m_customAppearance.get().c_str(); - return ServerObject::getClientSharedTemplateName(); -} // TangibleObject::getClientSharedTemplateName - -//----------------------------------------------------------------------- - -void TangibleObject::addLocationTarget(const LocationData & location) -{ - if(isAuthoritative()) - { - std::vector::const_iterator i; - for(i = m_locationTargets.begin(); i != m_locationTargets.end(); ++i) - { - if((*i).name == location.name) - { - m_locationTargets.set(static_cast(std::distance(m_locationTargets.begin(), i)), location); - return; - } - } - m_locationTargets.push_back(location); - scheduleForAlter(); - } - else - { - sendControllerMessageToAuthServer(CM_addLocationTarget, new MessageQueueGenericValueType(location)); - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::removeLocationTarget(const Unicode::String & locationName) -{ - if(isAuthoritative()) - { - std::vector::const_iterator i; - for(i = m_locationTargets.begin(); i != m_locationTargets.end(); ++i) - { - if((*i).name == locationName) - { - m_locationTargets.erase(static_cast(std::distance(m_locationTargets.begin(), i))); - return; - } - } - } - else - { - sendControllerMessageToAuthServer(CM_removeLocationTarget, new MessageQueueGenericValueType(locationName)); - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::onArrivedAtLocation(const LocationData & location) -{ - // only invokes a script trigger, which is automagically forwarded to - // the authoritative server - if(getScriptObject()) - { - ScriptParams p; - p.addParam(location.name); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_ARRIVE_AT_LOCATION, p)); - } -} -// ---------------------------------------------------------------------- - -/** - * This function is called after the TangibleObject has received a - * new custom appearance string. - * - * @arg value the value of the new custom appearance string - */ -void TangibleObject::customAppearanceModified(const std::string& value) -{ - // we don't value to use the value arg since we already have the - // data stored in m_customAppearance, but just in case the interface - // changes, we'll use it here. - - if (value.empty()) - return; -} // TangibleObject::customAppearanceModified - -// ---------------------------------------------------------------------- - -/** - * This function is called after the TangibleObject has received a - * new appearance data customization string. - * - * @arg value the value of the new appearance customization string - */ - -// ---------------------------------------------------------------------- - -void TangibleObject::appearanceDataModified(const std::string& value) -{ - // we don't value to use the value arg since we already have the - // data stored in m_appearanceData, but just in case the interface - // changes, we'll use it here. Technically we don't need to keep - // the m_appearanceData string around on the client. We can build - // it at will from the appearance. - - //-- skip no-content customization data - if (value.empty()) - return; - - // check if the property exists - CustomizationDataProperty *cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); - - if (!cdProperty) - { - // every debug warning I put here goes into never-never land in addr2line. real handy feature... - // DEBUG_WARNING(true, ("non-zero-length appearance string sent to object that doesn't declare any customization variables in its template.")); - // DEBUG_WARNING(true, ("received appear string for non-customizable object.")); - return; - } - - // retrieve the CustomizationData instance associated with the property - CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); - NOT_NULL(customizationData); - - //-- initialize CustomizationData variable values from the string - customizationData->loadLocalDataFromString(value); - - //-- release local reference - customizationData->release(); -} -//----------------------------------------------------------------------- - -/** - * Gets all the equipped items corresponding to a combat skeleton "bone". - * - * @param combatBone the bone we want equipment for - * @param items list to be filled in with the items - */ -void TangibleObject::getEquippedItems(uint32 combatBone, std::vector &items) const -{ - SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); - if (container == NULL) - return; - - std::vector itemIds; - container->getObjectsForCombatBone(combatBone, itemIds); - - std::vector::const_iterator iter; - for (iter = itemIds.begin(); iter != itemIds.end(); ++iter) - { - Object * object = (*iter).getObject(); - if (object != NULL) - { - TangibleObject * item = dynamic_cast(object); - if (item != NULL) - items.push_back(item); - } - } -} // TangibleObject::getEquippedItems - -//----------------------------------------------------------------------- - -/** - * Returns a random equipped item corresponding to a combat skeleton "bone". - * - * @param combatBone the bone we want the item for - * - * @return the item - */ -TangibleObject * TangibleObject::getRandomEquippedItem(uint32 combatBone) const -{ - std::vector items; - getEquippedItems(combatBone, items); - - if (items.empty()) - { - return NULL; - } - - int index = Random::random(0, items.size() - 1); - return items[index]; -} // TangibleObject::getRandomEquippedItem - -//----------------------------------------------------------------------- - -/** - * Updates the object for damage taken in battle. - * - * @param time current game time - * - * @return base class result - */ -float TangibleObject::alter(real time) -{ - PROFILER_AUTO_BLOCK_DEFINE("TangibleObject::alter"); - - if (isAuthoritative()) - { - // Determine the combat state of the object - { - CombatEngine::alter(*this); - - m_hateList.alter(); - - if (!m_hateList.isEmpty()) - { - if (!isPlayerControlled()) - { - // AI - - // Schedule the AI for an update - { - AiCombatPulseQueue::schedule(this, 0, static_cast(time * 1000.0f)); - } - } - else - { - // Player - - // Make sure the hate list is purged of invalid hate targets. If a player is no - // longer hated by a hate target, then remove that target from the player's list. - // A player must be in their hate target's hate list and vice versa. - { - typedef std::vector PurgeList; - static PurgeList purgeList; - purgeList.clear(); - - HateList::UnSortedList const & unSortedHateList = getUnSortedHateList(); - HateList::UnSortedList::const_iterator iterUnSortedHateList = unSortedHateList.begin(); - - for (; iterUnSortedHateList != unSortedHateList.end(); ++iterUnSortedHateList) - { - CachedNetworkId const & id = iterUnSortedHateList->first; - - if (!isHatedBy(id.getObject())) - { - purgeList.push_back(id); - } - } - - PurgeList::const_iterator iterPurgeList = purgeList.begin(); - - for (; iterPurgeList != purgeList.end(); ++iterPurgeList) - { - removeHateTarget(*iterPurgeList); - } - } - } - } - - if (m_hateList.isEmpty()) - { - if ( !isPlayerControlled() - || (getCombatDuration() > s_minCombatDuration)) - { - setInCombat(false); - } - } - } - } - - // check for location target arrival - if(isAuthoritative() && !m_locationTargets.empty()) - { - Vector const effectiveWorldLocation = findPosition_w(); - for (std::vector::const_iterator i = m_locationTargets.begin(); i != m_locationTargets.end(); ++i) - { - if ((*i).scene == ServerWorld::getSceneId()) - { - Sphere const &s = (*i).location; - // 3d targets are denoted by y coordinates > 50k, with 100k added to them - // If it's a 3d target, add 100k to our y coordinate - // If it's a 2d target, set our y coordinate to the target's - // 2d comparison, put locations on same plane - Vector v = effectiveWorldLocation; - if (s.getCenter().y > 50000.0f) - v.y += 100000.0f; - else - v.y = s.getCenter().y; - - if (s.contains(v)) - { - // copy the location data so we can remove it from the vector prior to triggerring - LocationData triggeredLocation(*i); - removeLocationTarget((*i).name); - // trigger any scripts - onArrivedAtLocation(triggeredLocation); - // we'll catch any additional location triggers going off during the next alter - break; - } - } - } - } - - //-- handle modified customization data - if (isCustomizationDataModified()) - { - // associated CustomizationData instance is modified. Pack CustomizationData - // into m_appearanceData string, which will get sent to others. - - //-- get property - CustomizationDataProperty *cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); - if (!cdProperty) - { - DEBUG_WARNING(true, ("customization data modified but no customization data!")); - } - else - { - // retrieve the CustomizationData instance associated with the property - CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); - NOT_NULL(customizationData); - - //-- initialize CustomizationData variable values from the string - m_appearanceData.set(customizationData->writeLocalDataToString()); - - //-- release reference - customizationData->release(); - - } - - // reset flag - setCustomizationDataModified(false); - } - - return ServerObject::alter(time); -} // TangibleObject::alter - -//----------------------------------------------------------------------- - -float TangibleObject::getNextAlterTime(float baseAlterTime) const -{ - if (baseAlterTime == AlterResult::cms_kill || baseAlterTime == AlterResult::cms_alterNextFrame) - return baseAlterTime; - - float result = baseAlterTime; - - if (getSynchronizedUi() && dynamic_cast(getSynchronizedUi())) - return AlterResult::cms_alterNextFrame; - - if (isAuthoritative()) - { - if (isInCombat()) - return AlterResult::cms_alterNextFrame; - - if (!m_locationTargets.empty()) - AlterResult::incorporateAlterResult(result, ConfigServerGame::getLocationTargetCheckIntervalSec()); - } - - return result; -} - -//----------------------------------------------------------------------- - -void TangibleObject::conclude() -{ - PROFILER_AUTO_BLOCK_DEFINE("TangibleObject::conclude"); - - // if we are a crafting tool, conclude our prototype and manf schematic - if (getSynchronizedUi() != NULL) - { - const CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync != NULL) - { - Object * object = sync->getPrototype().getObject(); - if (object != NULL) - object->conclude(); - object = sync->getManfSchematic().getObject(); - if (object != NULL) - object->conclude(); - } - } - - ServerObject::conclude(); -} - -//----------------------------------------------------------------------- - -float TangibleObject::getPvpRegionCheckTime() -{ - return ConfigServerGame::getTangiblePvpRegionCheckTime(); -} - -//----------------------------------------------------------------------- - -void TangibleObject::setPvpType(Pvp::PvpType pvpType) -{ - FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpType - this should only be called from the Pvp interface.")); - Pvp::PvpType oldType = static_cast(m_pvpType.get()); - if (oldType != pvpType) - { - m_pvpType.set(static_cast(pvpType)); - m_pvpFutureType.set(-1); - if (getScriptObject()) - { - ScriptParams params; - params.addParam(oldType); - params.addParam(pvpType); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_PVP_TYPE_CHANGED, params)); - } - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::setPvpFutureType(Pvp::PvpType pvpFutureType) -{ - FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpFutureType - this should only be called from the Pvp interface.")); - Pvp::PvpType oldFutureType = static_cast(m_pvpFutureType.get()); - if (oldFutureType != pvpFutureType) - { - m_pvpFutureType.set(static_cast(pvpFutureType)); - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::setPvpFaction(Pvp::FactionId factionId) -{ - FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpFaction - this should only be called from the Pvp interface.")); - Pvp::FactionId oldFaction = static_cast(m_pvpFaction.get()); - if (oldFaction != factionId) - { - m_pvpFaction.set(static_cast(factionId)); - if (getScriptObject()) - { - ScriptParams params; - params.addParam(static_cast(oldFaction)); - params.addParam(static_cast(factionId)); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_PVP_FACTION_CHANGED, params)); - } - - // if player character is changing faction, clear - // out current accumulated CGW points and rating; - // this *MUST* be done after m_pvpFaction has - // been set to the new faction because - // modifyCurrentGcwRating() uses the faction information - CreatureObject * creature = asCreatureObject(); - if (creature) - { - PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); - if (player) - { - // decrementing the value by a really large - // number will cause it to reset to 0 - static int const min = std::numeric_limits::min(); - - player->modifyCurrentGcwPoints(min, false); - player->modifyCurrentGcwRating(min, true); - - // if player is no longer factional, reset current pvp kills - if (!PvpData::isImperialFactionId(factionId) && !PvpData::isRebelFactionId(factionId)) - player->modifyCurrentPvpKills(min, false); - - // if new faction is not neutral, remove any mercenary status - if (!PvpData::isNeutralFactionId(factionId)) - Pvp::setNeutralMercenaryFaction(*creature, PvpData::getNeutralFactionId(), PvpType_Neutral); - } - } - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::setPvpMercenaryFaction(Pvp::FactionId factionId, Pvp::PvpType pvpType) -{ - FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpMercenaryFaction - this should only be called from the Pvp interface.")); - - // this only applies to neutral - if (!PvpData::isNeutralFactionId(m_pvpFaction.get()) && !PvpData::isNeutralFactionId(factionId)) - return; - - // this only applies to player character - PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); - if (!po || !po->isAuthoritative()) - return; - - // see if mercenary functionality is allowed - if (!PvpData::isNeutralFactionId(factionId)) - { - if (PvpData::isImperialFactionId(factionId)) - { - if (pvpType == PvpType_Covert) - { - if (!ConfigServerGame::getEnableCovertImperialMercenary()) - return; - - po->modifyCollectionSlotValue("covert_imperial_mercenary", 1); - po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); - po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); - po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); - - std::string const & currentTitle = po->getTitle(); - if (po->hasCompletedCollectionSlot("covert_imperial_mercenary")) - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle("covert_imperial_mercenary"); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle("covert_imperial_sympathizer"); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle("covert_imperial_loyalist"); - } - else - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle(std::string()); - } - } - else if (pvpType == PvpType_Declared) - { - if (!ConfigServerGame::getEnableOvertImperialMercenary()) - return; - - po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); - po->modifyCollectionSlotValue("overt_imperial_mercenary", 1); - po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); - po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); - - std::string const & currentTitle = po->getTitle(); - if (po->hasCompletedCollectionSlot("overt_imperial_mercenary")) - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle("overt_imperial_mercenary"); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle("overt_imperial_sympathizer"); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle("overt_imperial_loyalist"); - } - else - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle(std::string()); - } - } - else - { - return; - } - } - else if (PvpData::isRebelFactionId(factionId)) - { - if (pvpType == PvpType_Covert) - { - if (!ConfigServerGame::getEnableCovertRebelMercenary()) - return; - - po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); - po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); - po->modifyCollectionSlotValue("covert_rebel_mercenary", 1); - po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); - - std::string const & currentTitle = po->getTitle(); - if (po->hasCompletedCollectionSlot("covert_rebel_mercenary")) - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle("covert_rebel_mercenary"); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle("covert_rebel_sympathizer"); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle("covert_rebel_insurgent"); - } - else - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle(std::string()); - } - } - else if (pvpType == PvpType_Declared) - { - if (!ConfigServerGame::getEnableOvertRebelMercenary()) - return; - - po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); - po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); - po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); - po->modifyCollectionSlotValue("overt_rebel_mercenary", 1); - - std::string const & currentTitle = po->getTitle(); - if (po->hasCompletedCollectionSlot("overt_rebel_mercenary")) - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle("overt_rebel_mercenary"); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle("overt_rebel_sympathizer"); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle("overt_rebel_insurgent"); - } - else - { - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) - po->setTitle(std::string()); - else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - po->setTitle(std::string()); - } - } - else - { - return; - } - } - else - { - return; - } - } - else - { - po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); - po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); - po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); - po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); - - std::string const & currentTitle = po->getTitle(); - if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary") || - (currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer") || - (currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) - { - po->setTitle(std::string()); - } - } - - // flag when the player stopped being a factional helper for the particular faction - if (m_pvpMercenaryFaction.get() != factionId) - { - if (PvpData::isImperialFactionId(m_pvpMercenaryFaction.get())) - { - IGNORE_RETURN(setObjVarItem("factionalHelper.timeStopHelpingImperial", static_cast(::time(NULL)))); - removeObjVarItem("factionalHelper.timeStopHelpingRebel"); - } - else if (PvpData::isRebelFactionId(m_pvpMercenaryFaction.get())) - { - IGNORE_RETURN(setObjVarItem("factionalHelper.timeStopHelpingRebel", static_cast(::time(NULL)))); - removeObjVarItem("factionalHelper.timeStopHelpingImperial"); - } - } - - m_pvpMercenaryFaction.set(static_cast(factionId)); - m_pvpMercenaryType.set(((PvpData::isNeutralFactionId(factionId)) ? PvpType_Neutral : static_cast(pvpType))); -} - -//----------------------------------------------------------------------- - -Region const *TangibleObject::getPvpRegion() const -{ - uint32 crc = m_pvpRegionCrc.get(); - if (crc) - return Region::findRegionByNameCrc(crc); - return 0; -} - -//----------------------------------------------------------------------- - -/** - * Sets the pvp region this object is in. - * - * @param pvpRegion the pvp region - */ -void TangibleObject::setPvpRegion(Region const * pvpRegion) -{ - if (isAuthoritative()) - { - uint32 crc = pvpRegion ? pvpRegion->getNameCrc() : 0; - if (m_pvpRegionCrc.get() != crc) - m_pvpRegionCrc = crc; - } - else - { - FATAL(true, ("TangibleObject::setPvpRegion : send message to auth object!!!")); - } -} - -//----------------------------------------------------------------------- - -/** - * Creates a default controller for this object. - * - * @return the object's controller - */ -Controller* TangibleObject::createDefaultController(void) -{ - Controller* controller = new TangibleController(this); - NOT_NULL(controller); - - setController(controller); - return controller; -} // TangibleObject::createDefaultController - -//----------------------------------------------------------------------- - -void TangibleObject::forwardServerObjectSpecificBaselines() const -{ - ServerObject::forwardServerObjectSpecificBaselines(); -} - -//----------------------------------------------------------------------- - -TangibleObject const &TangibleObject::getPvpViewer(Client const &client) const -{ - TangibleObject const * const clientObj = safe_cast(client.getCharacterObject()); - FATAL(!clientObj, ("Client trying to get pvp viewer with no character object?")); - return *clientObj; -} - -//----------------------------------------------------------------------- - -void TangibleObject::sendObjectSpecificBaselinesToClient(Client const &client) const -{ - ServerObject::sendObjectSpecificBaselinesToClient(client); - if (!isNonPvpObject()) - { - uint32 flags, factionId; - Pvp::getClientVisibleStatus(client, *this, flags, factionId); - UpdatePvpStatusMessage const statusMessage(getNetworkId(), flags, factionId); - client.send(statusMessage, true); - PvpUpdateObserver::updatePvpStatusCache(&client, *this, flags, factionId); - } -} - -//----------------------------------------------------------------------- - -/** - * Flags the object as being cached on the client or not. - */ -void TangibleObject::setCacheVersion(const int cacheVersion) -{ - ServerObject::setCacheVersion(cacheVersion); - - // if we are cached, we need to be made invulnerable - // @todo: if we are not cached, do we need to change our invulnerability? - if (cacheVersion > 0) - setInvulnerable(true); -} // TangibleObject::setCacheVersion - -//----------------------------------------------------------------------- - -/** - * Allows an object to do pre-deletion cleanup. - */ -void TangibleObject::onRemovingFromWorld() -{ - ServerObject::onRemovingFromWorld(); - - clearHateList(); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::unload() -{ - ServerObject::unload(); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::onPermanentlyDestroyed() -{ - ServerObject::onPermanentlyDestroyed(); - - if (isAuthoritative()) - { - clearHateList(); - - if (isCraftingTool()) - { - ServerObject * owner = ServerWorld::findObjectByNetworkId(getOwnerId()); - if (owner != NULL && owner->asCreatureObject() != NULL) - { - PlayerObject * player = PlayerCreatureController::getPlayerObject( - owner->asCreatureObject()); - if (player != NULL && player->isCrafting() && player->getCraftingTool() == getNetworkId()) - player->stopCrafting(false); - } - } - } - - if (isWaypoint()) - { - ServerPathfindingNotification::destroyWaypoint(this); - } -} - -//----------------------------------------------------------------------- - -/** - * Creates a synchronized ui class in order to get data to the client during a - * crafting session. - * - * @return the newly created class - */ -ServerSynchronizedUi * TangibleObject::createSynchronizedUi () -{ - return new CraftingToolSyncUi(*this); -} - - -// ====================================================================== -// TangibleObject private static member functions -// ====================================================================== - -void TangibleObject::customizationDataModificationCallback(const CustomizationData & /* customizationData */, const void *context) -{ - if (!context) - return; - - //-- turn context into TangibleObject - TangibleObject *const tangibleObject = const_cast(reinterpret_cast(context)); - - //-- set the tangible object's customization data modification flag now. - // The reason we don't handle the customization data change now is that - // we want to lump up all the changes that occur during one server - // frame and handle the string conversion once. - tangibleObject->setCustomizationDataModified(true); -} - -// ====================================================================== -// TangibleObject private member functions -// ====================================================================== - -void TangibleObject::handleContainerSetup() -{ - -} - -//----------------------------------------------------------------------- - -void TangibleObject::setOwnerId(NetworkId const &id) -{ - if(isAuthoritative()) - { - // if we are changing owners, we are no longer insured - bool ownerChanged = false; - if (m_ownerId.get() != id) - { - ownerChanged = true; - setInsured(false); - } - - m_ownerId = id; - Container* container = ContainerInterface::getContainer(*this); - if (container) - { - ContainerIterator i = container->begin(); - for (; i != container->end(); ++i) - { - ServerObject* content = safe_cast((*i).getObject()); - if (content && !dynamic_cast(content)) - { - content->setOwnerId(id); - } - } - } - - // if we're hidden, who can see us has changed - if (ownerChanged && isInWorld() && isHidden()) - visibilityDataModified(); - } - else - { - sendControllerMessageToAuthServer(CM_setOwnerId, new MessageQueueNetworkId(id)); - } -} -//----------------------------------------------------------------------- - -bool TangibleObject::onContainerAboutToTransfer(ServerObject * destination, ServerObject* transferer) -{ - const int got = getGameObjectType (); - if (got == SharedObjectTemplate::GOT_misc_crafting_station && destination && !destination->asCellObject()) - { - //Only allow stations to be trasferred if their hoppers are empty - Container* container = ContainerInterface::getContainer(*this); - if (container) - { - ContainerIterator i = container->begin(); - for (; i != container->end(); ++i) - { - ServerObject* content = safe_cast((*i).getObject()); - if (!isEmpty(*content)) - { - - if (transferer && transferer->getClient()) - ContainerInterface::sendContainerMessageToClient(*transferer, Container::CEC_HopperNotEmpty); - return false; - } - } - } - } - if (destination != NULL && getObjVars().hasItem(OBJVAR_BIO_LINK_ID)) - { - // if this item is bio-linked and a player is trying to equip it, make - // sure the link id matches the player's id - if (destination->asCreatureObject() != NULL) - { - // allow holograms to have biolinked items transferred to them - int hologramVal = 0; - destination->getObjVars().getItem("hologram_performer", hologramVal); - - NetworkId linkId(getBioLink()); - if (linkId != destination->getNetworkId() && hologramVal == 0) - { - if (transferer && transferer->getClient()) - ContainerInterface::sendContainerMessageToClient(*transferer, Container::CEC_BioLinkedToOtherPlayer); - return false; - } - } - - // Check to see if we're trying to appearance equip a biolinked item. - Object * containedBy = ContainerInterface::getContainedByObject(*destination); - if(containedBy && containedBy->asServerObject() && containedBy->asServerObject()->asCreatureObject()) - { - CreatureObject * creatureContainer = containedBy->asServerObject()->asCreatureObject(); - if(creatureContainer && creatureContainer->getAppearanceInventory() && creatureContainer->getAppearanceInventory() == destination) - { - // We're trying to appearance equip a biolinked item. Make sure the BioLink ID matches our player ID. - NetworkId linkId(getBioLink()); - if (linkId != creatureContainer->getNetworkId()) - { - if (transferer && transferer->getClient()) - ContainerInterface::sendContainerMessageToClient(*transferer, Container::CEC_BioLinkedToOtherPlayer); - return false; - } - } - } - } - return ServerObject::onContainerAboutToTransfer(destination, transferer); -} - -//----------------------------------------------------------------------- - -bool TangibleObject::onContainerChildAboutToLoseItem(ServerObject *destination, ServerObject &item, ServerObject *transferer) -{ - int const got = getGameObjectType(); - if (transferer && got == SharedObjectTemplate::GOT_misc_crafting_station && !isInWorld()) - return false; - - if (getPortalProperty() && !onPobChildAboutToLoseItem(destination, item, transferer)) - return false; - - return ServerObject::onContainerChildAboutToLoseItem(destination, item, transferer); -} - -//----------------------------------------------------------------------- - -bool TangibleObject::onContainerChildAboutToGainItem(ServerObject &item, ServerObject *destination, ServerObject *transferer) -{ - int const got = getGameObjectType(); - if (transferer && got == SharedObjectTemplate::GOT_misc_crafting_station && !isInWorld()) - return false; - - if (getPortalProperty() && !onPobChildAboutToGainItem(item, destination, transferer)) - return false; - - return ServerObject::onContainerChildAboutToGainItem(item, destination, transferer); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::onContainerChildLostItem(ServerObject *destination, ServerObject &item, ServerObject *source, ServerObject *transferer) -{ - if (getPortalProperty()) - onPobChildLostItem(destination, item, source, transferer); - ServerObject::onContainerChildLostItem(destination, item, source, transferer); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::onContainerChildGainItem(ServerObject &item, ServerObject *source, ServerObject *transferer) -{ - if (getPortalProperty()) - onPobChildGainItem(item, source, transferer); - ServerObject::onContainerChildGainItem(item, source, transferer); -} - -// ---------------------------------------------------------------------- - -int TangibleObject::onContainerAboutToGainItem(ServerObject& item, ServerObject* transferer) -{ - if (transferer && isCraftingTool()) - { - return Container::CEC_BlockedByDestinationContainer; - } - return ServerObject::onContainerAboutToGainItem(item, transferer); -} - -//---------------------------------------------------------------------- - -void TangibleObject::onContainerGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) -{ - ServerObject::onContainerGainItem(item, source, transferer); - //do not set owners of creatures - //and do not set the owner of items going into the bazaar - if (getOwnerId() != NetworkId::cms_invalid && !item.asCreatureObject() && !isBazaarTerminal()) - item.setOwnerId(getOwnerId()); -} - -// ---------------------------------------------------------------------- - -Footprint *TangibleObject::getFootprint() -{ - CollisionProperty *const property = getCollisionProperty(); - if (property) - return property->getFootprint(); - else - return NULL; -} - -//----------------------------------------------------------------------- - -Footprint const *TangibleObject::getFootprint() const -{ - CollisionProperty const *const property = getCollisionProperty(); - if (property) - return property->getFootprint(); - else - return NULL; -} - -// ---------------------------------------------------------------------- - -/** - * Sets up the object for being in or out of combat. - * - * @param inCombat flag to put the object in combat-ready state or not - * - * @return true if state was set, false if something went wrong - */ -void TangibleObject::setInCombat(bool inCombat) -{ - m_inCombat = inCombat; -} - -//----------------------------------------------------------------------- - -/** - * If this object is in combat, adds an aim to it. - */ -void TangibleObject::addAim(void) -{ - if(isAuthoritative()) - { - if (isInCombat()) - { - CombatEngineData::AttackData & attackData = NON_NULL(getCombatData())->attackData; - - if (attackData.aims < ConfigCombatEngine::getMaxAims()) - { - ++attackData.aims; - } - } - } - else - { - sendControllerMessageToAuthServer(CM_addAim, 0); - } -} // TangibleObject::addAim - -//----------------------------------------------------------------------- - -/** - * If this object is in combat, clear's it's aims. - */ -void TangibleObject::clearAims(void) -{ - if(isAuthoritative()) - { - if (isInCombat()) - { - CombatEngineData::AttackData & attackData = NON_NULL(getCombatData())->attackData; - attackData.aims = 0; - } - } - else - { - sendControllerMessageToAuthServer(CM_clearAims, 0); - } -} // TangibleObject::clearAims - -//----------------------------------------------------------------------- - -/** - * Applies damage to the object. No other function should modify m_damageTaken. - * - * @param delta amount of damage to apply - * @param ignoreInvulnerable flag to ignore the invulnerable setting of this object - * @param source who is doing the damage - * - * @return the amount of damage actually applied - */ -int TangibleObject::alterHitPoints(int delta, bool ignoreInvulnerable, - const NetworkId & source) -{ - if(isAuthoritative()) - { -#ifdef _DEBUG - char debugBuffer[1024]; - const char * craftedString = ""; - Client *client = NULL; - ServerObject * sourceObject = safe_cast(NetworkIdManager::getObjectById(source)); - if (source != NetworkId::cms_invalid && sourceObject != NULL) - client = sourceObject->getClient(); -#endif - - // Only consider tangible invulnerability rules for this case - if (isDisabled() || (!ignoreInvulnerable && TangibleObject::isInvulnerable())) - return 0; - - int totalHitPoints = getMaxHitPoints(); - int totalDamageTaken = m_damageTaken.get() - delta; - -#ifdef _DEBUG - if (ConfigCombatEngine::getDebugDamage()) - { - snprintf(debugBuffer, sizeof(debugBuffer), "%s object %s (hp=%d) damaged " - "from %d to %d\n", craftedString, getNetworkId().getValueString().c_str(), - totalHitPoints, m_damageTaken.get(), totalDamageTaken); - DEBUG_REPORT_LOG (true, ("%s", debugBuffer)); - if (source != NetworkId::cms_invalid && client != NULL) - ConsoleMgr::broadcastString(debugBuffer, client); - } -#endif - - if (totalDamageTaken >= totalHitPoints) - { - // clip delta and damage taken - if (isDisabled()) - delta = 0; - else - delta += totalDamageTaken - totalHitPoints; - totalDamageTaken = totalHitPoints; - } - else if (totalDamageTaken < 0) - totalDamageTaken = 0; - if (totalDamageTaken == totalHitPoints) - setDisabled(true); - - m_damageTaken = totalDamageTaken; - - if (isDisabled()) - { -#ifdef _DEBUG - if (ConfigCombatEngine::getDebugDamage()) - { - snprintf(debugBuffer, sizeof(debugBuffer), "%s object %s has been " - "disabled\n", craftedString, getNetworkId().getValueString().c_str()); - DEBUG_REPORT_LOG (true, ("%s", debugBuffer)); - if (source != NetworkId::cms_invalid && client != NULL) - ConsoleMgr::broadcastString(debugBuffer, client); - } -#endif - ScriptParams params; - params.addParam(source); - IGNORE_RETURN(getScriptObject()->trigAllScripts( - Scripting::TRIG_OBJECT_DISABLED, params)); - } - scheduleForAlter(); - return delta; - } - else - { - sendControllerMessageToAuthServer(CM_alterHitPoints, new MessageQueueGenericValueType >(std::make_pair(delta, source))); - return 0; - } -} // TangibleObject::alterHitpoints - -//----------------------------------------------------------------------- - -/** - * Applies damage done during combat to the object. - * - * @param damageData the damage - */ -void TangibleObject::applyDamage(const CombatEngineData::DamageData &damageData) -{ - int totalDamage = 0; - - WARNING_STRICT_FATAL(! isAuthoritative(), ("TangibleObject::applyDamage() invoked on a NON-AUTHORITATIVE object %s:%s.", getObjectTemplateName(), getNetworkId().getValueString().c_str())); - - // it is possible for damageData to go bad if this object is being damaged from - // combat and it goes out of combat, so we copy the items we need off of it - const NetworkId attackerId(damageData.attackerId); - const NetworkId weaponId(damageData.weaponId); - - std::vector::const_iterator iter; - for (iter = damageData.damage.begin(); !isDisabled() && iter != damageData.damage.end(); - ++iter) - { - const AttribMod::AttribMod &mod = *iter; - if (mod.value == 0) - continue; - - if (AttribMod::isDirectDamage(mod)) - { - // apply instantanious damage directly - totalDamage -= alterHitPoints(mod.value, damageData.ignoreInvulnerable, - attackerId); - } - else - { - WARNING(true, ("Trying to apply non-immediate damage to tangible " - "object %s. This isn't supported, the damage won't be applied", - getNetworkId().getValueString().c_str())); - } - } - - // tell scripts we have taken combat damage - if (attackerId != NetworkId::cms_invalid && totalDamage > 0) - { - NOT_NULL(getScriptObject()); - ScriptParams params; - params.addParam(attackerId); - params.addParam(weaponId); - params.addParam(totalDamage); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_OBJECT_DAMAGED, - params)); - } -} - -// ---------------------------------------------------------------------- - -/** - * Sends a message to the Planet Server to update the position of the object. - */ -void TangibleObject::updatePlanetServerInternal(const bool forceUpdate) const -{ - // Don't send updates for contained tangibles without an interest radius, and only send when forced or moving - if ((forceUpdate || getPositionChanged()) && (!ContainerInterface::getContainedByObject(*this) || getInterestRadius() > 0)) - { - Object const * const topmostContainer = ContainerInterface::getTopmostContainer(*this); - FATAL(!topmostContainer, ("Object %s was contained by something, but getTopmostContainer() returned NULL\n",getNetworkId().getValueString().c_str())); - Vector const &position = topmostContainer->getPosition_p(); - - UpdateObjectOnPlanetMessage const msg( - getNetworkId(), - topmostContainer == this ? NetworkId::cms_invalid : topmostContainer->getNetworkId(), - static_cast(position.x), - static_cast(position.y), - static_cast(position.z), - getInterestRadius(), - static_cast (getLocationReservationRadius()), - false, - false, - static_cast(getObjectType()), - 0, - false, - getTemplateCrc(), - -1, - -1); - GameServer::getInstance().sendToPlanetServer(msg); - } -} - -//---------------------------------------------------------------------- - -/** - * Clears our damage list. - */ -void TangibleObject::clearDamageList(void) -{ - if (m_combatData != NULL) - { - m_combatData->defenseData.damage.clear(); - } -} - -//---------------------------------------------------------------------- - -bool TangibleObject::addHate(NetworkId const & target, float const hate) -{ - bool result = false; - - if (isAuthoritative()) - { - if (m_hateList.addHate(target, hate)) - { - result = true; - - CombatTracker::addDefender(this); - setInCombat(true); - scheduleForAlter(); - } - } - else - { - sendControllerMessageToAuthServer(CM_addHate, new MessageQueueGenericValueType >(std::make_pair(target, hate))); - } - - return result; -} - -//---------------------------------------------------------------------- - -void TangibleObject::addHateOverTime(NetworkId const & target, float const hate, int const seconds) -{ - if (seconds <= 0) - return; - - if (isAuthoritative()) - { - unsigned long const currentGameTime = ServerClock::getInstance().getGameTimeSeconds(); - unsigned long const endGameTime = currentGameTime + seconds; - - IGNORE_RETURN(addHate(target, hate)); - - bool const firstHateOverTime = m_hateOverTime.empty(); - m_hateOverTime.set(target, std::make_pair(hate, std::make_pair(currentGameTime, endGameTime))); - - if (firstHateOverTime) - MessageToQueue::sendMessageToC(getNetworkId(), "C++ProcessHateOverTime", std::string(), 1, false); - } - else - { - sendControllerMessageToAuthServer(CM_addHateOverTime, new MessageQueueGenericValueType > >(std::make_pair(target, std::make_pair(seconds, hate)))); - } -} - -//---------------------------------------------------------------------- - -bool TangibleObject::setHate(NetworkId const & target, float const hate) -{ - bool result = false; - - if (isAuthoritative()) - { - if (m_hateList.setHate(target, hate)) - { - result = true; - - CombatTracker::addDefender(this); - setInCombat(true); - scheduleForAlter(); - } - } - else - { - sendControllerMessageToAuthServer(CM_setHate, new MessageQueueGenericValueType >(std::make_pair(target, hate))); - } - - return result; -} - -//---------------------------------------------------------------------- - -float TangibleObject::getHate(NetworkId const & target) const -{ - return m_hateList.getHate(target); -} - -//---------------------------------------------------------------------- - -float TangibleObject::getMaxHate() const -{ - return m_hateList.getMaxHate(); -} - -//---------------------------------------------------------------------- - -CachedNetworkId const & TangibleObject::getHateTarget() const -{ - return m_hateList.getTarget(); -} - -//---------------------------------------------------------------------- - -void TangibleObject::removeHateTarget(NetworkId const & target) -{ - if (isAuthoritative()) - { - m_hateList.removeTarget(target); - scheduleForAlter(); - } - else - { - sendControllerMessageToAuthServer(CM_removeHateTarget, new MessageQueueGenericValueType(target)); - } -} - -//---------------------------------------------------------------------- - -void TangibleObject::clearHateList() -{ - if (isAuthoritative()) - { - m_hateList.clear(); - scheduleForAlter(); - } - else - { - sendControllerMessageToAuthServer(CM_clearHateList, NULL); - } -} - -//----------------------------------------------------------------------- - -HateList::UnSortedList const & TangibleObject::getUnSortedHateList() const -{ - return m_hateList.getUnSortedList(); -} - -//----------------------------------------------------------------------- - -void TangibleObject::getSortedHateList(HateList::SortedList & sortedHateList) const -{ - m_hateList.getSortedList(sortedHateList); -} - -//----------------------------------------------------------------------- - -void TangibleObject::verifyHateList() -{ - LOGC(ConfigServerGame::isAiLoggingEnabled(), "debug_ai", ("TangibleObject::verifyHateList() owner(%s:%s)", getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(getEncodedObjectName()).c_str())); - - m_hateList.alter(); -} - -//----------------------------------------------------------------------- - -bool TangibleObject::isHatedBy(Object * const object) -{ - bool result = false; - TangibleObject * const hatedByTangibleObject = TangibleObject::asTangibleObject(object); - - if (hatedByTangibleObject != NULL) - { - HateList::UnSortedList const & hateList = hatedByTangibleObject->getUnSortedHateList(); - - if (hateList.find(CachedNetworkId(*this)) != hateList.end()) - { - result = true; - } - } - - return result; -} - -//----------------------------------------------------------------------- - -bool TangibleObject::isOnHateList(NetworkId const & target) const -{ - return m_hateList.isOnList(target); -} - -//----------------------------------------------------------------------- - -int TangibleObject::getTimeSinceLastHateListUpdate() const -{ - return m_hateList.getTimeSinceLastUpdate(); -} - -//----------------------------------------------------------------------- - -bool TangibleObject::isHateListEmpty() const -{ - return m_hateList.isEmpty(); -} - -//----------------------------------------------------------------------- -HateList::RecentList const & TangibleObject::getRecentHateList() const -{ - return m_hateList.getRecentList(); -} - -//----------------------------------------------------------------------- -void TangibleObject::clearRecentHateList() -{ - m_hateList.clearRecentList(); - scheduleForAlter(); -} - -//----------------------------------------------------------------------- - -void TangibleObject::resetHateTimer() -{ - if (isAuthoritative()) - { - m_hateList.resetHateTimer(); - scheduleForAlter(); - } - else - { - sendControllerMessageToAuthServer(CM_resetHateTimer, NULL); - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::setHateListAutoExpireTargetEnabled(bool const enabled) -{ - m_hateList.setAutoExpireTargetEnabled(enabled); - - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_autoExpireHateListTargetEnabled, new MessageQueueGenericValueType(enabled)); - } -} - -//----------------------------------------------------------------------- - -bool TangibleObject::isHateListAutoExpireTargetEnabled() const -{ - return m_hateList.isAutoExpireTargetEnabled(); -} - -//----------------------------------------------------------------------- - -int TangibleObject::getHateListAutoExpireTargetDuration() const -{ - return m_hateList.getAutoExpireTargetDuration(); -} - -//----------------------------------------------------------------------- -float TangibleObject::getAILeashTime() const -{ - return m_hateList.getAILeashTime(); -} - - -//----------------------------------------------------------------------- -void TangibleObject::setAILeashTime( float time ) -{ - m_hateList.setAILeashTime( time ); -} - - -//----------------------------------------------------------------------- - -/** - * @return true if we are crafted, false if not - */ -bool TangibleObject::isCrafted(void) const -{ - return hasCondition(C_crafted); -} // TangibleObject::isCrafted - -//----------------------------------------------------------------------- - -/** - * Returns the id of the manufacturing schematic that was used to craft this - * item, or NetworkId::cms_invalid if the item wasn't crafted. - * - * @return the schematic id - */ -const NetworkId TangibleObject::getCraftedId(void) const -{ - NetworkId craftedId(NetworkId::cms_invalid); - getObjVars().getItem(OBJVAR_CRAFTING_SCHEMATIC,craftedId); - return craftedId; -} // TangibleObject::getCraftedId - -//----------------------------------------------------------------------- - -/** - * Sets the id of the manufacturing schematic used to create this object. - * - * @param id the schematic id - */ -void TangibleObject::setCraftedId(const NetworkId & id) -{ - if (isAuthoritative()) - { - if (id == NetworkId::cms_invalid) - { - IGNORE_RETURN(removeObjVarItem(OBJVAR_CRAFTING_SCHEMATIC)); - m_sourceDraftSchematic = 0; - clearCondition(C_crafted); - } - else - { - IGNORE_RETURN(setObjVarItem(OBJVAR_CRAFTING_SCHEMATIC, id)); - setCondition(C_crafted); - const Object * object = NetworkIdManager::getObjectById(id); - if (object != NULL) - { - const ManufactureSchematicObject * schematic = dynamic_cast< - const ManufactureSchematicObject *>(object); - if (schematic != NULL) - m_sourceDraftSchematic = schematic->getDraftSchematic(); - } - } - } - else - { - sendControllerMessageToAuthServer(CM_setCraftedId, - new MessageQueueGenericValueType(id)); - } -} // TangibleObject::setCraftedId - -//----------------------------------------------------------------------- - -/** - * Returns the crafting type of a crafting/repair tool. - * - * @return the crafting type - */ -int TangibleObject::getCraftingType(void) const -{ - int type = 0; - getObjVars().getItem(OBJVAR_CRAFTING_TYPE, type); - return type; -} // TangibleObject::getCraftingType - -//----------------------------------------------------------------------- - -/** - * Returns the crafted type of a crafted object. - * - * @return the crafted type - */ -int TangibleObject::getCraftedType(void) const -{ - int craftedType = 0; - getObjVars().getItem(OBJVAR_CRAFTING_REPAIR_TYPE,craftedType); - return craftedType; -} // TangibleObject::getCraftedType - -//----------------------------------------------------------------------- - -/** - * Sets the crafted type of a crafted object. - * - * @param type the crafted type - */ -void TangibleObject::setCraftedType(int type) -{ - if (isAuthoritative()) - { - IGNORE_RETURN(setObjVarItem(OBJVAR_CRAFTING_REPAIR_TYPE, type)); - } - else - { - sendControllerMessageToAuthServer(CM_setCraftedType, - new MessageQueueGenericValueType(type)); - } -} // TangibleObject::setCraftedType - -//----------------------------------------------------------------------- - -/** - * Returns the id of the object's creator's id. - * - * @return the object's creator's id - */ -const NetworkId TangibleObject::getCreatorId(void) const -{ - if (m_creatorId.get() == NetworkId::cms_invalid) - { - // @todo remove this code when no object has the objvar - // OBJVAR_CREATOR_ID - NetworkId creatorId(NetworkId::cms_invalid); - if (getObjVars().getItem(OBJVAR_CREATOR_ID, creatorId)) - { - const_cast(this)->setCreatorId(creatorId); - return creatorId; - } - } - return m_creatorId.get(); -} // TangibleObject::getCreatorId - -//----------------------------------------------------------------------- - -/** - * Sets the creator id of this object. - * - * @param creatorId the creator id - */ -void TangibleObject::setCreatorId(const NetworkId & creatorId) -{ - if (isAuthoritative()) - { - m_creatorId = creatorId; - if (getObjVars().hasItem(OBJVAR_CREATOR_ID)) - removeObjVarItem(OBJVAR_CREATOR_ID); - } - else - { - sendControllerMessageToAuthServer(CM_setCreatorId, - new MessageQueueGenericValueType(creatorId)); - } -} // TangibleObject::setCreatorId - -//----------------------------------------------------------------------- - -/** - * Returns the id of the object's creator's name. - * - * @return the object's creator's name - */ -const Unicode::String TangibleObject::getCreatorName(void) const -{ - return Unicode::narrowToWide(NameManager::getInstance().getPlayerName( - getCreatorId())); -} // TangibleObject::getCreatorName - -//----------------------------------------------------------------------- - -/** - * Returns the xp amount the creator of this object will get when it is "used". - * - * @return the xp amount - */ -int TangibleObject::getCreatorXp(void) const -{ - int creatorXp=0; - getObjVars().getItem(OBJVAR_CREATOR_XP,creatorXp); - return creatorXp; -} // TangibleObject::getCreatorXp - -//----------------------------------------------------------------------- - -/** - * Sets the xp amount the creator of this object will get when it is "used". - * - * @param xp the xp amount - */ -void TangibleObject::setCreatorXp(int xp) -{ - if (isAuthoritative()) - { - setObjVarItem(OBJVAR_CREATOR_XP, xp); - } - else - { - sendControllerMessageToAuthServer(CM_setCreatorXp, new MessageQueueGenericValueType(xp)); - } -} // TangibleObject::setCreatorXp - -//----------------------------------------------------------------------- - -/** - * Returns the xp type the creator of this object will get when it is "used". - * - * @return the xp type - */ -int TangibleObject::getCreatorXpType(void) const -{ - int creatorXpType = -1; - getObjVars().getItem(OBJVAR_CREATOR_XP_TYPE,creatorXpType); - return creatorXpType; -} // TangibleObject::getCreatorXpType - -//----------------------------------------------------------------------- - -/** - * Sets the xp type the creator of this object will get when it is "used". - * - * @param type the xp type - */ -void TangibleObject::setCreatorXpType(int type) -{ - if (isAuthoritative()) - { - setObjVarItem(OBJVAR_CREATOR_XP_TYPE, type); - } - else - { - sendControllerMessageToAuthServer(CM_setCreatorXpType, new MessageQueueGenericValueType(type)); - } -} // TangibleObject::setCreatorXpType - -//----------------------------------------------------------------------- - -/** - * Returns if this object is a crafting tool or not. - * - * @return true if we are a tool, false if not - */ -bool TangibleObject::isCraftingTool(void) const -{ - return getObjVars().hasItem(OBJVAR_CRAFTING_TOOL); -} // TangibleObject::isCraftingTool - -//----------------------------------------------------------------------- - -/** - * Returns if this object is a crafting station or not. - * - * @return true if we are a station, false if not - */ -bool TangibleObject::isCraftingStation(void) const -{ - return getObjVars().hasItem(OBJVAR_CRAFTING_STATION); -} // TangibleObject::isCraftingStation - -//----------------------------------------------------------------------- - -/** - * Returns if this object is a repair tool or not. - * - * @return true if we are a repair tool, false if not - */ -bool TangibleObject::isRepairTool(void) const -{ - return getObjVars().hasItem(OBJVAR_REPAIR_TOOL); -} // TangibleObject::isRepairTool - -//----------------------------------------------------------------------- - -/** -* If this is a crafting tool, tries to start a session with a player. -* -* @param crafter the player who wants to craft something -* -* @return true if the session was started, false if not -*/ -bool TangibleObject::startCraftingSession(CreatureObject & crafter) -{ - static const SlotId outputSlotId(SlotIdManager::findSlotId(MANF_OUTPUT_SLOT_NAME)); - - if(isAuthoritative()) - { - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - PlayerObject * crafterPlayer = PlayerCreatureController::getPlayerObject(&crafter); - if (crafterPlayer == NULL) - return false; - - // make sure we are a crafting tool - if (!isCraftingTool()) - { - DEBUG_WARNING(true, ("Tried to start crafting session on non-tool " - "object %s", myIdString)); - return false; - } - - if (isDisabled()) - { - DEBUG_WARNING(true, ("Tried to start crafting session on disabled " - "tool %s", myIdString)); - return false; - } - - // make sure the tool isn't creating a prototype - float realTimeVar = 0; - getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME,realTimeVar); - if (realTimeVar > 0) - { - StringId message("system_msg", "crafting_tool_creating_prototype"); - Unicode::String outOfBand; - Chat::sendSystemMessage(crafter, message, outOfBand); - return false; - } - - // make sure the tool isn't already being used - if (getObjVars().hasItem(OBJVAR_CRAFTING_CRAFTER)) - { - StringId message("system_msg", "crafting_tool_in_use"); - Unicode::String outOfBand; - Chat::sendSystemMessage(crafter, message, outOfBand); - return false; - } - - // make sure the output slot is empty - SlottedContainer const * const slotContainer = ContainerInterface::getSlottedContainer(*this); - if (slotContainer == NULL) - { - DEBUG_WARNING(true, ("Crafting tool %s does not have a container!", myIdString)); - return false; - } - Container::ContainerErrorCode tmp = Container::CEC_Success; - if (slotContainer->getObjectInSlot(outputSlotId, tmp) != Container::ContainedItem::cms_invalid) - { - StringId message("system_msg", "crafting_tool_full"); - Unicode::String outOfBand; - Chat::sendSystemMessage(crafter, message, outOfBand); - return false; - } - - // get the schematics list from the player and filter for the type of - // schematics we can make - int myType = getCraftingType(); - - bool sendComplexities = true; - if (!crafter.isSchematicFilteringEnabled()) - sendComplexities = false; - - std::vector goodSchematics; - std::vector scriptComplexities; - const std::map,int> & schematics = crafter.getDraftSchematics(); - std::map,int>::const_iterator iter; - for (iter = schematics.begin(); iter != schematics.end(); ++iter) - { - const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic((*iter).first.first); - if (schematic != NULL && ((myType & ServerObjectTemplate::CT_genericItem) != 0 || - ((schematic->getCategory() & myType) != 0))) - { - // make sure the player has all the skill commands needed for the - // schematic - int skillCount = schematic->getSkillCommandsCount(); - int i; - for (i = 0; i < skillCount; ++i) - { - if (!crafter.hasCommand(schematic->getSkillCommands(i))) - break; - } - if (i == skillCount) - { - goodSchematics.push_back((*iter).first.first); - if (sendComplexities) - scriptComplexities.push_back(schematic->getComplexity()); - else - scriptComplexities.push_back(1.0f); - } - } - } - - crafterPlayer->setCraftingTool(*this); - - if (goodSchematics.size() > 0) - { - ScriptParams params; - params.addParam(crafter.getNetworkId()); - params.addParam(goodSchematics); - params.addParam(scriptComplexities); - if (getScriptObject()->trigAllScripts(Scripting::TRIG_REQUEST_DRAFT_SCHEMATICS, params) != SCRIPT_CONTINUE) - { - std::vector empty; - crafterPlayer->sendUseableDraftSchematics (empty); - crafterPlayer->stopCrafting(true); - - return false; - } - setObjVarItem(OBJVAR_CRAFTING_CRAFTER, crafter.getNetworkId()); - } - else - { - std::vector empty; - crafterPlayer->sendUseableDraftSchematics (empty); - crafterPlayer->stopCrafting(true); - - StringId message("system_msg", "no_valid_schematics"); - Unicode::String outOfBand; - Chat::sendSystemMessage(crafter, message, outOfBand); - return false; - } - - // the following section to send the ingredients to the player is only needed for - // testing crafting via the console -#ifdef _DEBUG - - // send the player info about the ingredients in the tool's hopper; - // the actual sending of the messages could be spread out over a few - // frames -// listIngredientsInHopper(crafter); -#endif - } - else - { - sendControllerMessageToAuthServer(CM_startCraftingSession, new MessageQueueGenericValueType(crafter.getNetworkId())); - } - return true; -} // TangibleObject::startCraftingSession - -//----------------------------------------------------------------------- - -/** - * If this is a crafting tool, tries to stop a session with a player. - * - * @return true if the session was stopped, false if not - */ -bool TangibleObject::stopCraftingSession(void) -{ - if (isAuthoritative()) - { - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool()) - { - DEBUG_WARNING(true, ("Tried to stop crafting session on non-tool " - "object %s", myIdString)); - return false; - } - - // make sure a prototype object isn't being made (the session will be - // stopped when the prototype is done) - float realTimeVar = 0; - if (getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME, realTimeVar) && realTimeVar > 0) - return false; - - // make sure the tool isn't already being used - NetworkId crafterId; - if (!getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER,crafterId)) - { - DEBUG_REPORT_LOG(true, ("Crafting tool %s in not in use\n", myIdString)); - return false; - } - - clearCraftingManufactureSchematic(); - clearCraftingPrototype(); - removeObjVarItem(OBJVAR_CRAFTING_CRAFTER); - } - else - { - sendControllerMessageToAuthServer(CM_stopCraftingSession, 0); - } - return true; -} // TangibleObject::stopCraftingSession - -//----------------------------------------------------------------------- - -/** - * Test to see if an object is in a crafting tool's ingredient hopper. - * - * @param ingredientId object we want to test - * - * @return true if the object is in the hopper, false if not - */ -bool TangibleObject::isIngredientInHopper(const NetworkId & ingredientId) const -{ - ServerObject const * const hopper = getIngredientHopper(); - if (hopper == NULL) - return false; - - Object const * const ingredient = CachedNetworkId(ingredientId).getObject(); - if (ingredient == NULL) - return false; - - return ContainerInterface::isNestedWithin(*ingredient, getNetworkId()); -} // TangibleObject::isIngredientInHopper - -//----------------------------------------------------------------------- - -/** - * Returns this crafting station's ingredient hopper. - * - * @return the hopper - */ -ServerObject * TangibleObject::getIngredientHopper(void) const -{ -static const SlotId hopperSlotId(SlotIdManager::findSlotId(INGREDIENT_HOPPER_SLOT_NAME)); - - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting station - if (!isCraftingStation()) - { - DEBUG_WARNING(true, ("Tried to get input hopper for non-crafting station " - "object %s", myIdString)); - return NULL; - } - - // get the ingredient hopper - SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); - if (container == NULL) - { - DEBUG_WARNING(true, ("Crafting tool %s does not have a container!", myIdString)); - return NULL; - } - Container::ContainerErrorCode tmp = Container::CEC_Success; - Container::ContainedItem hopperId = container->getObjectInSlot(hopperSlotId, tmp); - if (hopperId == NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Crafting tool %s does not have a ingredient " - "hopper!", myIdString)); - return NULL; - } - ServerObject * hopper = safe_cast(hopperId.getObject()); - if (hopper == NULL) - { - DEBUG_WARNING(true, ("Can't find object for ingredient hopper id %s", - hopperId.getValueString().c_str())); - return NULL; - } - - return hopper; -} // TangibleObject::getIngredientHopper - -//---------------------------------------------------------------------- - -/** - * Adds an object to this tool's output slot. - * - * @param object the object to add - * @param transferer who is transferring the ingredient - * - * @return true on success, false on fail - */ -bool TangibleObject::addObjectToOutputSlot(ServerObject & object, - ServerObject * transferer) -{ -static const SlotId outputSlotId(SlotIdManager::findSlotId(MANF_OUTPUT_SLOT_NAME)); - - if(isAuthoritative()) - { - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // get output slot - SlottedContainer const * const slotContainer = ContainerInterface::getSlottedContainer(*this); - if (slotContainer == NULL) - { - DEBUG_WARNING(true, ("Crafting tool %s does not have a container!", myIdString)); - return false; - } - - // make sure the transferer is in the final stage of crafting - if (transferer == NULL) - { - DEBUG_WARNING(true, ("addObjectToOutputSlot, NULL transferer")); - return false; - } - NetworkId crafterVarId(NetworkId::cms_invalid); - if (!getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER, crafterVarId)) - { - // @todo: send a message to the player saying this tool is in use - DEBUG_WARNING(true, ("addObjectToOutputSlot, crafting tool %s has " - "no crafter", myIdString)); - return false; - } - if (crafterVarId != transferer->getNetworkId()) - { - DEBUG_WARNING(true, ("addObjectToOutputSlot, transferer %s is not the " - "crafter %s", transferer->getNetworkId().getValueString().c_str(), - crafterVarId.getValueString().c_str())); - return false; - } - CreatureObject const * const creatureTransferer = transferer->asCreatureObject(); - if (creatureTransferer == NULL) - { - DEBUG_WARNING(true, ("addObjectToOutputSlot, transferer %s is not a " - "creature", transferer->getNetworkId().getValueString().c_str())); - return false; - } - PlayerObject const * const creaturePlayer = PlayerCreatureController::getPlayerObject(creatureTransferer); - if (creaturePlayer == NULL) - return false; - - if (creaturePlayer->getCraftingStage() != Crafting::CS_finish) - { - DEBUG_WARNING(true, ("addObjectToOutputSlot, crafter %s is in the " - "wrong stage %d", transferer->getNetworkId().getValueString().c_str(), - static_cast(creaturePlayer->getCraftingStage()))); - return false; - } - - // if the object is our prototype, clear the prototype - if (getSynchronizedUi() != NULL) - { - CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync != NULL) - { - if (sync->getPrototype() == object.getNetworkId()) - { - sync->setPrototype(CachedNetworkId::cms_cachedInvalid); - } - } - } - - // put the object in the slot - Container::ContainerErrorCode tmp = Container::CEC_Success; - if (!ContainerInterface::transferItemToSlottedContainer(*this, object, outputSlotId, NULL, tmp)) - { - DEBUG_WARNING(true, ("Failed to transfer object %s to crafting " - "tool %s", object.getNetworkId().getValueString().c_str(), - myIdString)); - return false; - } - } - else - { - NetworkId transfererId; - if(transferer) - transfererId = transferer->getNetworkId(); - - sendControllerMessageToAuthServer(CM_addObjectToOutputSlot, new MessageQueueGenericValueType >(std::make_pair(object.getNetworkId(), transfererId))); - } - - return true; -} // TangibleObject::addObjectToOutputSlot - -//---------------------------------------------------------------------- - -/** - * Gets the temporary manufacturing schematic used during a crafting session. - * - * @return the schematic - */ -ManufactureSchematicObject * TangibleObject::getCraftingManufactureSchematic(void) const -{ - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool()) - { - DEBUG_WARNING(true, ("Tried to get non-crafting tool " - "object %s", myIdString)); - return NULL; - } - - SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); - if (container) - { - Container::ContainerErrorCode error; - const CachedNetworkId & schematicId = - container->getObjectInSlot(getCraftingManufactureSchematicSlotId(), error); - return safe_cast(schematicId.getObject()); - } - else - { - DEBUG_WARNING(true, ("ManufactureSchematicObject doesn't have a slotted container.")); - return NULL; - } -} // TangibleObject::getCraftingManufactureSchematic - -//---------------------------------------------------------------------- - -/** - * Gives the schematic to the player at the end of the session. - * - * @return the schematic - */ -ManufactureSchematicObject * TangibleObject::removeCraftingManufactureSchematic(void) -{ - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool() || getSynchronizedUi() == NULL) - { - DEBUG_WARNING(true, ("Tried to get non-crafting tool " - "object %s", myIdString)); - return NULL; - } - - CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync == NULL) - return NULL; - - ManufactureSchematicObject * schematic = safe_cast( - sync->getManfSchematic().getObject()); - - sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, - CachedNetworkId::cms_cachedInvalid, false); - - return schematic; -} // TangibleObject::removeCraftingManufactureSchematic - -//---------------------------------------------------------------------- - -/** - * Stores the temporary manufacturing schematic used during crafting in this - * crafting tool. - * - * @param schematic the schematic - */ -void TangibleObject::setCraftingManufactureSchematic(ManufactureSchematicObject & schematic) -{ - if(isAuthoritative()) - { - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool() || getSynchronizedUi() == NULL) - { - DEBUG_WARNING(true, ("Tried to get non-crafting tool " - "object %s", myIdString)); - return; - } - - CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync == NULL) - return; - - // see if there is already a schematic object set - const CachedNetworkId & schematicId = sync->getManfSchematic(); - if (schematicId == schematic.getNetworkId()) - return; - - // remove the old schematic - ServerObject * object = safe_cast(schematicId.getObject()); - if (object == NULL) - { - if (schematicId != NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Can't find object for schematic id %s", - schematicId.getValueString().c_str())); - // go on anyway - } - } - else - { - sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, - CachedNetworkId::cms_cachedInvalid, true); - object->permanentlyDestroy(DeleteReasons::Consumed); - } - - // the schematic isn't in the world or in a container, so we need to - // tell the client about it - int stationBonus = 0; - ServerObject * crafter = NULL; - NetworkId crafterId; - if (getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER,crafterId)) - { - crafter = safe_cast(NetworkIdManager::getObjectById(crafterId)); - } - if (crafter != NULL) - { - sync->setManfSchematic(CachedNetworkId(schematic), CachedNetworkId(*crafter), - true); - - // if the crafter is near a crafting station, get any crafting bonus - // it has - const PlayerObject * player = PlayerCreatureController::getPlayerObject( - crafter->asCreatureObject()); - if (player != NULL && player->getCraftingStation().getObject() != NULL) - { - player->getCraftingStation().getObject()->asServerObject()-> - getObjVars().getItem(OBJVAR_CRAFTING_STATIONMOD, stationBonus); - } - } - else - { - WARNING_STRICT_FATAL(true, ("TangibleObject::setCraftingManufactureSchematic " - "no crafter id on crafting tool %s!", myIdString)); - } - - // set any crafting bonus we give on the schematic - int myBonus = 0; - getObjVars().getItem(OBJVAR_CRAFTING_STATIONMOD, myBonus); - if (myBonus + stationBonus != 0) - { - schematic.setObjVarItem(OBJVAR_CRAFTING_STATIONMOD, myBonus + stationBonus); - } - } - else - { - sendControllerMessageToAuthServer(CM_setCraftingManufactureSchematic, new MessageQueueGenericValueType(schematic.getNetworkId())); - } -} // TangibleObject::setCraftingManufactureSchematic - -//---------------------------------------------------------------------- - -/** - * Removes the temporary manufacturing schematic from the crafting tool and - * deletes it. - */ -void TangibleObject::clearCraftingManufactureSchematic(void) -{ - if(isAuthoritative()) - { - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool()) - { - DEBUG_WARNING(true, ("Tried to get non-crafting tool " - "object %s", myIdString)); - return; - } - - // see if we have a schematic in our schematic slot - CachedNetworkId schematicId = CachedNetworkId::cms_cachedInvalid; - SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); - if (container) - { - Container::ContainerErrorCode error = Container::CEC_Success; - CachedNetworkId schematicId = container->getObjectInSlot( - getCraftingManufactureSchematicSlotId(), error); - } - else - { - DEBUG_WARNING(true, ("failed to get slotted container for schematic lookup.")); - } - - // get our ui - CraftingToolSyncUi * sync = NULL; - if (getSynchronizedUi() != NULL) - sync = dynamic_cast(getSynchronizedUi()); - - if (schematicId == CachedNetworkId::cms_cachedInvalid && sync == NULL) - { - // no schematic - return; - } - - if (schematicId == CachedNetworkId::cms_invalid) - schematicId = sync->getManfSchematic(); - else if (sync != NULL && sync->getManfSchematic() != CachedNetworkId::cms_invalid && - schematicId != sync->getManfSchematic()) - { - WARNING(true, ("TangibleObject::clearCraftingManufactureSchematic " - "crafting tool %s has schematic %s in its slot but schematic %s " - "in its ui!!!", getNetworkId().getValueString().c_str(), - schematicId.getValueString().c_str(), - sync->getManfSchematic().getValueString().c_str())); - if (schematicId.getObject() != NULL) - { - schematicId.getObject()->asServerObject()->permanentlyDestroy( - DeleteReasons::Consumed); - } - else - { - WARNING_STRICT_FATAL(true, ("TangibleObject::clearCraftingManufactureSchematic " - "crafting tool %s has slotted schematic %s with no object!", - getNetworkId().getValueString().c_str(), - schematicId.getValueString().c_str())); - } - schematicId = sync->getManfSchematic(); - } - - // get the schematic - ManufactureSchematicObject * manfSchematic = NULL; - ServerObject * object = safe_cast(schematicId.getObject()); - if (object == NULL && schematicId != CachedNetworkId::cms_invalid) - { - WARNING_STRICT_FATAL(true, ("Can't find object for manufactring schematic " - "id %s", schematicId.getValueString().c_str())); - } - else - manfSchematic = safe_cast(object); - - if (manfSchematic != NULL) - { - NetworkId crafterId; - if (getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER,crafterId)) - { - // if we are at the assembly stage of crafting, or the draft schematic says - // not to destroy the ingredients, put the ingredients in the schematic back - // in the tool - CreatureObject * const crafter = dynamic_cast(NetworkIdManager::getObjectById(crafterId)); - PlayerObject * const crafterPlayer = PlayerCreatureController::getPlayerObject(crafter); - if (!manfSchematic->mustDestroyIngredients() || (crafterPlayer != NULL && - crafterPlayer->getCraftingStage() == Crafting::CS_assembly)) - { - crafterPlayer->setAllowEmptySlot(true); - int count = manfSchematic->getSlotsCount(); - // note this loop is odd because when we clear a slot it may - // actually be removed if it was optional - Crafting::IngredientSlot manfSlot; - for (int i = 0; i < count;) - { - if (manfSchematic->getSlot(i, manfSlot, false)) - { - if (manfSlot.ingredientType != Crafting::IT_none && - !manfSlot.ingredients.empty()) - { - if (crafterPlayer->emptySlot(i, NetworkId::cms_invalid)) - { - if (count != manfSchematic->getSlotsCount()) - { - count = manfSchematic->getSlotsCount(); - continue; - } - } - } - } - ++i; - } - crafterPlayer->setAllowEmptySlot(false); - } - else - manfSchematic->destroyAllIngredients(); - } - } - - if (sync != NULL) - sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, CachedNetworkId::cms_cachedInvalid, true); - if (object != NULL) - { - object->permanentlyDestroy(DeleteReasons::Consumed); - } - } - else - { - sendControllerMessageToAuthServer(CM_clearCraftingManufactureSchematic, 0); - } -} // TangibleObject::clearCraftingManufactureSchematic - -//---------------------------------------------------------------------- - -/** - * Gets the temporary prototype used during a crafting session. May also be used - * to give the prototype to the player at the end of the session. - * - * @return the prototype - */ -ServerObject * TangibleObject::getCraftingPrototype(void) const -{ - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool() || getSynchronizedUi() == NULL) - { - DEBUG_WARNING(true, ("Tried to get non-crafting tool " - "object %s", myIdString)); - return NULL; - } - - const CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync == NULL) - return NULL; - - return safe_cast(sync->getPrototype().getObject()); -} // TangibleObject::getCraftingPrototype - -//---------------------------------------------------------------------- - -/** - * Stores the temporary prototype object used during crafting in this - * crafting tool. - * - * @param prototype the prototype - */ -void TangibleObject::setCraftingPrototype(ServerObject & prototype) -{ - if (isAuthoritative()) - { - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool() || getSynchronizedUi() == NULL) - { - DEBUG_WARNING(true, ("Tried to get non-crafting tool " - "object %s", myIdString)); - return; - } - - CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync == NULL) - return; - - // see if there is already a prototype object set - const CachedNetworkId & prototypeId = sync->getPrototype(); - if (prototypeId == prototype.getNetworkId()) - return; - - // remove the old prototype - ServerObject * object = safe_cast(prototypeId.getObject()); - if (object == NULL) - { - if (prototypeId != NetworkId::cms_invalid) - { - DEBUG_WARNING(true, ("Can't find object for prototype id %s", - prototypeId.getValueString().c_str())); - // go on anyway - } - } - else - { - sync->setPrototype(CachedNetworkId::cms_cachedInvalid); - object->permanentlyDestroy(DeleteReasons::Consumed); - } - - // put the prototype in the tool's slot so the crafter will get updates - // about it - Container::ContainerErrorCode tmp = Container::CEC_Success; - if (!ContainerInterface::transferItemToSlottedContainer(*this, prototype, - getCraftingPrototypeSlotId(), NULL, tmp)) - { - // see if there is something in the slot, and delete it if there is - bool failed = true; - SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); - NOT_NULL(container); - const Container::ContainedItem & oldItem = container->getObjectInSlot( - getCraftingPrototypeSlotId(), tmp); - if (oldItem != prototype.getNetworkId()) - { - if (oldItem.getObject() != NULL) - { - safe_cast(oldItem.getObject())->permanentlyDestroy( - DeleteReasons::Consumed); - // try the transfer again - if (ContainerInterface::transferItemToSlottedContainer(*this, - prototype, getCraftingPrototypeSlotId(), NULL, tmp)) - { - failed = false; - } - } - if (failed) - { - DEBUG_WARNING(true, ("Failed to transfer prototype %s to crafting " - "tool %s", prototype.getNetworkId().getValueString().c_str(), - myIdString)); - return; - } - } - } - - sync->setPrototype(CachedNetworkId(prototype)); - } - else - { - sendControllerMessageToAuthServer(CM_setCraftingPrototype, new MessageQueueGenericValueType(prototype.getNetworkId())); - } -} // TangibleObject::setCraftingPrototype - -//---------------------------------------------------------------------- - -/** - * Removes the temporary prototype from the crafting tool and - * deletes it. - */ -void TangibleObject::clearCraftingPrototype(void) -{ - if(isAuthoritative()) - { - const std::string myId(getNetworkId().getValueString()); - const char * myIdString = myId.c_str(); - UNREF(myIdString); // needed for release mode - - // make sure we are a crafting tool - if (!isCraftingTool() || getSynchronizedUi() == NULL) - { - DEBUG_WARNING(true, ("Tried to get non-crafting tool " - "object %s", myIdString)); - return; - } - - CraftingToolSyncUi * sync = dynamic_cast( - getSynchronizedUi()); - if (sync == NULL) - return; - - const CachedNetworkId & prototypeId = sync->getPrototype(); - ServerObject * object = safe_cast(prototypeId.getObject()); - if (object != NULL) - { - object->permanentlyDestroy(DeleteReasons::Consumed); - } - else - { - // double-check the prototype slot to make sure nothing is in it - SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); - NOT_NULL(container); - Container::ContainerErrorCode error; - const Container::ContainedItem & contents = container->getObjectInSlot( - getCraftingPrototypeSlotId(), error); - if (contents.getObject() != NULL) - { - safe_cast(contents.getObject())->permanentlyDestroy( - DeleteReasons::Consumed); - } - - } - sync->setPrototype(CachedNetworkId::cms_cachedInvalid); - } - else - { - sendControllerMessageToAuthServer(CM_clearCraftingPrototype, 0); - } -} // TangibleObject::clearCraftingPrototype - -// ---------------------------------------------------------------------- - -/** - * Sets the visible component string for this object. Note m_components is - * write-only on the server because this variable exists only to provide - * visual data to the client. - * - * @param components component table ids of visible components attached to this object - */ -void TangibleObject::setVisibleComponents(const std::vector & components) -{ - if(isAuthoritative()) - { - m_components.clear (); - - for (uint i = 0; i < components.size (); ++i) - m_components.insert(components [i]); - } - else - { - sendControllerMessageToAuthServer(CM_setVisibleComponents, new MessageQueueGenericValueType >(components)); - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::forceExecuteCommand(Command const &command, NetworkId const &targetId, Unicode::String const ¶ms, Command::ErrorCode &status, bool commandIsFromCommandQueue) -{ - if (!isAuthoritative()) - { - Controller *controller = getController(); - if (controller) - { - safe_cast(controller)->appendMessage( - CM_commandQueueForceExecuteCommandFwd, - 0.0f, - new MessageQueueCommandQueueForceExecuteCommandFwd(command.m_commandHash, targetId, params, status, commandIsFromCommandQueue), - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_SERVER); - } - return; - } - - if (status == Command::CEC_Success && ConfigServerGame::getLogAllCommands()) - { - LOGU( - "Command", - ("%s>%s %s", - getNetworkId().getValueString().c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str()), - params); - } - - if (getClient() && getClient()->isGod()) - { - CreatureObject* creatureObject = asCreatureObject(); - if (creatureObject) - { - LOGU( - "CustomerService", - ("Avatar: %s executed command: (%s) %s", - PlayerObject::getAccountDescription(creatureObject).c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str()), - params); - } - } - - if (getObjVars().hasItem("cheater")) - { - CreatureObject* creatureObject = asCreatureObject(); - if (creatureObject) - { - LOGU( - "CustomerService", - ("SuspectedCheaterChannel: %s executed command: (%s) %s", - PlayerObject::getAccountDescription(creatureObject).c_str(), - targetId.getValueString().c_str(), - command.m_commandName.c_str()), - params); - } - } - - PROFILER_BLOCK_DEFINE(profileBlockCommandIsFromCommandQueue, "TangibleObject::forceExecuteCommand commandIsFromCommandQueue"); - if (commandIsFromCommandQueue) - PROFILER_BLOCK_ENTER(profileBlockCommandIsFromCommandQueue); - - // attach temp script - bool needDetach = false; - if (command.m_tempScript.length()) - { - int ret = getScriptObject()->attachScript(command.m_tempScript, true); - if (ret != SCRIPT_OVERRIDE) - needDetach = true; - } - - // do script call - bool commandOverride = false; - if (status == Command::CEC_Success) - { - if (!command.m_scriptHook.empty()) - { - ScriptParams scriptParams; - scriptParams.addParam(targetId); - scriptParams.addParam(params); - scriptParams.addParam(command.m_defaultTime); - if (getScriptObject()->callScriptCommandHandler(command.m_scriptHook, scriptParams) == SCRIPT_OVERRIDE) - commandOverride = true; - } - } - else - { - if (!command.m_failScriptHook.empty()) - { - ScriptParams scriptParams; - scriptParams.addParam(targetId); - scriptParams.addParam(params); - scriptParams.addParam(command.m_defaultTime); - if (getScriptObject()->callScriptCommandHandler(command.m_failScriptHook, scriptParams) == SCRIPT_OVERRIDE) - { - commandOverride = true; - // an override in a failure script handler should mean to mark it as a success (used for standing from feign death) - status = Command::CEC_Success; - } - } - } - - // detach temp scripts - if (needDetach) - getScriptObject()->detachScript(command.m_tempScript); - - if ( commandOverride && commandIsFromCommandQueue ) - { - CommandQueue * const queue = getCommandQueue(); - - if (queue != NULL) - { - queue->cancelCurrentCommand(); - } - } - - // do c function call if not overridden by script - if (!commandOverride) - { - if (status == Command::CEC_Success) - { - if (command.m_cppHook) - (*command.m_cppHook)(command, getNetworkId(), targetId, params); - } - else - { - if (command.m_failCppHook) - (*command.m_failCppHook)(command, getNetworkId(), targetId, params); - } - } - - if (commandIsFromCommandQueue) - PROFILER_BLOCK_LEAVE(profileBlockCommandIsFromCommandQueue); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setCondition(int condition) -{ - if (isAuthoritative()) - m_condition = (m_condition.get() | condition); - else - sendControllerMessageToAuthServer(CM_setCondition, new MessageQueueGenericValueType(condition)); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::clearCondition(int condition) -{ - if (isAuthoritative()) - m_condition = (m_condition.get() & (~condition)); - else - sendControllerMessageToAuthServer(CM_clearCondition, new MessageQueueGenericValueType(condition)); -} - -// ---------------------------------------------------------------------- - -bool TangibleObject::isDisabled() const -{ - return hasCondition(ServerTangibleObjectTemplate::C_disabled); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setDisabled(bool disabled) -{ - if (disabled) - setCondition(ServerTangibleObjectTemplate::C_disabled); - else - clearCondition(ServerTangibleObjectTemplate::C_disabled); -} - -// ---------------------------------------------------------------------- - - -const NetworkId & TangibleObject::getOwnerId() const -{ - return m_ownerId.get(); -} - -// ---------------------------------------------------------------------- - -bool TangibleObject::isOwner(NetworkId const &id, Client const *client) const -{ - if (id == getOwnerId()) - return true; - if (client && client->isGod()) - return true; - return false; -} - -// ---------------------------------------------------------------------- - -/** - * Determine the initial visibility state of an object when it is created. - */ -void TangibleObject::initializeVisibility() -{ - if (isAuthoritative()) - { - const ServerTangibleObjectTemplate * myTemplate = safe_cast< - const ServerTangibleObjectTemplate *>(getObjectTemplate()); - if (myTemplate != NULL) - { - bool visible = false; - for (size_t i = 0; i < myTemplate->getVisibleFlagsCount(); ++i) - { - if (myTemplate->getVisibleFlags(i) == ServerObjectTemplate::VF_player) - { - visible = true; - break; - } - } - setVisible(visible); - } - } - else - { - WARNING(true, ("TangibleObject::initializeVisibility called on non-authoritative object %s", - getNetworkId().getValueString().c_str())); - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setVisible(bool isVisible) -{ - if (isAuthoritative()) - m_visible = isVisible; - else - sendControllerMessageToAuthServer(CM_setVisible, new MessageQueueGenericValueType(isVisible)); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setHidden(bool const hide) -{ - if (isAuthoritative()) - m_hideFromClient = hide; - else - sendControllerMessageToAuthServer(CM_hideFromClient, new MessageQueueGenericValueType(hide)); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::visibilityDataModified() -{ - if (isInWorld()) - { - if (isVisible() && !isHidden()) - { - // show the object - const TriggerVolume * triggerVolume = getTriggerVolume(NetworkTriggerVolumeNamespace::NetworkTriggerVolumeName); - if (triggerVolume != NULL) - { - std::vector observers; - ServerWorld::findPlayerCreaturesInRange(getPosition_w(), triggerVolume->getRadius(), observers); - if (!observers.empty()) - ObserveTracker::onObjectMadeVisibleTo(*this, observers); - } - } - else - { - // hide the object - ObserveTracker::onObjectMadeInvisible(*this); - - // if the object is hidden, show the object to - // players who have passively revealed the object - if (isVisible() && isHidden() && !m_passiveRevealPlayerCharacter.empty()) - { - const TriggerVolume * triggerVolume = getTriggerVolume(NetworkTriggerVolumeNamespace::NetworkTriggerVolumeName); - if (triggerVolume != NULL) - { - std::vector possibleObservers; - ServerWorld::findPlayerCreaturesInRange(getPosition_w(), triggerVolume->getRadius(), possibleObservers); - if (!possibleObservers.empty()) - { - std::vector allowedObservers; - for (std::vector::const_iterator i = possibleObservers.begin(); i != possibleObservers.end(); ++i) - { - if (m_passiveRevealPlayerCharacter.contains((*i)->getNetworkId())) - allowedObservers.push_back(*i); - } - - if (!allowedObservers.empty()) - ObserveTracker::onObjectMadeVisibleTo(*this, allowedObservers); - } - } - } - } - } -} -bool TangibleObject::isVisibleOnClient(Client const &client) const -{ - // Everyone can see visible objects. - // Gods and clients on the buildcluster can see everything. - if (client.isGod() || ConfigServerGame::getBuildCluster() || (isVisible() && !isHidden())) - return true; - - // Invisible objects are visible to a non-god client if the client's - // creature contains (or indirectly contains) the invisible object. - - ServerObject const * const characterObject = client.getCharacterObject(); - - { - for (ServerObject const *o = this; o; o = safe_cast(ContainerInterface::getContainedByObject(*o))) - { - if (o == characterObject) - return true; - if (o->isInWorld() || o->asCellObject()) - break; - } - } - - // Invisible objects are visible to a non-god client if they are in - // the client's character's containment chain. - { - for (ServerObject const *o = characterObject; o; o = safe_cast(ContainerInterface::getContainedByObject(*o))) - if (o == this) - return true; - } - - if (isVisible()) - { - // if the client's character is the owner, then he can see it. - const CachedNetworkId ownerId(getOwnerId()); - if (ownerId == characterObject->getNetworkId()) - return true; - - // if the client's character is grouped with the the owner, then he can see it. - const CreatureObject * owner = safe_cast(ownerId.getObject()); - if (owner != NULL) - { - const GroupObject * group = owner->getGroup(); - if (group != NULL) - { - if (group->isGroupMember(characterObject->getNetworkId())) - return true; - } - } - - // if the client's character has passively revealed the hidden object, then he can see it. - if (m_passiveRevealPlayerCharacter.contains(characterObject->getNetworkId())) - return true; - } - return false; -} - -// ---------------------------------------------------------------------- - -/** - * Tests if this item will encumber a player when equipped. - * - * @return true if the item has encumbrance data - */ -bool TangibleObject::hasEncumbrances() const - { - return getObjVars().hasItem(OBJVAR_ARMOR_BASE + '.' + OBJVAR_ARMOR_ENCUMBRANCE); -} // TangibleObject::hasEncumbrances - -// ---------------------------------------------------------------------- - -/** - * Returns the encumbrance values this object applies to a player when equipped. - * - * @param encumbrances vector to be filled in with encumbrance values for the health, - * action, and mind groups; will be empty if this object does not - * encumber a creature - * - * @return true if encumbrances has good data, false if not - */ -bool TangibleObject::getEncumbrances(std::vector & encumbrances) const - { -static int datatable_type_col = -1; -static int datatable_min_encumbrance_col = -1; -static int datatable_max_encumbrance_col = -1; - - // NOTE: it might be better if we do all this via script, to reduce - // duplicate functionality - - encumbrances.clear(); - - DataTable * dt = DataTableManager::getTable(DATATABLE_ARMOR, true); - if (dt == NULL) - return false; - else if (datatable_type_col == -1) - { - // cache the column indexes - datatable_type_col = dt->findColumnNumber(DATATABLE_TYPE_COL); - datatable_min_encumbrance_col = dt->findColumnNumber(DATATABLE_MIN_ENCUMBRANCE_COL); - datatable_max_encumbrance_col = dt->findColumnNumber(DATATABLE_MAX_ENCUMBRANCE_COL); - if (datatable_type_col < 0 || - datatable_min_encumbrance_col < 0 || - datatable_max_encumbrance_col < 0) - { - WARNING_STRICT_FATAL(true, ("TangibleObject::getEncumbrances: armor datatable missing expected columns")); - return false; - } - } - - // get the encumbrance values from the objvars - float baseEncumbrance = 0; - if (!getObjVars().getItem(OBJVAR_ARMOR_BASE + '.' + OBJVAR_ARMOR_ENCUMBRANCE, baseEncumbrance)) - return false; - std::vector encumbranceSplit; - if (!getObjVars().getItem(OBJVAR_ARMOR_BASE + '.' + OBJVAR_ENCUMBRANCE_SPLIT, encumbranceSplit)) - return false; - if (encumbranceSplit.size() != 3) - return false; - - // get the actual encumbrance range from the armor datatable - int armorLevel; - if (!getObjVars().getItem(OBJVAR_ARMOR_BASE + "." + OBJVAR_ARMOR_LEVEL, armorLevel)) - return false; - char armorLevelRowName[64]; - snprintf(armorLevelRowName, sizeof(armorLevelRowName), "%s%d", DATATABLE_FINAL_ROW.c_str(), armorLevel); - int armorLevelRow = dt->searchColumnInt(datatable_type_col, Crc::calculate(armorLevelRowName)); - if (armorLevelRow < 0) - return false; - int minEncumbrance = dt->getIntValue(datatable_min_encumbrance_col, armorLevelRow); - int maxEncumbrance = dt->getIntValue(datatable_max_encumbrance_col, armorLevelRow); - - // scale the base encumbrance by the actual encumbrance range - baseEncumbrance = baseEncumbrance * (maxEncumbrance - minEncumbrance) + minEncumbrance; - - // split the base encumbrace into the three attrib groups - encumbrances.resize(encumbranceSplit.size()); - std::vector::iterator j = encumbrances.begin(); - for (std::vector::const_iterator i = encumbranceSplit.begin(); i != encumbranceSplit.end(); ++i, ++j) - { - *j = static_cast((*i) * baseEncumbrance); - } - return true; - } - -// ---------------------------------------------------------------------- - -/** - * Returns the slot id of the slot we use to hold temporary crafting prototypes. - * - * @return the prototype slot id - */ -const SlotId & TangibleObject::getCraftingPrototypeSlotId() -{ -static const SlotId prototypeSlotId(SlotIdManager::findSlotId(TEMP_PROTOTYPE_SLOT_NAME)); - - return prototypeSlotId; -} - -// ---------------------------------------------------------------------- - -/** - * Returns the slot id of the slot we use to hold temporary manf schematics. - * - * @return the schematic slot id - */ -const SlotId & TangibleObject::getCraftingManufactureSchematicSlotId() -{ -static const SlotId schematicSlotId(SlotIdManager::findSlotId(TEMP_SCHEMATIC_SLOT_NAME)); - - return schematicSlotId; -} - -// ---------------------------------------------------------------------- - -/** - * Generates an id to allow players to identify a crafted component. NOTE: this - * returns a pointer to a static buffer, so make sure you save off the number - * before calling this function again. - * - * @param id network id that the serial number will be generated from - * - * @return the serial number - */ -const char * TangibleObject::generateSerialNumber(const NetworkId & id) -{ -static char buffer[11] = {'(', 0, 0, 0, 0, 0, 0, 0, 0, ')', 0}; -int i; -char c; -uint64 mask; - -#if defined(WIN32) - uint64 value = (id.getValue() & 0x000000FFFFFFFFFFi64); -#elif defined(linux) - uint64 value = (id.getValue() & 0x000000FFFFFFFFFFULL); -#else -#error unsupported OS -#endif - - for (i = 0; i < 10; ++i) - { - mask = ((value >> 4) | ((value & 0x0F) << 36)); - value ^= mask; - } - - for (i = 1; i < 9; ++i) - { - c = static_cast(value & 0x1F); - value >>= 5; - if (c < 10) - c += '0'; - else - c += ('a' - 10); - buffer[i] = c; - } - return buffer; -} // TangibleObject::generateSerialNumber - -//---------------------------------------------------------------------- - -/** - * Returns the attribute bonuses this object grants when equipped. - * - * @param attribBonuses list to be filled in with the bonuses - */ -void TangibleObject::getAttribBonuses(std::vector > & attribBonuses) const -{ - attribBonuses.clear(); - - DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_ATTRIBUTE_BONUS); - - for (DynamicVariableList::NestedList::const_iterator i = mods.begin(); - i != mods.end(); ++i) - { - int bonus = 0; - i.getValue(bonus); - int attribute = atoi(i.getName().c_str()); - if (isdigit(i.getName()[0]) && attribute >= 0 && - attribute < Attributes::NumberOfAttributes) - { - if (bonus > ConfigServerGame::getMaxItemAttribBonus()) - bonus = ConfigServerGame::getMaxItemAttribBonus(); - else if (bonus < -ConfigServerGame::getMaxItemAttribBonus()) - bonus = -ConfigServerGame::getMaxItemAttribBonus(); - attribBonuses.push_back(std::make_pair(attribute, bonus)); - } - else - { - WARNING(true, ("Object %s has invalid attribute bonus objvar name of %s", - getNetworkId().getValueString().c_str(), i.getName().c_str())); - } - } -} // TangibleObject::getAttribBonuses - -/** - * Returns the attribute bonuses this object grants when equipped. - * - * @param attribBonuses list of length 9 to be filled in with the bonuses - * - * @return true if we have bonuses, false if not - */ -bool TangibleObject::getAttribBonuses(std::vector & attribBonuses) const -{ - attribBonuses.clear(); - attribBonuses.resize(Attributes::NumberOfAttributes, 0); - - bool hasBonues = false; - typedef std::vector > BonusPairs; - BonusPairs pairedBonuses; - getAttribBonuses(pairedBonuses); - for (BonusPairs::const_iterator i = pairedBonuses.begin(); i != pairedBonuses.end(); ++i) - { - int index = (*i).first; - if (index >=0 && index < Attributes::NumberOfAttributes) - { - attribBonuses[index] = (*i).second; - hasBonues = true; - } - } - return hasBonues; -} // TangibleObject::getAttribBonuses - -//---------------------------------------------------------------------- - -/** - * Returns the attribute bonus of this object for a given attribute. - * - * @param attribute the attribute - * - * @return the bonus for the attribute - */ -int TangibleObject::getAttribBonus(int attribute) const -{ - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - return 0; - - DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_ATTRIBUTE_BONUS); - char buffer[8]; - snprintf(buffer, sizeof(buffer), "%d", attribute); - int bonus = 0; - IGNORE_RETURN(mods.getItem(buffer, bonus)); - - if (bonus > ConfigServerGame::getMaxItemAttribBonus()) - bonus = ConfigServerGame::getMaxItemAttribBonus(); - else if (bonus < -ConfigServerGame::getMaxItemAttribBonus()) - bonus = -ConfigServerGame::getMaxItemAttribBonus(); - return bonus; -} - -//---------------------------------------------------------------------- - -/** - * Sets the attribute bonus this object applies when equipped. - * - * @param attribute the attribute - * @param bonus the bonus - */ -void TangibleObject::setAttribBonus(int attribute, int bonus) -{ - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - return; - - char buffer[8]; - snprintf(buffer, sizeof(buffer), "%d", attribute); - if (bonus != 0) - setObjVarItem(OBJVAR_ATTRIBUTE_BONUS + '.' + buffer, bonus); - else - removeObjVarItem(OBJVAR_ATTRIBUTE_BONUS + '.' + buffer); -} - -//---------------------------------------------------------------------- - -/** - * Returns the skill mod bonuses this object grants when equipped. - * - * @param skillModBonuses list to be filled in with the bonuses - */ -void TangibleObject::getSkillModBonuses(std::vector > & skillModBonuses, bool includeCategorizedSkillmod /*= true*/) const -{ - static std::map mapSkillModBonuses; - mapSkillModBonuses.clear(); - - DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_SKILLMOD_BONUS); - for (DynamicVariableList::NestedList::const_iterator i = mods.begin(); - i != mods.end(); ++i) - { - int bonus = 0; - i.getValue(bonus); - - std::string const name = i.getName(); - std::map::iterator iterFind = mapSkillModBonuses.find(name); - if (iterFind != mapSkillModBonuses.end()) - iterFind->second += bonus; - else - IGNORE_RETURN(mapSkillModBonuses.insert(std::make_pair(name, bonus))); - } - - if (includeCategorizedSkillmod) - getCategorizedSkillModBonuses(*this, OBJVAR_CATEGORIZED_SKILLMOD_BONUS, mapSkillModBonuses); - - skillModBonuses.clear(); - for (std::map::const_iterator iterMapSkillModBonuses = mapSkillModBonuses.begin(); iterMapSkillModBonuses != mapSkillModBonuses.end(); ++iterMapSkillModBonuses) - { - if (iterMapSkillModBonuses->second != 0) - skillModBonuses.push_back(std::make_pair(iterMapSkillModBonuses->first, iterMapSkillModBonuses->second)); - } -} // TangibleObject::getSkillModBonuses - -//---------------------------------------------------------------------- - -/** - * Returns the skill mod bonus of this object for a given skill mod. - * - * @param skillMod the skill mod name - * - * @return the bonus for the skill mod - */ -int TangibleObject::getSkillModBonus(const std::string & skillMod, bool includeCategorizedSkillmod /*= true*/) const -{ - DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_SKILLMOD_BONUS); - int value = 0; - IGNORE_RETURN(mods.getItem(skillMod, value)); - - if (includeCategorizedSkillmod) - value += getCategorizedSkillModBonus(*this, OBJVAR_CATEGORIZED_SKILLMOD_BONUS, skillMod); - - return value; -} // TangibleObject::getSkillModBonus - -//---------------------------------------------------------------------- - -/** - * Sets the base skill mod bonus this object applies when equipped. - * - * @param skillMod the skill mod name - * @param bonus the bonus - */ -void TangibleObject::setSkillModBonus(const std::string & skillMod, int bonus) -{ - std::string const skillModObjvar = OBJVAR_SKILLMOD_BONUS + '.' + skillMod; - - if (bonus < 0) - { - setObjVarItem(skillModObjvar, bonus); - return; - } - else if (bonus == 0) - { - removeObjVarItem(skillModObjvar); - return; - } - - int const currentTotalBonus = getSkillModBonus(skillMod); - int const currentBonus = getSkillModBonus(skillMod, false); - if ((currentTotalBonus - currentBonus + bonus) > ConfigServerGame::getMaxObjectSkillModBonus()) - bonus = std::max(0, ConfigServerGame::getMaxObjectSkillModBonus() - currentTotalBonus + currentBonus); - - if (bonus != 0) - setObjVarItem(skillModObjvar, bonus); - else - removeObjVarItem(skillModObjvar); -} // TangibleObject::setSkillModBonus - -//---------------------------------------------------------------------- - -void TangibleObject::setSkillModBonus(const std::string & category, const std::string & skillMod, int bonus) -{ - if (category.empty()) - return; - - std::string const skillModObjvar = OBJVAR_CATEGORIZED_SKILLMOD_BONUS + '.' + category + '.' + skillMod; - if (bonus < 0) - { - setObjVarItem(skillModObjvar, bonus); - return; - } - else if (bonus == 0) - { - removeObjVarItem(skillModObjvar); - return; - } - - int const currentTotalBonus = getSkillModBonus(skillMod); - int currentBonus = 0; - IGNORE_RETURN(getObjVars().getItem(skillModObjvar, currentBonus)); - - if ((currentTotalBonus - currentBonus + bonus) > ConfigServerGame::getMaxObjectSkillModBonus()) - bonus = std::max(0, ConfigServerGame::getMaxObjectSkillModBonus() - currentTotalBonus + currentBonus); - - if (bonus != 0) - setObjVarItem(skillModObjvar, bonus); - else - removeObjVarItem(skillModObjvar); -} // TangibleObject::setSkillModBonus - -//---------------------------------------------------------------------- - -void TangibleObject::removeCategorizedSkillModBonuses(const std::string & category) -{ - if (category.empty()) - return; - - std::string const skillModObjvar = OBJVAR_CATEGORIZED_SKILLMOD_BONUS + '.' + category; - if (getObjVars().hasItem(skillModObjvar) && (getObjVars().getType(skillModObjvar) == DynamicVariable::LIST)) - removeObjVarItem(skillModObjvar); -} - -//---------------------------------------------------------------------- - -/** - * Adds a skill mod bonus to a skill mod socket, if the object has an open socket. - * - * @param skillMod the skill mod name - * @param bonus the bonus - * - * @return true if the bonus was added, false if the object didn't have an open socket - */ -bool TangibleObject::addSkillModSocketBonus(const std::string & skillMod, int bonus) -{ - if (bonus > ConfigServerGame::getMaxSocketSkillModBonus()) - bonus = ConfigServerGame::getMaxSocketSkillModBonus(); - - int sockets = getSkillModSockets(); - if (sockets > 0) - { - int currentBonus = getSkillModBonus(skillMod, false); - - // only apply the bonus if it's greater than the current bonus - /*if (bonus <= currentBonus) // This breaks multi-socketed items, so now we combine all values. - return false;*/ // Not sure if this code was ever hit in the first place. - - setSkillModBonus(skillMod, currentBonus + bonus); - - // trigger scripts - ScriptParams params; - std::vector skillModParam; - skillModParam.push_back(skillMod.c_str()); - std::vector bonusParam; - bonusParam.push_back(bonus); - params.addParam(skillModParam); - params.addParam(bonusParam); - IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SOCKET_USED, params)); - } - return sockets > 0; -} // TangibleObject::addSkillModSocketBonus - -//---------------------------------------------------------------------- - -/** - * Adds multiple skill mod bonuses to a skill mod socket, if the object has an - * open socket. Note that this call will only use up one socket, no matter how - * many bonuses are added. - * - * @param skillModBonuses the bonuses - * - * @return true if the bonus was added, false if the object didn't have an open socket - */ -bool TangibleObject::addSkillModSocketBonuses(const std::vector > & skillModBonuses) -{ - int sockets = getSkillModSockets(); - if (sockets > 0) - { - int i; - int count = skillModBonuses.size(); - std::vector bonusOrder(1, 0); - for (i = 1; i < count; ++i) - { - std::vector::iterator j; - for (j = bonusOrder.begin(); j != bonusOrder.end(); ++j) - { - if (skillModBonuses[i].second > skillModBonuses[*j].second) - { - bonusOrder.insert(j, i); - break; - } - } - if (j == bonusOrder.end()) - bonusOrder.push_back(i); - } - - bool someSucceeded = false; - for (i = 0; i < count; ++i) - { - int index = bonusOrder[i]; - if(addSkillModSocketBonus(skillModBonuses[index].first, - skillModBonuses[index].second)) - someSucceeded = true; - } - if(someSucceeded) - { - setSkillModSockets(sockets - 1); - return true; - } - } - return sockets > 0; -} // TangibleObject::addSkillModSocketBonuses - -//---------------------------------------------------------------------- - -/** - * Returns the number of available skill mod sockets. - * - * @return the number of sockets - */ -int TangibleObject::getSkillModSockets(void) const -{ - int sockets = 0; - - if (getGameObjectType() == SharedObjectTemplate::GOT_misc_container_wearable) - return 0; - - bool const isCybernetic = getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_arm || getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_legs; - - IGNORE_RETURN(getObjVars().getItem(OBJVAR_SKILLMOD_SOCKETS, sockets)); - return isCybernetic ? sockets : std::min(sockets, ConfigServerGame::getMaxSkillModSockets()); -} // TangibleObject::getSkillModSockets - -//---------------------------------------------------------------------- - -/** - * Sets the number of available skill mod sockets. - * - * @param sockets the number of sockets - */ -void TangibleObject::setSkillModSockets(int sockets) -{ - bool const isCybernetic = getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_arm || getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_legs; - - if (sockets > ConfigServerGame::getMaxSkillModSockets() && !isCybernetic) - sockets = ConfigServerGame::getMaxSkillModSockets(); - if (sockets > 0) - setObjVarItem(OBJVAR_SKILLMOD_SOCKETS, sockets); - else - removeObjVarItem(OBJVAR_SKILLMOD_SOCKETS); -} // TangibleObject::setSkillModSockets - -//---------------------------------------------------------------------- - -/** - * Returns the amount of time left before a crafted prototype object will be done. - * - * @return the time left, in secs - */ -int TangibleObject::getCraftingToolPrototypeTime() const -{ - int timeLeft = -1; - float prototypeTime = 0; - getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME,prototypeTime); - - if (prototypeTime > 0) - { - int startTime =0; - if (getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_START_TIME,startTime)) - { - const int currentTime = static_cast(ServerClock::getInstance().getGameTimeSeconds()); - timeLeft = static_cast(prototypeTime + 0.5f) - (currentTime - startTime); - } - } - return timeLeft; -} // TangibleObject::getCraftingToolPrototypeTime - -//---------------------------------------------------------------------- - -void TangibleObject::getAttributesForCraftingTool (AttributeVector & data) const -{ - char valueBuffer[32]; - - static const Unicode::String CRAFT_TOOL_WORKING (Unicode::narrowToWide("@crafting:tool_status_working")); - static const Unicode::String CRAFT_TOOL_FINISHED (Unicode::narrowToWide("@crafting:tool_status_finished")); - static const Unicode::String CRAFT_TOOL_READY (Unicode::narrowToWide("@crafting:tool_status_ready")); - static const SlotId outputSlotId(SlotIdManager::findSlotId(MANF_OUTPUT_SLOT_NAME)); - - float craft_effectiveness = 0.0f; - getObjVars ().getItem(OBJVAR_CRAFTING_STATIONMOD, craft_effectiveness); - snprintf (valueBuffer, sizeof (valueBuffer), "%.2f", craft_effectiveness); - data.push_back (std::make_pair(SharedObjectAttributes::craft_tool_effectiveness, Unicode::narrowToWide(valueBuffer))); - - // add some internal attribs for the crafting station state - - // see if we are making a prototype - - int prototypeTimeLeft = getCraftingToolPrototypeTime(); - if (prototypeTimeLeft > 0) - { - data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_status, CRAFT_TOOL_WORKING)); - _itoa(prototypeTimeLeft, valueBuffer, 10); - data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_time, Unicode::narrowToWide(valueBuffer))); - } - else - { - // see if there is an object in the output hopper - bool hasPrototype = false; - SlottedContainer const * const slotContainer = ContainerInterface::getSlottedContainer(*this); - if (slotContainer != NULL) - { - Container::ContainerErrorCode tmp = Container::CEC_Success; - if (slotContainer->getObjectInSlot(outputSlotId, tmp) != Container::ContainedItem::cms_invalid) - { - hasPrototype = true; - } - } - if (hasPrototype) - data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_status, CRAFT_TOOL_FINISHED)); - else - data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_status, CRAFT_TOOL_READY)); - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::getAttributes(const NetworkId & playerId, AttributeVector &data) const -{ - ServerObject::getAttributes(playerId, data); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::getAttributesForShipComponent (AttributeVector & data) const -{ - ShipComponentData * const componentData = ShipComponentDataManager::create(*this); - if(componentData) - { - componentData->getAttributes(data); - delete componentData; - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::getAttributes(AttributeVector & data) const -{ - ServerObject::getAttributes(data); - - char valueBuffer[32]; - - CreatureObject const * const thisCreature = asCreatureObject(); - - if (!thisCreature) - { - const int maxHit = getMaxHitPoints (); - // Only consider tangible invulnerability rules for this case - if (maxHit > 0 && !TangibleObject::isInvulnerable()) - { - snprintf (valueBuffer, sizeof (valueBuffer), "%d/%d", maxHit - getDamageTaken (), maxHit); - data.push_back (std::make_pair (SharedObjectAttributes::condition, Unicode::narrowToWide (valueBuffer))); - } - - const ServerObjectTemplate * const targetTemplate = safe_cast(getObjectTemplate()); - if (targetTemplate) - { - bool playerCanMove = false; - - for (size_t i = 0; i < targetTemplate->getMoveFlagsCount(); ++i) - { - if (targetTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_player) - { - playerCanMove = true; - break; - } - } - - if (getCacheVersion() <= 0 && playerCanMove) - { - snprintf (valueBuffer, sizeof (valueBuffer), "%d", std::max (1, getVolume ())); - data.push_back (std::make_pair (SharedObjectAttributes::volume, Unicode::narrowToWide (valueBuffer))); - } - } - } - - const int got = getGameObjectType (); - - switch (got) - { - case SharedObjectTemplate::GOT_misc_drink: - case SharedObjectTemplate::GOT_misc_food: - case SharedObjectTemplate::GOT_misc_pharmaceutical: - case SharedObjectTemplate::GOT_weapon_ranged_thrown: - case SharedObjectTemplate::GOT_weapon_heavy_misc: - case SharedObjectTemplate::GOT_misc_fishing_bait: - { - const int count = m_count.get (); - if (count) - { - snprintf (valueBuffer, sizeof (valueBuffer), "%d", m_count.get ()); - data.push_back (std::make_pair (SharedObjectAttributes::counter_uses_remaining, Unicode::narrowToWide (valueBuffer))); - } - } - break; - case SharedObjectTemplate::GOT_resource_container_pseudo: - { - int resourceValue = 0; - for (int i = 0; i < Crafting::RA_numResourceAttributes; ++i) - { - - const std::string ovName(OBJVAR_COMPONENT_DATA + "." + - Crafting::getResourceAttributeName(i)); - if (getObjVars().getItem(ovName, resourceValue)) - { - char buffer[24]; - snprintf(buffer, sizeof(buffer), "%i", resourceValue); - data.push_back(std::make_pair(Crafting::getResourceAttributeName(i),Unicode::narrowToWide(buffer))); - } - } - } - break; - default: - break; - } - - const VolumeContainer * const volumeContainer = ContainerInterface::getVolumeContainer (*this); - if (volumeContainer) - { - if (got != SharedObjectTemplate::GOT_misc_factory_crate) - { - const int curVol = volumeContainer->getCurrentVolume (); - const int totVol = volumeContainer->getTotalVolume (); - - if (curVol >= 0 && totVol >= 0) - { - snprintf (valueBuffer, sizeof (valueBuffer), "%d/%d", curVol, totVol); - data.push_back (std::make_pair (SharedObjectAttributes::contents, Unicode::narrowToWide (valueBuffer))); - } - } - } - - std::vector > skillModBonuses; - getSkillModBonuses(skillModBonuses); - if (!skillModBonuses.empty()) - { - char buffer[16]; - int count = skillModBonuses.size(); - for (int i = 0; i < count; ++i) - { - _itoa(skillModBonuses[i].second, buffer, 10); - data.push_back(std::make_pair(SharedObjectAttributes::cat_skill_mod_bonus + "." + "@stat_n:" + skillModBonuses[i].first, Unicode::narrowToWide(buffer))); - } - } - - std::vector attribBonuses; - if (getAttribBonuses(attribBonuses) && !attribBonuses.empty()) - { - char buffer[16]; - int const attribCount = attribBonuses.size(); - for (int attrib = 0; attrib < attribCount; ++attrib) - { - int const bonus = attribBonuses[attrib]; - if (bonus != 0) - { - _itoa(bonus, buffer, 10); - data.push_back(std::make_pair(SharedObjectAttributes::cat_attrib_mod_bonus + "." + "@att_bonus_n:" + s_attributeBonusNames[attrib], Unicode::narrowToWide(buffer))); - } - } - } - - int sockets = getSkillModSockets(); - if (sockets > 0) - { - char buffer[16]; - _itoa(sockets, buffer, 10); - data.push_back(std::make_pair(SharedObjectAttributes::sockets, Unicode::narrowToWide(buffer))); - } - - if (isCraftingTool()) - getAttributesForCraftingTool (data); - - if (getCreatorId() != NetworkId::cms_invalid) - data.push_back(std::make_pair(SharedObjectAttributes::crafter, getCreatorName())); - - if (isCrafted()) - data.push_back(std::make_pair(SharedObjectAttributes::serial_number, Unicode::narrowToWide(generateSerialNumber(getCraftedId())))); - - if(GameObjectTypes::isTypeOf(got, SharedObjectTemplate::GOT_ship_component)) - { - getAttributesForShipComponent(data); - } - - { - // If this is a fake ship component in the interior of a ship, get its attributes from the ship - - ServerObject const * const cell = safe_cast(ContainerInterface::getContainedByObject(*this)); - if (cell && cell->asCellObject()) - { - ServerObject const * const shipAsObject = safe_cast(ContainerInterface::getContainedByObject(*cell)); - if (shipAsObject) - { - ShipObject const * const ship = shipAsObject->asShipObject(); - if (ship) - { - int slot; - if (getObjVars().getItem("intSlot",slot)) - { - ShipComponentData const * const componentData = ship->createShipComponentData(slot); - if (componentData) - { - componentData->getAttributes(data); - delete componentData; - } - } - } - } - } - } - - if (getObjVars().hasItem(OBJVAR_BIO_LINK_ID)) - { - // display the bio-link info - if (getBioLink() == PENDING_BIO_LINK_NETWORK_ID) - { - data.push_back(std::make_pair(SharedObjectAttributes::bio_link, Unicode::narrowToWide("@"+SharedStringIds::bio_link_pending.getCanonicalRepresentation()))); - } - else - { - const std::string & bioLinkName = NameManager::getInstance().getPlayerFullName(getBioLink()); - if (!bioLinkName.empty()) - { - data.push_back(std::make_pair(SharedObjectAttributes::bio_link, Unicode::narrowToWide(bioLinkName))); - } - else - { - LOG("CustomerService", ("Biolink: object %s is flagged as bio-linked " - "to player %s that we can't find a name for", - getNetworkId().getValueString().c_str(), - PlayerObject::getAccountDescription(getBioLink()).c_str())); - data.push_back(std::make_pair(SharedObjectAttributes::bio_link, Unicode::narrowToWide("@"+SharedStringIds::bio_link_unknown.getCanonicalRepresentation()))); - } - } - } - - // No Trade - { - if (markedNoTrade()) - { - data.push_back(std::make_pair(SharedObjectAttributes::no_trade, Unicode::emptyString)); - - if (markedNoTradeShared(true)) - { - data.push_back(std::make_pair(SharedObjectAttributes::no_trade_shared, Unicode::emptyString)); - } - } - else - { - GameScriptObject * const gso = const_cast(getScriptObject()); - if (gso && gso->hasScript(NOMOVE_SCRIPT)) - { - data.push_back(std::make_pair(SharedObjectAttributes::no_trade, Unicode::emptyString)); - - if (markedNoTradeShared(false)) - { - data.push_back(std::make_pair(SharedObjectAttributes::no_trade_shared, Unicode::emptyString)); - } - } - } - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::getAttributesForAuction(AttributeVector &data) const -{ - static const std::string attributeAppearanceData("AppearanceData"); - - DEBUG_FATAL(getAppearanceData().length() > 1000,("Appearance data was more than 1000 characters long, too long to save.")); - data.push_back(std::make_pair(attributeAppearanceData, Unicode::narrowToWide(getAppearanceData()))); - ServerObject::getAttributesForAuction(data); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::showFlyText(const StringId &outputText, float scale, int r, int g, int b) -{ - //-- Get the controller. - Controller *const controller = getController(); - if (!controller) - { - DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); - return; - } - - //-- Send the showFlyText message to all clients. - uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; - if (isPlayerControlled()) - flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; - controller->appendMessage(static_cast(CM_showFlyText), 0.0f, new MessageQueueShowFlyText(getNetworkId(), outputText, scale, r, g, b, 0), flags); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::showFlyText(const Unicode::String &outputTextOOB, float scale, int r, int g, int b) -{ - //-- Get the controller. - Controller *const controller = getController(); - if (!controller) - { - DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); - return; - } - - //-- Send the showFlyText message to all clients. - uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; - if (isPlayerControlled()) - flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; - controller->appendMessage(static_cast(CM_showFlyText), 0.0f, new MessageQueueShowFlyText(getNetworkId(), outputTextOOB, scale, r, g, b, 0), flags); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::showFlyText(const Unicode::String &outputTextOOB, float scale, int r, int g, int b, int flags) -{ - //-- Get the controller. - Controller *const controller = getController(); - if (!controller) - { - DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); - return; - } - - //-- Send the showFlyText message to all clients. - uint32 netFlags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; - if (isPlayerControlled()) - flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; - controller->appendMessage(static_cast(CM_showFlyText), 0.0f, new MessageQueueShowFlyText(getNetworkId(), outputTextOOB, scale, r, g, b, flags), netFlags); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::showCombatText(const TangibleObject & attackerObject, const StringId &outputText, float scale, int r, int g, int b) -{ - //-- Get the controller. - Controller *const controller = getController(); - if (!controller) - { - DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); - return; - } - - //-- Send the showFlyText message to all clients. - uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; - if (isPlayerControlled()) - flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; - controller->appendMessage(static_cast(CM_showCombatText), 0.0f, new MessageQueueShowCombatText(getNetworkId(), attackerObject.getNetworkId(), outputText, scale, r, g, b, 0), flags); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::showCombatText(const TangibleObject & attackerObject, const Unicode::String &outputTextOOB, float scale, int r, int g, int b) -{ - //-- Get the controller. - Controller *const controller = getController(); - if (!controller) - { - DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); - return; - } - - //-- Send the showFlyText message to all clients. - uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; - if (isPlayerControlled()) - flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; - controller->appendMessage(static_cast(CM_showCombatText), 0.0f, new MessageQueueShowCombatText(getNetworkId(), attackerObject.getNetworkId(), outputTextOOB, scale, r, g, b, 0), flags); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::handleCMessageTo(const MessageToPayload &message) -{ - static const std::string methodname_updateCounter = "C++updateCounter"; - - if (message.getMethod() == methodname_updateCounter) - { - if (isCraftingTool()) - { - int timeLeft = getCraftingToolPrototypeTime(); - if (timeLeft <= 0) - { - // done - timeLeft = 0; - } - else - { - // update the count 5 sec from now - MessageToQueue::getInstance().sendMessageToC (getNetworkId(), methodname_updateCounter, std::string (), 5, false); - } - m_count = timeLeft; - } - } - else if (message.getMethod() == "C++UpdatePvp") - { - Pvp::forceStatusUpdate(*this); - } - else if (message.getMethod() == "C++PurgeStructure") - { - LOG("CustomerService",("Purge: Purging structure %s",getNetworkId().getValueString().c_str())); - rollupStructure(NetworkId(message.getDataAsString()),false); - } - else if (message.getMethod() == "C++WarnAboutPurge") - { - LOG("CustomerService",("Purge: Sending warning emails to the admins of structure %s",getNetworkId().getValueString().c_str())); - rollupStructure(NetworkId(message.getDataAsString()),true); - } - else if (message.getMethod() == "C++PurgeVendor") - { - LOG("CustomerService",("Purge: Purging vendor %s",getNetworkId().getValueString().c_str())); - permanentlyDestroy(DeleteReasons::Decay); // Script's onDestroy() method will handle cleanup - } - else if (message.getMethod() == "C++CheckPvpRegion") - { - // check for pvp region change - if (isAuthoritative() && !isInvulnerable() && !isNonPvpObject()) - { - Pvp::checkForRegionChange(*this); - } - - if (isPlayerControlled()) - { - std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); - std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); - if (iterFind != connectedCharacterLfgData.end()) - { - std::string regionName; - std::string playerCityName; - - std::string const & sceneId = ServerWorld::getSceneId(); - Vector const &position = findPosition_w(); - Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(sceneId, position.x, position.z); - if (region != NULL) - regionName = Unicode::wideToNarrow(region->getName()); - - int const cityId = CityInterface::getCityAtLocation(sceneId, static_cast(position.x), static_cast(position.z), 0); - if (cityId > 0) - playerCityName = CityInterface::getCityInfo(cityId).getCityName(); - - if (iterFind->second.locationRegion != regionName) - ServerUniverse::setConnectedCharacterRegionData(getNetworkId(), regionName); - - if (iterFind->second.locationPlayerCity != playerCityName) - ServerUniverse::setConnectedCharacterPlayerCityData(getNetworkId(), playerCityName); - - PlayerObject * const player = PlayerCreatureController::getPlayerObject(asCreatureObject()); - if (player) - player->updateGcwRegionInfo(); - } - } - } - else if (message.getMethod() == "C++ProcessHateOverTime") - { - if (!m_hateOverTime.empty()) - { - std::list expired; - unsigned long const currentGameTime = ServerClock::getInstance().getGameTimeSeconds(); - - for (std::map > >::const_iterator iter = m_hateOverTime.begin(); iter != m_hateOverTime.end(); ++iter) - { - if (iter->second.second.first < currentGameTime) - { - IGNORE_RETURN(addHate(iter->first, iter->second.first * static_cast(std::min(currentGameTime, iter->second.second.second) - iter->second.second.first))); - - if (iter->second.second.second <= currentGameTime) - { - expired.push_back(iter->first); - } - else - { - m_hateOverTime.set(iter->first, std::make_pair(iter->second.first, std::make_pair(currentGameTime, iter->second.second.second))); - } - } - } - - if (!expired.empty()) - { - for (std::list::const_iterator iterExpired = expired.begin(); iterExpired != expired.end(); ++iterExpired) - { - IGNORE_RETURN(m_hateOverTime.erase(*iterExpired)); - } - } - - if (!m_hateOverTime.empty()) - { - MessageToQueue::sendMessageToC(getNetworkId(), "C++ProcessHateOverTime", std::string(), 1, false); - } - } - } - else if (message.getMethod() == "C++DestroyDupedTcg5AtAtHeadItv") - { - LOG("CustomerService",("VeteranRewards: destroying duped tcg5_atat_head_itv item (%s) owned by (%s)", getNetworkId().getValueString().c_str(), getOwnerId().getValueString().c_str())); - permanentlyDestroy(DeleteReasons::Replaced); - } - else - ServerObject::handleCMessageTo(message); -} - -//---------------------------------------------------------------------- - -CustomizationData *TangibleObject::fetchCustomizationData () -{ - CustomizationDataProperty * const cdprop = safe_cast(getProperty (CustomizationDataProperty::getClassPropertyId())); - return cdprop ? cdprop->fetchCustomizationData () : 0; -} - -//---------------------------------------------------------------------- - -const CustomizationData *TangibleObject::fetchCustomizationData () const -{ - const CustomizationDataProperty * const cdprop = safe_cast(getProperty (CustomizationDataProperty::getClassPropertyId())); - return cdprop ? cdprop->fetchCustomizationData () : 0; -} - -// ---------------------------------------------------------------------- - -void TangibleObject::calcPvpableState() -{ - // a tangible is pvpable if it has hit points, has a shared template, does not have an arrangement descriptor, and is not player movable - // or m_attackableOverride is true - if (m_attackableOverride.get()) - { - setPvpable(true); - return; - } - - setPvpable(false); - if (getMaxHitPoints() && getSharedTemplate() && !getSharedTemplate()->getArrangementDescriptor()) - { - ServerObjectTemplate const *objTemplate = safe_cast(getObjectTemplate()); - for (size_t i = 0; i < objTemplate->getMoveFlagsCount(); ++i) - if (objTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_player) - return; - setPvpable(true); - } -} - -// ---------------------------------------------------------------------- - -bool TangibleObject::isInvulnerable() const -{ - return hasCondition(ServerTangibleObjectTemplate::C_invulnerable); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setInvulnerable(bool invulnerable) -{ - if (invulnerable) - { - setCondition(ServerTangibleObjectTemplate::C_invulnerable); - } - else - { - clearCondition(ServerTangibleObjectTemplate::C_invulnerable); - } - - GameScriptObject * const gameScriptObject = getScriptObject(); - - if (gameScriptObject != NULL) - { - ScriptParams scriptParams; - scriptParams.addParam(hasCondition(ServerTangibleObjectTemplate::C_invulnerable)); - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_INVULNERABLE_CHANGED, scriptParams)); - } -} - -// ---------------------------------------------------------------------- - -bool TangibleObject::isInsured(void) const -{ - return hasCondition(ServerTangibleObjectTemplate::C_insured); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setInsured(bool insured) -{ - if (insured) - setCondition(ServerTangibleObjectTemplate::C_insured); - else - clearCondition(ServerTangibleObjectTemplate::C_insured); -} - -// ---------------------------------------------------------------------- - -bool TangibleObject::isUninsurable(void) const -{ - return hasCondition(ServerTangibleObjectTemplate::C_uninsurable); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setUninsurable(bool uninsurable) -{ - if (uninsurable) - setCondition(ServerTangibleObjectTemplate::C_uninsurable); - else - clearCondition(ServerTangibleObjectTemplate::C_uninsurable); -} - -// ---------------------------------------------------------------------- - -bool TangibleObject::wantSawAttackTriggers() const -{ - if (isAuthoritative()) - return hasCondition(ServerTangibleObjectTemplate::C_wantSawAttackTrigger); - return false; -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setWantSawAttackTriggers(bool enable) -{ - if (enable) - setCondition(ServerTangibleObjectTemplate::C_wantSawAttackTrigger); - else - clearCondition(ServerTangibleObjectTemplate::C_wantSawAttackTrigger); -} - -//---------------------------------------------------------------------- - -int TangibleObject::getCombatSkeleton() const -{ - return static_cast((safe_cast(getObjectTemplate()))->getCombatSkeleton()); -} // TangibleObject::getCombatSkeleton() - -//----------------------------------------------------------------------- - -bool TangibleObject::canDropInWorld() const -{ - return true; -} - -//------------------------------------------------------------------------------------------ - -int TangibleObject::getNumberOfLots() const -{ - -//-- fetch the shared object template - const SharedTangibleObjectTemplate* const tangibleObjectTemplate = safe_cast (getSharedTemplate()); - if (!tangibleObjectTemplate) - { - return 0; - } - - //-- get the structure footprint - const StructureFootprint* const structureFootprint = tangibleObjectTemplate->getStructureFootprint (); - if (!structureFootprint) - { - return 0; - } - - //-- return the number of lots - return structureFootprint->getNumberOfStructureReservations (); -} - -//------------------------------------------------------------------------------------------ - -bool TangibleObject::isOnAdminList(const CreatureObject& player) const -{ - //shortcut for owners - if (getOwnerId() == player.getNetworkId()) - return true; - - if(player.getClient() && player.getClient()->isGod()) - return true; - - // In script, the admin list is stored as a list of strings. - // The format of the list is: - // 1) All player are stored as network IDs represented as a string - // 2) All guilds are stored as guild IDs represted as a string and prefixed with "guild:" - - typedef stdvector::fwd StringVector; - static StringVector sv; - sv.clear (); - - if (getObjVars().getItem("player_structure.admin.adminList", sv)) - { - const NetworkId requestorNetworkId = player.getNetworkId(); - - // Convert the network ID to a Unicode string - Unicode::String requestorNetworkIdString = Unicode::narrowToWide( requestorNetworkId.getValueString() ); - - // Try to match the string - for (StringVector::const_iterator it = sv.begin(); it != sv.end(); ++it) - { - const Unicode::String & adminString = *it; - if (Unicode::caseInsensitiveCompare(adminString, requestorNetworkIdString)) - { - return true; - } - } - } - - return false; -} - -//------------------------------------------------------------------------------------------ - -bool TangibleObject::isOnHopperList(const CreatureObject& player) const -{ - if (getOwnerId() == player.getNetworkId()) - return true; - - if(player.getClient() && player.getClient()->isGod()) - return true; - - // In script, the hopper list is stored as a list of strings. - // The format of the list is: - // 1) All player are stored as network IDs represented as a string - // 2) All guilds are stored as guild IDs represted as a string and prefixed with "guild:" - - typedef stdvector::fwd StringVector; - static StringVector sv; - sv.clear (); - - if (getObjVars().getItem("player_structure.hopper.hopperList", sv)) - { - const NetworkId requestorNetworkId = player.getNetworkId(); - - // Convert the network ID to a Unicode string - Unicode::String requestorNetworkIdString = Unicode::narrowToWide( requestorNetworkId.getValueString() ); - - // Try to match the string - for (StringVector::const_iterator it = sv.begin(); it != sv.end(); ++it) - { - const Unicode::String & adminString = *it; - if (Unicode::caseInsensitiveCompare(adminString, requestorNetworkIdString)) - { - return true; - } - } - } - return false; -} - -// ---------------------------------------------------------------------- - -bool TangibleObject::isCustomizationDataModified() const -{ - return getLocalFlag(LocalObjectFlags::TangibleObject_CustomizationDataModified); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setCustomizationDataModified(bool modified) -{ - setLocalFlag(LocalObjectFlags::TangibleObject_CustomizationDataModified, modified); - scheduleForAlter(); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setPvpable(bool pvpable) -{ - bool oldPvpable = !isNonPvpObject(); - setLocalFlag(LocalObjectFlags::TangibleObject_Pvpable, pvpable); - - if ((oldPvpable != pvpable) && !getObservers().empty()) - { - // did the object's "pvp sync" status change because of the Pvpable change? - bool const wasPvpSync = PvpUpdateObserver::satisfyPvpSyncCondition(!oldPvpable, hasCondition(ServerTangibleObjectTemplate::C_invulnerable), (asCreatureObject() != NULL), getPvpFaction()); - bool const isPvpSync = PvpUpdateObserver::satisfyPvpSyncCondition(!pvpable, hasCondition(ServerTangibleObjectTemplate::C_invulnerable), (asCreatureObject() != NULL), getPvpFaction()); - - if (wasPvpSync != isPvpSync) - { - // force pvp status update - Pvp::forceStatusUpdate(*this); - - const std::set &observers = getObservers(); - for (std::set::const_iterator i = observers.begin(); i != observers.end(); ++i) - { - if (isPvpSync) - (*i)->addObservingPvpSync(this); - else - (*i)->removeObservingPvpSync(this); - } - } - } - - if (isAuthoritative()) - { - if (pvpable && !oldPvpable) - MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++CheckPvpRegion", std::string(), static_cast(getPvpRegionCheckTime())); - else if (!pvpable && oldPvpable) - MessageToQueue::cancelRecurringMessageTo(getNetworkId(), "C++CheckPvpRegion"); - } -} - -// ---------------------------------------------------------------------- - -int TangibleObject::getInterestRadius() const -{ - if (isPlayerControlled()) - return ConfigServerGame::getPlayerInterestRange(); - ServerTangibleObjectTemplate const *myTemplate = safe_cast(getObjectTemplate()); - return myTemplate->getInterestRadius(); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::getRequiredCertifications(std::vector & results) const -{ - const SharedTangibleObjectTemplate *const sharedObjectTemplate = safe_cast(getSharedTemplate()); - if (sharedObjectTemplate) - { - const int numRequired = sharedObjectTemplate->getCertificationsRequiredCount(); - for(int i=0; igetCertificationsRequired(i)); - } - } -} - -// ====================================================================== - -void TangibleObject::MaxHitPointsCallback::modified(TangibleObject &target, int oldValue, int value, bool) const -{ - // if the values actually changed, and if it changed from 0 or to 0, then we need to recalculate pvp state - if ((oldValue != value) && ((oldValue == 0) || (value == 0))) - { - bool oldNonPvpState = target.isNonPvpObject(); - target.calcPvpableState(); - - // if pvp state changed, need to update clients - if (oldNonPvpState != target.isNonPvpObject()) - Pvp::forceStatusUpdate(target); - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::AttackableOverrideCallback::modified(TangibleObject &target, bool oldValue, bool value, bool) const -{ - // if the values actually changed, then we need to recalculate pvp state - if (oldValue != value) - { - bool oldNonPvpState = target.isNonPvpObject(); - target.calcPvpableState(); - - // if pvp state changed, need to update clients - if (oldNonPvpState != target.isNonPvpObject()) - Pvp::forceStatusUpdate(target); - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::AppearanceDataCallback::modified(TangibleObject &target, const std::string &oldValue, const std::string &value, bool isLocal) const -{ - UNREF(isLocal); - - //-- Log any time an authoritative, player-controlled object has customizations set to the empty string. - // This most likely is something very wrong since the player is going to get reset to default cusotmizations. - if (value.empty() && !oldValue.empty()) - { - if (target.isPlayerControlled() && target.isAuthoritative()) - { - std::string const oldAppearanceDataDump = CustomizationData::makeSelectDumpFormat(oldValue.c_str()); - LOG("customization-data-loss", ("non-empty old customization data getting wiped, id=[%s],template=[%s],old m_appearanceData in SELECT DUMP format:[%s]", target.getNetworkId().getValueString().c_str(), target.getObjectTemplateName(), oldAppearanceDataDump.c_str() )); - } - } - - //-- Notify the object that its appearance data has been modified. - target.appearanceDataModified(value); - - Object * const objectContainer = ContainerInterface::getContainedByObject(target); - ServerObject * const serverContainer = objectContainer ? objectContainer->asServerObject() : NULL; - TangibleObject * const tangibleContainer = serverContainer ? serverContainer->asTangibleObject() : NULL; - if(tangibleContainer) - tangibleContainer->onContainedItemAppearanceDataModified(target, oldValue, value); -} - -// ---------------------------------------------------------------------- - -void TangibleObject::onContainedItemAppearanceDataModified(TangibleObject const & , std::string const & , std::string const & ) -{ - //do nothing. Tangibles don't care if their contained objects have their appearance data change -} - -// ---------------------------------------------------------------------- - -void TangibleObject::getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const -{ - if(name == "customAppearance") - { - m_customAppearance.pack(target); - } - else if(name == "appearanceData") - { - m_appearanceData.pack(target); - } - else if(name == "incubatorResourceData") - { - std::string resourceData; - - static const uint32 crcIncubator = CrcLowerString::calculateCrc("object/tangible/crafting/station/incubator_station.iff"); - if (getTemplateCrc() == crcIncubator) - { - DynamicVariableList const & objvars = getObjVars(); - if (objvars.hasItem("power.name") && (DynamicVariable::STRING == objvars.getType("power.name"))) - { - std::string resourceName; - IGNORE_RETURN(objvars.getItem("power.name", resourceName)); - - ResourceTypeObject const * const rto = ServerUniverse::getInstance().getResourceTypeByName(resourceName); - if (rto && !rto->getParentClass().isRecycled() && !rto->getParentClass().isPermanent()) - resourceData = rto->getResourceTypeDataForExport(); - } - } - - Archive::put(target, resourceData); - } - else - { - ServerObject::getByteStreamFromAutoVariable(name, target); - } -} - -// ---------------------------------------------------------------------- - -void TangibleObject::setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source) -{ - Archive::ReadIterator ri(source); - if(name == "customAppearance") - { - m_customAppearance.unpackDelta(ri); - } - else if(name == "appearanceData") - { - m_appearanceData.unpackDelta(ri); - } - else if(name == "incubatorResourceData") - { - std::string resourceData; - Archive::get(ri, resourceData); - - static const uint32 crcIncubator = CrcLowerString::calculateCrc("object/tangible/crafting/station/incubator_station.iff"); - if ((getTemplateCrc() == crcIncubator) && !resourceData.empty()) - { - DynamicVariableList const & objvars = getObjVars(); - if (objvars.hasItem("power.name") && (DynamicVariable::STRING == objvars.getType("power.name"))) - { - NetworkId const importedResourceType = ResourceTypeObject::addImportedResourceType(resourceData); - if (importedResourceType.isValid()) - { - if (importedResourceType.getValue() > NetworkId::cms_maxNetworkIdWithoutClusterId) - { - // need to tell all proxy game servers, if any, to create the imported - // resource type, if it hasn't already been created on that game server - ProxyList const &proxyList = getExposedProxyList(); - if (!proxyList.empty()) - { - ServerMessageForwarding::begin(std::vector(proxyList.begin(), proxyList.end())); - - GenericValueTypeMessage > const addImportedResourceTypeMsg("AddImportedResourceType", std::make_pair(importedResourceType, resourceData)); - ServerMessageForwarding::send(addImportedResourceTypeMsg); - - ServerMessageForwarding::end(); - } - } - - ResourceTypeObject const * const rto = ServerUniverse::getInstance().getResourceTypeById(importedResourceType); - if (rto) - { - IGNORE_RETURN(setObjVarItem("power.name", rto->getResourceName())); - - if (importedResourceType.getValue() > NetworkId::cms_maxNetworkIdWithoutClusterId) - IGNORE_RETURN(setObjVarItem("power.resourceData", resourceData)); - else - removeObjVarItem("power.resourceData"); - } - } - } - } - } - else - { - ServerObject::setAutoVariableFromByteStream(name, source); - } - addObjectToConcludeList(); -} - -// ---------------------------------------------------------------------- - -/** - * Sets a bio-link on this object. This object will only be able to be equipped by - * the player who's id matches the bio-link id. - * - * @param playerId the player to link this object to - */ -void TangibleObject::setBioLink(const NetworkId & playerId) -{ - if (playerId != NetworkId::cms_invalid) - { - if (isAuthoritative()) - { - setObjVarItem(OBJVAR_BIO_LINK_ID, playerId); - } - else - { - sendControllerMessageToAuthServer(CM_setBioLink, new MessageQueueGenericValueType(playerId)); - } - } -} - -// ---------------------------------------------------------------------- - -/** - * Sets the pending bio-link on this object. This will prevent the object from - * being equipped by any player until a real bio-link is set. - */ -void TangibleObject::setPendingBioLink() -{ - setBioLink(PENDING_BIO_LINK_NETWORK_ID); -} - -// ---------------------------------------------------------------------- - -/** - * Removes the bio-link on this object. - */ -void TangibleObject::clearBioLink() -{ - if (isAuthoritative()) - { - removeObjVarItem(OBJVAR_BIO_LINK); - } - else - { - sendControllerMessageToAuthServer(CM_setBioLink, new MessageQueueGenericValueType(NetworkId::cms_invalid)); - } -} - -// ---------------------------------------------------------------------- - -/** - * Returns the bio-link id of this object. - * - * @return the bio-link player id (NetworkId::cms_invalid if the object isn't bio-linked) - */ -NetworkId TangibleObject::getBioLink() const -{ - NetworkId linkId; - if (getObjVars().getItem(OBJVAR_BIO_LINK_ID, linkId)) - return linkId; - return NetworkId::cms_invalid; -} - -// ---------------------------------------------------------------------- - -/** - * Returns whether an object, or any contained object, is biolinked - * - * @return true if a biolinked object is found - */ -bool TangibleObject::isBioLinked() const -{ - NetworkId const linkId = getBioLink(); - - if( (linkId != NetworkId::cms_invalid) && (linkId != PENDING_BIO_LINK_NETWORK_ID) ) - { - // If the network ID is valid and does not correspond to a pending bio-link - // then we will assume that the tangible object is bio-linked - return true; - } - - return false; -} - -// ---------------------------------------------------------------------- - -void TangibleObject::rollupStructure(NetworkId const & owner, bool warnOnly) -{ - GameScriptObject* gso = getScriptObject(); - if (gso) - { - gso->attachScript("structure.structure_rollup", true); - ScriptParams params; - params.addParam(owner); - params.addParam(warnOnly); - gso->trigAllScripts(Scripting::TRIG_DO_STRUCTURE_ROLLUP, params); - gso->detachScript("structure.structure_rollup"); - } -} - -// ---------------------------------------------------------------------- - -CommandQueue * TangibleObject::getCommandQueue() const -{ - return CommandQueue::getCommandQueue(*const_cast(this)); -} - -//----------------------------------------------------------------------- - -void TangibleObject::commandQueueEnqueue(Command const &command, NetworkId const &targetId, Unicode::String const ¶ms, uint32 const sequenceId, bool const clearable, Command::Priority const priority, bool fromServer) -{ - if(!fromServer) - { - if(command.m_fromServerOnly) - { - LOG("CustomerService", ("CheatChannel: attempt to queue server-only command %s from client on object %s", command.m_commandName.c_str(), getNetworkId().getValueString().c_str())); - return; - } - } - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_commandQueueEnqueueFwd, new MessageQueueCommandQueueEnqueueFwd(sequenceId, command.m_commandHash, targetId, params, clearable, static_cast(priority), fromServer)); - } - else - { - CommandQueue * const queue = getCommandQueue(); - if (queue != NULL) - { - queue->enqueue(command, targetId, params, sequenceId, clearable, priority); - } - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::commandQueueRemove(uint32 const sequenceId) -{ - if (!isAuthoritative()) - { - sendControllerMessageToAuthServer(CM_commandQueueRemove, new MessageQueueCommandQueueRemove(sequenceId, 0.0f, static_cast(Command::CEC_Success), 0)); - } - else - { - CommandQueue * const queue = getCommandQueue(); - if (queue != NULL) - { - queue->remove(sequenceId); - } - } -} - -//----------------------------------------------------------------------- - -void TangibleObject::commandQueueClear() -{ - // commandQueueRemove clears the queue when passed a 0 sequenceId - commandQueueRemove(0); -} - -//----------------------------------------------------------------------- - -bool TangibleObject::commandQueueHasCommandFromGroup(uint32 groupHash) const -{ - CommandQueue * const queue = getCommandQueue(); - if (queue != NULL) - { - return queue->hasCommandFromGroup(groupHash); - } - return false; -} - -//----------------------------------------------------------------------- - -void TangibleObject::commandQueueClearCommandsFromGroup(uint32 groupHash, bool force) -{ - CommandQueue * const queue = getCommandQueue(); - if (queue != NULL) - { - queue->clearCommandsFromGroup(groupHash, force); - } -} - -//----------------------------------------------------------------------- - -CombatEngineData::CombatData * TangibleObject::getCombatData() -{ - return m_combatData; -} - -//----------------------------------------------------------------------- - -CombatEngineData::CombatData const * TangibleObject::getCombatData() const -{ - return m_combatData; -} - -//----------------------------------------------------------------------- - -void TangibleObject::CombatStateChangedCallback::modified(TangibleObject & target, bool /*oldValue*/, bool newValue, bool /*local*/) const -{ - if (newValue) - { - // Starting Combat - - LOGC(ConfigServerGame::isAiLoggingEnabled(), "debug_ai", ("TangibleObject::Callbacks::CombatStateChanged::modified() STARTING COMBAT owner(%s:%s)", target.getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(target.getEncodedObjectName()).c_str())); - - if (target.isAuthoritative()) - { - target.createCombatData(); - - target.m_combatStartTime = Os::getRealSystemTime(); - - if (!target.isPlayerControlled()) - { - ObjectTracker::addCombatAI(); - } - - AICreatureController * const aiCreatureController = AICreatureController::asAiCreatureController(target.getController()); - - if (aiCreatureController != NULL) - { - aiCreatureController->markCombatStartLocation(); - } - - if (target.getScriptObject() != NULL) - { - ScriptParams params; - IGNORE_RETURN(target.getScriptObject()->trigAllScripts(Scripting::TRIG_ENTERED_COMBAT, params)); - } - - target.scheduleForAlter(); - } - } - else - { - // Exiting Combat - - LOGC(ConfigServerGame::isAiLoggingEnabled(), "debug_ai", ("TangibleObject::Callbacks::CombatStateChanged::modified() EXITING COMBAT owner(%s:%s)", target.getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(target.getEncodedObjectName()).c_str())); - - if (target.isAuthoritative()) - { - if (!target.isPlayerControlled()) - { - ObjectTracker::removeCombatAI(); - } - - //target.clearHateList(); - - target.commandQueueClearCommandsFromGroup(COMMAND_GROUP_COMBAT.getCrc()); - - if (target.getScriptObject() != NULL) - { - ScriptParams params; - IGNORE_RETURN(target.getScriptObject()->trigAllScripts(Scripting::TRIG_EXITED_COMBAT, params)); - } - - target.scheduleForAlter(); - } - } -} - -//----------------------------------------------------------------------- -int TangibleObject::getCombatDuration() const -{ - int result = 0; - - if (isInCombat()) - { - result = static_cast(Os::getRealSystemTime() - m_combatStartTime.get()); - } - - return result; -} - -//----------------------------------------------------------------------- -void TangibleObject::setAttackableOverride(bool attackable) -{ - if (isAuthoritative()) - { - if (m_attackableOverride.get() != attackable) - m_attackableOverride = attackable; - } - else - { - sendControllerMessageToAuthServer(CM_setAttackableOverride, new MessageQueueGenericValueType(attackable)); - } -} - -//----------------------------------------------------------------------- -bool TangibleObject::hasAutoDeclineDuel() const -{ - return getObjVars().hasItem(OBJVAR_DECLINE_DUEL); -} - -//---------------------------------------------------------------------- - -int TangibleObject::getPassiveRevealRange(NetworkId const & target) const -{ - Archive::AutoDeltaMap::const_iterator i = m_passiveReveal.find(target); - if (i == m_passiveReveal.end()) - return -1; - - return i->second; -} - -//---------------------------------------------------------------------- - -void TangibleObject::addPassiveReveal(TangibleObject const & target, int range) -{ - addPassiveReveal(target.getNetworkId(), range, (NULL != PlayerCreatureController::getPlayerObject(target.asCreatureObject()))); -} - -//---------------------------------------------------------------------- - -void TangibleObject::addPassiveReveal(NetworkId const & target, int range, bool isTargetPlayerCharacter) -{ - // and object cannot passively reveal itself - if (target == getNetworkId()) - return; - - // range must be > 0 - if (range <= 0) - return; - - if(isAuthoritative()) - { - m_passiveReveal.set(target, range); - - if (isTargetPlayerCharacter) - m_passiveRevealPlayerCharacter.insert(target); - } - else - { - sendControllerMessageToAuthServer(CM_addPassiveReveal, new MessageQueueGenericValueType, NetworkId> >(std::make_pair(std::make_pair(range, (isTargetPlayerCharacter ? 1 : 0)), target))); - } -} - -//---------------------------------------------------------------------- - -void TangibleObject::removePassiveReveal(NetworkId const & target) -{ - if(isAuthoritative()) - { - IGNORE_RETURN(m_passiveReveal.erase(target)); - IGNORE_RETURN(m_passiveRevealPlayerCharacter.erase(target)); - } - else - { - sendControllerMessageToAuthServer(CM_removePassiveReveal, new MessageQueueGenericValueType(target)); - } -} - -//---------------------------------------------------------------------- - -void TangibleObject::removeAllPassiveReveal() -{ - if(isAuthoritative()) - { - m_passiveReveal.clear(); - m_passiveRevealPlayerCharacter.clear(); - } - else - { - sendControllerMessageToAuthServer(CM_removeAllPassiveReveal, 0); - } -} - -//---------------------------------------------------------------------- - -bool TangibleObject::setOverrideMapColor(unsigned char r, unsigned char g, unsigned char b) -{ - if(!isAuthoritative()) - { - return false; - } - - PackedArgb color(255, r, g, b); - m_mapColorOverride.set(color.getArgb()); - return true; -} - -//---------------------------------------------------------------------- - -bool TangibleObject::clearOverrideMapColor() -{ - if(!isAuthoritative()) - { - return false; - } - - m_mapColorOverride.set(0); - return true; -} - -//---------------------------------------------------------------------- - -bool TangibleObject::getOverrideMapColor(unsigned char & r, unsigned char & g, unsigned char & b) const -{ - PackedArgb color(m_mapColorOverride.get()); - if(color.getA() == 0) - { - return false; - } - - r = color.getR(); - g = color.getG(); - b = color.getB(); - return true; -} - -//---------------------------------------------------------------------- - -void TangibleObject::handleIncubatorCommit(CreatureObject const & owner, IncubatorCommitMessage const & msg) -{ - // this operation *REQUIRES* that both the incubator and the - // character manipulating the incubator be authoritative on - // the same game server, so it's really not possible to - // pass this handler over to the authoritative incubator, - // since there's no guarantee that the character will be - // authoritative on that game server either - if (!isAuthoritative() || !owner.isAuthoritative()) - return; - - GameScriptObject * const scriptObject = getScriptObject(); - if (scriptObject) - { - ScriptParams params; - params.addParam(owner.getNetworkId(), "playerId"); - params.addParam(getNetworkId(), "terminalId"); - params.addParam(msg.getSlot1Id(), "slot1Id"); - params.addParam(msg.getSlot2Id(), "slot2Id"); - params.addParam(msg.getSlot3Id(), "slot3Id"); - params.addParam(msg.getSlot4Id(), "slot4Id"); - params.addParam(msg.getInitialPointsSurvival(), "initialPointsSurvival"); - params.addParam(msg.getInitialPointsBeastialResilience(),"initialPointsBeastialResilience"); - params.addParam(msg.getInitialPointsCunning(),"initialPointsCunning"); - params.addParam(msg.getInitialPointsIntelligence(),"initialPointsIntelligence"); - params.addParam(msg.getInitialPointsAggression(),"initialPointsAggression"); - params.addParam(msg.getInitialPointsHuntersInstinct(),"initialPointsHuntersInstinct"); - params.addParam(msg.getTotalPointsSurvival(),"totalPointsSurvival"); - params.addParam(msg.getTotalPointsBeastialResilience(),"totalPointsBeastialResilience"); - params.addParam(msg.getTotalPointsCunning(),"totalPointsCunning"); - params.addParam(msg.getTotalPointsIntelligence(),"totalPointsIntelligence"); - params.addParam(msg.getTotalPointsAggression(),"totalPointsAggression"); - params.addParam(msg.getTotalPointsHuntersInstinct(),"totalPointsHuntersInstinct"); - params.addParam(msg.getTemperatureGauge(),"temperatureGauge"); - params.addParam(msg.getNutrientGauge(),"nutrientGauge"); - params.addParam(msg.getNewCreatureColorIndex(), "newCreatureColorIndex"); - - IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_INCUBATOR_COMMITTED, params)); - } -} - -void TangibleObject::handleIncubatorCancel(CreatureObject const & owner) -{ - // this operation *REQUIRES* that both the incubator and the - // character manipulating the incubator be authoritative on - // the same game server, so it's really not possible to - // pass this handler over to the authoritative incubator, - // since there's no guarantee that the character will be - // authoritative on that game server either - if (!isAuthoritative() || !owner.isAuthoritative()) - return; - - GameScriptObject * const scriptObject = getScriptObject(); - if (scriptObject) - { - ScriptParams params; - params.addParam(owner.getNetworkId(), "playerId"); - params.addParam(getNetworkId(), "terminalId"); - - IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_INCUBATOR_CANCELED, params)); - } -} - -void TangibleObject::forceHateTarget(NetworkId const & target) -{ - if(isAuthoritative()) - { - m_hateList.forceHateTarget(target); - scheduleForAlter(); - } - else - { - sendControllerMessageToAuthServer(CM_forceHateTarget, new MessageQueueGenericValueType(target)); - } - -} - -bool TangibleObject::isUserOnAccessList(NetworkId const user) const -{ - return (std::find(m_accessList.begin(), m_accessList.end(), user) != m_accessList.end()); -} - -bool TangibleObject::isGuildOnAccessList(int guildId) const -{ - return (std::find(m_guildAccessList.begin(), m_guildAccessList.end(), guildId) != m_guildAccessList.end()); -} - -void TangibleObject::addUserToAccessList(const NetworkId user) -{ - if(isAuthoritative()) - { - if(m_accessList.find(user) == m_accessList.end()) - { - if(!hasCondition(C_locked)) // If we weren't locked before, we are now. - setCondition(C_locked); - - m_accessList.insert(user); - - copyUserAccessListToObjVars(); - } - } - else - { - sendControllerMessageToAuthServer(CM_addUserToAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(-1, user) ) ); - } -} - -void TangibleObject::addGuildToAccessList(int guildId) -{ - if(isAuthoritative()) - { - if(m_guildAccessList.find(guildId) == m_guildAccessList.end()) - { - if(!hasCondition(C_locked)) // If we weren't locked before, we are now. - setCondition(C_locked); - - m_guildAccessList.insert(guildId); - - copyGuildAccessListToObjVars(); - } - } - else - { - sendControllerMessageToAuthServer(CM_addUserToAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(guildId, NetworkId::cms_invalid) ) ); - } -} - - -void TangibleObject::removeUserFromAccessList(const NetworkId user) -{ - if(isAuthoritative()) - { - Archive::AutoDeltaSet::const_iterator iter = m_accessList.find(user); - if(iter != m_accessList.end()) - { - m_accessList.erase(iter); - if(m_accessList.empty()) - { - if(hasCondition(C_locked)) - clearCondition(C_locked); // Containers with no access list are open to whomever. - - removeObjVarItem(s_accessListScriptVar); // Remove our objvars, no need for them anymore. - - return; - } - - copyUserAccessListToObjVars(); - - } - } - else - { - sendControllerMessageToAuthServer(CM_removeUserFromAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(-1, user))); - } -} - -void TangibleObject::removeGuildFromAccessList(int guildId) -{ - if(isAuthoritative()) - { - Archive::AutoDeltaSet::const_iterator iter = m_guildAccessList.find(guildId); - if(iter != m_guildAccessList.end()) - { - m_guildAccessList.erase(iter); - if(m_guildAccessList.empty()) - { - if(hasCondition(C_locked) && m_accessList.empty()) - clearCondition(C_locked); // Containers with no access list are open to whomever. - - removeObjVarItem(s_guildAccessListScriptVar); // Remove our objvars, no need for them anymore. - - return; - } - - copyGuildAccessListToObjVars(); - - } - } - else - { - sendControllerMessageToAuthServer(CM_removeUserFromAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(guildId, NetworkId::cms_invalid))); - } -} - -void TangibleObject::copyUserAccessListToObjVars() -{ - std::vector newAccessList; - Archive::AutoDeltaSet::const_iterator iter = m_accessList.begin(); - for(; iter != m_accessList.end(); ++iter) - newAccessList.push_back((*iter)); - - setObjVarItem(s_accessListScriptVar, newAccessList); -} - -void TangibleObject::copyGuildAccessListToObjVars() -{ - std::vector newAccessList; - Archive::AutoDeltaSet::const_iterator iter = m_guildAccessList.begin(); - for(; iter != m_guildAccessList.end(); ++iter) - newAccessList.push_back((*iter)); - - setObjVarItem(s_guildAccessListScriptVar, newAccessList); -} - - -void TangibleObject::readInUserAccessListObjVars() -{ - std::vector inputVector; - if(getObjVars().getItem(s_accessListScriptVar, inputVector)) - { - // We have some obj vars to add to our list! - std::vector::size_type i = 0; - for( ; i < inputVector.size(); ++i) - { - m_accessList.insert(inputVector[i]); - } - } -} - -void TangibleObject::readInGuildAccessListObjVars() -{ - std::vector inputVector; - if(getObjVars().getItem(s_guildAccessListScriptVar, inputVector)) - { - // We have some obj vars to add to our list! - std::vector::size_type i = 0; - for( ; i < inputVector.size(); ++i) - { - m_guildAccessList.insert(inputVector[i]); - } - } -} - -void TangibleObject::clearUserAccessList() -{ - if(isAuthoritative()) - { - if(hasCondition(C_locked) && m_guildAccessList.empty()) // No access list = total unlock. - clearCondition(C_locked); - - m_accessList.clear(); - - removeObjVarItem(s_accessListScriptVar); // Remove our objvars, no need for them anymore. - - } - else - { - sendControllerMessageToAuthServer(CM_clearUserAccessList, new MessageQueueGenericValueType(false)); - } -} - -void TangibleObject::clearGuildAccessList() -{ - if(isAuthoritative()) - { - if(hasCondition(C_locked) && m_accessList.empty()) // No access list = total unlock. - clearCondition(C_locked); - - m_guildAccessList.clear(); - - removeObjVarItem(s_guildAccessListScriptVar); // Remove our objvars, no need for them anymore. - - } - else - { - sendControllerMessageToAuthServer(CM_clearUserAccessList, new MessageQueueGenericValueType(true)); - } -} - -void TangibleObject::getUserAccessList(std::vector & ids) -{ - getObjVars().getItem(s_accessListScriptVar, ids); -} - -void TangibleObject::getGuildAccessList(std::vector & ids) -{ - getObjVars().getItem(s_guildAccessListScriptVar, ids); -} - -void TangibleObject::addObjectEffect(std::string const & filename, std::string const & hardpoint, Vector const & offset, float scale, std::string const & label) -{ - if(isAuthoritative()) - { - if(m_effectsMap.find(label) != m_effectsMap.end()) - return; - - m_effectsMap.insert(label, std::make_pair(filename, std::make_pair( hardpoint, std::make_pair(offset, scale )))); - } - else - sendControllerMessageToAuthServer(CM_addObjectEffect, - new MessageQueueGenericValueType > > > >(std::make_pair(label, std::make_pair(filename, std::make_pair(hardpoint, std::make_pair(offset, scale)))))); -} - -void TangibleObject::removeObjectEffect(std::string const & label) -{ - if(isAuthoritative()) - { - Archive::AutoDeltaMap > > >::const_iterator iter = m_effectsMap.find(label); - if(iter == m_effectsMap.end()) - return; - - m_effectsMap.erase(iter); - } - else - sendControllerMessageToAuthServer(CM_removeObjectEffect, new MessageQueueGenericValueType(label)); -} - -bool TangibleObject::hasObjectEffect(std::string const & label) -{ - return m_effectsMap.find(label) != m_effectsMap.end(); -} - -void TangibleObject::removeAllObjectEffects() -{ - if(isAuthoritative()) - { - m_effectsMap.clear(); - } - else - sendControllerMessageToAuthServer(CM_removeAllObjectEffect, new MessageQueueGenericValueType(true)); -} -// ====================================================================== +// ====================================================================== +// +// TangibleObject.cpp +// Copyright 2001, 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/TangibleObject.h" + +#include "SwgGameServer/CombatEngine.h" +#include "SwgGameServer/ConfigCombatEngine.h" +#include "serverGame/AiCombatPulseQueue.h" +#include "serverGame/AiCreatureController.h" +#include "serverGame/Chat.h" +#include "serverGame/CityInfo.h" +#include "serverGame/CityInterface.h" +#include "serverGame/Client.h" +#include "serverGame/CombatTracker.h" +#include "serverGame/CommandQueue.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/DraftSchematicObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/GroupObject.h" +#include "serverGame/ManufactureSchematicObject.h" +#include "serverGame/MessageToQueue.h" +#include "serverGame/NameManager.h" +#include "serverGame/NetworkTriggerVolume.h" +#include "serverGame/NpcConversation.h" +#include "serverGame/ObjectTracker.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/Pvp.h" +#include "serverGame/RegionMaster.h" +#include "serverGame/RegionPvp.h" +#include "serverGame/ResourceContainerObject.h" +#include "serverGame/ResourceTypeObject.h" +#include "serverGame/ServerCollisionProperty.h" +#include "serverGame/ServerLotManagerNotification.h" +#include "serverGame/ServerMessageForwarding.h" +#include "serverGame/ServerResourceClassObject.h" +#include "serverGame/ServerSynchronizedUi.h" +#include "serverGame/ServerTangibleObjectTemplate.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/ShipComponentDataManager.h" +#include "serverGame/ShipObject.h" +#include "serverGame/TangibleController.h" +#include "serverNetworkMessages/MessageQueueCommandQueueEnqueueFwd.h" +#include "serverNetworkMessages/MessageQueueCommandQueueForceExecuteCommandFwd.h" +#include "serverNetworkMessages/MessageToPayload.h" +#include "serverNetworkMessages/UpdateObjectOnPlanetMessage.h" +#include "serverPathfinding/ServerPathfindingNotification.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptDictionary.h" +#include "serverScript/ScriptFunctionTable.h" +#include "serverScript/ScriptParameters.h" +#include "serverUtility/ServerClock.h" +#include "sharedDebug/Profiler.h" +#include "sharedFile/FileNameUtils.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/DynamicVariable.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedFoundation/Os.h" +#include "sharedGame/Command.h" +#include "sharedGame/CraftingData.h" +#include "sharedGame/GameObjectTypes.h" +#include "sharedGame/LfgCharacterData.h" +#include "sharedGame/PvpData.h" +#include "sharedGame/SharedObjectAttributes.h" +#include "sharedGame/SharedObjectTemplate.h" +#include "sharedGame/SharedStringIds.h" +#include "sharedGame/SharedTangibleObjectTemplate.h" +#include "sharedGame/ShipComponentData.h" +#include "sharedLog/Log.h" +#include "sharedMath/PackedArgb.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/IncubatorCommitMessage.h" +#include "sharedNetworkMessages/MessageQueueCommandQueueRemove.h" +#include "sharedNetworkMessages/MessageQueueCraftIngredients.h" +#include "sharedNetworkMessages/MessageQueueGenericValueType.h" +#include "sharedNetworkMessages/MessageQueueNetworkId.h" +#include "sharedNetworkMessages/MessageQueueOpponentInfo.h" +#include "sharedNetworkMessages/MessageQueueShowFlyText.h" +#include "sharedNetworkMessages/MessageQueueShowCombatText.h" +#include "sharedNetworkMessages/MessageQueueStartNpcConversation.h" +#include "sharedNetworkMessages/MessageQueueStopNpcConversation.h" +#include "sharedNetworkMessages/ObjectChannelMessages.h" +#include "sharedNetworkMessages/UpdatePvpStatusMessage.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/ContainedByProperty.h" +#include "sharedObject/Container.h" +#include "sharedObject/CustomizationData.h" +#include "sharedObject/CustomizationDataProperty.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/SlotIdManager.h" +#include "sharedObject/SlottedContainer.h" +#include "sharedObject/SlottedContainmentProperty.h" +#include "sharedObject/StructureFootprint.h" +#include "sharedObject/VolumeContainer.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" + +#ifdef _DEBUG +#include "serverGame/ConsoleManager.h" +#endif + +#include +#include +#include + +#pragma warning(disable:4355) + + +namespace TangibleObjectNamespace +{ + int const s_minCombatDuration = 4; + const int NUM_DAMAGE_TYPES = 9; + + const int s_ignoreDamageTypes = + static_cast(ServerArmorTemplate::DT_environmental_heat) | + static_cast(ServerArmorTemplate::DT_environmental_cold) | + static_cast(ServerArmorTemplate::DT_environmental_acid) | + static_cast(ServerArmorTemplate::DT_environmental_electrical); + + bool isEmpty(const ServerObject& obj) + { + const Container* container = obj.getContainerProperty(); + if (container) + { + return (container->getNumberOfItems() == 0); + } + return true; + } + + std::string const s_attributeBonusNames[] = + { + "health", + "health_regen", + "action", + "action_regen", + "mind", + "mind_regen" + }; + + const char * const s_accessListScriptVar = "tangible_object.accessList"; + const char * const s_guildAccessListScriptVar = "tangible_object.guildAccessList"; + + void getCategorizedSkillModBonuses(TangibleObject const & to, std::string const & objvarName, std::map & skillModBonuses); + int getCategorizedSkillModBonus(TangibleObject const & to, std::string const & objvarName, std::string const & skillMod); +} + +//---------------------------------------------------------------------- + +void TangibleObjectNamespace::getCategorizedSkillModBonuses(TangibleObject const & to, std::string const & objvarName, std::map & skillModBonuses) +{ + DynamicVariableList::NestedList children(to.getObjVars(), objvarName); + for (DynamicVariableList::NestedList::const_iterator iterChildren = children.begin(); iterChildren != children.end(); ++iterChildren) + { + DynamicVariable::DynamicVariableType const type = iterChildren.getType(); + if (type == DynamicVariable::INT) + { + int bonus = 0; + iterChildren.getValue(bonus); + + std::string const childName = iterChildren.getName(); + std::map::iterator iterFind = skillModBonuses.find(childName); + if (iterFind != skillModBonuses.end()) + iterFind->second += bonus; + else + IGNORE_RETURN(skillModBonuses.insert(std::make_pair(childName, bonus))); + } + else if (type == DynamicVariable::LIST) + { + std::string const childFullName = objvarName + '.' + iterChildren.getName(); + getCategorizedSkillModBonuses(to, childFullName, skillModBonuses); + } + } +} + +//---------------------------------------------------------------------- + +int TangibleObjectNamespace::getCategorizedSkillModBonus(TangibleObject const & to, std::string const & objvarName, std::string const & skillMod) +{ + int totalBonus = 0; + DynamicVariableList::NestedList children(to.getObjVars(), objvarName); + for (DynamicVariableList::NestedList::const_iterator iterChildren = children.begin(); iterChildren != children.end(); ++iterChildren) + { + DynamicVariable::DynamicVariableType const type = iterChildren.getType(); + if (type == DynamicVariable::INT) + { + if (iterChildren.getName() == skillMod) + { + int bonus = 0; + iterChildren.getValue(bonus); + + totalBonus += bonus; + } + } + else if (type == DynamicVariable::LIST) + { + std::string const childFullName = objvarName + '.' + iterChildren.getName(); + totalBonus += getCategorizedSkillModBonus(to, childFullName, skillMod); + } + } + + return totalBonus; +} + +//---------------------------------------------------------------------- + +using namespace TangibleObjectNamespace; + +//======================================================================= +// class TangibleObject::CraftingToolSyncUi + +class TangibleObject::CraftingToolSyncUi : public ServerSynchronizedUi +{ +public: + CraftingToolSyncUi(TangibleObject & owner) : + ServerSynchronizedUi(owner), + m_prototype(), + m_manfSchematic(), + m_manfSchematicObserver() + { + addToUiPackage(m_prototype); + addToUiPackage(m_manfSchematic); + } + + virtual ~CraftingToolSyncUi() + { + if (!isOwnerChangingAuthority()) + { + if (m_manfSchematic.get() != CachedNetworkId::cms_cachedInvalid) + { + safe_cast(getOwner())->clearCraftingManufactureSchematic(); + } + if (m_prototype.get() != CachedNetworkId::cms_cachedInvalid) + { + safe_cast(getOwner())->clearCraftingPrototype(); + } + } + } + + const CachedNetworkId & getPrototype(void) const + { + return m_prototype.get(); + } + + void setPrototype(const CachedNetworkId & prototype) + { + m_prototype = prototype; + } + + const CachedNetworkId & getManfSchematic(void) const + { + return m_manfSchematic.get(); + } + + void setManfSchematic(const CachedNetworkId & manfSchematic, const CachedNetworkId & observer, bool deleteSchematic) + { + m_manfSchematic = manfSchematic; + m_manfSchematicObserver = observer; + } + +private: + + CraftingToolSyncUi(const CraftingToolSyncUi & src); + CraftingToolSyncUi & operator =(const CraftingToolSyncUi & src); + +private: + + Archive::AutoDeltaVariable m_prototype; + Archive::AutoDeltaVariable m_manfSchematic; + + CachedNetworkId m_manfSchematicObserver; +}; + +//======================================================================= + +static const ConstCharCrcLowerString COMMAND_GROUP_COMBAT("combat"); + +// armor objvars - also defined in armor.scriptlib +static const std::string OBJVAR_ARMOR_BASE = "armor"; +static const std::string OBJVAR_ARMOR_ENCUMBRANCE = "armorencumbrance"; +static const std::string OBJVAR_ENCUMBRANCE_SPLIT = "encumbranceSplit"; +static const std::string OBJVAR_ARMOR_LEVEL = "armorLevel"; + +// objvar to flag the object as a shield +static const std::string OBJVAR_ARMOR_SHIELD = "armor.isShield"; + +// armor datatable strings +static const std::string DATATABLE_ARMOR = "datatables/crafting/armor.iff"; +static const std::string DATATABLE_FINAL_ROW = "final"; +static const std::string DATATABLE_TYPE_COL = "type"; +static const std::string DATATABLE_MIN_ENCUMBRANCE_COL = "min_encumbrance"; +static const std::string DATATABLE_MAX_ENCUMBRANCE_COL = "max_encumbrance"; + +// bio-link objvars +static const std::string OBJVAR_BIO_LINK = "biolink"; +static const std::string OBJVAR_BIO_LINK_ID = "biolink.id"; +// This id is used for a bio-linked item that is linked to no one. +// It is safe as long as no player has id 1 (which should be a good assumption). +// Note this value is reflected in library.utils.scriptlib. +static const NetworkId PENDING_BIO_LINK_NETWORK_ID(static_cast(1)); + +// template for crafting components container +const static ConstCharCrcLowerString CRAFTING_COMPONENTS_CONTAINER = "object/tangible/crafting/crafting_components_container.iff"; + +// slots for a crafting tool +const static ConstCharCrcLowerString INGREDIENT_HOPPER_SLOT_NAME = "ingredient_hopper"; +const static ConstCharCrcLowerString MANF_OUTPUT_SLOT_NAME = "anythingnomod2"; +const static ConstCharCrcLowerString TEMP_PROTOTYPE_SLOT_NAME = "anythingnomod1"; +const static ConstCharCrcLowerString TEMP_SCHEMATIC_SLOT_NAME = "test_manf_schematic"; + +// objvars for crafting +const static std::string OBJVAR_CRAFTING_TOOL = "crafting.tool"; +const static std::string OBJVAR_CRAFTING_STATION = "crafting.station"; +const static std::string OBJVAR_CRAFTING_CRAFTER = "crafting.crafter"; +const static std::string OBJVAR_CRAFTING_COMPONENTS = "crafting.components"; +const static std::string OBJVAR_CRAFTING_SCHEMATIC = "crafting.source_schematic"; +const static std::string OBJVAR_CRAFTING_TYPE = "crafting.type"; +const static std::string OBJVAR_CRAFTING_REPAIR_TYPE = "crafting.repair_type"; +const static std::string OBJVAR_CRAFTING_PROTOTYPE_TIME = "crafting.prototypeTime"; +const static std::string OBJVAR_CRAFTING_PROTOTYPE_START_TIME = "crafting.prototypeStartTime"; +const static std::string OBJVAR_CRAFTING_PROTOTYPE_OBJECT = "crafting.prototypeObject"; +const static std::string OBJVAR_CRAFTING_PROTOTYPE_CRAFTER = "crafting.prototypeCrafter"; +const static std::string OBJVAR_CREATOR_ID = "crafting.creator.id"; +const static std::string OBJVAR_CREATOR_XP = "crafting.creator.xp"; +const static std::string OBJVAR_CREATOR_XP_TYPE = "crafting.creator.xpType"; +const static std::string OBJVAR_REPAIR_TOOL = "crafting.repair"; +const static std::string OBJVAR_CRAFTING_STATIONMOD = "crafting.stationMod"; +const static std::string OBJVAR_SKILLMOD_BONUS = "skillmod.bonus"; +const static std::string OBJVAR_CATEGORIZED_SKILLMOD_BONUS = "categorizedSkillmod.bonus"; +const static std::string OBJVAR_SKILLMOD_SOCKETS = "skillmod.sockets"; +const static std::string OBJVAR_ATTRIBUTE_BONUS = "attribute.bonus"; + +const std::string OBJVAR_COMPONENT_DATA("crafting_components"); + +// battlefield objvars +const static std::string OBJVAR_BATTLEFIELD_PARTICIPANTS = "battleDudes"; + +// no trade +static const std::string NOMOVE_SCRIPT = "item.special.nomove"; + +static const std::string OBJVAR_DECLINE_DUEL = "decline_duel"; + +const SharedObjectTemplate * TangibleObject::m_defaultSharedTemplate = NULL; + + +//----------------------------------------------------------------------- +TangibleObject::TangibleObject(const ServerTangibleObjectTemplate* newTemplate) : + ServerObject(newTemplate), + m_combatData(NULL), + m_pvpType(), + m_pvpMercenaryType(PvpType_Neutral), + m_pvpFutureType(-1), + m_pvpFaction(), + m_pvpMercenaryFaction(PvpData::getNeutralFactionId()), + m_pvpRegionCrc(), + m_pvpEnemies(), + m_damageTaken(0), + m_maxHitPoints(newTemplate->getMaxHitPoints()), + m_ownerId(NetworkId(static_cast(0))), + m_customAppearance(), + m_appearanceData(), + m_locationTargets(), + m_components(), + m_visible(true), + m_hideFromClient(false), + m_count(newTemplate->getCount()), + m_condition(newTemplate->getCondition()), + m_creatorId(NetworkId::cms_invalid), + m_sourceDraftSchematic(0), + m_hateList(), + m_hateOverTime(), + m_inCombat(false), + m_combatStartTime(0), + m_attackableOverride(false), + m_passiveReveal(), + m_passiveRevealPlayerCharacter(), + m_mapColorOverride(0), + m_accessList(), + m_guildAccessList(), + m_effectsMap(), + m_npcConversation(NULL), + m_conversations() +{ + WARNING_STRICT_FATAL(!getSharedTemplate(), ("Tried to create a TANGIBLE %s object without a shared template!\n", newTemplate->DataResource::getName())); + + m_hateList.addServerNpAutoDeltaVariables(m_serverPackage_np); + m_hateList.setOwner(this); + + m_maxHitPoints.setSourceObject(this); + m_ownerId.setSourceObject(this); + m_customAppearance.setSourceObject(this); + m_appearanceData.setSourceObject(this); + m_pvpType.setSourceObject(this); + m_pvpMercenaryType.setSourceObject(this); + m_pvpFaction.setSourceObject(this); + m_pvpMercenaryFaction.setSourceObject(this); + m_pvpRegionCrc.setSourceObject(this); + m_pvpEnemies.setSourceObject(this); + m_visible.setSourceObject(this); + m_hideFromClient.setSourceObject(this); + m_condition.setSourceObject(this); + m_inCombat.setSourceObject(this); + m_attackableOverride.setSourceObject(this); + m_passiveRevealPlayerCharacter.setSourceObject(this); + + // set to not disabled, and set invulnerable and wantSawAttack from template + int condition = m_condition.get(); + condition &= ~( ServerTangibleObjectTemplate::C_disabled + | ServerTangibleObjectTemplate::C_invulnerable + | ServerTangibleObjectTemplate::C_wantSawAttackTrigger); + if (newTemplate->getInvulnerable()) + condition |= ServerTangibleObjectTemplate::C_invulnerable; + if (newTemplate->getWantSawAttackTriggers()) + condition |= ServerTangibleObjectTemplate::C_wantSawAttackTrigger; + m_condition = condition; + + // attach trigger volumes to this object + size_t i; + size_t count = newTemplate->getTriggerVolumesCount(); + for (i = 0; i < count; ++i) + { + const TriggerVolumeData & trigger = newTemplate->getTriggerVolumes(static_cast(i)); + createTriggerVolume(trigger.getRadius(), trigger.getName(), true); //@todo : add "promiscuous param to template entry + } + + //-- initialize CustomizationDataProperty if any customization variables are declared + // for the SharedTangibleObjectTemplate. + const SharedTangibleObjectTemplate *const sharedObjectTemplate = safe_cast(getSharedTemplate()); + if (sharedObjectTemplate) + { + //-- create CustomizationDataProperty if appropriate + sharedObjectTemplate->createCustomizationDataPropertyAsNeeded(*this); + + //-- if a CustomizationDataProperty was created, attach a modification listener. + // check if the property exists + CustomizationDataProperty *cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); + + if (cdProperty) + { + // retrieve the CustomizationData instance associated with the property + CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); + NOT_NULL(customizationData); + + // attach modification callback + customizationData->registerModificationListener(customizationDataModificationCallback, this); + + // release local reference + customizationData->release(); + } + + if(ConfigServerGame::getCreateAppearances()) + { + const std::string &appearanceString = sharedObjectTemplate->getAppearanceFilename(); + if (appearanceString.size() != 0 && strstr (appearanceString.c_str (), ".apt") != 0) + { + Appearance * newAppearance = AppearanceTemplateList::createAppearance(appearanceString.c_str()); + + if(newAppearance != NULL) + { + setAppearance(newAppearance); + } + } + } + } + + // If the object is a path node, attach the pathfinding notification + + if (isWaypoint()) + { + addNotification( ServerPathfindingNotification::getInstance() ); + } + + // attach the collision property + + ServerCollisionProperty* collision = new ServerCollisionProperty(*this,getSharedTemplate()); + + addProperty(*collision); + + addMembersToPackages(); + + ObjectTracker::addTangible(); + + if(getGameObjectType() == SharedObjectTemplate::GOT_loadbeacon) + { + ServerWorld::addLoadBeacon(this); + } + + //-- add the lot manager notification + { + SharedTangibleObjectTemplate const * const sharedTangibleObjectTemplate = dynamic_cast (getSharedTemplate ()); + if (sharedTangibleObjectTemplate) + { + StructureFootprint const * const structureFootprint = sharedTangibleObjectTemplate->getStructureFootprint (); + if (structureFootprint) + addNotification (ServerLotManagerNotification::getInstance ()); + } + else + DEBUG_WARNING (true, ("TangibleObject::TangibleObject - [%s] does not have a shared tangible object template", getObjectTemplate ()->getName ())); + } +} + +//----------------------------------------------------------------------- + +TangibleObject::~TangibleObject() +{ + //-- This must be the first line in the destructor to invalidate any watchers watching this object + nullWatchers(); + + if (getSynchronizedUi() != NULL) + { + CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync != NULL) + { + if (isAuthoritative() && isCraftingTool()) + { + clearCraftingPrototype(); + clearCraftingManufactureSchematic(); + } + else + { + if (!isAuthoritative()) + { + WARNING(true, ("Tangible object %s is not authoritative " + "but has a SynchronizedUi", + getNetworkId().getValueString().c_str())); + } + if (!isCraftingTool()) + { + WARNING(true, ("Tangible object %s is not a crafting tool " + "but has a CraftingToolSyncUi", + getNetworkId().getValueString().c_str())); + } + sync->setPrototype(CachedNetworkId::cms_cachedInvalid); + sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, + CachedNetworkId::cms_cachedInvalid, true); + } + } + } + + if(getGameObjectType() == SharedObjectTemplate::GOT_loadbeacon) + { + ServerWorld::removeLoadBeacon(this); + } + + CombatTracker::removeDefender(this); + + if (m_combatData != NULL) + { + if (isAuthoritative()) + { + if (!getCombatData()->defenseData.damage.empty()) + { + WARNING(true, ("\tobject still has a non-empty damage list")); + + // look up the call stack information + const int callStackOffset = 4; + const int maxStackDepth = 64; + const int callStackSize = callStackOffset + maxStackDepth; + uint32 callStack[callStackOffset + maxStackDepth]; + DebugHelp::getCallStack(callStack, callStackOffset + maxStackDepth); + + // look up the caller's file and line + if (callStack[callStackOffset]) + { + char lib[4 * 1024] = { '\0' }; + char file[4 * 1024] = { '\0' }; + int line = 0; + REPORT_LOG(true, ("\tCall stack:")); + for (int i = callStackOffset; i < callStackSize; ++i) + { + if (callStack[i]) + { + if (DebugHelp::lookupAddress(callStack[i], lib, file, sizeof(file), line)) + REPORT_LOG(true, ("\t%s(%d) : caller %d\n", file, line, i-callStackOffset)); + else + REPORT_LOG(true, ("\tunknown(0x%08X) : caller %d\n", static_cast(callStack[i]), i-callStackOffset)); + } + } + } + } + } + + delete m_combatData; + m_combatData = NULL; + + if (!isPlayerControlled()) + ObjectTracker::removeCombatAI(); + } + + if (m_npcConversation != NULL) + { + delete m_npcConversation; + m_npcConversation = NULL; + } + + ObjectTracker::removeTangible(); +} // TangibleObject::~TangibleObject + +//----------------------------------------------------------------------- + +/** + * Initializes a newly created object. + */ +void TangibleObject::initializeFirstTimeObject() +{ + DEBUG_FATAL(!isAuthoritative(), ("Trying to initialize non auth object %s", getNetworkId().getValueString().c_str())); + + // set up armor from the template + const ServerTangibleObjectTemplate * newTemplate = safe_cast< + const ServerTangibleObjectTemplate *>(getObjectTemplate()); + if (newTemplate != NULL) + { + setInvulnerable(newTemplate->getInvulnerable()); + + if (isAuthoritative()) + { + initializeVisibility(); + + const ServerArmorTemplate * armorTemplate = newTemplate->getArmor(); + if (armorTemplate != NULL) + { + int const rating = static_cast(armorTemplate->getRating()); + if ( rating < static_cast(ServerArmorTemplate::AR_armorNone) + || rating > static_cast(ServerArmorTemplate::AR_armorHeavy)) + { + WARNING(true, ("TangibleObject::initializeFirstTimeObject trying " + "to add armor data from template %s with an invalid rating " + "of %d", armorTemplate->getName(), rating)); + } + else + { + // armor integrity replaces hitpoints + m_maxHitPoints = armorTemplate->getIntegrity(); + } + } + } + } + + // attach the combat skeleton script to this object + ServerTangibleObjectTemplate::CombatSkeleton skeleton = static_cast(getCombatSkeleton()); + const ConfigCombatEngine::SkeletonAttackMod & skeletonMod = + ConfigCombatEngine::getSkeletonAttackMod(skeleton); + if (!skeletonMod.script.empty() && skeletonMod.script[0] != '\0') + { + NOT_NULL(getScriptObject()); + getScriptObject()->attachScript(skeletonMod.script, true); + } + + handleContainerSetup(); + + ServerObject::initializeFirstTimeObject(); + + setDefaultAlterTime(AlterResult::cms_keepNoAlter); + + calcPvpableState(); + if (!isNonPvpObject()) + MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++CheckPvpRegion", std::string(), static_cast(getPvpRegionCheckTime())); +} + +//----------------------------------------------------------------------- + +/** + * Initializes a proxy object. + */ +void TangibleObject::endBaselines() +{ + ServerObject::endBaselines(); + handleContainerSetup(); + + // set the hate list owner to ensure the player object is set correctly + m_hateList.setOwner(this); + + if (isAuthoritative()) + { + // fix the load_with values if they don't match + if ( getLoadWith() != ContainerInterface::getLoadWithContainerId(*this)) + { + setLoadWith(ContainerInterface::getLoadWithContainerId(*this)); + } + + // test to flag the object as disabled + if (getDamageTaken() >= getMaxHitPoints()) + setDisabled(true); + + // pvp needs to be notified after an object is both initialized and made authoritative. + Pvp::handleAuthorityAcquire(*this); + + // this code is for legacy objects already in the database + // Don't consider virtual overrides for invulnerability in this case + if (getCacheVersion() > 0 && !TangibleObject::isInvulnerable()) + setInvulnerable(true); + + if (getObjVars().hasItem(OBJVAR_CRAFTING_SCHEMATIC)) + setCondition(C_crafted); + else + clearCondition(C_crafted); + + removeObjVarItem("debuggingLogCommandEnqueue"); + + // destroy duped TCG Set5 AT-AT Head ITV + if ((getStaticItemName() == "item_tcg_loot_reward_series5_atat_head_itv") && !getObjVars().hasItem("rewardGrantInfo")) + { + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++DestroyDupedTcg5AtAtHeadItv", + "", + 5, + false); + } + } + + calcPvpableState(); + + // check for existence of objvar to enable/disable m_logCommandEnqueue + CommandQueue * const queue = getCommandQueue(); + if (queue != NULL) + { + queue->setLogCommandEnqueue(getObjVars().hasItem("debuggingLogCommandEnqueue")); + } + + // if this is an incubator, and it contains imported resource from another + // galaxy, register the imported resource type on this game server, if it + // hasn't already been registered on this game server; this must be done + // on each game server as it receives the incubator + static const uint32 crcIncubator = CrcLowerString::calculateCrc("object/tangible/crafting/station/incubator_station.iff"); + if (getTemplateCrc() == crcIncubator) + { + DynamicVariableList const & objvars = getObjVars(); + if (objvars.hasItem("power.resourceData") && (DynamicVariable::STRING == objvars.getType("power.resourceData"))) + { + std::string resourceData; + IGNORE_RETURN(objvars.getItem("power.resourceData", resourceData)); + IGNORE_RETURN(ResourceTypeObject::addImportedResourceType(resourceData)); + } + } +} // TangibleObject::endBaselines + +//----------------------------------------------------------------------- + +void TangibleObject::onLoadedFromDatabase() +{ + ServerObject::onLoadedFromDatabase(); + + // if we are a crafting tool that is counting down a prototype, + // reactivate the counter + if (isCraftingTool() && isAuthoritative()) + { + float prototypeTime = 0; + getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME, prototypeTime); + if (prototypeTime > 0) + { + int timeLeft = getCraftingToolPrototypeTime(); + if (timeLeft < 1) + timeLeft = 1; + + NetworkId ownerId; + NetworkId prototypeId; + bool result = getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_OBJECT, + prototypeId) && getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_CRAFTER, + ownerId); + if (result) + { + ScriptParams params; + params.addParam(ownerId, "crafter"); + params.addParam(prototypeId, "prototype"); + ScriptDictionaryPtr dictionary; + getScriptObject()->makeScriptDictionary(params, dictionary); + if (dictionary.get() != NULL) + { + dictionary->serialize(); + MessageToQueue::getInstance().sendMessageToJava(getNetworkId(), + "prototypeDone", dictionary->getSerializedData(), + timeLeft, false); + MessageToQueue::getInstance().sendMessageToC(getNetworkId(), + "C++updateCounter", "", 1, false); + } + } + } + } + + setDefaultAlterTime(AlterResult::cms_keepNoAlter); + + calcPvpableState(); + if (!isNonPvpObject()) + MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++CheckPvpRegion", std::string(), static_cast(getPvpRegionCheckTime())); + + if(isLocked()) + { + readInUserAccessListObjVars(); + readInGuildAccessListObjVars(); + } + + // Invalid Socket check. + bool checkForInvalidSockets = (GameObjectTypes::isTypeOf(getGameObjectType(), SharedObjectTemplate::GOT_clothing) || + GameObjectTypes::isTypeOf(getGameObjectType(), SharedObjectTemplate::GOT_armor) ) && isCrafted(); + if(checkForInvalidSockets) + { + std::vector< std::pair< std::string, int > > skillMods; + getSkillModBonuses(skillMods, false); + + if(skillMods.size() > 3) // 3 is the max legit amount for any 1 socket item + { + // Check all our stats, make sure they aren't over the limit for 1 socket, cross reference names with the reverse engineering datatable. + DataTable * modTable = DataTableManager::getTable("datatables/crafting/reverse_engineering_mods.iff", true); + if(!modTable) + return; + int invalidSkillCounter = 0; + // Check each skill mod against the datatable. If we don't have that skill mod in the table, then it could be a legitimate item from the older system. + for(unsigned int i = 0; i < skillMods.size(); ++i) + { + std::string skillModName = skillMods[i].first; + int row = modTable->searchColumnString(0, skillModName); + + if(row < 0) // wasn't in our table, could be legit. + continue; + + ++invalidSkillCounter; + } + + if(invalidSkillCounter <= 3) // Valid item. + return; + + // Player Name + std::string playerName = NameManager::getInstance().getPlayerFullName(getOwnerId()); + Unicode::String objName = getObjectName(); + std::string narrowObjName; + if(!objName.empty()) + narrowObjName = Unicode::wideToNarrow(objName); + // Possible invalid item. + LOG("CustomerService", ("extraSocketExploit:Reason: Invalid # of Skill mods. Item Name: [%s] OID:[%s] Shared Template Name: [%s]", + narrowObjName.empty() ? "" : narrowObjName.c_str(), getNetworkId().getValueString().c_str(), getSharedTemplateName() ? getSharedTemplateName() : "")); + LOG("CustomerService", ("extraSocketExploit:Owner OID: [%s] Owner Station ID: [%u] Owner Name: [%s]", + getOwnerId().getValueString().c_str(), NameManager::getInstance().getPlayerStationId(getOwnerId()), playerName.empty() ? "" : playerName.c_str())); + LOG("CustomerService", ("extraSocketExploit:Skill Mods are:")); + + for(unsigned int i = 0; i < skillMods.size(); ++i) + { + int row = modTable->searchColumnString(0, skillMods[i].first); + int currentValue = skillMods[i].second; + int maxValue = 0; + + if(row < 0) + { + LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[i].first.c_str(), skillMods[i].second)); + continue; + } + + int ratioValue = modTable->getIntValue(1, row); + + if(ratioValue != 0) + maxValue = 35 / ratioValue; + + if(currentValue > maxValue) + LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [%d]", skillMods[i].first.c_str(), skillMods[i].second, maxValue)); + else if(currentValue > 35) + LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [35]", skillMods[i].first.c_str(), skillMods[i].second)); + else + LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[i].first.c_str(), skillMods[i].second)); + } + } + else + { + // Check all our stats, make sure they aren't over the limit for 1 socket. + DataTable * modTable = DataTableManager::getTable("datatables/crafting/reverse_engineering_mods.iff", true); + if(!modTable) + return; + + for(unsigned int i = 0; i < skillMods.size(); ++i) + { + std::string skillModName = skillMods[i].first; + int currentValue = skillMods[i].second; + int maxValue = 0; + bool logItem = false; + + if(currentValue > 35) + logItem = true; + else + { + int row = modTable->searchColumnString(0, skillModName); + + if(row < 0) + return; + + int ratioValue = modTable->getIntValue(1, row); + + if(ratioValue != 0) + maxValue = 35 / ratioValue; + + if(currentValue > maxValue) + logItem = true; + } + + if(logItem) + { + // Player Name + std::string playerName = NameManager::getInstance().getPlayerFullName(getOwnerId()); + Unicode::String objName = getObjectName(); + std::string narrowObjName; + if(!objName.empty()) + narrowObjName = Unicode::wideToNarrow(objName); + // Possible invalid item. + LOG("CustomerService", ("extraSocketExploit:Reason: Invalid Skill mod value. Item Name: [%s] OID:[%s] Shared Template Name: [%s]", + narrowObjName.empty() ? "" : narrowObjName.c_str(), getNetworkId().getValueString().c_str(), getSharedTemplateName() ? getSharedTemplateName() : "")); + LOG("CustomerService", ("extraSocketExploit:Owner OID: [%s] Owner Station ID: [%u] Owner Name: [%s]", + getOwnerId().getValueString().c_str(), NameManager::getInstance().getPlayerStationId(getOwnerId()), playerName.empty() ? "" : playerName.c_str())); + LOG("CustomerService", ("extraSocketExploit:Skill Mods are:")); + + for(unsigned int j = 0; j < skillMods.size(); ++j) + { + + int row = modTable->searchColumnString(0, skillMods[j].first); + currentValue = skillMods[j].second; + + if(row < 0) + { + LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[j].first.c_str(), skillMods[j].second)); + continue; + } + + int ratioValue = modTable->getIntValue(1, row); + + if(ratioValue != 0) + maxValue = 35 / ratioValue; + + if(currentValue > maxValue) + LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [%d]", skillMods[j].first.c_str(), skillMods[j].second, maxValue)); + else if(currentValue > 35) + LOG("CustomerService", ("extraSocketExploit:(Invalid)Skill Mod: [%s] Value: [%d] Max Legal Value [35]", skillMods[j].first.c_str(), skillMods[j].second)); + else + LOG("CustomerService", ("extraSocketExploit:Skill Mod: [%s] Value: [%d]", skillMods[j].first.c_str(), skillMods[j].second)); + } + + return; + } + } + } + } + + // start the decay process going +} + +//----------------------------------------------------------------------- + +void TangibleObject::virtualOnSetAuthority() +{ + ServerObject::virtualOnSetAuthority(); +} + +//----------------------------------------------------------------------- + +TangibleObject * TangibleObject::getTangibleObject(NetworkId const & networkId) +{ + return asTangibleObject(NetworkIdManager::getObjectById(networkId)); +} + +//----------------------------------------------------------------------- + +TangibleObject * TangibleObject::asTangibleObject(Object * object) +{ + ServerObject * serverObject = (object != NULL) ? object->asServerObject() : NULL; + return (serverObject != NULL) ? serverObject->asTangibleObject() : NULL; +} + +//----------------------------------------------------------------------- + +TangibleObject const * TangibleObject::asTangibleObject(Object const * object) +{ + ServerObject const * serverObject = (object != NULL) ? object->asServerObject() : NULL; + return (serverObject != NULL) ? serverObject->asTangibleObject() : NULL; +} + +//----------------------------------------------------------------------- + +TangibleObject * TangibleObject::asTangibleObject() +{ + return this; +} + +// ---------------------------------------------------------------------- + +TangibleObject const * TangibleObject::asTangibleObject() const +{ + return this; +} + +// ---------------------------------------------------------------------- + +/** + * Returns a shared template if none was given for this object. + * + * @return the shared template + */ +const SharedObjectTemplate * TangibleObject::getDefaultSharedTemplate(void) const +{ +static const ConstCharCrcLowerString templateName("object/tangible/base/shared_tangible_default.iff"); + + if (m_defaultSharedTemplate == NULL) + { + m_defaultSharedTemplate = safe_cast( + ObjectTemplateList::fetch(templateName)); + WARNING_STRICT_FATAL(m_defaultSharedTemplate == NULL, ("Cannot create " + "default shared object template %s", templateName.getString())); + if (m_defaultSharedTemplate != NULL) + ExitChain::add (removeDefaultTemplate, "TangibleObject::removeDefaultTemplate"); + } + return m_defaultSharedTemplate; +} // TangibleObject::getDefaultSharedTemplate + +//----------------------------------------------------------------------- + +/** + * Cleans up the default shared template. + */ +void TangibleObject::removeDefaultTemplate(void) +{ + if (m_defaultSharedTemplate != NULL) + { + m_defaultSharedTemplate->releaseReference(); + m_defaultSharedTemplate = NULL; + } +} // TangibleObject::removeDefaultTemplate + +//----------------------------------------------------------------------- + +/** + * Returns the name of the shared template that will be sent to the client when + * this object is created. If this object has a custom appearance, that template + * name will be returned, otherwise the default name will be returned. + * + * + */ +const char * TangibleObject::getClientSharedTemplateName(void) const +{ + if (!m_customAppearance.get().empty()) + return m_customAppearance.get().c_str(); + return ServerObject::getClientSharedTemplateName(); +} // TangibleObject::getClientSharedTemplateName + +//----------------------------------------------------------------------- + +void TangibleObject::addLocationTarget(const LocationData & location) +{ + if(isAuthoritative()) + { + std::vector::const_iterator i; + for(i = m_locationTargets.begin(); i != m_locationTargets.end(); ++i) + { + if((*i).name == location.name) + { + m_locationTargets.set(static_cast(std::distance(m_locationTargets.begin(), i)), location); + return; + } + } + m_locationTargets.push_back(location); + scheduleForAlter(); + } + else + { + sendControllerMessageToAuthServer(CM_addLocationTarget, new MessageQueueGenericValueType(location)); + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::removeLocationTarget(const Unicode::String & locationName) +{ + if(isAuthoritative()) + { + std::vector::const_iterator i; + for(i = m_locationTargets.begin(); i != m_locationTargets.end(); ++i) + { + if((*i).name == locationName) + { + m_locationTargets.erase(static_cast(std::distance(m_locationTargets.begin(), i))); + return; + } + } + } + else + { + sendControllerMessageToAuthServer(CM_removeLocationTarget, new MessageQueueGenericValueType(locationName)); + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::onArrivedAtLocation(const LocationData & location) +{ + // only invokes a script trigger, which is automagically forwarded to + // the authoritative server + if(getScriptObject()) + { + ScriptParams p; + p.addParam(location.name); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_ARRIVE_AT_LOCATION, p)); + } +} +// ---------------------------------------------------------------------- + +/** + * This function is called after the TangibleObject has received a + * new custom appearance string. + * + * @arg value the value of the new custom appearance string + */ +void TangibleObject::customAppearanceModified(const std::string& value) +{ + // we don't value to use the value arg since we already have the + // data stored in m_customAppearance, but just in case the interface + // changes, we'll use it here. + + if (value.empty()) + return; +} // TangibleObject::customAppearanceModified + +// ---------------------------------------------------------------------- + +/** + * This function is called after the TangibleObject has received a + * new appearance data customization string. + * + * @arg value the value of the new appearance customization string + */ + +// ---------------------------------------------------------------------- + +void TangibleObject::appearanceDataModified(const std::string& value) +{ + // we don't value to use the value arg since we already have the + // data stored in m_appearanceData, but just in case the interface + // changes, we'll use it here. Technically we don't need to keep + // the m_appearanceData string around on the client. We can build + // it at will from the appearance. + + //-- skip no-content customization data + if (value.empty()) + return; + + // check if the property exists + CustomizationDataProperty *cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); + + if (!cdProperty) + { + // every debug warning I put here goes into never-never land in addr2line. real handy feature... + // DEBUG_WARNING(true, ("non-zero-length appearance string sent to object that doesn't declare any customization variables in its template.")); + // DEBUG_WARNING(true, ("received appear string for non-customizable object.")); + return; + } + + // retrieve the CustomizationData instance associated with the property + CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); + NOT_NULL(customizationData); + + //-- initialize CustomizationData variable values from the string + customizationData->loadLocalDataFromString(value); + + //-- release local reference + customizationData->release(); +} +//----------------------------------------------------------------------- + +/** + * Gets all the equipped items corresponding to a combat skeleton "bone". + * + * @param combatBone the bone we want equipment for + * @param items list to be filled in with the items + */ +void TangibleObject::getEquippedItems(uint32 combatBone, std::vector &items) const +{ + SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); + if (container == NULL) + return; + + std::vector itemIds; + container->getObjectsForCombatBone(combatBone, itemIds); + + std::vector::const_iterator iter; + for (iter = itemIds.begin(); iter != itemIds.end(); ++iter) + { + Object * object = (*iter).getObject(); + if (object != NULL) + { + TangibleObject * item = dynamic_cast(object); + if (item != NULL) + items.push_back(item); + } + } +} // TangibleObject::getEquippedItems + +//----------------------------------------------------------------------- + +/** + * Returns a random equipped item corresponding to a combat skeleton "bone". + * + * @param combatBone the bone we want the item for + * + * @return the item + */ +TangibleObject * TangibleObject::getRandomEquippedItem(uint32 combatBone) const +{ + std::vector items; + getEquippedItems(combatBone, items); + + if (items.empty()) + { + return NULL; + } + + int index = Random::random(0, items.size() - 1); + return items[index]; +} // TangibleObject::getRandomEquippedItem + +//----------------------------------------------------------------------- + +/** + * Updates the object for damage taken in battle. + * + * @param time current game time + * + * @return base class result + */ +float TangibleObject::alter(real time) +{ + PROFILER_AUTO_BLOCK_DEFINE("TangibleObject::alter"); + + if (isAuthoritative()) + { + // Determine the combat state of the object + { + CombatEngine::alter(*this); + + m_hateList.alter(); + + if (!m_hateList.isEmpty()) + { + if (!isPlayerControlled()) + { + // AI + + // Schedule the AI for an update + { + AiCombatPulseQueue::schedule(this, 0, static_cast(time * 1000.0f)); + } + } + else + { + // Player + + // Make sure the hate list is purged of invalid hate targets. If a player is no + // longer hated by a hate target, then remove that target from the player's list. + // A player must be in their hate target's hate list and vice versa. + { + typedef std::vector PurgeList; + static PurgeList purgeList; + purgeList.clear(); + + HateList::UnSortedList const & unSortedHateList = getUnSortedHateList(); + HateList::UnSortedList::const_iterator iterUnSortedHateList = unSortedHateList.begin(); + + for (; iterUnSortedHateList != unSortedHateList.end(); ++iterUnSortedHateList) + { + CachedNetworkId const & id = iterUnSortedHateList->first; + + if (!isHatedBy(id.getObject())) + { + purgeList.push_back(id); + } + } + + PurgeList::const_iterator iterPurgeList = purgeList.begin(); + + for (; iterPurgeList != purgeList.end(); ++iterPurgeList) + { + removeHateTarget(*iterPurgeList); + } + } + } + } + + if (m_hateList.isEmpty()) + { + if ( !isPlayerControlled() + || (getCombatDuration() > s_minCombatDuration)) + { + setInCombat(false); + } + } + } + } + + // check for location target arrival + if(isAuthoritative() && !m_locationTargets.empty()) + { + Vector const effectiveWorldLocation = findPosition_w(); + for (std::vector::const_iterator i = m_locationTargets.begin(); i != m_locationTargets.end(); ++i) + { + if ((*i).scene == ServerWorld::getSceneId()) + { + Sphere const &s = (*i).location; + // 3d targets are denoted by y coordinates > 50k, with 100k added to them + // If it's a 3d target, add 100k to our y coordinate + // If it's a 2d target, set our y coordinate to the target's + // 2d comparison, put locations on same plane + Vector v = effectiveWorldLocation; + if (s.getCenter().y > 50000.0f) + v.y += 100000.0f; + else + v.y = s.getCenter().y; + + if (s.contains(v)) + { + // copy the location data so we can remove it from the vector prior to triggerring + LocationData triggeredLocation(*i); + removeLocationTarget((*i).name); + // trigger any scripts + onArrivedAtLocation(triggeredLocation); + // we'll catch any additional location triggers going off during the next alter + break; + } + } + } + } + + //-- handle modified customization data + if (isCustomizationDataModified()) + { + // associated CustomizationData instance is modified. Pack CustomizationData + // into m_appearanceData string, which will get sent to others. + + //-- get property + CustomizationDataProperty *cdProperty = safe_cast(getProperty(CustomizationDataProperty::getClassPropertyId())); + if (!cdProperty) + { + DEBUG_WARNING(true, ("customization data modified but no customization data!")); + } + else + { + // retrieve the CustomizationData instance associated with the property + CustomizationData *const customizationData = cdProperty->fetchCustomizationData(); + NOT_NULL(customizationData); + + //-- initialize CustomizationData variable values from the string + m_appearanceData.set(customizationData->writeLocalDataToString()); + + //-- release reference + customizationData->release(); + + } + + // reset flag + setCustomizationDataModified(false); + } + + return ServerObject::alter(time); +} // TangibleObject::alter + +//----------------------------------------------------------------------- + +float TangibleObject::getNextAlterTime(float baseAlterTime) const +{ + if (baseAlterTime == AlterResult::cms_kill || baseAlterTime == AlterResult::cms_alterNextFrame) + return baseAlterTime; + + float result = baseAlterTime; + + if (getSynchronizedUi() && dynamic_cast(getSynchronizedUi())) + return AlterResult::cms_alterNextFrame; + + if (isAuthoritative()) + { + if (isInCombat()) + return AlterResult::cms_alterNextFrame; + + if (!m_locationTargets.empty()) + AlterResult::incorporateAlterResult(result, ConfigServerGame::getLocationTargetCheckIntervalSec()); + } + + return result; +} + +//----------------------------------------------------------------------- + +void TangibleObject::conclude() +{ + PROFILER_AUTO_BLOCK_DEFINE("TangibleObject::conclude"); + + // if we are a crafting tool, conclude our prototype and manf schematic + if (getSynchronizedUi() != NULL) + { + const CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync != NULL) + { + Object * object = sync->getPrototype().getObject(); + if (object != NULL) + object->conclude(); + object = sync->getManfSchematic().getObject(); + if (object != NULL) + object->conclude(); + } + } + + ServerObject::conclude(); +} + +//----------------------------------------------------------------------- + +float TangibleObject::getPvpRegionCheckTime() +{ + return ConfigServerGame::getTangiblePvpRegionCheckTime(); +} + +//----------------------------------------------------------------------- + +void TangibleObject::setPvpType(Pvp::PvpType pvpType) +{ + FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpType - this should only be called from the Pvp interface.")); + Pvp::PvpType oldType = static_cast(m_pvpType.get()); + if (oldType != pvpType) + { + m_pvpType.set(static_cast(pvpType)); + m_pvpFutureType.set(-1); + if (getScriptObject()) + { + ScriptParams params; + params.addParam(oldType); + params.addParam(pvpType); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_PVP_TYPE_CHANGED, params)); + } + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::setPvpFutureType(Pvp::PvpType pvpFutureType) +{ + FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpFutureType - this should only be called from the Pvp interface.")); + Pvp::PvpType oldFutureType = static_cast(m_pvpFutureType.get()); + if (oldFutureType != pvpFutureType) + { + m_pvpFutureType.set(static_cast(pvpFutureType)); + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::setPvpFaction(Pvp::FactionId factionId) +{ + FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpFaction - this should only be called from the Pvp interface.")); + Pvp::FactionId oldFaction = static_cast(m_pvpFaction.get()); + if (oldFaction != factionId) + { + m_pvpFaction.set(static_cast(factionId)); + if (getScriptObject()) + { + ScriptParams params; + params.addParam(static_cast(oldFaction)); + params.addParam(static_cast(factionId)); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_PVP_FACTION_CHANGED, params)); + } + + // if player character is changing faction, clear + // out current accumulated CGW points and rating; + // this *MUST* be done after m_pvpFaction has + // been set to the new faction because + // modifyCurrentGcwRating() uses the faction information + CreatureObject * creature = asCreatureObject(); + if (creature) + { + PlayerObject * player = PlayerCreatureController::getPlayerObject(creature); + if (player) + { + // decrementing the value by a really large + // number will cause it to reset to 0 + static int const min = std::numeric_limits::min(); + + player->modifyCurrentGcwPoints(min, false); + player->modifyCurrentGcwRating(min, true); + + // if player is no longer factional, reset current pvp kills + if (!PvpData::isImperialFactionId(factionId) && !PvpData::isRebelFactionId(factionId)) + player->modifyCurrentPvpKills(min, false); + + // if new faction is not neutral, remove any mercenary status + if (!PvpData::isNeutralFactionId(factionId)) + Pvp::setNeutralMercenaryFaction(*creature, PvpData::getNeutralFactionId(), PvpType_Neutral); + } + } + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::setPvpMercenaryFaction(Pvp::FactionId factionId, Pvp::PvpType pvpType) +{ + FATAL(!isAuthoritative(), ("Inappropriate use of TangibleObject::setPvpMercenaryFaction - this should only be called from the Pvp interface.")); + + // this only applies to neutral + if (!PvpData::isNeutralFactionId(m_pvpFaction.get()) && !PvpData::isNeutralFactionId(factionId)) + return; + + // this only applies to player character + PlayerObject * const po = PlayerCreatureController::getPlayerObject(asCreatureObject()); + if (!po || !po->isAuthoritative()) + return; + + // see if mercenary functionality is allowed + if (!PvpData::isNeutralFactionId(factionId)) + { + if (PvpData::isImperialFactionId(factionId)) + { + if (pvpType == PvpType_Covert) + { + if (!ConfigServerGame::getEnableCovertImperialMercenary()) + return; + + po->modifyCollectionSlotValue("covert_imperial_mercenary", 1); + po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); + po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); + po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); + + std::string const & currentTitle = po->getTitle(); + if (po->hasCompletedCollectionSlot("covert_imperial_mercenary")) + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle("covert_imperial_mercenary"); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle("covert_imperial_sympathizer"); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle("covert_imperial_loyalist"); + } + else + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle(std::string()); + } + } + else if (pvpType == PvpType_Declared) + { + if (!ConfigServerGame::getEnableOvertImperialMercenary()) + return; + + po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); + po->modifyCollectionSlotValue("overt_imperial_mercenary", 1); + po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); + po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); + + std::string const & currentTitle = po->getTitle(); + if (po->hasCompletedCollectionSlot("overt_imperial_mercenary")) + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle("overt_imperial_mercenary"); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle("overt_imperial_sympathizer"); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle("overt_imperial_loyalist"); + } + else + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle(std::string()); + } + } + else + { + return; + } + } + else if (PvpData::isRebelFactionId(factionId)) + { + if (pvpType == PvpType_Covert) + { + if (!ConfigServerGame::getEnableCovertRebelMercenary()) + return; + + po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); + po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); + po->modifyCollectionSlotValue("covert_rebel_mercenary", 1); + po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); + + std::string const & currentTitle = po->getTitle(); + if (po->hasCompletedCollectionSlot("covert_rebel_mercenary")) + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle("covert_rebel_mercenary"); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle("covert_rebel_sympathizer"); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle("covert_rebel_insurgent"); + } + else + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle(std::string()); + } + } + else if (pvpType == PvpType_Declared) + { + if (!ConfigServerGame::getEnableOvertRebelMercenary()) + return; + + po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); + po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); + po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); + po->modifyCollectionSlotValue("overt_rebel_mercenary", 1); + + std::string const & currentTitle = po->getTitle(); + if (po->hasCompletedCollectionSlot("overt_rebel_mercenary")) + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle("overt_rebel_mercenary"); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle("overt_rebel_sympathizer"); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle("overt_rebel_insurgent"); + } + else + { + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer")) + po->setTitle(std::string()); + else if ((currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + po->setTitle(std::string()); + } + } + else + { + return; + } + } + else + { + return; + } + } + else + { + po->modifyCollectionSlotValue("covert_imperial_mercenary", -1); + po->modifyCollectionSlotValue("overt_imperial_mercenary", -1); + po->modifyCollectionSlotValue("covert_rebel_mercenary", -1); + po->modifyCollectionSlotValue("overt_rebel_mercenary", -1); + + std::string const & currentTitle = po->getTitle(); + if ((currentTitle == "covert_imperial_mercenary") || (currentTitle == "overt_imperial_mercenary") || (currentTitle == "covert_rebel_mercenary") || (currentTitle == "overt_rebel_mercenary") || + (currentTitle == "covert_imperial_sympathizer") || (currentTitle == "overt_imperial_sympathizer") || (currentTitle == "covert_rebel_sympathizer") || (currentTitle == "overt_rebel_sympathizer") || + (currentTitle == "covert_imperial_loyalist") || (currentTitle == "overt_imperial_loyalist") || (currentTitle == "covert_rebel_insurgent") || (currentTitle == "overt_rebel_insurgent")) + { + po->setTitle(std::string()); + } + } + + // flag when the player stopped being a factional helper for the particular faction + if (m_pvpMercenaryFaction.get() != factionId) + { + if (PvpData::isImperialFactionId(m_pvpMercenaryFaction.get())) + { + IGNORE_RETURN(setObjVarItem("factionalHelper.timeStopHelpingImperial", static_cast(::time(NULL)))); + removeObjVarItem("factionalHelper.timeStopHelpingRebel"); + } + else if (PvpData::isRebelFactionId(m_pvpMercenaryFaction.get())) + { + IGNORE_RETURN(setObjVarItem("factionalHelper.timeStopHelpingRebel", static_cast(::time(NULL)))); + removeObjVarItem("factionalHelper.timeStopHelpingImperial"); + } + } + + m_pvpMercenaryFaction.set(static_cast(factionId)); + m_pvpMercenaryType.set(((PvpData::isNeutralFactionId(factionId)) ? PvpType_Neutral : static_cast(pvpType))); +} + +//----------------------------------------------------------------------- + +Region const *TangibleObject::getPvpRegion() const +{ + uint32 crc = m_pvpRegionCrc.get(); + if (crc) + return Region::findRegionByNameCrc(crc); + return 0; +} + +//----------------------------------------------------------------------- + +/** + * Sets the pvp region this object is in. + * + * @param pvpRegion the pvp region + */ +void TangibleObject::setPvpRegion(Region const * pvpRegion) +{ + if (isAuthoritative()) + { + uint32 crc = pvpRegion ? pvpRegion->getNameCrc() : 0; + if (m_pvpRegionCrc.get() != crc) + m_pvpRegionCrc = crc; + } + else + { + FATAL(true, ("TangibleObject::setPvpRegion : send message to auth object!!!")); + } +} + +//----------------------------------------------------------------------- + +/** + * Creates a default controller for this object. + * + * @return the object's controller + */ +Controller* TangibleObject::createDefaultController(void) +{ + Controller* controller = new TangibleController(this); + NOT_NULL(controller); + + setController(controller); + return controller; +} // TangibleObject::createDefaultController + +//----------------------------------------------------------------------- + +void TangibleObject::forwardServerObjectSpecificBaselines() const +{ + ServerObject::forwardServerObjectSpecificBaselines(); +} + +//----------------------------------------------------------------------- + +TangibleObject const &TangibleObject::getPvpViewer(Client const &client) const +{ + TangibleObject const * const clientObj = safe_cast(client.getCharacterObject()); + FATAL(!clientObj, ("Client trying to get pvp viewer with no character object?")); + return *clientObj; +} + +//----------------------------------------------------------------------- + +void TangibleObject::sendObjectSpecificBaselinesToClient(Client const &client) const +{ + ServerObject::sendObjectSpecificBaselinesToClient(client); + if (!isNonPvpObject()) + { + uint32 flags, factionId; + Pvp::getClientVisibleStatus(client, *this, flags, factionId); + UpdatePvpStatusMessage const statusMessage(getNetworkId(), flags, factionId); + client.send(statusMessage, true); + PvpUpdateObserver::updatePvpStatusCache(&client, *this, flags, factionId); + } +} + +//----------------------------------------------------------------------- + +/** + * Flags the object as being cached on the client or not. + */ +void TangibleObject::setCacheVersion(const int cacheVersion) +{ + ServerObject::setCacheVersion(cacheVersion); + + // if we are cached, we need to be made invulnerable + // @todo: if we are not cached, do we need to change our invulnerability? + if (cacheVersion > 0) + setInvulnerable(true); +} // TangibleObject::setCacheVersion + +//----------------------------------------------------------------------- + +/** + * Allows an object to do pre-deletion cleanup. + */ +void TangibleObject::onRemovingFromWorld() +{ + ServerObject::onRemovingFromWorld(); + + clearHateList(); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::unload() +{ + ServerObject::unload(); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::onPermanentlyDestroyed() +{ + ServerObject::onPermanentlyDestroyed(); + + if (isAuthoritative()) + { + clearHateList(); + + if (isCraftingTool()) + { + ServerObject * owner = ServerWorld::findObjectByNetworkId(getOwnerId()); + if (owner != NULL && owner->asCreatureObject() != NULL) + { + PlayerObject * player = PlayerCreatureController::getPlayerObject( + owner->asCreatureObject()); + if (player != NULL && player->isCrafting() && player->getCraftingTool() == getNetworkId()) + player->stopCrafting(false); + } + } + } + + if (isWaypoint()) + { + ServerPathfindingNotification::destroyWaypoint(this); + } +} + +//----------------------------------------------------------------------- + +/** + * Creates a synchronized ui class in order to get data to the client during a + * crafting session. + * + * @return the newly created class + */ +ServerSynchronizedUi * TangibleObject::createSynchronizedUi () +{ + return new CraftingToolSyncUi(*this); +} + + +// ====================================================================== +// TangibleObject private static member functions +// ====================================================================== + +void TangibleObject::customizationDataModificationCallback(const CustomizationData & /* customizationData */, const void *context) +{ + if (!context) + return; + + //-- turn context into TangibleObject + TangibleObject *const tangibleObject = const_cast(reinterpret_cast(context)); + + //-- set the tangible object's customization data modification flag now. + // The reason we don't handle the customization data change now is that + // we want to lump up all the changes that occur during one server + // frame and handle the string conversion once. + tangibleObject->setCustomizationDataModified(true); +} + +// ====================================================================== +// TangibleObject private member functions +// ====================================================================== + +void TangibleObject::handleContainerSetup() +{ + +} + +//----------------------------------------------------------------------- + +void TangibleObject::setOwnerId(NetworkId const &id) +{ + if(isAuthoritative()) + { + // if we are changing owners, we are no longer insured + bool ownerChanged = false; + if (m_ownerId.get() != id) + { + ownerChanged = true; + setInsured(false); + } + + m_ownerId = id; + Container* container = ContainerInterface::getContainer(*this); + if (container) + { + ContainerIterator i = container->begin(); + for (; i != container->end(); ++i) + { + ServerObject* content = safe_cast((*i).getObject()); + if (content && !dynamic_cast(content)) + { + content->setOwnerId(id); + } + } + } + + // if we're hidden, who can see us has changed + if (ownerChanged && isInWorld() && isHidden()) + visibilityDataModified(); + } + else + { + sendControllerMessageToAuthServer(CM_setOwnerId, new MessageQueueNetworkId(id)); + } +} +//----------------------------------------------------------------------- + +bool TangibleObject::onContainerAboutToTransfer(ServerObject * destination, ServerObject* transferer) +{ + const int got = getGameObjectType (); + if (got == SharedObjectTemplate::GOT_misc_crafting_station && destination && !destination->asCellObject()) + { + //Only allow stations to be trasferred if their hoppers are empty + Container* container = ContainerInterface::getContainer(*this); + if (container) + { + ContainerIterator i = container->begin(); + for (; i != container->end(); ++i) + { + ServerObject* content = safe_cast((*i).getObject()); + if (!isEmpty(*content)) + { + + if (transferer && transferer->getClient()) + ContainerInterface::sendContainerMessageToClient(*transferer, Container::CEC_HopperNotEmpty); + return false; + } + } + } + } + if (destination != NULL && getObjVars().hasItem(OBJVAR_BIO_LINK_ID)) + { + // if this item is bio-linked and a player is trying to equip it, make + // sure the link id matches the player's id + if (destination->asCreatureObject() != NULL) + { + // allow holograms to have biolinked items transferred to them + int hologramVal = 0; + destination->getObjVars().getItem("hologram_performer", hologramVal); + + NetworkId linkId(getBioLink()); + if (linkId != destination->getNetworkId() && hologramVal == 0) + { + if (transferer && transferer->getClient()) + ContainerInterface::sendContainerMessageToClient(*transferer, Container::CEC_BioLinkedToOtherPlayer); + return false; + } + } + + // Check to see if we're trying to appearance equip a biolinked item. + Object * containedBy = ContainerInterface::getContainedByObject(*destination); + if(containedBy && containedBy->asServerObject() && containedBy->asServerObject()->asCreatureObject()) + { + CreatureObject * creatureContainer = containedBy->asServerObject()->asCreatureObject(); + if(creatureContainer && creatureContainer->getAppearanceInventory() && creatureContainer->getAppearanceInventory() == destination) + { + // We're trying to appearance equip a biolinked item. Make sure the BioLink ID matches our player ID. + NetworkId linkId(getBioLink()); + if (linkId != creatureContainer->getNetworkId()) + { + if (transferer && transferer->getClient()) + ContainerInterface::sendContainerMessageToClient(*transferer, Container::CEC_BioLinkedToOtherPlayer); + return false; + } + } + } + } + return ServerObject::onContainerAboutToTransfer(destination, transferer); +} + +//----------------------------------------------------------------------- + +bool TangibleObject::onContainerChildAboutToLoseItem(ServerObject *destination, ServerObject &item, ServerObject *transferer) +{ + int const got = getGameObjectType(); + if (transferer && got == SharedObjectTemplate::GOT_misc_crafting_station && !isInWorld()) + return false; + + if (getPortalProperty() && !onPobChildAboutToLoseItem(destination, item, transferer)) + return false; + + return ServerObject::onContainerChildAboutToLoseItem(destination, item, transferer); +} + +//----------------------------------------------------------------------- + +bool TangibleObject::onContainerChildAboutToGainItem(ServerObject &item, ServerObject *destination, ServerObject *transferer) +{ + int const got = getGameObjectType(); + if (transferer && got == SharedObjectTemplate::GOT_misc_crafting_station && !isInWorld()) + return false; + + if (getPortalProperty() && !onPobChildAboutToGainItem(item, destination, transferer)) + return false; + + return ServerObject::onContainerChildAboutToGainItem(item, destination, transferer); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::onContainerChildLostItem(ServerObject *destination, ServerObject &item, ServerObject *source, ServerObject *transferer) +{ + if (getPortalProperty()) + onPobChildLostItem(destination, item, source, transferer); + ServerObject::onContainerChildLostItem(destination, item, source, transferer); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::onContainerChildGainItem(ServerObject &item, ServerObject *source, ServerObject *transferer) +{ + if (getPortalProperty()) + onPobChildGainItem(item, source, transferer); + ServerObject::onContainerChildGainItem(item, source, transferer); +} + +// ---------------------------------------------------------------------- + +int TangibleObject::onContainerAboutToGainItem(ServerObject& item, ServerObject* transferer) +{ + if (transferer && isCraftingTool()) + { + return Container::CEC_BlockedByDestinationContainer; + } + return ServerObject::onContainerAboutToGainItem(item, transferer); +} + +//---------------------------------------------------------------------- + +void TangibleObject::onContainerGainItem(ServerObject& item, ServerObject* source, ServerObject* transferer) +{ + ServerObject::onContainerGainItem(item, source, transferer); + //do not set owners of creatures + //and do not set the owner of items going into the bazaar + if (getOwnerId() != NetworkId::cms_invalid && !item.asCreatureObject() && !isBazaarTerminal()) + item.setOwnerId(getOwnerId()); +} + +// ---------------------------------------------------------------------- + +Footprint *TangibleObject::getFootprint() +{ + CollisionProperty *const property = getCollisionProperty(); + if (property) + return property->getFootprint(); + else + return NULL; +} + +//----------------------------------------------------------------------- + +Footprint const *TangibleObject::getFootprint() const +{ + CollisionProperty const *const property = getCollisionProperty(); + if (property) + return property->getFootprint(); + else + return NULL; +} + +// ---------------------------------------------------------------------- + +/** + * Sets up the object for being in or out of combat. + * + * @param inCombat flag to put the object in combat-ready state or not + * + * @return true if state was set, false if something went wrong + */ +void TangibleObject::setInCombat(bool inCombat) +{ + m_inCombat = inCombat; +} + +//----------------------------------------------------------------------- + +/** + * If this object is in combat, adds an aim to it. + */ +void TangibleObject::addAim(void) +{ + if(isAuthoritative()) + { + if (isInCombat()) + { + CombatEngineData::AttackData & attackData = NON_NULL(getCombatData())->attackData; + + if (attackData.aims < ConfigCombatEngine::getMaxAims()) + { + ++attackData.aims; + } + } + } + else + { + sendControllerMessageToAuthServer(CM_addAim, 0); + } +} // TangibleObject::addAim + +//----------------------------------------------------------------------- + +/** + * If this object is in combat, clear's it's aims. + */ +void TangibleObject::clearAims(void) +{ + if(isAuthoritative()) + { + if (isInCombat()) + { + CombatEngineData::AttackData & attackData = NON_NULL(getCombatData())->attackData; + attackData.aims = 0; + } + } + else + { + sendControllerMessageToAuthServer(CM_clearAims, 0); + } +} // TangibleObject::clearAims + +//----------------------------------------------------------------------- + +/** + * Applies damage to the object. No other function should modify m_damageTaken. + * + * @param delta amount of damage to apply + * @param ignoreInvulnerable flag to ignore the invulnerable setting of this object + * @param source who is doing the damage + * + * @return the amount of damage actually applied + */ +int TangibleObject::alterHitPoints(int delta, bool ignoreInvulnerable, + const NetworkId & source) +{ + if(isAuthoritative()) + { +#ifdef _DEBUG + char debugBuffer[1024]; + const char * craftedString = ""; + Client *client = NULL; + ServerObject * sourceObject = safe_cast(NetworkIdManager::getObjectById(source)); + if (source != NetworkId::cms_invalid && sourceObject != NULL) + client = sourceObject->getClient(); +#endif + + // Only consider tangible invulnerability rules for this case + if (isDisabled() || (!ignoreInvulnerable && TangibleObject::isInvulnerable())) + return 0; + + int totalHitPoints = getMaxHitPoints(); + int totalDamageTaken = m_damageTaken.get() - delta; + +#ifdef _DEBUG + if (ConfigCombatEngine::getDebugDamage()) + { + snprintf(debugBuffer, sizeof(debugBuffer), "%s object %s (hp=%d) damaged " + "from %d to %d\n", craftedString, getNetworkId().getValueString().c_str(), + totalHitPoints, m_damageTaken.get(), totalDamageTaken); + DEBUG_REPORT_LOG (true, ("%s", debugBuffer)); + if (source != NetworkId::cms_invalid && client != NULL) + ConsoleMgr::broadcastString(debugBuffer, client); + } +#endif + + if (totalDamageTaken >= totalHitPoints) + { + // clip delta and damage taken + if (isDisabled()) + delta = 0; + else + delta += totalDamageTaken - totalHitPoints; + totalDamageTaken = totalHitPoints; + } + else if (totalDamageTaken < 0) + totalDamageTaken = 0; + if (totalDamageTaken == totalHitPoints) + setDisabled(true); + + m_damageTaken = totalDamageTaken; + + if (isDisabled()) + { +#ifdef _DEBUG + if (ConfigCombatEngine::getDebugDamage()) + { + snprintf(debugBuffer, sizeof(debugBuffer), "%s object %s has been " + "disabled\n", craftedString, getNetworkId().getValueString().c_str()); + DEBUG_REPORT_LOG (true, ("%s", debugBuffer)); + if (source != NetworkId::cms_invalid && client != NULL) + ConsoleMgr::broadcastString(debugBuffer, client); + } +#endif + ScriptParams params; + params.addParam(source); + IGNORE_RETURN(getScriptObject()->trigAllScripts( + Scripting::TRIG_OBJECT_DISABLED, params)); + } + scheduleForAlter(); + return delta; + } + else + { + sendControllerMessageToAuthServer(CM_alterHitPoints, new MessageQueueGenericValueType >(std::make_pair(delta, source))); + return 0; + } +} // TangibleObject::alterHitpoints + +//----------------------------------------------------------------------- + +/** + * Applies damage done during combat to the object. + * + * @param damageData the damage + */ +void TangibleObject::applyDamage(const CombatEngineData::DamageData &damageData) +{ + int totalDamage = 0; + + WARNING_STRICT_FATAL(! isAuthoritative(), ("TangibleObject::applyDamage() invoked on a NON-AUTHORITATIVE object %s:%s.", getObjectTemplateName(), getNetworkId().getValueString().c_str())); + + // it is possible for damageData to go bad if this object is being damaged from + // combat and it goes out of combat, so we copy the items we need off of it + const NetworkId attackerId(damageData.attackerId); + const NetworkId weaponId(damageData.weaponId); + + std::vector::const_iterator iter; + for (iter = damageData.damage.begin(); !isDisabled() && iter != damageData.damage.end(); + ++iter) + { + const AttribMod::AttribMod &mod = *iter; + if (mod.value == 0) + continue; + + if (AttribMod::isDirectDamage(mod)) + { + // apply instantanious damage directly + totalDamage -= alterHitPoints(mod.value, damageData.ignoreInvulnerable, + attackerId); + } + else + { + WARNING(true, ("Trying to apply non-immediate damage to tangible " + "object %s. This isn't supported, the damage won't be applied", + getNetworkId().getValueString().c_str())); + } + } + + // tell scripts we have taken combat damage + if (attackerId != NetworkId::cms_invalid && totalDamage > 0) + { + NOT_NULL(getScriptObject()); + ScriptParams params; + params.addParam(attackerId); + params.addParam(weaponId); + params.addParam(totalDamage); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_OBJECT_DAMAGED, + params)); + } +} + +// ---------------------------------------------------------------------- + +/** + * Sends a message to the Planet Server to update the position of the object. + */ +void TangibleObject::updatePlanetServerInternal(const bool forceUpdate) const +{ + // Don't send updates for contained tangibles without an interest radius, and only send when forced or moving + if ((forceUpdate || getPositionChanged()) && (!ContainerInterface::getContainedByObject(*this) || getInterestRadius() > 0)) + { + Object const * const topmostContainer = ContainerInterface::getTopmostContainer(*this); + FATAL(!topmostContainer, ("Object %s was contained by something, but getTopmostContainer() returned NULL\n",getNetworkId().getValueString().c_str())); + Vector const &position = topmostContainer->getPosition_p(); + + UpdateObjectOnPlanetMessage const msg( + getNetworkId(), + topmostContainer == this ? NetworkId::cms_invalid : topmostContainer->getNetworkId(), + static_cast(position.x), + static_cast(position.y), + static_cast(position.z), + getInterestRadius(), + static_cast (getLocationReservationRadius()), + false, + false, + static_cast(getObjectType()), + 0, + false, + getTemplateCrc(), + -1, + -1); + GameServer::getInstance().sendToPlanetServer(msg); + } +} + +//---------------------------------------------------------------------- + +/** + * Clears our damage list. + */ +void TangibleObject::clearDamageList(void) +{ + if (m_combatData != NULL) + { + m_combatData->defenseData.damage.clear(); + } +} + +//---------------------------------------------------------------------- + +bool TangibleObject::addHate(NetworkId const & target, float const hate) +{ + bool result = false; + + if (isAuthoritative()) + { + if (m_hateList.addHate(target, hate)) + { + result = true; + + CombatTracker::addDefender(this); + setInCombat(true); + scheduleForAlter(); + } + } + else + { + sendControllerMessageToAuthServer(CM_addHate, new MessageQueueGenericValueType >(std::make_pair(target, hate))); + } + + return result; +} + +//---------------------------------------------------------------------- + +void TangibleObject::addHateOverTime(NetworkId const & target, float const hate, int const seconds) +{ + if (seconds <= 0) + return; + + if (isAuthoritative()) + { + unsigned long const currentGameTime = ServerClock::getInstance().getGameTimeSeconds(); + unsigned long const endGameTime = currentGameTime + seconds; + + IGNORE_RETURN(addHate(target, hate)); + + bool const firstHateOverTime = m_hateOverTime.empty(); + m_hateOverTime.set(target, std::make_pair(hate, std::make_pair(currentGameTime, endGameTime))); + + if (firstHateOverTime) + MessageToQueue::sendMessageToC(getNetworkId(), "C++ProcessHateOverTime", std::string(), 1, false); + } + else + { + sendControllerMessageToAuthServer(CM_addHateOverTime, new MessageQueueGenericValueType > >(std::make_pair(target, std::make_pair(seconds, hate)))); + } +} + +//---------------------------------------------------------------------- + +bool TangibleObject::setHate(NetworkId const & target, float const hate) +{ + bool result = false; + + if (isAuthoritative()) + { + if (m_hateList.setHate(target, hate)) + { + result = true; + + CombatTracker::addDefender(this); + setInCombat(true); + scheduleForAlter(); + } + } + else + { + sendControllerMessageToAuthServer(CM_setHate, new MessageQueueGenericValueType >(std::make_pair(target, hate))); + } + + return result; +} + +//---------------------------------------------------------------------- + +float TangibleObject::getHate(NetworkId const & target) const +{ + return m_hateList.getHate(target); +} + +//---------------------------------------------------------------------- + +float TangibleObject::getMaxHate() const +{ + return m_hateList.getMaxHate(); +} + +//---------------------------------------------------------------------- + +CachedNetworkId const & TangibleObject::getHateTarget() const +{ + return m_hateList.getTarget(); +} + +//---------------------------------------------------------------------- + +void TangibleObject::removeHateTarget(NetworkId const & target) +{ + if (isAuthoritative()) + { + m_hateList.removeTarget(target); + scheduleForAlter(); + } + else + { + sendControllerMessageToAuthServer(CM_removeHateTarget, new MessageQueueGenericValueType(target)); + } +} + +//---------------------------------------------------------------------- + +void TangibleObject::clearHateList() +{ + if (isAuthoritative()) + { + m_hateList.clear(); + scheduleForAlter(); + } + else + { + sendControllerMessageToAuthServer(CM_clearHateList, NULL); + } +} + +//----------------------------------------------------------------------- + +HateList::UnSortedList const & TangibleObject::getUnSortedHateList() const +{ + return m_hateList.getUnSortedList(); +} + +//----------------------------------------------------------------------- + +void TangibleObject::getSortedHateList(HateList::SortedList & sortedHateList) const +{ + m_hateList.getSortedList(sortedHateList); +} + +//----------------------------------------------------------------------- + +void TangibleObject::verifyHateList() +{ + LOGC(ConfigServerGame::isAiLoggingEnabled(), "debug_ai", ("TangibleObject::verifyHateList() owner(%s:%s)", getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(getEncodedObjectName()).c_str())); + + m_hateList.alter(); +} + +//----------------------------------------------------------------------- + +bool TangibleObject::isHatedBy(Object * const object) +{ + bool result = false; + TangibleObject * const hatedByTangibleObject = TangibleObject::asTangibleObject(object); + + if (hatedByTangibleObject != NULL) + { + HateList::UnSortedList const & hateList = hatedByTangibleObject->getUnSortedHateList(); + + if (hateList.find(CachedNetworkId(*this)) != hateList.end()) + { + result = true; + } + } + + return result; +} + +//----------------------------------------------------------------------- + +bool TangibleObject::isOnHateList(NetworkId const & target) const +{ + return m_hateList.isOnList(target); +} + +//----------------------------------------------------------------------- + +int TangibleObject::getTimeSinceLastHateListUpdate() const +{ + return m_hateList.getTimeSinceLastUpdate(); +} + +//----------------------------------------------------------------------- + +bool TangibleObject::isHateListEmpty() const +{ + return m_hateList.isEmpty(); +} + +//----------------------------------------------------------------------- +HateList::RecentList const & TangibleObject::getRecentHateList() const +{ + return m_hateList.getRecentList(); +} + +//----------------------------------------------------------------------- +void TangibleObject::clearRecentHateList() +{ + m_hateList.clearRecentList(); + scheduleForAlter(); +} + +//----------------------------------------------------------------------- + +void TangibleObject::resetHateTimer() +{ + if (isAuthoritative()) + { + m_hateList.resetHateTimer(); + scheduleForAlter(); + } + else + { + sendControllerMessageToAuthServer(CM_resetHateTimer, NULL); + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::setHateListAutoExpireTargetEnabled(bool const enabled) +{ + m_hateList.setAutoExpireTargetEnabled(enabled); + + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_autoExpireHateListTargetEnabled, new MessageQueueGenericValueType(enabled)); + } +} + +//----------------------------------------------------------------------- + +bool TangibleObject::isHateListAutoExpireTargetEnabled() const +{ + return m_hateList.isAutoExpireTargetEnabled(); +} + +//----------------------------------------------------------------------- + +int TangibleObject::getHateListAutoExpireTargetDuration() const +{ + return m_hateList.getAutoExpireTargetDuration(); +} + +//----------------------------------------------------------------------- +float TangibleObject::getAILeashTime() const +{ + return m_hateList.getAILeashTime(); +} + + +//----------------------------------------------------------------------- +void TangibleObject::setAILeashTime( float time ) +{ + m_hateList.setAILeashTime( time ); +} + + +//----------------------------------------------------------------------- + +/** + * @return true if we are crafted, false if not + */ +bool TangibleObject::isCrafted(void) const +{ + return hasCondition(C_crafted); +} // TangibleObject::isCrafted + +//----------------------------------------------------------------------- + +/** + * Returns the id of the manufacturing schematic that was used to craft this + * item, or NetworkId::cms_invalid if the item wasn't crafted. + * + * @return the schematic id + */ +const NetworkId TangibleObject::getCraftedId(void) const +{ + NetworkId craftedId(NetworkId::cms_invalid); + getObjVars().getItem(OBJVAR_CRAFTING_SCHEMATIC,craftedId); + return craftedId; +} // TangibleObject::getCraftedId + +//----------------------------------------------------------------------- + +/** + * Sets the id of the manufacturing schematic used to create this object. + * + * @param id the schematic id + */ +void TangibleObject::setCraftedId(const NetworkId & id) +{ + if (isAuthoritative()) + { + if (id == NetworkId::cms_invalid) + { + IGNORE_RETURN(removeObjVarItem(OBJVAR_CRAFTING_SCHEMATIC)); + m_sourceDraftSchematic = 0; + clearCondition(C_crafted); + } + else + { + IGNORE_RETURN(setObjVarItem(OBJVAR_CRAFTING_SCHEMATIC, id)); + setCondition(C_crafted); + const Object * object = NetworkIdManager::getObjectById(id); + if (object != NULL) + { + const ManufactureSchematicObject * schematic = dynamic_cast< + const ManufactureSchematicObject *>(object); + if (schematic != NULL) + m_sourceDraftSchematic = schematic->getDraftSchematic(); + } + } + } + else + { + sendControllerMessageToAuthServer(CM_setCraftedId, + new MessageQueueGenericValueType(id)); + } +} // TangibleObject::setCraftedId + +//----------------------------------------------------------------------- + +/** + * Returns the crafting type of a crafting/repair tool. + * + * @return the crafting type + */ +int TangibleObject::getCraftingType(void) const +{ + int type = 0; + getObjVars().getItem(OBJVAR_CRAFTING_TYPE, type); + return type; +} // TangibleObject::getCraftingType + +//----------------------------------------------------------------------- + +/** + * Returns the crafted type of a crafted object. + * + * @return the crafted type + */ +int TangibleObject::getCraftedType(void) const +{ + int craftedType = 0; + getObjVars().getItem(OBJVAR_CRAFTING_REPAIR_TYPE,craftedType); + return craftedType; +} // TangibleObject::getCraftedType + +//----------------------------------------------------------------------- + +/** + * Sets the crafted type of a crafted object. + * + * @param type the crafted type + */ +void TangibleObject::setCraftedType(int type) +{ + if (isAuthoritative()) + { + IGNORE_RETURN(setObjVarItem(OBJVAR_CRAFTING_REPAIR_TYPE, type)); + } + else + { + sendControllerMessageToAuthServer(CM_setCraftedType, + new MessageQueueGenericValueType(type)); + } +} // TangibleObject::setCraftedType + +//----------------------------------------------------------------------- + +/** + * Returns the id of the object's creator's id. + * + * @return the object's creator's id + */ +const NetworkId TangibleObject::getCreatorId(void) const +{ + if (m_creatorId.get() == NetworkId::cms_invalid) + { + // @todo remove this code when no object has the objvar + // OBJVAR_CREATOR_ID + NetworkId creatorId(NetworkId::cms_invalid); + if (getObjVars().getItem(OBJVAR_CREATOR_ID, creatorId)) + { + const_cast(this)->setCreatorId(creatorId); + return creatorId; + } + } + return m_creatorId.get(); +} // TangibleObject::getCreatorId + +//----------------------------------------------------------------------- + +/** + * Sets the creator id of this object. + * + * @param creatorId the creator id + */ +void TangibleObject::setCreatorId(const NetworkId & creatorId) +{ + if (isAuthoritative()) + { + m_creatorId = creatorId; + if (getObjVars().hasItem(OBJVAR_CREATOR_ID)) + removeObjVarItem(OBJVAR_CREATOR_ID); + } + else + { + sendControllerMessageToAuthServer(CM_setCreatorId, + new MessageQueueGenericValueType(creatorId)); + } +} // TangibleObject::setCreatorId + +//----------------------------------------------------------------------- + +/** + * Returns the id of the object's creator's name. + * + * @return the object's creator's name + */ +const Unicode::String TangibleObject::getCreatorName(void) const +{ + return Unicode::narrowToWide(NameManager::getInstance().getPlayerName( + getCreatorId())); +} // TangibleObject::getCreatorName + +//----------------------------------------------------------------------- + +/** + * Returns the xp amount the creator of this object will get when it is "used". + * + * @return the xp amount + */ +int TangibleObject::getCreatorXp(void) const +{ + int creatorXp=0; + getObjVars().getItem(OBJVAR_CREATOR_XP,creatorXp); + return creatorXp; +} // TangibleObject::getCreatorXp + +//----------------------------------------------------------------------- + +/** + * Sets the xp amount the creator of this object will get when it is "used". + * + * @param xp the xp amount + */ +void TangibleObject::setCreatorXp(int xp) +{ + if (isAuthoritative()) + { + setObjVarItem(OBJVAR_CREATOR_XP, xp); + } + else + { + sendControllerMessageToAuthServer(CM_setCreatorXp, new MessageQueueGenericValueType(xp)); + } +} // TangibleObject::setCreatorXp + +//----------------------------------------------------------------------- + +/** + * Returns the xp type the creator of this object will get when it is "used". + * + * @return the xp type + */ +int TangibleObject::getCreatorXpType(void) const +{ + int creatorXpType = -1; + getObjVars().getItem(OBJVAR_CREATOR_XP_TYPE,creatorXpType); + return creatorXpType; +} // TangibleObject::getCreatorXpType + +//----------------------------------------------------------------------- + +/** + * Sets the xp type the creator of this object will get when it is "used". + * + * @param type the xp type + */ +void TangibleObject::setCreatorXpType(int type) +{ + if (isAuthoritative()) + { + setObjVarItem(OBJVAR_CREATOR_XP_TYPE, type); + } + else + { + sendControllerMessageToAuthServer(CM_setCreatorXpType, new MessageQueueGenericValueType(type)); + } +} // TangibleObject::setCreatorXpType + +//----------------------------------------------------------------------- + +/** + * Returns if this object is a crafting tool or not. + * + * @return true if we are a tool, false if not + */ +bool TangibleObject::isCraftingTool(void) const +{ + return getObjVars().hasItem(OBJVAR_CRAFTING_TOOL); +} // TangibleObject::isCraftingTool + +//----------------------------------------------------------------------- + +/** + * Returns if this object is a crafting station or not. + * + * @return true if we are a station, false if not + */ +bool TangibleObject::isCraftingStation(void) const +{ + return getObjVars().hasItem(OBJVAR_CRAFTING_STATION); +} // TangibleObject::isCraftingStation + +//----------------------------------------------------------------------- + +/** + * Returns if this object is a repair tool or not. + * + * @return true if we are a repair tool, false if not + */ +bool TangibleObject::isRepairTool(void) const +{ + return getObjVars().hasItem(OBJVAR_REPAIR_TOOL); +} // TangibleObject::isRepairTool + +//----------------------------------------------------------------------- + +/** +* If this is a crafting tool, tries to start a session with a player. +* +* @param crafter the player who wants to craft something +* +* @return true if the session was started, false if not +*/ +bool TangibleObject::startCraftingSession(CreatureObject & crafter) +{ + static const SlotId outputSlotId(SlotIdManager::findSlotId(MANF_OUTPUT_SLOT_NAME)); + + if(isAuthoritative()) + { + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + PlayerObject * crafterPlayer = PlayerCreatureController::getPlayerObject(&crafter); + if (crafterPlayer == NULL) + return false; + + // make sure we are a crafting tool + if (!isCraftingTool()) + { + DEBUG_WARNING(true, ("Tried to start crafting session on non-tool " + "object %s", myIdString)); + return false; + } + + if (isDisabled()) + { + DEBUG_WARNING(true, ("Tried to start crafting session on disabled " + "tool %s", myIdString)); + return false; + } + + // make sure the tool isn't creating a prototype + float realTimeVar = 0; + getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME,realTimeVar); + if (realTimeVar > 0) + { + StringId message("system_msg", "crafting_tool_creating_prototype"); + Unicode::String outOfBand; + Chat::sendSystemMessage(crafter, message, outOfBand); + return false; + } + + // make sure the tool isn't already being used + if (getObjVars().hasItem(OBJVAR_CRAFTING_CRAFTER)) + { + StringId message("system_msg", "crafting_tool_in_use"); + Unicode::String outOfBand; + Chat::sendSystemMessage(crafter, message, outOfBand); + return false; + } + + // make sure the output slot is empty + SlottedContainer const * const slotContainer = ContainerInterface::getSlottedContainer(*this); + if (slotContainer == NULL) + { + DEBUG_WARNING(true, ("Crafting tool %s does not have a container!", myIdString)); + return false; + } + Container::ContainerErrorCode tmp = Container::CEC_Success; + if (slotContainer->getObjectInSlot(outputSlotId, tmp) != Container::ContainedItem::cms_invalid) + { + StringId message("system_msg", "crafting_tool_full"); + Unicode::String outOfBand; + Chat::sendSystemMessage(crafter, message, outOfBand); + return false; + } + + // get the schematics list from the player and filter for the type of + // schematics we can make + int myType = getCraftingType(); + + bool sendComplexities = true; + if (!crafter.isSchematicFilteringEnabled()) + sendComplexities = false; + + std::vector goodSchematics; + std::vector scriptComplexities; + const std::map,int> & schematics = crafter.getDraftSchematics(); + std::map,int>::const_iterator iter; + for (iter = schematics.begin(); iter != schematics.end(); ++iter) + { + const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic((*iter).first.first); + if (schematic != NULL && ((myType & ServerObjectTemplate::CT_genericItem) != 0 || + ((schematic->getCategory() & myType) != 0))) + { + // make sure the player has all the skill commands needed for the + // schematic + int skillCount = schematic->getSkillCommandsCount(); + int i; + for (i = 0; i < skillCount; ++i) + { + if (!crafter.hasCommand(schematic->getSkillCommands(i))) + break; + } + if (i == skillCount) + { + goodSchematics.push_back((*iter).first.first); + if (sendComplexities) + scriptComplexities.push_back(schematic->getComplexity()); + else + scriptComplexities.push_back(1.0f); + } + } + } + + crafterPlayer->setCraftingTool(*this); + + if (goodSchematics.size() > 0) + { + ScriptParams params; + params.addParam(crafter.getNetworkId()); + params.addParam(goodSchematics); + params.addParam(scriptComplexities); + if (getScriptObject()->trigAllScripts(Scripting::TRIG_REQUEST_DRAFT_SCHEMATICS, params) != SCRIPT_CONTINUE) + { + std::vector empty; + crafterPlayer->sendUseableDraftSchematics (empty); + crafterPlayer->stopCrafting(true); + + return false; + } + setObjVarItem(OBJVAR_CRAFTING_CRAFTER, crafter.getNetworkId()); + } + else + { + std::vector empty; + crafterPlayer->sendUseableDraftSchematics (empty); + crafterPlayer->stopCrafting(true); + + StringId message("system_msg", "no_valid_schematics"); + Unicode::String outOfBand; + Chat::sendSystemMessage(crafter, message, outOfBand); + return false; + } + + // the following section to send the ingredients to the player is only needed for + // testing crafting via the console +#ifdef _DEBUG + + // send the player info about the ingredients in the tool's hopper; + // the actual sending of the messages could be spread out over a few + // frames +// listIngredientsInHopper(crafter); +#endif + } + else + { + sendControllerMessageToAuthServer(CM_startCraftingSession, new MessageQueueGenericValueType(crafter.getNetworkId())); + } + return true; +} // TangibleObject::startCraftingSession + +//----------------------------------------------------------------------- + +/** + * If this is a crafting tool, tries to stop a session with a player. + * + * @return true if the session was stopped, false if not + */ +bool TangibleObject::stopCraftingSession(void) +{ + if (isAuthoritative()) + { + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool()) + { + DEBUG_WARNING(true, ("Tried to stop crafting session on non-tool " + "object %s", myIdString)); + return false; + } + + // make sure a prototype object isn't being made (the session will be + // stopped when the prototype is done) + float realTimeVar = 0; + if (getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME, realTimeVar) && realTimeVar > 0) + return false; + + // make sure the tool isn't already being used + NetworkId crafterId; + if (!getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER,crafterId)) + { + DEBUG_REPORT_LOG(true, ("Crafting tool %s in not in use\n", myIdString)); + return false; + } + + clearCraftingManufactureSchematic(); + clearCraftingPrototype(); + removeObjVarItem(OBJVAR_CRAFTING_CRAFTER); + } + else + { + sendControllerMessageToAuthServer(CM_stopCraftingSession, 0); + } + return true; +} // TangibleObject::stopCraftingSession + +//----------------------------------------------------------------------- + +/** + * Test to see if an object is in a crafting tool's ingredient hopper. + * + * @param ingredientId object we want to test + * + * @return true if the object is in the hopper, false if not + */ +bool TangibleObject::isIngredientInHopper(const NetworkId & ingredientId) const +{ + ServerObject const * const hopper = getIngredientHopper(); + if (hopper == NULL) + return false; + + Object const * const ingredient = CachedNetworkId(ingredientId).getObject(); + if (ingredient == NULL) + return false; + + return ContainerInterface::isNestedWithin(*ingredient, getNetworkId()); +} // TangibleObject::isIngredientInHopper + +//----------------------------------------------------------------------- + +/** + * Returns this crafting station's ingredient hopper. + * + * @return the hopper + */ +ServerObject * TangibleObject::getIngredientHopper(void) const +{ +static const SlotId hopperSlotId(SlotIdManager::findSlotId(INGREDIENT_HOPPER_SLOT_NAME)); + + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting station + if (!isCraftingStation()) + { + DEBUG_WARNING(true, ("Tried to get input hopper for non-crafting station " + "object %s", myIdString)); + return NULL; + } + + // get the ingredient hopper + SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); + if (container == NULL) + { + DEBUG_WARNING(true, ("Crafting tool %s does not have a container!", myIdString)); + return NULL; + } + Container::ContainerErrorCode tmp = Container::CEC_Success; + Container::ContainedItem hopperId = container->getObjectInSlot(hopperSlotId, tmp); + if (hopperId == NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Crafting tool %s does not have a ingredient " + "hopper!", myIdString)); + return NULL; + } + ServerObject * hopper = safe_cast(hopperId.getObject()); + if (hopper == NULL) + { + DEBUG_WARNING(true, ("Can't find object for ingredient hopper id %s", + hopperId.getValueString().c_str())); + return NULL; + } + + return hopper; +} // TangibleObject::getIngredientHopper + +//---------------------------------------------------------------------- + +/** + * Adds an object to this tool's output slot. + * + * @param object the object to add + * @param transferer who is transferring the ingredient + * + * @return true on success, false on fail + */ +bool TangibleObject::addObjectToOutputSlot(ServerObject & object, + ServerObject * transferer) +{ +static const SlotId outputSlotId(SlotIdManager::findSlotId(MANF_OUTPUT_SLOT_NAME)); + + if(isAuthoritative()) + { + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // get output slot + SlottedContainer const * const slotContainer = ContainerInterface::getSlottedContainer(*this); + if (slotContainer == NULL) + { + DEBUG_WARNING(true, ("Crafting tool %s does not have a container!", myIdString)); + return false; + } + + // make sure the transferer is in the final stage of crafting + if (transferer == NULL) + { + DEBUG_WARNING(true, ("addObjectToOutputSlot, NULL transferer")); + return false; + } + NetworkId crafterVarId(NetworkId::cms_invalid); + if (!getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER, crafterVarId)) + { + // @todo: send a message to the player saying this tool is in use + DEBUG_WARNING(true, ("addObjectToOutputSlot, crafting tool %s has " + "no crafter", myIdString)); + return false; + } + if (crafterVarId != transferer->getNetworkId()) + { + DEBUG_WARNING(true, ("addObjectToOutputSlot, transferer %s is not the " + "crafter %s", transferer->getNetworkId().getValueString().c_str(), + crafterVarId.getValueString().c_str())); + return false; + } + CreatureObject const * const creatureTransferer = transferer->asCreatureObject(); + if (creatureTransferer == NULL) + { + DEBUG_WARNING(true, ("addObjectToOutputSlot, transferer %s is not a " + "creature", transferer->getNetworkId().getValueString().c_str())); + return false; + } + PlayerObject const * const creaturePlayer = PlayerCreatureController::getPlayerObject(creatureTransferer); + if (creaturePlayer == NULL) + return false; + + if (creaturePlayer->getCraftingStage() != Crafting::CS_finish) + { + DEBUG_WARNING(true, ("addObjectToOutputSlot, crafter %s is in the " + "wrong stage %d", transferer->getNetworkId().getValueString().c_str(), + static_cast(creaturePlayer->getCraftingStage()))); + return false; + } + + // if the object is our prototype, clear the prototype + if (getSynchronizedUi() != NULL) + { + CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync != NULL) + { + if (sync->getPrototype() == object.getNetworkId()) + { + sync->setPrototype(CachedNetworkId::cms_cachedInvalid); + } + } + } + + // put the object in the slot + Container::ContainerErrorCode tmp = Container::CEC_Success; + if (!ContainerInterface::transferItemToSlottedContainer(*this, object, outputSlotId, NULL, tmp)) + { + DEBUG_WARNING(true, ("Failed to transfer object %s to crafting " + "tool %s", object.getNetworkId().getValueString().c_str(), + myIdString)); + return false; + } + } + else + { + NetworkId transfererId; + if(transferer) + transfererId = transferer->getNetworkId(); + + sendControllerMessageToAuthServer(CM_addObjectToOutputSlot, new MessageQueueGenericValueType >(std::make_pair(object.getNetworkId(), transfererId))); + } + + return true; +} // TangibleObject::addObjectToOutputSlot + +//---------------------------------------------------------------------- + +/** + * Gets the temporary manufacturing schematic used during a crafting session. + * + * @return the schematic + */ +ManufactureSchematicObject * TangibleObject::getCraftingManufactureSchematic(void) const +{ + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool()) + { + DEBUG_WARNING(true, ("Tried to get non-crafting tool " + "object %s", myIdString)); + return NULL; + } + + SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); + if (container) + { + Container::ContainerErrorCode error; + const CachedNetworkId & schematicId = + container->getObjectInSlot(getCraftingManufactureSchematicSlotId(), error); + return safe_cast(schematicId.getObject()); + } + else + { + DEBUG_WARNING(true, ("ManufactureSchematicObject doesn't have a slotted container.")); + return NULL; + } +} // TangibleObject::getCraftingManufactureSchematic + +//---------------------------------------------------------------------- + +/** + * Gives the schematic to the player at the end of the session. + * + * @return the schematic + */ +ManufactureSchematicObject * TangibleObject::removeCraftingManufactureSchematic(void) +{ + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool() || getSynchronizedUi() == NULL) + { + DEBUG_WARNING(true, ("Tried to get non-crafting tool " + "object %s", myIdString)); + return NULL; + } + + CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync == NULL) + return NULL; + + ManufactureSchematicObject * schematic = safe_cast( + sync->getManfSchematic().getObject()); + + sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, + CachedNetworkId::cms_cachedInvalid, false); + + return schematic; +} // TangibleObject::removeCraftingManufactureSchematic + +//---------------------------------------------------------------------- + +/** + * Stores the temporary manufacturing schematic used during crafting in this + * crafting tool. + * + * @param schematic the schematic + */ +void TangibleObject::setCraftingManufactureSchematic(ManufactureSchematicObject & schematic) +{ + if(isAuthoritative()) + { + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool() || getSynchronizedUi() == NULL) + { + DEBUG_WARNING(true, ("Tried to get non-crafting tool " + "object %s", myIdString)); + return; + } + + CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync == NULL) + return; + + // see if there is already a schematic object set + const CachedNetworkId & schematicId = sync->getManfSchematic(); + if (schematicId == schematic.getNetworkId()) + return; + + // remove the old schematic + ServerObject * object = safe_cast(schematicId.getObject()); + if (object == NULL) + { + if (schematicId != NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Can't find object for schematic id %s", + schematicId.getValueString().c_str())); + // go on anyway + } + } + else + { + sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, + CachedNetworkId::cms_cachedInvalid, true); + object->permanentlyDestroy(DeleteReasons::Consumed); + } + + // the schematic isn't in the world or in a container, so we need to + // tell the client about it + int stationBonus = 0; + ServerObject * crafter = NULL; + NetworkId crafterId; + if (getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER,crafterId)) + { + crafter = safe_cast(NetworkIdManager::getObjectById(crafterId)); + } + if (crafter != NULL) + { + sync->setManfSchematic(CachedNetworkId(schematic), CachedNetworkId(*crafter), + true); + + // if the crafter is near a crafting station, get any crafting bonus + // it has + const PlayerObject * player = PlayerCreatureController::getPlayerObject( + crafter->asCreatureObject()); + if (player != NULL && player->getCraftingStation().getObject() != NULL) + { + player->getCraftingStation().getObject()->asServerObject()-> + getObjVars().getItem(OBJVAR_CRAFTING_STATIONMOD, stationBonus); + } + } + else + { + WARNING_STRICT_FATAL(true, ("TangibleObject::setCraftingManufactureSchematic " + "no crafter id on crafting tool %s!", myIdString)); + } + + // set any crafting bonus we give on the schematic + int myBonus = 0; + getObjVars().getItem(OBJVAR_CRAFTING_STATIONMOD, myBonus); + if (myBonus + stationBonus != 0) + { + schematic.setObjVarItem(OBJVAR_CRAFTING_STATIONMOD, myBonus + stationBonus); + } + } + else + { + sendControllerMessageToAuthServer(CM_setCraftingManufactureSchematic, new MessageQueueGenericValueType(schematic.getNetworkId())); + } +} // TangibleObject::setCraftingManufactureSchematic + +//---------------------------------------------------------------------- + +/** + * Removes the temporary manufacturing schematic from the crafting tool and + * deletes it. + */ +void TangibleObject::clearCraftingManufactureSchematic(void) +{ + if(isAuthoritative()) + { + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool()) + { + DEBUG_WARNING(true, ("Tried to get non-crafting tool " + "object %s", myIdString)); + return; + } + + // see if we have a schematic in our schematic slot + CachedNetworkId schematicId = CachedNetworkId::cms_cachedInvalid; + SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); + if (container) + { + Container::ContainerErrorCode error = Container::CEC_Success; + CachedNetworkId schematicId = container->getObjectInSlot( + getCraftingManufactureSchematicSlotId(), error); + } + else + { + DEBUG_WARNING(true, ("failed to get slotted container for schematic lookup.")); + } + + // get our ui + CraftingToolSyncUi * sync = NULL; + if (getSynchronizedUi() != NULL) + sync = dynamic_cast(getSynchronizedUi()); + + if (schematicId == CachedNetworkId::cms_cachedInvalid && sync == NULL) + { + // no schematic + return; + } + + if (schematicId == CachedNetworkId::cms_invalid) + schematicId = sync->getManfSchematic(); + else if (sync != NULL && sync->getManfSchematic() != CachedNetworkId::cms_invalid && + schematicId != sync->getManfSchematic()) + { + WARNING(true, ("TangibleObject::clearCraftingManufactureSchematic " + "crafting tool %s has schematic %s in its slot but schematic %s " + "in its ui!!!", getNetworkId().getValueString().c_str(), + schematicId.getValueString().c_str(), + sync->getManfSchematic().getValueString().c_str())); + if (schematicId.getObject() != NULL) + { + schematicId.getObject()->asServerObject()->permanentlyDestroy( + DeleteReasons::Consumed); + } + else + { + WARNING_STRICT_FATAL(true, ("TangibleObject::clearCraftingManufactureSchematic " + "crafting tool %s has slotted schematic %s with no object!", + getNetworkId().getValueString().c_str(), + schematicId.getValueString().c_str())); + } + schematicId = sync->getManfSchematic(); + } + + // get the schematic + ManufactureSchematicObject * manfSchematic = NULL; + ServerObject * object = safe_cast(schematicId.getObject()); + if (object == NULL && schematicId != CachedNetworkId::cms_invalid) + { + WARNING_STRICT_FATAL(true, ("Can't find object for manufactring schematic " + "id %s", schematicId.getValueString().c_str())); + } + else + manfSchematic = safe_cast(object); + + if (manfSchematic != NULL) + { + NetworkId crafterId; + if (getObjVars().getItem(OBJVAR_CRAFTING_CRAFTER,crafterId)) + { + // if we are at the assembly stage of crafting, or the draft schematic says + // not to destroy the ingredients, put the ingredients in the schematic back + // in the tool + CreatureObject * const crafter = dynamic_cast(NetworkIdManager::getObjectById(crafterId)); + PlayerObject * const crafterPlayer = PlayerCreatureController::getPlayerObject(crafter); + if (!manfSchematic->mustDestroyIngredients() || (crafterPlayer != NULL && + crafterPlayer->getCraftingStage() == Crafting::CS_assembly)) + { + crafterPlayer->setAllowEmptySlot(true); + int count = manfSchematic->getSlotsCount(); + // note this loop is odd because when we clear a slot it may + // actually be removed if it was optional + Crafting::IngredientSlot manfSlot; + for (int i = 0; i < count;) + { + if (manfSchematic->getSlot(i, manfSlot, false)) + { + if (manfSlot.ingredientType != Crafting::IT_none && + !manfSlot.ingredients.empty()) + { + if (crafterPlayer->emptySlot(i, NetworkId::cms_invalid)) + { + if (count != manfSchematic->getSlotsCount()) + { + count = manfSchematic->getSlotsCount(); + continue; + } + } + } + } + ++i; + } + crafterPlayer->setAllowEmptySlot(false); + } + else + manfSchematic->destroyAllIngredients(); + } + } + + if (sync != NULL) + sync->setManfSchematic(CachedNetworkId::cms_cachedInvalid, CachedNetworkId::cms_cachedInvalid, true); + if (object != NULL) + { + object->permanentlyDestroy(DeleteReasons::Consumed); + } + } + else + { + sendControllerMessageToAuthServer(CM_clearCraftingManufactureSchematic, 0); + } +} // TangibleObject::clearCraftingManufactureSchematic + +//---------------------------------------------------------------------- + +/** + * Gets the temporary prototype used during a crafting session. May also be used + * to give the prototype to the player at the end of the session. + * + * @return the prototype + */ +ServerObject * TangibleObject::getCraftingPrototype(void) const +{ + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool() || getSynchronizedUi() == NULL) + { + DEBUG_WARNING(true, ("Tried to get non-crafting tool " + "object %s", myIdString)); + return NULL; + } + + const CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync == NULL) + return NULL; + + return safe_cast(sync->getPrototype().getObject()); +} // TangibleObject::getCraftingPrototype + +//---------------------------------------------------------------------- + +/** + * Stores the temporary prototype object used during crafting in this + * crafting tool. + * + * @param prototype the prototype + */ +void TangibleObject::setCraftingPrototype(ServerObject & prototype) +{ + if (isAuthoritative()) + { + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool() || getSynchronizedUi() == NULL) + { + DEBUG_WARNING(true, ("Tried to get non-crafting tool " + "object %s", myIdString)); + return; + } + + CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync == NULL) + return; + + // see if there is already a prototype object set + const CachedNetworkId & prototypeId = sync->getPrototype(); + if (prototypeId == prototype.getNetworkId()) + return; + + // remove the old prototype + ServerObject * object = safe_cast(prototypeId.getObject()); + if (object == NULL) + { + if (prototypeId != NetworkId::cms_invalid) + { + DEBUG_WARNING(true, ("Can't find object for prototype id %s", + prototypeId.getValueString().c_str())); + // go on anyway + } + } + else + { + sync->setPrototype(CachedNetworkId::cms_cachedInvalid); + object->permanentlyDestroy(DeleteReasons::Consumed); + } + + // put the prototype in the tool's slot so the crafter will get updates + // about it + Container::ContainerErrorCode tmp = Container::CEC_Success; + if (!ContainerInterface::transferItemToSlottedContainer(*this, prototype, + getCraftingPrototypeSlotId(), NULL, tmp)) + { + // see if there is something in the slot, and delete it if there is + bool failed = true; + SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); + NOT_NULL(container); + const Container::ContainedItem & oldItem = container->getObjectInSlot( + getCraftingPrototypeSlotId(), tmp); + if (oldItem != prototype.getNetworkId()) + { + if (oldItem.getObject() != NULL) + { + safe_cast(oldItem.getObject())->permanentlyDestroy( + DeleteReasons::Consumed); + // try the transfer again + if (ContainerInterface::transferItemToSlottedContainer(*this, + prototype, getCraftingPrototypeSlotId(), NULL, tmp)) + { + failed = false; + } + } + if (failed) + { + DEBUG_WARNING(true, ("Failed to transfer prototype %s to crafting " + "tool %s", prototype.getNetworkId().getValueString().c_str(), + myIdString)); + return; + } + } + } + + sync->setPrototype(CachedNetworkId(prototype)); + } + else + { + sendControllerMessageToAuthServer(CM_setCraftingPrototype, new MessageQueueGenericValueType(prototype.getNetworkId())); + } +} // TangibleObject::setCraftingPrototype + +//---------------------------------------------------------------------- + +/** + * Removes the temporary prototype from the crafting tool and + * deletes it. + */ +void TangibleObject::clearCraftingPrototype(void) +{ + if(isAuthoritative()) + { + const std::string myId(getNetworkId().getValueString()); + const char * myIdString = myId.c_str(); + UNREF(myIdString); // needed for release mode + + // make sure we are a crafting tool + if (!isCraftingTool() || getSynchronizedUi() == NULL) + { + DEBUG_WARNING(true, ("Tried to get non-crafting tool " + "object %s", myIdString)); + return; + } + + CraftingToolSyncUi * sync = dynamic_cast( + getSynchronizedUi()); + if (sync == NULL) + return; + + const CachedNetworkId & prototypeId = sync->getPrototype(); + ServerObject * object = safe_cast(prototypeId.getObject()); + if (object != NULL) + { + object->permanentlyDestroy(DeleteReasons::Consumed); + } + else + { + // double-check the prototype slot to make sure nothing is in it + SlottedContainer const * const container = ContainerInterface::getSlottedContainer(*this); + NOT_NULL(container); + Container::ContainerErrorCode error; + const Container::ContainedItem & contents = container->getObjectInSlot( + getCraftingPrototypeSlotId(), error); + if (contents.getObject() != NULL) + { + safe_cast(contents.getObject())->permanentlyDestroy( + DeleteReasons::Consumed); + } + + } + sync->setPrototype(CachedNetworkId::cms_cachedInvalid); + } + else + { + sendControllerMessageToAuthServer(CM_clearCraftingPrototype, 0); + } +} // TangibleObject::clearCraftingPrototype + +// ---------------------------------------------------------------------- + +/** + * Sets the visible component string for this object. Note m_components is + * write-only on the server because this variable exists only to provide + * visual data to the client. + * + * @param components component table ids of visible components attached to this object + */ +void TangibleObject::setVisibleComponents(const std::vector & components) +{ + if(isAuthoritative()) + { + m_components.clear (); + + for (uint i = 0; i < components.size (); ++i) + m_components.insert(components [i]); + } + else + { + sendControllerMessageToAuthServer(CM_setVisibleComponents, new MessageQueueGenericValueType >(components)); + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::forceExecuteCommand(Command const &command, NetworkId const &targetId, Unicode::String const ¶ms, Command::ErrorCode &status, bool commandIsFromCommandQueue) +{ + if (!isAuthoritative()) + { + Controller *controller = getController(); + if (controller) + { + safe_cast(controller)->appendMessage( + CM_commandQueueForceExecuteCommandFwd, + 0.0f, + new MessageQueueCommandQueueForceExecuteCommandFwd(command.m_commandHash, targetId, params, status, commandIsFromCommandQueue), + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_SERVER); + } + return; + } + + if (status == Command::CEC_Success && ConfigServerGame::getLogAllCommands()) + { + LOGU( + "Command", + ("%s>%s %s", + getNetworkId().getValueString().c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str()), + params); + } + + if (getClient() && getClient()->isGod()) + { + CreatureObject* creatureObject = asCreatureObject(); + if (creatureObject) + { + LOGU( + "CustomerService", + ("Avatar: %s executed command: (%s) %s", + PlayerObject::getAccountDescription(creatureObject).c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str()), + params); + } + } + + if (getObjVars().hasItem("cheater")) + { + CreatureObject* creatureObject = asCreatureObject(); + if (creatureObject) + { + LOGU( + "CustomerService", + ("SuspectedCheaterChannel: %s executed command: (%s) %s", + PlayerObject::getAccountDescription(creatureObject).c_str(), + targetId.getValueString().c_str(), + command.m_commandName.c_str()), + params); + } + } + + PROFILER_BLOCK_DEFINE(profileBlockCommandIsFromCommandQueue, "TangibleObject::forceExecuteCommand commandIsFromCommandQueue"); + if (commandIsFromCommandQueue) + PROFILER_BLOCK_ENTER(profileBlockCommandIsFromCommandQueue); + + // attach temp script + bool needDetach = false; + if (command.m_tempScript.length()) + { + int ret = getScriptObject()->attachScript(command.m_tempScript, true); + if (ret != SCRIPT_OVERRIDE) + needDetach = true; + } + + // do script call + bool commandOverride = false; + if (status == Command::CEC_Success) + { + if (!command.m_scriptHook.empty()) + { + ScriptParams scriptParams; + scriptParams.addParam(targetId); + scriptParams.addParam(params); + scriptParams.addParam(command.m_defaultTime); + if (getScriptObject()->callScriptCommandHandler(command.m_scriptHook, scriptParams) == SCRIPT_OVERRIDE) + commandOverride = true; + } + } + else + { + if (!command.m_failScriptHook.empty()) + { + ScriptParams scriptParams; + scriptParams.addParam(targetId); + scriptParams.addParam(params); + scriptParams.addParam(command.m_defaultTime); + if (getScriptObject()->callScriptCommandHandler(command.m_failScriptHook, scriptParams) == SCRIPT_OVERRIDE) + { + commandOverride = true; + // an override in a failure script handler should mean to mark it as a success (used for standing from feign death) + status = Command::CEC_Success; + } + } + } + + // detach temp scripts + if (needDetach) + getScriptObject()->detachScript(command.m_tempScript); + + if ( commandOverride && commandIsFromCommandQueue ) + { + CommandQueue * const queue = getCommandQueue(); + + if (queue != NULL) + { + queue->cancelCurrentCommand(); + } + } + + // do c function call if not overridden by script + if (!commandOverride) + { + if (status == Command::CEC_Success) + { + if (command.m_cppHook) + (*command.m_cppHook)(command, getNetworkId(), targetId, params); + } + else + { + if (command.m_failCppHook) + (*command.m_failCppHook)(command, getNetworkId(), targetId, params); + } + } + + if (commandIsFromCommandQueue) + PROFILER_BLOCK_LEAVE(profileBlockCommandIsFromCommandQueue); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setCondition(int condition) +{ + if (isAuthoritative()) + m_condition = (m_condition.get() | condition); + else + sendControllerMessageToAuthServer(CM_setCondition, new MessageQueueGenericValueType(condition)); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::clearCondition(int condition) +{ + if (isAuthoritative()) + m_condition = (m_condition.get() & (~condition)); + else + sendControllerMessageToAuthServer(CM_clearCondition, new MessageQueueGenericValueType(condition)); +} + +// ---------------------------------------------------------------------- + +bool TangibleObject::isDisabled() const +{ + return hasCondition(ServerTangibleObjectTemplate::C_disabled); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setDisabled(bool disabled) +{ + if (disabled) + setCondition(ServerTangibleObjectTemplate::C_disabled); + else + clearCondition(ServerTangibleObjectTemplate::C_disabled); +} + +// ---------------------------------------------------------------------- + + +const NetworkId & TangibleObject::getOwnerId() const +{ + return m_ownerId.get(); +} + +// ---------------------------------------------------------------------- + +bool TangibleObject::isOwner(NetworkId const &id, Client const *client) const +{ + if (id == getOwnerId()) + return true; + if (client && client->isGod()) + return true; + return false; +} + +// ---------------------------------------------------------------------- + +/** + * Determine the initial visibility state of an object when it is created. + */ +void TangibleObject::initializeVisibility() +{ + if (isAuthoritative()) + { + const ServerTangibleObjectTemplate * myTemplate = safe_cast< + const ServerTangibleObjectTemplate *>(getObjectTemplate()); + if (myTemplate != NULL) + { + bool visible = false; + for (size_t i = 0; i < myTemplate->getVisibleFlagsCount(); ++i) + { + if (myTemplate->getVisibleFlags(i) == ServerObjectTemplate::VF_player) + { + visible = true; + break; + } + } + setVisible(visible); + } + } + else + { + WARNING(true, ("TangibleObject::initializeVisibility called on non-authoritative object %s", + getNetworkId().getValueString().c_str())); + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setVisible(bool isVisible) +{ + if (isAuthoritative()) + m_visible = isVisible; + else + sendControllerMessageToAuthServer(CM_setVisible, new MessageQueueGenericValueType(isVisible)); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setHidden(bool const hide) +{ + if (isAuthoritative()) + m_hideFromClient = hide; + else + sendControllerMessageToAuthServer(CM_hideFromClient, new MessageQueueGenericValueType(hide)); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::visibilityDataModified() +{ + if (isInWorld()) + { + if (isVisible() && !isHidden()) + { + // show the object + const TriggerVolume * triggerVolume = getTriggerVolume(NetworkTriggerVolumeNamespace::NetworkTriggerVolumeName); + if (triggerVolume != NULL) + { + std::vector observers; + ServerWorld::findPlayerCreaturesInRange(getPosition_w(), triggerVolume->getRadius(), observers); + if (!observers.empty()) + ObserveTracker::onObjectMadeVisibleTo(*this, observers); + } + } + else + { + // hide the object + ObserveTracker::onObjectMadeInvisible(*this); + + // if the object is hidden, show the object to + // players who have passively revealed the object + if (isVisible() && isHidden() && !m_passiveRevealPlayerCharacter.empty()) + { + const TriggerVolume * triggerVolume = getTriggerVolume(NetworkTriggerVolumeNamespace::NetworkTriggerVolumeName); + if (triggerVolume != NULL) + { + std::vector possibleObservers; + ServerWorld::findPlayerCreaturesInRange(getPosition_w(), triggerVolume->getRadius(), possibleObservers); + if (!possibleObservers.empty()) + { + std::vector allowedObservers; + for (std::vector::const_iterator i = possibleObservers.begin(); i != possibleObservers.end(); ++i) + { + if (m_passiveRevealPlayerCharacter.contains((*i)->getNetworkId())) + allowedObservers.push_back(*i); + } + + if (!allowedObservers.empty()) + ObserveTracker::onObjectMadeVisibleTo(*this, allowedObservers); + } + } + } + } + } +} +bool TangibleObject::isVisibleOnClient(Client const &client) const +{ + // Everyone can see visible objects. + // Gods and clients on the buildcluster can see everything. + if (client.isGod() || ConfigServerGame::getBuildCluster() || (isVisible() && !isHidden())) + return true; + + // Invisible objects are visible to a non-god client if the client's + // creature contains (or indirectly contains) the invisible object. + + ServerObject const * const characterObject = client.getCharacterObject(); + + { + for (ServerObject const *o = this; o; o = safe_cast(ContainerInterface::getContainedByObject(*o))) + { + if (o == characterObject) + return true; + if (o->isInWorld() || o->asCellObject()) + break; + } + } + + // Invisible objects are visible to a non-god client if they are in + // the client's character's containment chain. + { + for (ServerObject const *o = characterObject; o; o = safe_cast(ContainerInterface::getContainedByObject(*o))) + if (o == this) + return true; + } + + if (isVisible()) + { + // if the client's character is the owner, then he can see it. + const CachedNetworkId ownerId(getOwnerId()); + if (ownerId == characterObject->getNetworkId()) + return true; + + // if the client's character is grouped with the the owner, then he can see it. + const CreatureObject * owner = safe_cast(ownerId.getObject()); + if (owner != NULL) + { + const GroupObject * group = owner->getGroup(); + if (group != NULL) + { + if (group->isGroupMember(characterObject->getNetworkId())) + return true; + } + } + + // if the client's character has passively revealed the hidden object, then he can see it. + if (m_passiveRevealPlayerCharacter.contains(characterObject->getNetworkId())) + return true; + } + return false; +} + +// ---------------------------------------------------------------------- + +/** + * Tests if this item will encumber a player when equipped. + * + * @return true if the item has encumbrance data + */ +bool TangibleObject::hasEncumbrances() const + { + return getObjVars().hasItem(OBJVAR_ARMOR_BASE + '.' + OBJVAR_ARMOR_ENCUMBRANCE); +} // TangibleObject::hasEncumbrances + +// ---------------------------------------------------------------------- + +/** + * Returns the encumbrance values this object applies to a player when equipped. + * + * @param encumbrances vector to be filled in with encumbrance values for the health, + * action, and mind groups; will be empty if this object does not + * encumber a creature + * + * @return true if encumbrances has good data, false if not + */ +bool TangibleObject::getEncumbrances(std::vector & encumbrances) const + { +static int datatable_type_col = -1; +static int datatable_min_encumbrance_col = -1; +static int datatable_max_encumbrance_col = -1; + + // NOTE: it might be better if we do all this via script, to reduce + // duplicate functionality + + encumbrances.clear(); + + DataTable * dt = DataTableManager::getTable(DATATABLE_ARMOR, true); + if (dt == NULL) + return false; + else if (datatable_type_col == -1) + { + // cache the column indexes + datatable_type_col = dt->findColumnNumber(DATATABLE_TYPE_COL); + datatable_min_encumbrance_col = dt->findColumnNumber(DATATABLE_MIN_ENCUMBRANCE_COL); + datatable_max_encumbrance_col = dt->findColumnNumber(DATATABLE_MAX_ENCUMBRANCE_COL); + if (datatable_type_col < 0 || + datatable_min_encumbrance_col < 0 || + datatable_max_encumbrance_col < 0) + { + WARNING_STRICT_FATAL(true, ("TangibleObject::getEncumbrances: armor datatable missing expected columns")); + return false; + } + } + + // get the encumbrance values from the objvars + float baseEncumbrance = 0; + if (!getObjVars().getItem(OBJVAR_ARMOR_BASE + '.' + OBJVAR_ARMOR_ENCUMBRANCE, baseEncumbrance)) + return false; + std::vector encumbranceSplit; + if (!getObjVars().getItem(OBJVAR_ARMOR_BASE + '.' + OBJVAR_ENCUMBRANCE_SPLIT, encumbranceSplit)) + return false; + if (encumbranceSplit.size() != 3) + return false; + + // get the actual encumbrance range from the armor datatable + int armorLevel; + if (!getObjVars().getItem(OBJVAR_ARMOR_BASE + "." + OBJVAR_ARMOR_LEVEL, armorLevel)) + return false; + char armorLevelRowName[64]; + snprintf(armorLevelRowName, sizeof(armorLevelRowName), "%s%d", DATATABLE_FINAL_ROW.c_str(), armorLevel); + int armorLevelRow = dt->searchColumnInt(datatable_type_col, Crc::calculate(armorLevelRowName)); + if (armorLevelRow < 0) + return false; + int minEncumbrance = dt->getIntValue(datatable_min_encumbrance_col, armorLevelRow); + int maxEncumbrance = dt->getIntValue(datatable_max_encumbrance_col, armorLevelRow); + + // scale the base encumbrance by the actual encumbrance range + baseEncumbrance = baseEncumbrance * (maxEncumbrance - minEncumbrance) + minEncumbrance; + + // split the base encumbrace into the three attrib groups + encumbrances.resize(encumbranceSplit.size()); + std::vector::iterator j = encumbrances.begin(); + for (std::vector::const_iterator i = encumbranceSplit.begin(); i != encumbranceSplit.end(); ++i, ++j) + { + *j = static_cast((*i) * baseEncumbrance); + } + return true; + } + +// ---------------------------------------------------------------------- + +/** + * Returns the slot id of the slot we use to hold temporary crafting prototypes. + * + * @return the prototype slot id + */ +const SlotId & TangibleObject::getCraftingPrototypeSlotId() +{ +static const SlotId prototypeSlotId(SlotIdManager::findSlotId(TEMP_PROTOTYPE_SLOT_NAME)); + + return prototypeSlotId; +} + +// ---------------------------------------------------------------------- + +/** + * Returns the slot id of the slot we use to hold temporary manf schematics. + * + * @return the schematic slot id + */ +const SlotId & TangibleObject::getCraftingManufactureSchematicSlotId() +{ +static const SlotId schematicSlotId(SlotIdManager::findSlotId(TEMP_SCHEMATIC_SLOT_NAME)); + + return schematicSlotId; +} + +// ---------------------------------------------------------------------- + +/** + * Generates an id to allow players to identify a crafted component. NOTE: this + * returns a pointer to a static buffer, so make sure you save off the number + * before calling this function again. + * + * @param id network id that the serial number will be generated from + * + * @return the serial number + */ +const char * TangibleObject::generateSerialNumber(const NetworkId & id) +{ +static char buffer[11] = {'(', 0, 0, 0, 0, 0, 0, 0, 0, ')', 0}; +int i; +char c; +uint64 mask; + +#if defined(WIN32) + uint64 value = (id.getValue() & 0x000000FFFFFFFFFFi64); +#elif defined(linux) + uint64 value = (id.getValue() & 0x000000FFFFFFFFFFULL); +#else +#error unsupported OS +#endif + + for (i = 0; i < 10; ++i) + { + mask = ((value >> 4) | ((value & 0x0F) << 36)); + value ^= mask; + } + + for (i = 1; i < 9; ++i) + { + c = static_cast(value & 0x1F); + value >>= 5; + if (c < 10) + c += '0'; + else + c += ('a' - 10); + buffer[i] = c; + } + return buffer; +} // TangibleObject::generateSerialNumber + +//---------------------------------------------------------------------- + +/** + * Returns the attribute bonuses this object grants when equipped. + * + * @param attribBonuses list to be filled in with the bonuses + */ +void TangibleObject::getAttribBonuses(std::vector > & attribBonuses) const +{ + attribBonuses.clear(); + + DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_ATTRIBUTE_BONUS); + + for (DynamicVariableList::NestedList::const_iterator i = mods.begin(); + i != mods.end(); ++i) + { + int bonus = 0; + i.getValue(bonus); + int attribute = atoi(i.getName().c_str()); + if (isdigit(i.getName()[0]) && attribute >= 0 && + attribute < Attributes::NumberOfAttributes) + { + if (bonus > ConfigServerGame::getMaxItemAttribBonus()) + bonus = ConfigServerGame::getMaxItemAttribBonus(); + else if (bonus < -ConfigServerGame::getMaxItemAttribBonus()) + bonus = -ConfigServerGame::getMaxItemAttribBonus(); + attribBonuses.push_back(std::make_pair(attribute, bonus)); + } + else + { + WARNING(true, ("Object %s has invalid attribute bonus objvar name of %s", + getNetworkId().getValueString().c_str(), i.getName().c_str())); + } + } +} // TangibleObject::getAttribBonuses + +/** + * Returns the attribute bonuses this object grants when equipped. + * + * @param attribBonuses list of length 9 to be filled in with the bonuses + * + * @return true if we have bonuses, false if not + */ +bool TangibleObject::getAttribBonuses(std::vector & attribBonuses) const +{ + attribBonuses.clear(); + attribBonuses.resize(Attributes::NumberOfAttributes, 0); + + bool hasBonues = false; + typedef std::vector > BonusPairs; + BonusPairs pairedBonuses; + getAttribBonuses(pairedBonuses); + for (BonusPairs::const_iterator i = pairedBonuses.begin(); i != pairedBonuses.end(); ++i) + { + int index = (*i).first; + if (index >=0 && index < Attributes::NumberOfAttributes) + { + attribBonuses[index] = (*i).second; + hasBonues = true; + } + } + return hasBonues; +} // TangibleObject::getAttribBonuses + +//---------------------------------------------------------------------- + +/** + * Returns the attribute bonus of this object for a given attribute. + * + * @param attribute the attribute + * + * @return the bonus for the attribute + */ +int TangibleObject::getAttribBonus(int attribute) const +{ + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + return 0; + + DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_ATTRIBUTE_BONUS); + char buffer[8]; + snprintf(buffer, sizeof(buffer), "%d", attribute); + int bonus = 0; + IGNORE_RETURN(mods.getItem(buffer, bonus)); + + if (bonus > ConfigServerGame::getMaxItemAttribBonus()) + bonus = ConfigServerGame::getMaxItemAttribBonus(); + else if (bonus < -ConfigServerGame::getMaxItemAttribBonus()) + bonus = -ConfigServerGame::getMaxItemAttribBonus(); + return bonus; +} + +//---------------------------------------------------------------------- + +/** + * Sets the attribute bonus this object applies when equipped. + * + * @param attribute the attribute + * @param bonus the bonus + */ +void TangibleObject::setAttribBonus(int attribute, int bonus) +{ + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + return; + + char buffer[8]; + snprintf(buffer, sizeof(buffer), "%d", attribute); + if (bonus != 0) + setObjVarItem(OBJVAR_ATTRIBUTE_BONUS + '.' + buffer, bonus); + else + removeObjVarItem(OBJVAR_ATTRIBUTE_BONUS + '.' + buffer); +} + +//---------------------------------------------------------------------- + +/** + * Returns the skill mod bonuses this object grants when equipped. + * + * @param skillModBonuses list to be filled in with the bonuses + */ +void TangibleObject::getSkillModBonuses(std::vector > & skillModBonuses, bool includeCategorizedSkillmod /*= true*/) const +{ + static std::map mapSkillModBonuses; + mapSkillModBonuses.clear(); + + DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_SKILLMOD_BONUS); + for (DynamicVariableList::NestedList::const_iterator i = mods.begin(); + i != mods.end(); ++i) + { + int bonus = 0; + i.getValue(bonus); + + std::string const name = i.getName(); + std::map::iterator iterFind = mapSkillModBonuses.find(name); + if (iterFind != mapSkillModBonuses.end()) + iterFind->second += bonus; + else + IGNORE_RETURN(mapSkillModBonuses.insert(std::make_pair(name, bonus))); + } + + if (includeCategorizedSkillmod) + getCategorizedSkillModBonuses(*this, OBJVAR_CATEGORIZED_SKILLMOD_BONUS, mapSkillModBonuses); + + skillModBonuses.clear(); + for (std::map::const_iterator iterMapSkillModBonuses = mapSkillModBonuses.begin(); iterMapSkillModBonuses != mapSkillModBonuses.end(); ++iterMapSkillModBonuses) + { + if (iterMapSkillModBonuses->second != 0) + skillModBonuses.push_back(std::make_pair(iterMapSkillModBonuses->first, iterMapSkillModBonuses->second)); + } +} // TangibleObject::getSkillModBonuses + +//---------------------------------------------------------------------- + +/** + * Returns the skill mod bonus of this object for a given skill mod. + * + * @param skillMod the skill mod name + * + * @return the bonus for the skill mod + */ +int TangibleObject::getSkillModBonus(const std::string & skillMod, bool includeCategorizedSkillmod /*= true*/) const +{ + DynamicVariableList::NestedList mods(getObjVars(), OBJVAR_SKILLMOD_BONUS); + int value = 0; + IGNORE_RETURN(mods.getItem(skillMod, value)); + + if (includeCategorizedSkillmod) + value += getCategorizedSkillModBonus(*this, OBJVAR_CATEGORIZED_SKILLMOD_BONUS, skillMod); + + return value; +} // TangibleObject::getSkillModBonus + +//---------------------------------------------------------------------- + +/** + * Sets the base skill mod bonus this object applies when equipped. + * + * @param skillMod the skill mod name + * @param bonus the bonus + */ +void TangibleObject::setSkillModBonus(const std::string & skillMod, int bonus) +{ + std::string const skillModObjvar = OBJVAR_SKILLMOD_BONUS + '.' + skillMod; + + if (bonus < 0) + { + setObjVarItem(skillModObjvar, bonus); + return; + } + else if (bonus == 0) + { + removeObjVarItem(skillModObjvar); + return; + } + + int const currentTotalBonus = getSkillModBonus(skillMod); + int const currentBonus = getSkillModBonus(skillMod, false); + if ((currentTotalBonus - currentBonus + bonus) > ConfigServerGame::getMaxObjectSkillModBonus()) + bonus = std::max(0, ConfigServerGame::getMaxObjectSkillModBonus() - currentTotalBonus + currentBonus); + + if (bonus != 0) + setObjVarItem(skillModObjvar, bonus); + else + removeObjVarItem(skillModObjvar); +} // TangibleObject::setSkillModBonus + +//---------------------------------------------------------------------- + +void TangibleObject::setSkillModBonus(const std::string & category, const std::string & skillMod, int bonus) +{ + if (category.empty()) + return; + + std::string const skillModObjvar = OBJVAR_CATEGORIZED_SKILLMOD_BONUS + '.' + category + '.' + skillMod; + if (bonus < 0) + { + setObjVarItem(skillModObjvar, bonus); + return; + } + else if (bonus == 0) + { + removeObjVarItem(skillModObjvar); + return; + } + + int const currentTotalBonus = getSkillModBonus(skillMod); + int currentBonus = 0; + IGNORE_RETURN(getObjVars().getItem(skillModObjvar, currentBonus)); + + if ((currentTotalBonus - currentBonus + bonus) > ConfigServerGame::getMaxObjectSkillModBonus()) + bonus = std::max(0, ConfigServerGame::getMaxObjectSkillModBonus() - currentTotalBonus + currentBonus); + + if (bonus != 0) + setObjVarItem(skillModObjvar, bonus); + else + removeObjVarItem(skillModObjvar); +} // TangibleObject::setSkillModBonus + +//---------------------------------------------------------------------- + +void TangibleObject::removeCategorizedSkillModBonuses(const std::string & category) +{ + if (category.empty()) + return; + + std::string const skillModObjvar = OBJVAR_CATEGORIZED_SKILLMOD_BONUS + '.' + category; + if (getObjVars().hasItem(skillModObjvar) && (getObjVars().getType(skillModObjvar) == DynamicVariable::LIST)) + removeObjVarItem(skillModObjvar); +} + +//---------------------------------------------------------------------- + +/** + * Adds a skill mod bonus to a skill mod socket, if the object has an open socket. + * + * @param skillMod the skill mod name + * @param bonus the bonus + * + * @return true if the bonus was added, false if the object didn't have an open socket + */ +bool TangibleObject::addSkillModSocketBonus(const std::string & skillMod, int bonus) +{ + if (bonus > ConfigServerGame::getMaxSocketSkillModBonus()) + bonus = ConfigServerGame::getMaxSocketSkillModBonus(); + + int sockets = getSkillModSockets(); + if (sockets > 0) + { + int currentBonus = getSkillModBonus(skillMod, false); + + // only apply the bonus if it's greater than the current bonus + /*if (bonus <= currentBonus) // This breaks multi-socketed items, so now we combine all values. + return false;*/ // Not sure if this code was ever hit in the first place. + + setSkillModBonus(skillMod, currentBonus + bonus); + + // trigger scripts + ScriptParams params; + std::vector skillModParam; + skillModParam.push_back(skillMod.c_str()); + std::vector bonusParam; + bonusParam.push_back(bonus); + params.addParam(skillModParam); + params.addParam(bonusParam); + IGNORE_RETURN(getScriptObject()->trigAllScripts(Scripting::TRIG_SOCKET_USED, params)); + } + return sockets > 0; +} // TangibleObject::addSkillModSocketBonus + +//---------------------------------------------------------------------- + +/** + * Adds multiple skill mod bonuses to a skill mod socket, if the object has an + * open socket. Note that this call will only use up one socket, no matter how + * many bonuses are added. + * + * @param skillModBonuses the bonuses + * + * @return true if the bonus was added, false if the object didn't have an open socket + */ +bool TangibleObject::addSkillModSocketBonuses(const std::vector > & skillModBonuses) +{ + int sockets = getSkillModSockets(); + if (sockets > 0) + { + int i; + int count = skillModBonuses.size(); + std::vector bonusOrder(1, 0); + for (i = 1; i < count; ++i) + { + std::vector::iterator j; + for (j = bonusOrder.begin(); j != bonusOrder.end(); ++j) + { + if (skillModBonuses[i].second > skillModBonuses[*j].second) + { + bonusOrder.insert(j, i); + break; + } + } + if (j == bonusOrder.end()) + bonusOrder.push_back(i); + } + + bool someSucceeded = false; + for (i = 0; i < count; ++i) + { + int index = bonusOrder[i]; + if(addSkillModSocketBonus(skillModBonuses[index].first, + skillModBonuses[index].second)) + someSucceeded = true; + } + if(someSucceeded) + { + setSkillModSockets(sockets - 1); + return true; + } + } + return sockets > 0; +} // TangibleObject::addSkillModSocketBonuses + +//---------------------------------------------------------------------- + +/** + * Returns the number of available skill mod sockets. + * + * @return the number of sockets + */ +int TangibleObject::getSkillModSockets(void) const +{ + int sockets = 0; + + if (getGameObjectType() == SharedObjectTemplate::GOT_misc_container_wearable) + return 0; + + bool const isCybernetic = getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_arm || getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_legs; + + IGNORE_RETURN(getObjVars().getItem(OBJVAR_SKILLMOD_SOCKETS, sockets)); + return isCybernetic ? sockets : std::min(sockets, ConfigServerGame::getMaxSkillModSockets()); +} // TangibleObject::getSkillModSockets + +//---------------------------------------------------------------------- + +/** + * Sets the number of available skill mod sockets. + * + * @param sockets the number of sockets + */ +void TangibleObject::setSkillModSockets(int sockets) +{ + bool const isCybernetic = getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_arm || getGameObjectType() == SharedObjectTemplate::GOT_cybernetic_legs; + + if (sockets > ConfigServerGame::getMaxSkillModSockets() && !isCybernetic) + sockets = ConfigServerGame::getMaxSkillModSockets(); + if (sockets > 0) + setObjVarItem(OBJVAR_SKILLMOD_SOCKETS, sockets); + else + removeObjVarItem(OBJVAR_SKILLMOD_SOCKETS); +} // TangibleObject::setSkillModSockets + +//---------------------------------------------------------------------- + +/** + * Returns the amount of time left before a crafted prototype object will be done. + * + * @return the time left, in secs + */ +int TangibleObject::getCraftingToolPrototypeTime() const +{ + int timeLeft = -1; + float prototypeTime = 0; + getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_TIME,prototypeTime); + + if (prototypeTime > 0) + { + int startTime =0; + if (getObjVars().getItem(OBJVAR_CRAFTING_PROTOTYPE_START_TIME,startTime)) + { + const int currentTime = static_cast(ServerClock::getInstance().getGameTimeSeconds()); + timeLeft = static_cast(prototypeTime + 0.5f) - (currentTime - startTime); + } + } + return timeLeft; +} // TangibleObject::getCraftingToolPrototypeTime + +//---------------------------------------------------------------------- + +void TangibleObject::getAttributesForCraftingTool (AttributeVector & data) const +{ + char valueBuffer[32]; + + static const Unicode::String CRAFT_TOOL_WORKING (Unicode::narrowToWide("@crafting:tool_status_working")); + static const Unicode::String CRAFT_TOOL_FINISHED (Unicode::narrowToWide("@crafting:tool_status_finished")); + static const Unicode::String CRAFT_TOOL_READY (Unicode::narrowToWide("@crafting:tool_status_ready")); + static const SlotId outputSlotId(SlotIdManager::findSlotId(MANF_OUTPUT_SLOT_NAME)); + + float craft_effectiveness = 0.0f; + getObjVars ().getItem(OBJVAR_CRAFTING_STATIONMOD, craft_effectiveness); + snprintf (valueBuffer, sizeof (valueBuffer), "%.2f", craft_effectiveness); + data.push_back (std::make_pair(SharedObjectAttributes::craft_tool_effectiveness, Unicode::narrowToWide(valueBuffer))); + + // add some internal attribs for the crafting station state + + // see if we are making a prototype + + int prototypeTimeLeft = getCraftingToolPrototypeTime(); + if (prototypeTimeLeft > 0) + { + data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_status, CRAFT_TOOL_WORKING)); + _itoa(prototypeTimeLeft, valueBuffer, 10); + data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_time, Unicode::narrowToWide(valueBuffer))); + } + else + { + // see if there is an object in the output hopper + bool hasPrototype = false; + SlottedContainer const * const slotContainer = ContainerInterface::getSlottedContainer(*this); + if (slotContainer != NULL) + { + Container::ContainerErrorCode tmp = Container::CEC_Success; + if (slotContainer->getObjectInSlot(outputSlotId, tmp) != Container::ContainedItem::cms_invalid) + { + hasPrototype = true; + } + } + if (hasPrototype) + data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_status, CRAFT_TOOL_FINISHED)); + else + data.push_back(std::make_pair(SharedObjectAttributes::craft_tool_status, CRAFT_TOOL_READY)); + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::getAttributes(const NetworkId & playerId, AttributeVector &data) const +{ + ServerObject::getAttributes(playerId, data); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::getAttributesForShipComponent (AttributeVector & data) const +{ + ShipComponentData * const componentData = ShipComponentDataManager::create(*this); + if(componentData) + { + componentData->getAttributes(data); + delete componentData; + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::getAttributes(AttributeVector & data) const +{ + ServerObject::getAttributes(data); + + char valueBuffer[32]; + + CreatureObject const * const thisCreature = asCreatureObject(); + + if (!thisCreature) + { + const int maxHit = getMaxHitPoints (); + // Only consider tangible invulnerability rules for this case + if (maxHit > 0 && !TangibleObject::isInvulnerable()) + { + snprintf (valueBuffer, sizeof (valueBuffer), "%d/%d", maxHit - getDamageTaken (), maxHit); + data.push_back (std::make_pair (SharedObjectAttributes::condition, Unicode::narrowToWide (valueBuffer))); + } + + const ServerObjectTemplate * const targetTemplate = safe_cast(getObjectTemplate()); + if (targetTemplate) + { + bool playerCanMove = false; + + for (size_t i = 0; i < targetTemplate->getMoveFlagsCount(); ++i) + { + if (targetTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_player) + { + playerCanMove = true; + break; + } + } + + if (getCacheVersion() <= 0 && playerCanMove) + { + snprintf (valueBuffer, sizeof (valueBuffer), "%d", std::max (1, getVolume ())); + data.push_back (std::make_pair (SharedObjectAttributes::volume, Unicode::narrowToWide (valueBuffer))); + } + } + } + + const int got = getGameObjectType (); + + switch (got) + { + case SharedObjectTemplate::GOT_misc_drink: + case SharedObjectTemplate::GOT_misc_food: + case SharedObjectTemplate::GOT_misc_pharmaceutical: + case SharedObjectTemplate::GOT_weapon_ranged_thrown: + case SharedObjectTemplate::GOT_weapon_heavy_misc: + case SharedObjectTemplate::GOT_misc_fishing_bait: + { + const int count = m_count.get (); + if (count) + { + snprintf (valueBuffer, sizeof (valueBuffer), "%d", m_count.get ()); + data.push_back (std::make_pair (SharedObjectAttributes::counter_uses_remaining, Unicode::narrowToWide (valueBuffer))); + } + } + break; + case SharedObjectTemplate::GOT_resource_container_pseudo: + { + int resourceValue = 0; + for (int i = 0; i < Crafting::RA_numResourceAttributes; ++i) + { + + const std::string ovName(OBJVAR_COMPONENT_DATA + "." + + Crafting::getResourceAttributeName(i)); + if (getObjVars().getItem(ovName, resourceValue)) + { + char buffer[24]; + snprintf(buffer, sizeof(buffer), "%i", resourceValue); + data.push_back(std::make_pair(Crafting::getResourceAttributeName(i),Unicode::narrowToWide(buffer))); + } + } + } + break; + default: + break; + } + + const VolumeContainer * const volumeContainer = ContainerInterface::getVolumeContainer (*this); + if (volumeContainer) + { + if (got != SharedObjectTemplate::GOT_misc_factory_crate) + { + const int curVol = volumeContainer->getCurrentVolume (); + const int totVol = volumeContainer->getTotalVolume (); + + if (curVol >= 0 && totVol >= 0) + { + snprintf (valueBuffer, sizeof (valueBuffer), "%d/%d", curVol, totVol); + data.push_back (std::make_pair (SharedObjectAttributes::contents, Unicode::narrowToWide (valueBuffer))); + } + } + } + + std::vector > skillModBonuses; + getSkillModBonuses(skillModBonuses); + if (!skillModBonuses.empty()) + { + char buffer[16]; + int count = skillModBonuses.size(); + for (int i = 0; i < count; ++i) + { + _itoa(skillModBonuses[i].second, buffer, 10); + data.push_back(std::make_pair(SharedObjectAttributes::cat_skill_mod_bonus + "." + "@stat_n:" + skillModBonuses[i].first, Unicode::narrowToWide(buffer))); + } + } + + std::vector attribBonuses; + if (getAttribBonuses(attribBonuses) && !attribBonuses.empty()) + { + char buffer[16]; + int const attribCount = attribBonuses.size(); + for (int attrib = 0; attrib < attribCount; ++attrib) + { + int const bonus = attribBonuses[attrib]; + if (bonus != 0) + { + _itoa(bonus, buffer, 10); + data.push_back(std::make_pair(SharedObjectAttributes::cat_attrib_mod_bonus + "." + "@att_bonus_n:" + s_attributeBonusNames[attrib], Unicode::narrowToWide(buffer))); + } + } + } + + int sockets = getSkillModSockets(); + if (sockets > 0) + { + char buffer[16]; + _itoa(sockets, buffer, 10); + data.push_back(std::make_pair(SharedObjectAttributes::sockets, Unicode::narrowToWide(buffer))); + } + + if (isCraftingTool()) + getAttributesForCraftingTool (data); + + if (getCreatorId() != NetworkId::cms_invalid) + data.push_back(std::make_pair(SharedObjectAttributes::crafter, getCreatorName())); + + if (isCrafted()) + data.push_back(std::make_pair(SharedObjectAttributes::serial_number, Unicode::narrowToWide(generateSerialNumber(getCraftedId())))); + + if(GameObjectTypes::isTypeOf(got, SharedObjectTemplate::GOT_ship_component)) + { + getAttributesForShipComponent(data); + } + + { + // If this is a fake ship component in the interior of a ship, get its attributes from the ship + + ServerObject const * const cell = safe_cast(ContainerInterface::getContainedByObject(*this)); + if (cell && cell->asCellObject()) + { + ServerObject const * const shipAsObject = safe_cast(ContainerInterface::getContainedByObject(*cell)); + if (shipAsObject) + { + ShipObject const * const ship = shipAsObject->asShipObject(); + if (ship) + { + int slot; + if (getObjVars().getItem("intSlot",slot)) + { + ShipComponentData const * const componentData = ship->createShipComponentData(slot); + if (componentData) + { + componentData->getAttributes(data); + delete componentData; + } + } + } + } + } + } + + if (getObjVars().hasItem(OBJVAR_BIO_LINK_ID)) + { + // display the bio-link info + if (getBioLink() == PENDING_BIO_LINK_NETWORK_ID) + { + data.push_back(std::make_pair(SharedObjectAttributes::bio_link, Unicode::narrowToWide("@"+SharedStringIds::bio_link_pending.getCanonicalRepresentation()))); + } + else + { + const std::string & bioLinkName = NameManager::getInstance().getPlayerFullName(getBioLink()); + if (!bioLinkName.empty()) + { + data.push_back(std::make_pair(SharedObjectAttributes::bio_link, Unicode::narrowToWide(bioLinkName))); + } + else + { + LOG("CustomerService", ("Biolink: object %s is flagged as bio-linked " + "to player %s that we can't find a name for", + getNetworkId().getValueString().c_str(), + PlayerObject::getAccountDescription(getBioLink()).c_str())); + data.push_back(std::make_pair(SharedObjectAttributes::bio_link, Unicode::narrowToWide("@"+SharedStringIds::bio_link_unknown.getCanonicalRepresentation()))); + } + } + } + + // No Trade + { + if (markedNoTrade()) + { + data.push_back(std::make_pair(SharedObjectAttributes::no_trade, Unicode::emptyString)); + + if (markedNoTradeShared(true)) + { + data.push_back(std::make_pair(SharedObjectAttributes::no_trade_shared, Unicode::emptyString)); + } + } + else + { + GameScriptObject * const gso = const_cast(getScriptObject()); + if (gso && gso->hasScript(NOMOVE_SCRIPT)) + { + data.push_back(std::make_pair(SharedObjectAttributes::no_trade, Unicode::emptyString)); + + if (markedNoTradeShared(false)) + { + data.push_back(std::make_pair(SharedObjectAttributes::no_trade_shared, Unicode::emptyString)); + } + } + } + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::getAttributesForAuction(AttributeVector &data) const +{ + static const std::string attributeAppearanceData("AppearanceData"); + + DEBUG_FATAL(getAppearanceData().length() > 1000,("Appearance data was more than 1000 characters long, too long to save.")); + data.push_back(std::make_pair(attributeAppearanceData, Unicode::narrowToWide(getAppearanceData()))); + ServerObject::getAttributesForAuction(data); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::showFlyText(const StringId &outputText, float scale, int r, int g, int b) +{ + //-- Get the controller. + Controller *const controller = getController(); + if (!controller) + { + DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); + return; + } + + //-- Send the showFlyText message to all clients. + uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; + if (isPlayerControlled()) + flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; + controller->appendMessage(static_cast(CM_showFlyText), 0.0f, new MessageQueueShowFlyText(getNetworkId(), outputText, scale, r, g, b, 0), flags); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::showFlyText(const Unicode::String &outputTextOOB, float scale, int r, int g, int b) +{ + //-- Get the controller. + Controller *const controller = getController(); + if (!controller) + { + DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); + return; + } + + //-- Send the showFlyText message to all clients. + uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; + if (isPlayerControlled()) + flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; + controller->appendMessage(static_cast(CM_showFlyText), 0.0f, new MessageQueueShowFlyText(getNetworkId(), outputTextOOB, scale, r, g, b, 0), flags); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::showFlyText(const Unicode::String &outputTextOOB, float scale, int r, int g, int b, int flags) +{ + //-- Get the controller. + Controller *const controller = getController(); + if (!controller) + { + DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); + return; + } + + //-- Send the showFlyText message to all clients. + uint32 netFlags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; + if (isPlayerControlled()) + flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; + controller->appendMessage(static_cast(CM_showFlyText), 0.0f, new MessageQueueShowFlyText(getNetworkId(), outputTextOOB, scale, r, g, b, flags), netFlags); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::showCombatText(const TangibleObject & attackerObject, const StringId &outputText, float scale, int r, int g, int b) +{ + //-- Get the controller. + Controller *const controller = getController(); + if (!controller) + { + DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); + return; + } + + //-- Send the showFlyText message to all clients. + uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; + if (isPlayerControlled()) + flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; + controller->appendMessage(static_cast(CM_showCombatText), 0.0f, new MessageQueueShowCombatText(getNetworkId(), attackerObject.getNetworkId(), outputText, scale, r, g, b, 0), flags); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::showCombatText(const TangibleObject & attackerObject, const Unicode::String &outputTextOOB, float scale, int r, int g, int b) +{ + //-- Get the controller. + Controller *const controller = getController(); + if (!controller) + { + DEBUG_WARNING(true, ("showFlyText(): object [%s] has no controller.", getNetworkId().getValueString().c_str())); + return; + } + + //-- Send the showFlyText message to all clients. + uint32 flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::RELIABLE | GameControllerMessageFlags::DEST_PROXY_CLIENT; + if (isPlayerControlled()) + flags |= GameControllerMessageFlags::DEST_AUTH_CLIENT; + controller->appendMessage(static_cast(CM_showCombatText), 0.0f, new MessageQueueShowCombatText(getNetworkId(), attackerObject.getNetworkId(), outputTextOOB, scale, r, g, b, 0), flags); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::handleCMessageTo(const MessageToPayload &message) +{ + static const std::string methodname_updateCounter = "C++updateCounter"; + + if (message.getMethod() == methodname_updateCounter) + { + if (isCraftingTool()) + { + int timeLeft = getCraftingToolPrototypeTime(); + if (timeLeft <= 0) + { + // done + timeLeft = 0; + } + else + { + // update the count 5 sec from now + MessageToQueue::getInstance().sendMessageToC (getNetworkId(), methodname_updateCounter, std::string (), 5, false); + } + m_count = timeLeft; + } + } + else if (message.getMethod() == "C++UpdatePvp") + { + Pvp::forceStatusUpdate(*this); + } + else if (message.getMethod() == "C++PurgeStructure") + { + LOG("CustomerService",("Purge: Purging structure %s",getNetworkId().getValueString().c_str())); + rollupStructure(NetworkId(message.getDataAsString()),false); + } + else if (message.getMethod() == "C++WarnAboutPurge") + { + LOG("CustomerService",("Purge: Sending warning emails to the admins of structure %s",getNetworkId().getValueString().c_str())); + rollupStructure(NetworkId(message.getDataAsString()),true); + } + else if (message.getMethod() == "C++PurgeVendor") + { + LOG("CustomerService",("Purge: Purging vendor %s",getNetworkId().getValueString().c_str())); + permanentlyDestroy(DeleteReasons::Decay); // Script's onDestroy() method will handle cleanup + } + else if (message.getMethod() == "C++CheckPvpRegion") + { + // check for pvp region change + if (isAuthoritative() && !isInvulnerable() && !isNonPvpObject()) + { + Pvp::checkForRegionChange(*this); + } + + if (isPlayerControlled()) + { + std::map const & connectedCharacterLfgData = ServerUniverse::getConnectedCharacterLfgData(); + std::map::const_iterator iterFind = connectedCharacterLfgData.find(getNetworkId()); + if (iterFind != connectedCharacterLfgData.end()) + { + std::string regionName; + std::string playerCityName; + + std::string const & sceneId = ServerWorld::getSceneId(); + Vector const &position = findPosition_w(); + Region const * const region = RegionMaster::getSmallestVisibleRegionAtPoint(sceneId, position.x, position.z); + if (region != NULL) + regionName = Unicode::wideToNarrow(region->getName()); + + int const cityId = CityInterface::getCityAtLocation(sceneId, static_cast(position.x), static_cast(position.z), 0); + if (cityId > 0) + playerCityName = CityInterface::getCityInfo(cityId).getCityName(); + + if (iterFind->second.locationRegion != regionName) + ServerUniverse::setConnectedCharacterRegionData(getNetworkId(), regionName); + + if (iterFind->second.locationPlayerCity != playerCityName) + ServerUniverse::setConnectedCharacterPlayerCityData(getNetworkId(), playerCityName); + + PlayerObject * const player = PlayerCreatureController::getPlayerObject(asCreatureObject()); + if (player) + player->updateGcwRegionInfo(); + } + } + } + else if (message.getMethod() == "C++ProcessHateOverTime") + { + if (!m_hateOverTime.empty()) + { + std::list expired; + unsigned long const currentGameTime = ServerClock::getInstance().getGameTimeSeconds(); + + for (std::map > >::const_iterator iter = m_hateOverTime.begin(); iter != m_hateOverTime.end(); ++iter) + { + if (iter->second.second.first < currentGameTime) + { + IGNORE_RETURN(addHate(iter->first, iter->second.first * static_cast(std::min(currentGameTime, iter->second.second.second) - iter->second.second.first))); + + if (iter->second.second.second <= currentGameTime) + { + expired.push_back(iter->first); + } + else + { + m_hateOverTime.set(iter->first, std::make_pair(iter->second.first, std::make_pair(currentGameTime, iter->second.second.second))); + } + } + } + + if (!expired.empty()) + { + for (std::list::const_iterator iterExpired = expired.begin(); iterExpired != expired.end(); ++iterExpired) + { + IGNORE_RETURN(m_hateOverTime.erase(*iterExpired)); + } + } + + if (!m_hateOverTime.empty()) + { + MessageToQueue::sendMessageToC(getNetworkId(), "C++ProcessHateOverTime", std::string(), 1, false); + } + } + } + else if (message.getMethod() == "C++DestroyDupedTcg5AtAtHeadItv") + { + LOG("CustomerService",("VeteranRewards: destroying duped tcg5_atat_head_itv item (%s) owned by (%s)", getNetworkId().getValueString().c_str(), getOwnerId().getValueString().c_str())); + permanentlyDestroy(DeleteReasons::Replaced); + } + else + ServerObject::handleCMessageTo(message); +} + +//---------------------------------------------------------------------- + +CustomizationData *TangibleObject::fetchCustomizationData () +{ + CustomizationDataProperty * const cdprop = safe_cast(getProperty (CustomizationDataProperty::getClassPropertyId())); + return cdprop ? cdprop->fetchCustomizationData () : 0; +} + +//---------------------------------------------------------------------- + +const CustomizationData *TangibleObject::fetchCustomizationData () const +{ + const CustomizationDataProperty * const cdprop = safe_cast(getProperty (CustomizationDataProperty::getClassPropertyId())); + return cdprop ? cdprop->fetchCustomizationData () : 0; +} + +// ---------------------------------------------------------------------- + +void TangibleObject::calcPvpableState() +{ + // a tangible is pvpable if it has hit points, has a shared template, does not have an arrangement descriptor, and is not player movable + // or m_attackableOverride is true + if (m_attackableOverride.get()) + { + setPvpable(true); + return; + } + + setPvpable(false); + if (getMaxHitPoints() && getSharedTemplate() && !getSharedTemplate()->getArrangementDescriptor()) + { + ServerObjectTemplate const *objTemplate = safe_cast(getObjectTemplate()); + for (size_t i = 0; i < objTemplate->getMoveFlagsCount(); ++i) + if (objTemplate->getMoveFlags(i) == ServerObjectTemplate::MF_player) + return; + setPvpable(true); + } +} + +// ---------------------------------------------------------------------- + +bool TangibleObject::isInvulnerable() const +{ + return hasCondition(ServerTangibleObjectTemplate::C_invulnerable); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setInvulnerable(bool invulnerable) +{ + if (invulnerable) + { + setCondition(ServerTangibleObjectTemplate::C_invulnerable); + } + else + { + clearCondition(ServerTangibleObjectTemplate::C_invulnerable); + } + + GameScriptObject * const gameScriptObject = getScriptObject(); + + if (gameScriptObject != NULL) + { + ScriptParams scriptParams; + scriptParams.addParam(hasCondition(ServerTangibleObjectTemplate::C_invulnerable)); + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_INVULNERABLE_CHANGED, scriptParams)); + } +} + +// ---------------------------------------------------------------------- + +bool TangibleObject::isInsured(void) const +{ + return hasCondition(ServerTangibleObjectTemplate::C_insured); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setInsured(bool insured) +{ + if (insured) + setCondition(ServerTangibleObjectTemplate::C_insured); + else + clearCondition(ServerTangibleObjectTemplate::C_insured); +} + +// ---------------------------------------------------------------------- + +bool TangibleObject::isUninsurable(void) const +{ + return hasCondition(ServerTangibleObjectTemplate::C_uninsurable); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setUninsurable(bool uninsurable) +{ + if (uninsurable) + setCondition(ServerTangibleObjectTemplate::C_uninsurable); + else + clearCondition(ServerTangibleObjectTemplate::C_uninsurable); +} + +// ---------------------------------------------------------------------- + +bool TangibleObject::wantSawAttackTriggers() const +{ + if (isAuthoritative()) + return hasCondition(ServerTangibleObjectTemplate::C_wantSawAttackTrigger); + return false; +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setWantSawAttackTriggers(bool enable) +{ + if (enable) + setCondition(ServerTangibleObjectTemplate::C_wantSawAttackTrigger); + else + clearCondition(ServerTangibleObjectTemplate::C_wantSawAttackTrigger); +} + +//---------------------------------------------------------------------- + +int TangibleObject::getCombatSkeleton() const +{ + return static_cast((safe_cast(getObjectTemplate()))->getCombatSkeleton()); +} // TangibleObject::getCombatSkeleton() + +//----------------------------------------------------------------------- + +bool TangibleObject::canDropInWorld() const +{ + return true; +} + +//------------------------------------------------------------------------------------------ + +int TangibleObject::getNumberOfLots() const +{ + +//-- fetch the shared object template + const SharedTangibleObjectTemplate* const tangibleObjectTemplate = safe_cast (getSharedTemplate()); + if (!tangibleObjectTemplate) + { + return 0; + } + + //-- get the structure footprint + const StructureFootprint* const structureFootprint = tangibleObjectTemplate->getStructureFootprint (); + if (!structureFootprint) + { + return 0; + } + + //-- return the number of lots + return structureFootprint->getNumberOfStructureReservations (); +} + +//------------------------------------------------------------------------------------------ + +bool TangibleObject::isOnAdminList(const CreatureObject& player) const +{ + //shortcut for owners + if (getOwnerId() == player.getNetworkId()) + return true; + + if(player.getClient() && player.getClient()->isGod()) + return true; + + // In script, the admin list is stored as a list of strings. + // The format of the list is: + // 1) All player are stored as network IDs represented as a string + // 2) All guilds are stored as guild IDs represted as a string and prefixed with "guild:" + + typedef stdvector::fwd StringVector; + static StringVector sv; + sv.clear (); + + if (getObjVars().getItem("player_structure.admin.adminList", sv)) + { + const NetworkId requestorNetworkId = player.getNetworkId(); + + // Convert the network ID to a Unicode string + Unicode::String requestorNetworkIdString = Unicode::narrowToWide( requestorNetworkId.getValueString() ); + + // Try to match the string + for (StringVector::const_iterator it = sv.begin(); it != sv.end(); ++it) + { + const Unicode::String & adminString = *it; + if (Unicode::caseInsensitiveCompare(adminString, requestorNetworkIdString)) + { + return true; + } + } + } + + return false; +} + +//------------------------------------------------------------------------------------------ + +bool TangibleObject::isOnHopperList(const CreatureObject& player) const +{ + if (getOwnerId() == player.getNetworkId()) + return true; + + if(player.getClient() && player.getClient()->isGod()) + return true; + + // In script, the hopper list is stored as a list of strings. + // The format of the list is: + // 1) All player are stored as network IDs represented as a string + // 2) All guilds are stored as guild IDs represted as a string and prefixed with "guild:" + + typedef stdvector::fwd StringVector; + static StringVector sv; + sv.clear (); + + if (getObjVars().getItem("player_structure.hopper.hopperList", sv)) + { + const NetworkId requestorNetworkId = player.getNetworkId(); + + // Convert the network ID to a Unicode string + Unicode::String requestorNetworkIdString = Unicode::narrowToWide( requestorNetworkId.getValueString() ); + + // Try to match the string + for (StringVector::const_iterator it = sv.begin(); it != sv.end(); ++it) + { + const Unicode::String & adminString = *it; + if (Unicode::caseInsensitiveCompare(adminString, requestorNetworkIdString)) + { + return true; + } + } + } + return false; +} + +// ---------------------------------------------------------------------- + +bool TangibleObject::isCustomizationDataModified() const +{ + return getLocalFlag(LocalObjectFlags::TangibleObject_CustomizationDataModified); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setCustomizationDataModified(bool modified) +{ + setLocalFlag(LocalObjectFlags::TangibleObject_CustomizationDataModified, modified); + scheduleForAlter(); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setPvpable(bool pvpable) +{ + bool oldPvpable = !isNonPvpObject(); + setLocalFlag(LocalObjectFlags::TangibleObject_Pvpable, pvpable); + + if ((oldPvpable != pvpable) && !getObservers().empty()) + { + // did the object's "pvp sync" status change because of the Pvpable change? + bool const wasPvpSync = PvpUpdateObserver::satisfyPvpSyncCondition(!oldPvpable, hasCondition(ServerTangibleObjectTemplate::C_invulnerable), (asCreatureObject() != NULL), getPvpFaction()); + bool const isPvpSync = PvpUpdateObserver::satisfyPvpSyncCondition(!pvpable, hasCondition(ServerTangibleObjectTemplate::C_invulnerable), (asCreatureObject() != NULL), getPvpFaction()); + + if (wasPvpSync != isPvpSync) + { + // force pvp status update + Pvp::forceStatusUpdate(*this); + + const std::set &observers = getObservers(); + for (std::set::const_iterator i = observers.begin(); i != observers.end(); ++i) + { + if (isPvpSync) + (*i)->addObservingPvpSync(this); + else + (*i)->removeObservingPvpSync(this); + } + } + } + + if (isAuthoritative()) + { + if (pvpable && !oldPvpable) + MessageToQueue::sendRecurringMessageToC(getNetworkId(), "C++CheckPvpRegion", std::string(), static_cast(getPvpRegionCheckTime())); + else if (!pvpable && oldPvpable) + MessageToQueue::cancelRecurringMessageTo(getNetworkId(), "C++CheckPvpRegion"); + } +} + +// ---------------------------------------------------------------------- + +int TangibleObject::getInterestRadius() const +{ + if (isPlayerControlled()) + return ConfigServerGame::getPlayerInterestRange(); + ServerTangibleObjectTemplate const *myTemplate = safe_cast(getObjectTemplate()); + return myTemplate->getInterestRadius(); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::getRequiredCertifications(std::vector & results) const +{ + const SharedTangibleObjectTemplate *const sharedObjectTemplate = safe_cast(getSharedTemplate()); + if (sharedObjectTemplate) + { + const int numRequired = sharedObjectTemplate->getCertificationsRequiredCount(); + for(int i=0; igetCertificationsRequired(i)); + } + } +} + +// ====================================================================== + +void TangibleObject::MaxHitPointsCallback::modified(TangibleObject &target, int oldValue, int value, bool) const +{ + // if the values actually changed, and if it changed from 0 or to 0, then we need to recalculate pvp state + if ((oldValue != value) && ((oldValue == 0) || (value == 0))) + { + bool oldNonPvpState = target.isNonPvpObject(); + target.calcPvpableState(); + + // if pvp state changed, need to update clients + if (oldNonPvpState != target.isNonPvpObject()) + Pvp::forceStatusUpdate(target); + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::AttackableOverrideCallback::modified(TangibleObject &target, bool oldValue, bool value, bool) const +{ + // if the values actually changed, then we need to recalculate pvp state + if (oldValue != value) + { + bool oldNonPvpState = target.isNonPvpObject(); + target.calcPvpableState(); + + // if pvp state changed, need to update clients + if (oldNonPvpState != target.isNonPvpObject()) + Pvp::forceStatusUpdate(target); + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::AppearanceDataCallback::modified(TangibleObject &target, const std::string &oldValue, const std::string &value, bool isLocal) const +{ + UNREF(isLocal); + + //-- Log any time an authoritative, player-controlled object has customizations set to the empty string. + // This most likely is something very wrong since the player is going to get reset to default cusotmizations. + if (value.empty() && !oldValue.empty()) + { + if (target.isPlayerControlled() && target.isAuthoritative()) + { + std::string const oldAppearanceDataDump = CustomizationData::makeSelectDumpFormat(oldValue.c_str()); + LOG("customization-data-loss", ("non-empty old customization data getting wiped, id=[%s],template=[%s],old m_appearanceData in SELECT DUMP format:[%s]", target.getNetworkId().getValueString().c_str(), target.getObjectTemplateName(), oldAppearanceDataDump.c_str() )); + } + } + + //-- Notify the object that its appearance data has been modified. + target.appearanceDataModified(value); + + Object * const objectContainer = ContainerInterface::getContainedByObject(target); + ServerObject * const serverContainer = objectContainer ? objectContainer->asServerObject() : NULL; + TangibleObject * const tangibleContainer = serverContainer ? serverContainer->asTangibleObject() : NULL; + if(tangibleContainer) + tangibleContainer->onContainedItemAppearanceDataModified(target, oldValue, value); +} + +// ---------------------------------------------------------------------- + +void TangibleObject::onContainedItemAppearanceDataModified(TangibleObject const & , std::string const & , std::string const & ) +{ + //do nothing. Tangibles don't care if their contained objects have their appearance data change +} + +// ---------------------------------------------------------------------- + +void TangibleObject::getByteStreamFromAutoVariable(const std::string & name, Archive::ByteStream & target) const +{ + if(name == "customAppearance") + { + m_customAppearance.pack(target); + } + else if(name == "appearanceData") + { + m_appearanceData.pack(target); + } + else if(name == "incubatorResourceData") + { + std::string resourceData; + + static const uint32 crcIncubator = CrcLowerString::calculateCrc("object/tangible/crafting/station/incubator_station.iff"); + if (getTemplateCrc() == crcIncubator) + { + DynamicVariableList const & objvars = getObjVars(); + if (objvars.hasItem("power.name") && (DynamicVariable::STRING == objvars.getType("power.name"))) + { + std::string resourceName; + IGNORE_RETURN(objvars.getItem("power.name", resourceName)); + + ResourceTypeObject const * const rto = ServerUniverse::getInstance().getResourceTypeByName(resourceName); + if (rto && !rto->getParentClass().isRecycled() && !rto->getParentClass().isPermanent()) + resourceData = rto->getResourceTypeDataForExport(); + } + } + + Archive::put(target, resourceData); + } + else + { + ServerObject::getByteStreamFromAutoVariable(name, target); + } +} + +// ---------------------------------------------------------------------- + +void TangibleObject::setAutoVariableFromByteStream(const std::string & name, const Archive::ByteStream & source) +{ + Archive::ReadIterator ri(source); + if(name == "customAppearance") + { + m_customAppearance.unpackDelta(ri); + } + else if(name == "appearanceData") + { + m_appearanceData.unpackDelta(ri); + } + else if(name == "incubatorResourceData") + { + std::string resourceData; + Archive::get(ri, resourceData); + + static const uint32 crcIncubator = CrcLowerString::calculateCrc("object/tangible/crafting/station/incubator_station.iff"); + if ((getTemplateCrc() == crcIncubator) && !resourceData.empty()) + { + DynamicVariableList const & objvars = getObjVars(); + if (objvars.hasItem("power.name") && (DynamicVariable::STRING == objvars.getType("power.name"))) + { + NetworkId const importedResourceType = ResourceTypeObject::addImportedResourceType(resourceData); + if (importedResourceType.isValid()) + { + if (importedResourceType.getValue() > NetworkId::cms_maxNetworkIdWithoutClusterId) + { + // need to tell all proxy game servers, if any, to create the imported + // resource type, if it hasn't already been created on that game server + ProxyList const &proxyList = getExposedProxyList(); + if (!proxyList.empty()) + { + ServerMessageForwarding::begin(std::vector(proxyList.begin(), proxyList.end())); + + GenericValueTypeMessage > const addImportedResourceTypeMsg("AddImportedResourceType", std::make_pair(importedResourceType, resourceData)); + ServerMessageForwarding::send(addImportedResourceTypeMsg); + + ServerMessageForwarding::end(); + } + } + + ResourceTypeObject const * const rto = ServerUniverse::getInstance().getResourceTypeById(importedResourceType); + if (rto) + { + IGNORE_RETURN(setObjVarItem("power.name", rto->getResourceName())); + + if (importedResourceType.getValue() > NetworkId::cms_maxNetworkIdWithoutClusterId) + IGNORE_RETURN(setObjVarItem("power.resourceData", resourceData)); + else + removeObjVarItem("power.resourceData"); + } + } + } + } + } + else + { + ServerObject::setAutoVariableFromByteStream(name, source); + } + addObjectToConcludeList(); +} + +// ---------------------------------------------------------------------- + +/** + * Sets a bio-link on this object. This object will only be able to be equipped by + * the player who's id matches the bio-link id. + * + * @param playerId the player to link this object to + */ +void TangibleObject::setBioLink(const NetworkId & playerId) +{ + if (playerId != NetworkId::cms_invalid) + { + if (isAuthoritative()) + { + setObjVarItem(OBJVAR_BIO_LINK_ID, playerId); + } + else + { + sendControllerMessageToAuthServer(CM_setBioLink, new MessageQueueGenericValueType(playerId)); + } + } +} + +// ---------------------------------------------------------------------- + +/** + * Sets the pending bio-link on this object. This will prevent the object from + * being equipped by any player until a real bio-link is set. + */ +void TangibleObject::setPendingBioLink() +{ + setBioLink(PENDING_BIO_LINK_NETWORK_ID); +} + +// ---------------------------------------------------------------------- + +/** + * Removes the bio-link on this object. + */ +void TangibleObject::clearBioLink() +{ + if (isAuthoritative()) + { + removeObjVarItem(OBJVAR_BIO_LINK); + } + else + { + sendControllerMessageToAuthServer(CM_setBioLink, new MessageQueueGenericValueType(NetworkId::cms_invalid)); + } +} + +// ---------------------------------------------------------------------- + +/** + * Returns the bio-link id of this object. + * + * @return the bio-link player id (NetworkId::cms_invalid if the object isn't bio-linked) + */ +NetworkId TangibleObject::getBioLink() const +{ + NetworkId linkId; + if (getObjVars().getItem(OBJVAR_BIO_LINK_ID, linkId)) + return linkId; + return NetworkId::cms_invalid; +} + +// ---------------------------------------------------------------------- + +/** + * Returns whether an object, or any contained object, is biolinked + * + * @return true if a biolinked object is found + */ +bool TangibleObject::isBioLinked() const +{ + NetworkId const linkId = getBioLink(); + + if( (linkId != NetworkId::cms_invalid) && (linkId != PENDING_BIO_LINK_NETWORK_ID) ) + { + // If the network ID is valid and does not correspond to a pending bio-link + // then we will assume that the tangible object is bio-linked + return true; + } + + return false; +} + +// ---------------------------------------------------------------------- + +void TangibleObject::rollupStructure(NetworkId const & owner, bool warnOnly) +{ + GameScriptObject* gso = getScriptObject(); + if (gso) + { + gso->attachScript("structure.structure_rollup", true); + ScriptParams params; + params.addParam(owner); + params.addParam(warnOnly); + gso->trigAllScripts(Scripting::TRIG_DO_STRUCTURE_ROLLUP, params); + gso->detachScript("structure.structure_rollup"); + } +} + +// ---------------------------------------------------------------------- + +CommandQueue * TangibleObject::getCommandQueue() const +{ + return CommandQueue::getCommandQueue(*const_cast(this)); +} + +//----------------------------------------------------------------------- + +void TangibleObject::commandQueueEnqueue(Command const &command, NetworkId const &targetId, Unicode::String const ¶ms, uint32 const sequenceId, bool const clearable, Command::Priority const priority, bool fromServer) +{ + if(!fromServer) + { + if(command.m_fromServerOnly) + { + LOG("CustomerService", ("CheatChannel: attempt to queue server-only command %s from client on object %s", command.m_commandName.c_str(), getNetworkId().getValueString().c_str())); + return; + } + } + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_commandQueueEnqueueFwd, new MessageQueueCommandQueueEnqueueFwd(sequenceId, command.m_commandHash, targetId, params, clearable, static_cast(priority), fromServer)); + } + else + { + CommandQueue * const queue = getCommandQueue(); + if (queue != NULL) + { + queue->enqueue(command, targetId, params, sequenceId, clearable, priority); + } + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::commandQueueRemove(uint32 const sequenceId) +{ + if (!isAuthoritative()) + { + sendControllerMessageToAuthServer(CM_commandQueueRemove, new MessageQueueCommandQueueRemove(sequenceId, 0.0f, static_cast(Command::CEC_Success), 0)); + } + else + { + CommandQueue * const queue = getCommandQueue(); + if (queue != NULL) + { + queue->remove(sequenceId); + } + } +} + +//----------------------------------------------------------------------- + +void TangibleObject::commandQueueClear() +{ + // commandQueueRemove clears the queue when passed a 0 sequenceId + commandQueueRemove(0); +} + +//----------------------------------------------------------------------- + +bool TangibleObject::commandQueueHasCommandFromGroup(uint32 groupHash) const +{ + CommandQueue * const queue = getCommandQueue(); + if (queue != NULL) + { + return queue->hasCommandFromGroup(groupHash); + } + return false; +} + +//----------------------------------------------------------------------- + +void TangibleObject::commandQueueClearCommandsFromGroup(uint32 groupHash, bool force) +{ + CommandQueue * const queue = getCommandQueue(); + if (queue != NULL) + { + queue->clearCommandsFromGroup(groupHash, force); + } +} + +//----------------------------------------------------------------------- + +CombatEngineData::CombatData * TangibleObject::getCombatData() +{ + return m_combatData; +} + +//----------------------------------------------------------------------- + +CombatEngineData::CombatData const * TangibleObject::getCombatData() const +{ + return m_combatData; +} + +//----------------------------------------------------------------------- + +void TangibleObject::CombatStateChangedCallback::modified(TangibleObject & target, bool /*oldValue*/, bool newValue, bool /*local*/) const +{ + if (newValue) + { + // Starting Combat + + LOGC(ConfigServerGame::isAiLoggingEnabled(), "debug_ai", ("TangibleObject::Callbacks::CombatStateChanged::modified() STARTING COMBAT owner(%s:%s)", target.getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(target.getEncodedObjectName()).c_str())); + + if (target.isAuthoritative()) + { + target.createCombatData(); + + target.m_combatStartTime = Os::getRealSystemTime(); + + if (!target.isPlayerControlled()) + { + ObjectTracker::addCombatAI(); + } + + AICreatureController * const aiCreatureController = AICreatureController::asAiCreatureController(target.getController()); + + if (aiCreatureController != NULL) + { + aiCreatureController->markCombatStartLocation(); + } + + if (target.getScriptObject() != NULL) + { + ScriptParams params; + IGNORE_RETURN(target.getScriptObject()->trigAllScripts(Scripting::TRIG_ENTERED_COMBAT, params)); + } + + target.scheduleForAlter(); + } + } + else + { + // Exiting Combat + + LOGC(ConfigServerGame::isAiLoggingEnabled(), "debug_ai", ("TangibleObject::Callbacks::CombatStateChanged::modified() EXITING COMBAT owner(%s:%s)", target.getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(target.getEncodedObjectName()).c_str())); + + if (target.isAuthoritative()) + { + if (!target.isPlayerControlled()) + { + ObjectTracker::removeCombatAI(); + } + + //target.clearHateList(); + + target.commandQueueClearCommandsFromGroup(COMMAND_GROUP_COMBAT.getCrc()); + + if (target.getScriptObject() != NULL) + { + ScriptParams params; + IGNORE_RETURN(target.getScriptObject()->trigAllScripts(Scripting::TRIG_EXITED_COMBAT, params)); + } + + target.scheduleForAlter(); + } + } +} + +//----------------------------------------------------------------------- +int TangibleObject::getCombatDuration() const +{ + int result = 0; + + if (isInCombat()) + { + result = static_cast(Os::getRealSystemTime() - m_combatStartTime.get()); + } + + return result; +} + +//----------------------------------------------------------------------- +void TangibleObject::setAttackableOverride(bool attackable) +{ + if (isAuthoritative()) + { + if (m_attackableOverride.get() != attackable) + m_attackableOverride = attackable; + } + else + { + sendControllerMessageToAuthServer(CM_setAttackableOverride, new MessageQueueGenericValueType(attackable)); + } +} + +//----------------------------------------------------------------------- +bool TangibleObject::hasAutoDeclineDuel() const +{ + return getObjVars().hasItem(OBJVAR_DECLINE_DUEL); +} + +//---------------------------------------------------------------------- + +int TangibleObject::getPassiveRevealRange(NetworkId const & target) const +{ + Archive::AutoDeltaMap::const_iterator i = m_passiveReveal.find(target); + if (i == m_passiveReveal.end()) + return -1; + + return i->second; +} + +//---------------------------------------------------------------------- + +void TangibleObject::addPassiveReveal(TangibleObject const & target, int range) +{ + addPassiveReveal(target.getNetworkId(), range, (NULL != PlayerCreatureController::getPlayerObject(target.asCreatureObject()))); +} + +//---------------------------------------------------------------------- + +void TangibleObject::addPassiveReveal(NetworkId const & target, int range, bool isTargetPlayerCharacter) +{ + // and object cannot passively reveal itself + if (target == getNetworkId()) + return; + + // range must be > 0 + if (range <= 0) + return; + + if(isAuthoritative()) + { + m_passiveReveal.set(target, range); + + if (isTargetPlayerCharacter) + m_passiveRevealPlayerCharacter.insert(target); + } + else + { + sendControllerMessageToAuthServer(CM_addPassiveReveal, new MessageQueueGenericValueType, NetworkId> >(std::make_pair(std::make_pair(range, (isTargetPlayerCharacter ? 1 : 0)), target))); + } +} + +//---------------------------------------------------------------------- + +void TangibleObject::removePassiveReveal(NetworkId const & target) +{ + if(isAuthoritative()) + { + IGNORE_RETURN(m_passiveReveal.erase(target)); + IGNORE_RETURN(m_passiveRevealPlayerCharacter.erase(target)); + } + else + { + sendControllerMessageToAuthServer(CM_removePassiveReveal, new MessageQueueGenericValueType(target)); + } +} + +//---------------------------------------------------------------------- + +void TangibleObject::removeAllPassiveReveal() +{ + if(isAuthoritative()) + { + m_passiveReveal.clear(); + m_passiveRevealPlayerCharacter.clear(); + } + else + { + sendControllerMessageToAuthServer(CM_removeAllPassiveReveal, 0); + } +} + +//---------------------------------------------------------------------- + +bool TangibleObject::setOverrideMapColor(unsigned char r, unsigned char g, unsigned char b) +{ + if(!isAuthoritative()) + { + return false; + } + + PackedArgb color(255, r, g, b); + m_mapColorOverride.set(color.getArgb()); + return true; +} + +//---------------------------------------------------------------------- + +bool TangibleObject::clearOverrideMapColor() +{ + if(!isAuthoritative()) + { + return false; + } + + m_mapColorOverride.set(0); + return true; +} + +//---------------------------------------------------------------------- + +bool TangibleObject::getOverrideMapColor(unsigned char & r, unsigned char & g, unsigned char & b) const +{ + PackedArgb color(m_mapColorOverride.get()); + if(color.getA() == 0) + { + return false; + } + + r = color.getR(); + g = color.getG(); + b = color.getB(); + return true; +} + +//---------------------------------------------------------------------- + +void TangibleObject::handleIncubatorCommit(CreatureObject const & owner, IncubatorCommitMessage const & msg) +{ + // this operation *REQUIRES* that both the incubator and the + // character manipulating the incubator be authoritative on + // the same game server, so it's really not possible to + // pass this handler over to the authoritative incubator, + // since there's no guarantee that the character will be + // authoritative on that game server either + if (!isAuthoritative() || !owner.isAuthoritative()) + return; + + GameScriptObject * const scriptObject = getScriptObject(); + if (scriptObject) + { + ScriptParams params; + params.addParam(owner.getNetworkId(), "playerId"); + params.addParam(getNetworkId(), "terminalId"); + params.addParam(msg.getSlot1Id(), "slot1Id"); + params.addParam(msg.getSlot2Id(), "slot2Id"); + params.addParam(msg.getSlot3Id(), "slot3Id"); + params.addParam(msg.getSlot4Id(), "slot4Id"); + params.addParam(msg.getInitialPointsSurvival(), "initialPointsSurvival"); + params.addParam(msg.getInitialPointsBeastialResilience(),"initialPointsBeastialResilience"); + params.addParam(msg.getInitialPointsCunning(),"initialPointsCunning"); + params.addParam(msg.getInitialPointsIntelligence(),"initialPointsIntelligence"); + params.addParam(msg.getInitialPointsAggression(),"initialPointsAggression"); + params.addParam(msg.getInitialPointsHuntersInstinct(),"initialPointsHuntersInstinct"); + params.addParam(msg.getTotalPointsSurvival(),"totalPointsSurvival"); + params.addParam(msg.getTotalPointsBeastialResilience(),"totalPointsBeastialResilience"); + params.addParam(msg.getTotalPointsCunning(),"totalPointsCunning"); + params.addParam(msg.getTotalPointsIntelligence(),"totalPointsIntelligence"); + params.addParam(msg.getTotalPointsAggression(),"totalPointsAggression"); + params.addParam(msg.getTotalPointsHuntersInstinct(),"totalPointsHuntersInstinct"); + params.addParam(msg.getTemperatureGauge(),"temperatureGauge"); + params.addParam(msg.getNutrientGauge(),"nutrientGauge"); + params.addParam(msg.getNewCreatureColorIndex(), "newCreatureColorIndex"); + + IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_INCUBATOR_COMMITTED, params)); + } +} + +void TangibleObject::handleIncubatorCancel(CreatureObject const & owner) +{ + // this operation *REQUIRES* that both the incubator and the + // character manipulating the incubator be authoritative on + // the same game server, so it's really not possible to + // pass this handler over to the authoritative incubator, + // since there's no guarantee that the character will be + // authoritative on that game server either + if (!isAuthoritative() || !owner.isAuthoritative()) + return; + + GameScriptObject * const scriptObject = getScriptObject(); + if (scriptObject) + { + ScriptParams params; + params.addParam(owner.getNetworkId(), "playerId"); + params.addParam(getNetworkId(), "terminalId"); + + IGNORE_RETURN(scriptObject->trigAllScripts(Scripting::TRIG_INCUBATOR_CANCELED, params)); + } +} + +void TangibleObject::forceHateTarget(NetworkId const & target) +{ + if(isAuthoritative()) + { + m_hateList.forceHateTarget(target); + scheduleForAlter(); + } + else + { + sendControllerMessageToAuthServer(CM_forceHateTarget, new MessageQueueGenericValueType(target)); + } + +} + +bool TangibleObject::isUserOnAccessList(NetworkId const user) const +{ + return (std::find(m_accessList.begin(), m_accessList.end(), user) != m_accessList.end()); +} + +bool TangibleObject::isGuildOnAccessList(int guildId) const +{ + return (std::find(m_guildAccessList.begin(), m_guildAccessList.end(), guildId) != m_guildAccessList.end()); +} + +void TangibleObject::addUserToAccessList(const NetworkId user) +{ + if(isAuthoritative()) + { + if(m_accessList.find(user) == m_accessList.end()) + { + if(!hasCondition(C_locked)) // If we weren't locked before, we are now. + setCondition(C_locked); + + m_accessList.insert(user); + + copyUserAccessListToObjVars(); + } + } + else + { + sendControllerMessageToAuthServer(CM_addUserToAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(-1, user) ) ); + } +} + +void TangibleObject::addGuildToAccessList(int guildId) +{ + if(isAuthoritative()) + { + if(m_guildAccessList.find(guildId) == m_guildAccessList.end()) + { + if(!hasCondition(C_locked)) // If we weren't locked before, we are now. + setCondition(C_locked); + + m_guildAccessList.insert(guildId); + + copyGuildAccessListToObjVars(); + } + } + else + { + sendControllerMessageToAuthServer(CM_addUserToAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(guildId, NetworkId::cms_invalid) ) ); + } +} + + +void TangibleObject::removeUserFromAccessList(const NetworkId user) +{ + if(isAuthoritative()) + { + Archive::AutoDeltaSet::const_iterator iter = m_accessList.find(user); + if(iter != m_accessList.end()) + { + m_accessList.erase(iter); + if(m_accessList.empty()) + { + if(hasCondition(C_locked)) + clearCondition(C_locked); // Containers with no access list are open to whomever. + + removeObjVarItem(s_accessListScriptVar); // Remove our objvars, no need for them anymore. + + return; + } + + copyUserAccessListToObjVars(); + + } + } + else + { + sendControllerMessageToAuthServer(CM_removeUserFromAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(-1, user))); + } +} + +void TangibleObject::removeGuildFromAccessList(int guildId) +{ + if(isAuthoritative()) + { + Archive::AutoDeltaSet::const_iterator iter = m_guildAccessList.find(guildId); + if(iter != m_guildAccessList.end()) + { + m_guildAccessList.erase(iter); + if(m_guildAccessList.empty()) + { + if(hasCondition(C_locked) && m_accessList.empty()) + clearCondition(C_locked); // Containers with no access list are open to whomever. + + removeObjVarItem(s_guildAccessListScriptVar); // Remove our objvars, no need for them anymore. + + return; + } + + copyGuildAccessListToObjVars(); + + } + } + else + { + sendControllerMessageToAuthServer(CM_removeUserFromAccessList, new MessageQueueGenericValueType< std::pair >(std::make_pair(guildId, NetworkId::cms_invalid))); + } +} + +void TangibleObject::copyUserAccessListToObjVars() +{ + std::vector newAccessList; + Archive::AutoDeltaSet::const_iterator iter = m_accessList.begin(); + for(; iter != m_accessList.end(); ++iter) + newAccessList.push_back((*iter)); + + setObjVarItem(s_accessListScriptVar, newAccessList); +} + +void TangibleObject::copyGuildAccessListToObjVars() +{ + std::vector newAccessList; + Archive::AutoDeltaSet::const_iterator iter = m_guildAccessList.begin(); + for(; iter != m_guildAccessList.end(); ++iter) + newAccessList.push_back((*iter)); + + setObjVarItem(s_guildAccessListScriptVar, newAccessList); +} + + +void TangibleObject::readInUserAccessListObjVars() +{ + std::vector inputVector; + if(getObjVars().getItem(s_accessListScriptVar, inputVector)) + { + // We have some obj vars to add to our list! + std::vector::size_type i = 0; + for( ; i < inputVector.size(); ++i) + { + m_accessList.insert(inputVector[i]); + } + } +} + +void TangibleObject::readInGuildAccessListObjVars() +{ + std::vector inputVector; + if(getObjVars().getItem(s_guildAccessListScriptVar, inputVector)) + { + // We have some obj vars to add to our list! + std::vector::size_type i = 0; + for( ; i < inputVector.size(); ++i) + { + m_guildAccessList.insert(inputVector[i]); + } + } +} + +void TangibleObject::clearUserAccessList() +{ + if(isAuthoritative()) + { + if(hasCondition(C_locked) && m_guildAccessList.empty()) // No access list = total unlock. + clearCondition(C_locked); + + m_accessList.clear(); + + removeObjVarItem(s_accessListScriptVar); // Remove our objvars, no need for them anymore. + + } + else + { + sendControllerMessageToAuthServer(CM_clearUserAccessList, new MessageQueueGenericValueType(false)); + } +} + +void TangibleObject::clearGuildAccessList() +{ + if(isAuthoritative()) + { + if(hasCondition(C_locked) && m_accessList.empty()) // No access list = total unlock. + clearCondition(C_locked); + + m_guildAccessList.clear(); + + removeObjVarItem(s_guildAccessListScriptVar); // Remove our objvars, no need for them anymore. + + } + else + { + sendControllerMessageToAuthServer(CM_clearUserAccessList, new MessageQueueGenericValueType(true)); + } +} + +void TangibleObject::getUserAccessList(std::vector & ids) +{ + getObjVars().getItem(s_accessListScriptVar, ids); +} + +void TangibleObject::getGuildAccessList(std::vector & ids) +{ + getObjVars().getItem(s_guildAccessListScriptVar, ids); +} + +void TangibleObject::addObjectEffect(std::string const & filename, std::string const & hardpoint, Vector const & offset, float scale, std::string const & label) +{ + if(isAuthoritative()) + { + if(m_effectsMap.find(label) != m_effectsMap.end()) + return; + + m_effectsMap.insert(label, std::make_pair(filename, std::make_pair( hardpoint, std::make_pair(offset, scale )))); + } + else + sendControllerMessageToAuthServer(CM_addObjectEffect, + new MessageQueueGenericValueType > > > >(std::make_pair(label, std::make_pair(filename, std::make_pair(hardpoint, std::make_pair(offset, scale)))))); +} + +void TangibleObject::removeObjectEffect(std::string const & label) +{ + if(isAuthoritative()) + { + Archive::AutoDeltaMap > > >::const_iterator iter = m_effectsMap.find(label); + if(iter == m_effectsMap.end()) + return; + + m_effectsMap.erase(iter); + } + else + sendControllerMessageToAuthServer(CM_removeObjectEffect, new MessageQueueGenericValueType(label)); +} + +bool TangibleObject::hasObjectEffect(std::string const & label) +{ + return m_effectsMap.find(label) != m_effectsMap.end(); +} + +void TangibleObject::removeAllObjectEffects() +{ + if(isAuthoritative()) + { + m_effectsMap.clear(); + } + else + sendControllerMessageToAuthServer(CM_removeAllObjectEffect, new MessageQueueGenericValueType(true)); +} +// ====================================================================== diff --git a/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerCreatureObjectTemplate.cpp b/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerCreatureObjectTemplate.cpp index e5ba56559..babf8d0aa 100644 --- a/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerCreatureObjectTemplate.cpp +++ b/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerCreatureObjectTemplate.cpp @@ -168,7 +168,7 @@ int ServerCreatureObjectTemplate::getAttributes(Attributes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 6, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 6, ("template param static_cast(index) getAttribModsCount(); - if (index < baseCount) + if (static_cast(index) < baseCount) { base->getAttribMods(data, index); return; @@ -1403,7 +1403,7 @@ void ServerCreatureObjectTemplate::getAttribMods(AttribMod &data, int index) con index -= baseCount; } - DEBUG_FATAL(index < 0 || static_cast(index) >= m_attribMods.size(), ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= m_attribMods.size(), ("template param static_cast(index) (structTemplate); @@ -1441,7 +1441,7 @@ void ServerCreatureObjectTemplate::getAttribModsMin(AttribMod &data, int index) if (m_attribModsAppend && base != NULL) { int baseCount = base->getAttribModsCount(); - if (index < baseCount) + if (static_cast(index) < baseCount) { base->getAttribModsMin(data, index); return; @@ -1449,7 +1449,7 @@ void ServerCreatureObjectTemplate::getAttribModsMin(AttribMod &data, int index) index -= baseCount; } - DEBUG_FATAL(index < 0 || static_cast(index) >= m_attribMods.size(), ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= m_attribMods.size(), ("template param static_cast(index) (structTemplate); @@ -1487,7 +1487,7 @@ void ServerCreatureObjectTemplate::getAttribModsMax(AttribMod &data, int index) if (m_attribModsAppend && base != NULL) { int baseCount = base->getAttribModsCount(); - if (index < baseCount) + if (static_cast(index) < baseCount) { base->getAttribModsMax(data, index); return; @@ -1495,7 +1495,7 @@ void ServerCreatureObjectTemplate::getAttribModsMax(AttribMod &data, int index) index -= baseCount; } - DEBUG_FATAL(index < 0 || static_cast(index) >= m_attribMods.size(), ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= m_attribMods.size(), ("template param static_cast(index) (structTemplate); @@ -2007,7 +2007,7 @@ float ServerCreatureObjectTemplate::getMaxMentalStates(MentalStates index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 4, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 4, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 4, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 4, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 4, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 4, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 4, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 4, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 4, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 4, ("template param static_cast(index) (m_baseData); } - DEBUG_FATAL(index < 0 || index >= 4, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 4, ("template param static_cast(index) (index) >= m_triggerVolumes.size(), ("template param index out of range")); - const TriggerVolumeData & value = m_triggerVolumes[index]->getValue(); + const TriggerVolumeData value = m_triggerVolumes[index]->getValue(); + return value; } // ServerTangibleObjectTemplate::getTriggerVolumes diff --git a/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerTangibleObjectTemplate.h b/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerTangibleObjectTemplate.h index 5c941b2d9..785cc5d51 100644 --- a/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerTangibleObjectTemplate.h +++ b/src/engine/server/library/serverGame/src/shared/objectTemplate/ServerTangibleObjectTemplate.h @@ -84,7 +84,7 @@ public: }; public: - const TriggerVolumeData & getTriggerVolumes(int index) const; + const TriggerVolumeData getTriggerVolumes(int index) const; size_t getTriggerVolumesCount(void) const; CombatSkeleton getCombatSkeleton(bool testData = false) const; int getMaxHitPoints(bool testData = false) const; diff --git a/src/engine/server/library/serverGame/src/shared/region/RegionMaster.cpp b/src/engine/server/library/serverGame/src/shared/region/RegionMaster.cpp index 8f2f83d02..6cbb77109 100644 --- a/src/engine/server/library/serverGame/src/shared/region/RegionMaster.cpp +++ b/src/engine/server/library/serverGame/src/shared/region/RegionMaster.cpp @@ -1,1255 +1,1255 @@ -//======================================================================== -// -// RegionMaster.cpp -// -// copyright 2001 Sony Online Entertainment -// -//======================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/RegionMaster.h" - -#include "serverGame/ConfigServerGame.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/GameServer.h" -#include "serverGame/PlanetObject.h" -#include "serverGame/Region.h" -#include "serverGame/RegionPvp.h" -#include "serverGame/ServerUniverse.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/UniverseObject.h" -#include "serverNetworkMessages/CreateDynamicRegionCircleMessage.h" -#include "serverNetworkMessages/CreateDynamicRegionRectangleMessage.h" -#include "serverNetworkMessages/CreateDynamicSpawnRegionCircleMessage.h" -#include "sharedFoundation/CalendarTime.h" -#include "sharedFoundation/DynamicVariableList.h" -#include "sharedFoundation/FloatMath.h" -#include "sharedFoundation/ExitChain.h" -#include "sharedMath/MxCifQuadTree.h" -#include "sharedMath/MxCifQuadTreeBounds.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptParameters.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" -#include -#include -#include - - -// objvars for dynamic regions -const static std::string OBJVAR_DYNAMIC_REGION("dynamic_region"); -const static std::string OBJVAR_DYNAMIC_REGION_PLANET("planet"); -const static std::string OBJVAR_DYNAMIC_REGION_NAME("name"); -const static std::string OBJVAR_DYNAMIC_REGION_GEOMETRY("geometry"); -const static std::string OBJVAR_DYNAMIC_REGION_MINX("minX"); -const static std::string OBJVAR_DYNAMIC_REGION_MINY("minY"); -const static std::string OBJVAR_DYNAMIC_REGION_MAXX("maxX"); -const static std::string OBJVAR_DYNAMIC_REGION_MAXY("maxY"); -const static std::string OBJVAR_DYNAMIC_REGION_PVP("pvp"); -const static std::string OBJVAR_DYNAMIC_REGION_GEOGRAPHY("geography"); -const static std::string OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY("minDifficulty"); -const static std::string OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY("maxDifficulty"); -const static std::string OBJVAR_DYNAMIC_REGION_SPAWN("spawn"); -const static std::string OBJVAR_DYNAMIC_REGION_MISSION("mission"); -const static std::string OBJVAR_DYNAMIC_REGION_BUILDABLE("buildable"); -const static std::string OBJVAR_DYNAMIC_REGION_MUNICIPAL("municipal"); -const static std::string OBJVAR_DYNAMIC_REGION_VISIBLE("visible"); -const static std::string OBJVAR_DYNAMIC_REGION_BATTLEFIELD_MARKER("_battlefield"); -const static std::string OBJVAR_DYNAMIC_REGION_NOTIFY("notify"); -const static std::string OBJVAR_DYNAMIC_REGION_SPAWNTABLE("spawntable"); -const static std::string OBJVAR_DYNAMIC_REGION_DURATION("duration"); -const static std::string OBJVAR_DYNAMIC_REGION_MAXDURATION("maxDuration"); -const static std::string OBJVAR_DYNAMIC_REGION_BIRTH("birth"); -const static std::string OBJVAR_DYNAMIC_REGION_READABLE_BIRTH("calendarBirth"); -const static std::string OBJVAR_DYNAMIC_REGION_READABLE_DEATH("calenderDeath"); -const static std::string OBJVAR_DYNAMIC_REGION_CREATURE_LIST("creatureList"); - -// template used to make dynamic regions -const static std::string DYNAMIC_REGION_TEMPLATE_NAME("object/universe/dynamic_region.iff"); - - - -enum RegionGeometry -{ - RG_rectagle, - RG_circle -}; - -//---------------------------------------------------------------------- - -struct RegionMaster::RegionData -{ - MxCifQuadTree * tree; - RegionsMappedByName nameMap; - - RegionData() : tree(NULL), nameMap() {} -}; - -namespace RegionMasterNamspace -{ - EnvironmentInfo convertFromStringToEnvironmentInfo(std::string const & stringList); - - std::string s_environmentFlagsDataTable = "datatables/region/region_environment_flags.iff"; - std::map s_conversionMap; - - std::string s_dynamicMasterScript = "systems.regions.dynamic_region_master"; -} - -using namespace RegionMasterNamspace; -//======================================================================== -// static member vars - -std::map RegionMaster::ms_planetRegions; -std::vector RegionMaster::ms_staticRegions; -std::vector RegionMaster::ms_dynamicRegions; -bool RegionMaster::ms_installed = false; - -//======================================================================== - -/** - * Called on program startup. Creates the RegionMaster. - */ -void RegionMaster::install() -{ - if (!ms_installed) - { - ms_installed = true; - readRegionDataTables(); - ExitChain::add(exit, "RegionMaster"); - } -} - -//----------------------------------------------------------------------- - -/** - * Called on program shutdown. Deletes the RegionMaster. - */ -void RegionMaster::exit() -{ - if (ms_installed) - { - { - for (std::map::iterator i1 = ms_planetRegions.begin(); - i1 != ms_planetRegions.end(); ++i1) - { - delete (*i1).second.tree; - (*i1).second.tree = NULL; - } - ms_planetRegions.clear(); - } - - { - for (std::vector::iterator i2 = ms_staticRegions.begin(); - i2 != ms_staticRegions.end(); ++i2) - { - delete const_cast(*i2); - *i2 = NULL; - } - ms_staticRegions.clear(); - } - - { - for (std::vector::iterator i2 = ms_dynamicRegions.begin(); - i2 != ms_dynamicRegions.end(); ++i2) - { - delete const_cast(*i2); - *i2 = NULL; - } - ms_dynamicRegions.clear(); - } - - ms_installed = false; - } -} - -//----------------------------------------------------------------------- - -/** - * Reads the static region info from the planets' region datatables. - */ -void RegionMaster::readRegionDataTables() -{ - if (!ms_installed) - { - WARNING(true, ("RegionMaster::readRegionDataTables, not installed")); - return; - } - - const char * regionFilesName = ConfigServerGame::getRegionFilesName(); - - DataTable * const regionFilesTable = DataTableManager::getTable(regionFilesName, true); - if (regionFilesTable == NULL) - { - WARNING(true, ("RegionMaster::readRegionDataTables could not open file %s, static regions will not be read!", regionFilesName)); - return; - } - - { - const int numRegionFiles = regionFilesTable->getNumRows(); - for (int i = 0; i < numRegionFiles; ++i) - { - // get the region table from the filename table - const std::string & planetName = regionFilesTable->getStringValue(0, i); - const std::string & regionFileName = regionFilesTable->getStringValue(1, i); - float regionMinX = regionFilesTable->getFloatValue (2, i); - float regionMinY = regionFilesTable->getFloatValue (3, i); - float regionMaxX = regionFilesTable->getFloatValue (4, i); - float regionMaxY = regionFilesTable->getFloatValue (5, i); - - DataTable * const regionTable = DataTableManager::getTable(regionFileName, true); - if (regionTable == NULL) - { - WARNING(true, ("RegionMaster::readRegionDataTables could not open region file %s.", regionFileName.c_str())); - continue; - } - - RegionData & regionData = ms_planetRegions[planetName]; - if (regionData.tree == NULL) - { - regionData.tree = new MxCifQuadTree(regionMinX, regionMinY, regionMaxX, regionMaxY, ConfigServerGame::getRegionTreeDepth()); - } - - int numRegions = regionTable->getNumRows(); - for (int j = 0; j < numRegions; ++j) - { - // read the region data from the table - const Unicode::String name(Unicode::narrowToWide(regionTable->getStringValue( 0, j))); - int geometry = regionTable->getIntValue ( 1, j); - float minX = regionTable->getFloatValue ( 2, j); - float minY = regionTable->getFloatValue ( 3, j); - float maxX = regionTable->getFloatValue ( 4, j); - float maxY = regionTable->getFloatValue ( 5, j); - int pvp = regionTable->getIntValue ( 6, j); - int geography = regionTable->getIntValue ( 7, j); - int minDifficulty = regionTable->getIntValue ( 8, j); - int maxDifficulty = regionTable->getIntValue ( 9, j); - int spawn = regionTable->getIntValue (10, j); - int mission = regionTable->getIntValue (11, j); - int buildable = regionTable->getIntValue (12, j); - int municipal = regionTable->getIntValue (13, j); - int visible = regionTable->getIntValue (14, j); - int notify = regionTable->getIntValue (15, j); - EnvironmentInfo envFlags = convertFromStringToEnvironmentInfo( regionTable->getStringValue(16, j) ); - - // make sure the region has a unique name - if (name.empty()) - { - WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s has no region name", - j, regionFileName.c_str())); - continue; - } - else if (regionData.nameMap.find(name) != regionData.nameMap.end()) - { - WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s is trying to add duplicate region %s", - j, regionFileName.c_str(), Unicode::wideToNarrow(name).c_str())); - continue; - } - - // create a rectangular or circular region and add it to the region tree - Region * region = NULL; - switch (geometry) - { - case RG_rectagle: - { - RegionRectangle * const rectangle = new RegionRectangle(minX, minY, maxX, maxY); - if (regionData.tree->addObject(rectangle->getBounds())) - region = rectangle; - else - delete rectangle; - } - break; - case RG_circle: - { - if (pvp == PR_battlefieldPvp || pvp == PR_battlefieldPve) - { - RegionPvp * battlefield = new RegionPvp(minX, minY, maxX); - if (regionData.tree->addObject(battlefield->getBounds())) - region = battlefield; - else - delete battlefield; - } - else - { - RegionCircle * circle = new RegionCircle(minX, minY, maxX); - if (regionData.tree->addObject(circle->getBounds())) - region = circle; - else - delete circle; - } - } - break; - default: - WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s has invalid geometry parameter %d", - j, regionFileName.c_str(), geometry)); - continue; - } - // set the rest of the region's data - if (region != NULL) - { - region->setName(name); - region->setPlanet(planetName); - region->setPvp(pvp); - region->setGeography(geography); - region->setMinDifficulty(minDifficulty); - region->setMaxDifficulty(maxDifficulty); - region->setSpawn(spawn); - region->setMission(mission); - region->setBuildable(buildable); - region->setMunicipal(municipal); - region->setVisible(visible); - region->setNotify(notify); - region->setEnvironmentFlags(envFlags); - ms_staticRegions.push_back(region); - regionData.nameMap[name] = region; - } - else - { - FATAL(true, ("RegionMaster::readRegionDataTables could not add row %d (%s) of table %s to region tree", - j, Unicode::wideToNarrow(name).c_str(), regionFileName.c_str())); - } - } - DataTableManager::close(regionFileName); - } - } - DataTableManager::close(regionFilesName); -} // RegionMaster::readRegionDataTables - -//----------------------------------------------------------------------- - -/** - * Creates a new rectangular dynamic region. - * - * @param minX min x coordinate - * @param minZ min z coordinate - * @param maxX max x coordinate - * @param maxZ max z coordinate - * @param name region name - * @param planet region planet name - * @param pvp pvp state - * @param buildable buildable state - * @param municipal municipal state - * @param geography geography state - * @param minDifficulty min difficulty state - * @param maxDifficulty max difficulty state - * @param spawnable spawnable state - * @param mission mission state - * @param visible visible flag - * @param notify notify flag - */ -void RegionMaster::createNewDynamicRegion(float minX, float minZ, - float maxX, float maxZ, const Unicode::String & name, const std::string & planet, - int pvp, int buildable, int municipal, int geography, int minDifficulty, - int maxDifficulty, int spawnable, int mission, bool visible, bool notify) -{ - // no creating duplicate regions - if (getRegionByName(planet, name)) - return; - - // only the universe process may create universe objects - if (!ServerUniverse::getInstance().isAuthoritative()) - { - CreateDynamicRegionRectangleMessage const createMessage(minX, minZ, maxX, maxZ, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify); - GameServer::getInstance().sendToCentralServer(createMessage); - return; - } - - // create a new UniverseObject that will be used to hold the region data - Transform tr; - tr.setPosition_p(Vector::xyz111); - UniverseObject *regionObject = safe_cast(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false)); - - if (!regionObject) - return; - - if (!setDynamicRegionObjectData(*regionObject, name, planet, RG_rectagle, minX, - minZ, maxX, maxZ, pvp, buildable, municipal, geography, minDifficulty, - maxDifficulty, spawnable, mission, visible, notify)) - { - regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); - return; - } - - const Region * region = addDynamicRegion(*regionObject); - if (region) - regionObject->persist(); - else - { - regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION); - regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); - } -} - -//---------------------------------------------------------------------- - -/** - * Creates a new circlular dynamic region. - * - * @param centerX x coordinate of circle center - * @param centerZ z coordinate of circle center - * @param radius circle radius - * @param name region name - * @param planet region planet name - * @param pvp pvp state - * @param buildable buildable state - * @param municipal municipal state - * @param geography geography state - * @param minDifficulty min difficulty state - * @param maxDifficulty max difficulty state - * @param spawnable spawnable state - * @param mission mission state - * @param visible visible flag - * @param notify notify flag - * - * @return the new region, or NULL on error - */ -void RegionMaster::createNewDynamicRegion(float centerX, float centerZ, - float radius, const Unicode::String & name, const std::string & planet, int pvp, - int buildable, int municipal, int geography, int minDifficulty, int maxDifficulty, - int spawnable, int mission, bool visible, bool notify) -{ - // no creating duplicate regions - if (getRegionByName(planet, name)) - return; - - // only the universe process may create universe objects - if (!ServerUniverse::getInstance().isAuthoritative()) - { - CreateDynamicRegionCircleMessage const createMessage(centerX, centerZ, radius, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify); - GameServer::getInstance().sendToCentralServer(createMessage); - return; - } - - // create a new UniverseObject that will be used to hold the region data - Transform tr; - tr.setPosition_p(Vector::xyz111); - UniverseObject *regionObject = safe_cast(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false)); - - if (!regionObject) - return; - - if (!setDynamicRegionObjectData(*regionObject, name, planet, RG_circle, centerX, - centerZ, radius, 0, pvp, buildable, municipal, geography, minDifficulty, - maxDifficulty, spawnable, mission, visible, notify)) - { - regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); - return; - } - - regionObject->addToWorld(); - - const Region * region = addDynamicRegion(*regionObject); - if (region) - regionObject->persist(); - else - { - regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION); - regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); - } -} - -//---------------------------------------------------------------------- - -/** - * Sets the objvars on a universe object to turn it into a dynamic region - * object. - * - * @param object the object - * @param name region name - * @param planet region planet name - * @param geometry region geometry (rect or circle) - * @param minX min x coordinate/center x - * @param minZ min z coordinate/center z - * @param maxX max x coordinate/radius - * @param maxZ max z coordinate/ignored - * @param pvp pvp state - * @param buildable buildable state - * @param municipal municipal state - * @param geography geography state - * @param minDifficulty min difficulty state - * @param maxDifficulty max difficulty state - * @param spawnable spawnable state - * @param mission mission state - * @param visible visible flag - * @param notify notify flag - * - * @return true on success, false if there was an error - */ -bool RegionMaster::setDynamicRegionObjectData(UniverseObject & object, - const Unicode::String & name, const std::string & planet, int geometry, - float minX, float minZ, float maxX, float maxZ, int pvp, int buildable, - int municipal, int geography, int minDifficulty, int maxDifficulty, int spawnable, - int mission, bool visible, bool notify) -{ - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NAME, name); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PLANET, Unicode::narrowToWide(planet)); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOMETRY, geometry); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINX, minX); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINY, minZ); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXX, maxX); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXY, maxZ); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PVP, pvp); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOGRAPHY, geography); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWN, spawnable); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MISSION, mission); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BUILDABLE, buildable); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MUNICIPAL, municipal); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_VISIBLE, static_cast(visible)); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NOTIFY, static_cast(notify)); - return true; -} // RegionMaster::setDynamicRegionObjectData - -//---------------------------------------------------------------------- - -/** - * Adds a dynamic region to the world. - * - * @param source the source of the region - */ -const Region * RegionMaster::addDynamicRegion(const UniverseObject & source) -{ - if (!ms_installed) - { - WARNING(true, ("RegionMaster::addDynamicRegion, not installed")); - return NULL; - } - - DynamicVariableList::NestedList regionObjvars(source.getObjVars(),OBJVAR_DYNAMIC_REGION); - - Unicode::String planet; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no planet data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - Unicode::String name; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no name data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - if (name.empty()) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has empty " - "name data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int geometry = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_GEOMETRY,geometry)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "geometry data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - float minX; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MINX,minX)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "minX data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - float minY; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MINY,minY)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "minY data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - float maxX; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAXX,maxX)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "maxX data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - float maxY; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAXY,maxY)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "maxY data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int pvp=0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PVP,pvp)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "pvp data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int geography=0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_GEOGRAPHY,geography)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "geography data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int minDifficulty = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "min difficulty data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int maxDifficulty = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "max difficulty data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int spawn = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_SPAWN,spawn)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "spawn data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int mission = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MISSION,mission)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "mission data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int buildable = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_BUILDABLE,buildable)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "buildable data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int municipal = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MUNICIPAL,municipal)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "municipal data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int visible = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_VISIBLE,visible)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "visible data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - int notify = 0; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NOTIFY,notify)) - { - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " - "notify data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - - // find the appropriate region data for the planet - // note that dynamic regions cannot define new planets - std::map::iterator result = ms_planetRegions.find( - Unicode::wideToNarrow(planet)); - if (result == ms_planetRegions.end()) - { - WARNING(true, ("RegionMaster::addDynamicRegion object %s gave unknown " - "planet %s for its region", source.getNetworkId().getValueString().c_str(), - Unicode::wideToNarrow(planet).c_str())); - return NULL; - } - RegionData & regionData = (*result).second; - if (regionData.tree == NULL) - { - WARNING_STRICT_FATAL(true, ("RegionMaster::addDynamicRegion planet %s " - "has no tree defined!", Unicode::wideToNarrow(planet).c_str())); - return NULL; - } - - // make sure the region name is unique - if (regionData.nameMap.find(name) != regionData.nameMap.end()) - { - WARNING(true, ("RegionMaster::addDynamicRegion object %s is trying " - "to add duplicate region %s", source.getNetworkId().getValueString().c_str(), - Unicode::wideToNarrow(name).c_str())); - return NULL; - } - - // create a rectangular or circular region and add it to the region tree - Region * region = NULL; - switch (geometry) - { - case RG_rectagle: - { - RegionRectangle * rectangle = new RegionRectangle(minX, minY, maxX, maxY, CachedNetworkId(source)); - if (regionData.tree->addObject(rectangle->getBounds())) - region = rectangle; - else - delete rectangle; - } - break; - case RG_circle: - { - if (pvp == PR_battlefieldPvp || pvp == PR_battlefieldPve) - { - RegionPvp * battlefield = new RegionPvp(minX, minY, maxX, CachedNetworkId(source)); - if (regionData.tree->addObject(battlefield->getBounds())) - region = battlefield; - else - delete battlefield; - } - else - { - RegionCircle * circle = new RegionCircle(minX, minY, maxX, CachedNetworkId(source)); - if (regionData.tree->addObject(circle->getBounds())) - region = circle; - else - delete circle; - } - } - break; - default: - DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has unknown " - "geometry type", source.getNetworkId().getValueString().c_str(), - geometry)); - return NULL; - } - if (region == NULL) - { - WARNING(true, ("RegionMaster::readRegionDataTables could " - "not add region defined by object %s to region tree", - source.getNetworkId().getValueString().c_str())); - return NULL; - } - - // set the rest of the region's data - region->setName(name); - region->setPlanet(Unicode::wideToNarrow(planet)); - region->setPvp(pvp); - region->setGeography(geography); - region->setMinDifficulty(minDifficulty); - region->setMaxDifficulty(maxDifficulty); - region->setSpawn(spawn); - region->setMission(mission); - region->setBuildable(buildable); - region->setMunicipal(municipal); - region->setVisible(visible); - region->setNotify(notify); - ms_dynamicRegions.push_back(region); - regionData.nameMap[name] = region; - - if (region->asRegionPvp()) - region->asRegionPvp()->checkBattlefieldMarker(); - - // if the region is a notify region, force checkNotifyRegions() to be - // called on all character creatures in the region as soon as possible so - // notifications will be sent that the creature has entered the region - if (notify) - { - std::vector regions; - - CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures(); - for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i) - { - CreatureObject *creatureObj = const_cast(*i); - if (creatureObj->isInitialized() && creatureObj->isAuthoritative() && creatureObj->isPlayerControlled() && creatureObj->isInWorld()) - { - regions.clear(); - getRegionsAtPoint(ServerWorld::getSceneId(), creatureObj->getPosition_w().x, creatureObj->getPosition_w().z, regions); - if (std::find(regions.begin(), regions.end(), region) != regions.end()) - creatureObj->forceNotifyRegionsCheck(); - } - } - } - - return region; -} // RegionMaster::addDynamicRegion - -//---------------------------------------------------------------------- - -/** - * Removes a dynamic region from the world. - * - * @param source the source of the region - */ -void RegionMaster::removeDynamicRegion(const UniverseObject & source) -{ - if (!ms_installed) - { - WARNING(true, ("RegionMaster::removeDynamicRegion, not installed")); - return; - } - - DynamicVariableList::NestedList regionObjvars(source.getObjVars(),OBJVAR_DYNAMIC_REGION); - - Unicode::String planet; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet)) - { - DEBUG_WARNING(true, ("RegionMaster::removeDynamicRegion object %s has no " - "planet data", source.getNetworkId().getValueString().c_str())); - return; - } - Unicode::String name; - if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name)) - { - DEBUG_WARNING(true, ("RegionMaster::removeDynamicRegion object %s has no " - "name data", source.getNetworkId().getValueString().c_str())); - return; - } - - // find the appropriate region data for the planet - // note that dynamic regions cannot define new planets - std::map::iterator dataResult = ms_planetRegions.find( - Unicode::wideToNarrow(planet)); - if (dataResult == ms_planetRegions.end()) - { - WARNING(true, ("RegionMaster::removeDynamicRegion object %s gave unknown " - "planet %s for its region", source.getNetworkId().getValueString().c_str(), - Unicode::wideToNarrow(planet).c_str())); - return; - } - RegionData & regionData = (*dataResult).second; - if (regionData.tree == NULL) - { - WARNING_STRICT_FATAL(true, ("RegionMaster::addDynamicRegion planet %s " - "has no tree defined!", Unicode::wideToNarrow(planet).c_str())); - return; - } - - // find the region by its name - RegionsMappedByName::iterator regionResult = regionData.nameMap.find(name); - if (regionResult == regionData.nameMap.end()) - { - WARNING(true, ("RegionMaster::removeDynamicRegion object %s gave unknown " - "name %s for its region", source.getNetworkId().getValueString().c_str(), - Unicode::wideToNarrow(name).c_str())); - return; - } - const Region * region = (*regionResult).second; - if (region && !region->isDynamic()) - { - WARNING(true, ("RegionMaster::removeDynamicRegion object %s tried to remove static region %s", - source.getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(name).c_str())); - return; - } - - // if the region is a notify region, force checkNotifyRegions() to be - // called on all character creatures in the region as soon as possible so - // notifications will be sent that the creature has left the region - if (region->getNotify()) - { - std::vector regions; - - CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures(); - for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i) - { - CreatureObject *creatureObj = const_cast(*i); - if (creatureObj->isInitialized() && creatureObj->isAuthoritative() && creatureObj->isPlayerControlled() && creatureObj->isInWorld()) - { - regions.clear(); - getRegionsAtPoint(ServerWorld::getSceneId(), creatureObj->getPosition_w().x, creatureObj->getPosition_w().z, regions); - if (std::find(regions.begin(), regions.end(), region) != regions.end()) - creatureObj->forceNotifyRegionsCheck(); - } - } - } - - regionData.nameMap.erase(regionResult); - - // remove the region from the tree - if (!regionData.tree->removeObject(region->getBounds())) - { - WARNING(true, ("RegionMaster::removeDynamicRegion error removing dynamic " - "region %s from region tree, continuing anyway", - source.getNetworkId().getValueString().c_str())); - } - - // remove the region from the dynamic region list - std::vector::iterator removeResult = std::find( - ms_dynamicRegions.begin(), ms_dynamicRegions.end(), region); - if (removeResult != ms_dynamicRegions.end()) - { - ms_dynamicRegions.erase(removeResult); - } - else - { - WARNING(true, ("RegionMaster::removeDynamicRegion dynamic region %s was " - "not in the dynamic region list, continuing anyway", - source.getNetworkId().getValueString().c_str())); - } - - // remove the region - delete region; -} // RegionMaster::removeDynamicRegion - -//---------------------------------------------------------------------- - -/** - * Returns the dynamic region associated with a UniverseObject. - * - * @param source the object to get the region from - */ -const Region * RegionMaster::getDynamicRegionFromObject(const UniverseObject & source) -{ - if (!ms_installed) - { - WARNING(true, ("RegionMaster::getDynamicRegionFromObject, not installed")); - return NULL; - } - - DynamicVariableList::NestedList regionObjVars(source.getObjVars(),OBJVAR_DYNAMIC_REGION); - - Unicode::String planet; - if (!regionObjVars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet)) - { - DEBUG_WARNING(true, ("RegionMaster::getDynamicRegionFromObject object %s has no " - "planet data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - Unicode::String name; - if (!regionObjVars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name)) - { - DEBUG_WARNING(true, ("RegionMaster::getDynamicRegionFromObject object %s has no " - "name data", source.getNetworkId().getValueString().c_str())); - return NULL; - } - - return getRegionByName(Unicode::wideToNarrow(planet), name); -} // RegionMaster::getDynamicRegionFromObject - -//---------------------------------------------------------------------- - -/** - * Returns the region with the given name. - */ -Region * RegionMaster::getRegionByName(const std::string & planetName, const Unicode::String & regionName) -{ - if (!ms_installed) - { - WARNING(true, ("RegionMaster::getRegionByName, not installed")); - return NULL; - } - - const RegionData & regionData = ms_planetRegions[planetName]; - if (regionData.tree != NULL) - { - RegionsMappedByName::const_iterator result = regionData.nameMap.find(regionName); - if (result != regionData.nameMap.end()) - return (*result).second; - } - return NULL; -} // RegionMaster::getRegionByName - -//---------------------------------------------------------------------- - -/** - * Finds the region with the smallest area at a given point. - */ -const Region * RegionMaster::getSmallestRegionAtPoint(const std::string & planet, float x, float z) -{ - if (!ms_installed) - { - WARNING(true, ("RegionMaster::getSmallestRegionAtPoint, not installed")); - return NULL; - } - - std::vector regions; - getRegionsAtPoint(planet, x, z, regions); - - float area = 0; - const Region * region = NULL; - for (std::vector::const_iterator iter = regions.begin(); - iter != regions.end(); ++iter) - { - if (region == NULL) - { - region = *iter; - area = region->getArea(); - } - else - { - float testArea = (*iter)->getArea(); - if (testArea < area) - { - area = testArea; - region = *iter; - } - } - } - return region; -} // RegionMaster::getSmallestRegionAtPoint - -//---------------------------------------------------------------------- - -/** - * Same as getSmallestRegionAtPoint, but the region must be marked as visible. - */ -const Region * RegionMaster::getSmallestVisibleRegionAtPoint(const std::string & planet, float x, float z) -{ - if (!ms_installed) - { - WARNING(true, ("RegionMaster::getSmallestRegionAtPoint, not installed")); - return NULL; - } - - std::vector regions; - getRegionsAtPoint(planet, x, z, regions); - - float area = 0; - const Region * region = NULL; - for (std::vector::const_iterator iter = regions.begin(); iter != regions.end(); ++iter) - { - if ((*iter)->isVisible()) - { - if (region == NULL) - { - region = *iter; - area = region->getArea(); - } - else - { - float testArea = (*iter)->getArea(); - if (testArea < area) - { - area = testArea; - region = *iter; - } - } - } - } - return region; -} // RegionMaster::getSmallestVisibleRegionAtPoint - -//---------------------------------------------------------------------- - -/** - * Finds the regions at a given point. - * - * @param planet planet name of region to get - * @param x x coordinate of point - * @param z z coordinate of point - * @param regions vector to be filled in with list of regions at the point - */ -void RegionMaster::getRegionsAtPoint(const std::string & planet, float x, float z, - std::vector & regions) -{ - regions.clear(); - - if (!ms_installed) - { - WARNING(true, ("RegionMaster::getRegionsAtPoint, not installed")); - return; - } - - const RegionData & regionData = ms_planetRegions[planet]; - if (regionData.tree != NULL) - { - std::vector objects; - regionData.tree->getObjectsAt(x, z, objects); - for (std::vector::const_iterator iter = objects.begin(); - iter != objects.end(); ++iter) - { - regions.push_back(static_cast((*iter)->getData())); - } - } -} // RegionMaster::getRegionsAtPoint - -//---------------------------------------------------------------------- - -/** - * Returns all the regions for a given planet. - */ -void RegionMaster::getRegionsForPlanet(const std::string & planetName, - std::vector & regions) -{ - regions.clear(); - - if (!ms_installed) - { - WARNING(true, ("RegionMaster::getRegionsForPlanet, not installed")); - return; - } - - const RegionData & regionData = ms_planetRegions[planetName]; - if (regionData.tree != NULL) - { - std::vector objects; - regionData.tree->getAllObjects(objects); - for (std::vector::const_iterator iter = objects.begin(); - iter != objects.end(); ++iter) - { - regions.push_back(static_cast((*iter)->getData())); - } - } -} // RegionMaster::getRegionsForPlanet - -//---------------------------------------------------------------------- - -void RegionMaster::registerBattlefieldMarker(const std::string ®ionName, BattlefieldMarkerObject *marker) -{ - Region *region = getRegionByName(ServerWorld::getSceneId(), Unicode::narrowToWide(regionName)); - if (region) - { - RegionPvp *regionPvp = region->asRegionPvp(); - if (regionPvp) - regionPvp->setBattlefieldMarker(marker); - } -} - -EnvironmentInfo RegionMasterNamspace::convertFromStringToEnvironmentInfo(std::string const & stringList) -{ - if(stringList.empty()) - return 0; - - if(s_conversionMap.empty()) - { - // Fill the Datatable with values from our environment flags datatable. - DataTable * const environmentFlagTable = DataTableManager::getTable(s_environmentFlagsDataTable, true); - for(int i = 0; i < environmentFlagTable->getNumRows(); ++i) - { - s_conversionMap.insert( std::pair(environmentFlagTable->getStringValue(0,i), static_cast(1 << i) ) ); - } - } - - std::string parserList = stringList; - const char delimiter = ','; - EnvironmentInfo outputValue = 0; - - // Parse the input string using , as the delimiter. - std::vector parsedStringVector; - std::string::size_type loc = parserList.find(delimiter); - - if (std::string::npos != loc) // We found a comma - { - std::vector locations; - locations.push_back(loc); - while (std::string::npos != (loc = parserList.find(delimiter, loc+1))) - { - locations.push_back(loc); - } - - for(std::vector::size_type i = 0; i < locations.size(); ++i) - { - std::string subString; - - if(i == 0) - subString = parserList.substr(0, locations[i]); - else - subString = parserList.substr(locations[i - 1], locations[i]); - - parsedStringVector.push_back(subString); - } - - } - else - parsedStringVector.push_back(parserList); // No comma, must be one item in the list. - - // Now we just search our map for the strings we just read in. If we find it, we add that flag to our output value. - for(std::vector::size_type i = 0; i < parsedStringVector.size(); ++i) - { - std::map::iterator searchIter = s_conversionMap.find(parsedStringVector[i]); - - if( searchIter != s_conversionMap.end()) - { - outputValue |= searchIter->second; - } - } - - - return outputValue; -} - -NetworkId RegionMaster::createNewDynamicRegionWithSpawn(float centerX, float centerY, float centerZ, - float radius, const Unicode::String & name, const std::string & planet, int pvp, - int buildable, int municipal, int geography, int minDifficulty, int maxDifficulty, - int spawnable, int mission, bool visible, bool notify, std::string spawnDatatable, int duration) -{ - // no creating duplicate regions - if (getRegionByName(planet, name)) - return NetworkId(); - - // only the universe process may create universe objects - if (!ServerUniverse::getInstance().isAuthoritative()) - { - CreateDynamicSpawnRegionCircleMessage const createMessage(centerX, centerY, centerZ, radius, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify, spawnDatatable, duration); - GameServer::getInstance().sendToCentralServer(createMessage); - return NetworkId(); - } - - // create a new UniverseObject that will be used to hold the region data - Transform tr; - tr.setPosition_p(Vector::xyz111); - UniverseObject *regionObject = safe_cast(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false)); - - if (!regionObject || !regionObject->getScriptObject()) - return NetworkId(); - - if (!setDynamicSpawnRegionObjectData(*regionObject, name, planet, RG_circle, centerX, - centerZ, radius, 0, pvp, buildable, municipal, geography, minDifficulty, - maxDifficulty, spawnable, mission, visible, notify, spawnDatatable, duration)) - { - regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); - return NetworkId(); - } - - regionObject->addToWorld(); - - const Region * region = addDynamicRegion(*regionObject); - if (region) - regionObject->persist(); - else - { - regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION); - regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); - } - - // Everything went okay. Add dynamic spawn script and other objvars. - regionObject->getScriptObject()->attachScript(s_dynamicMasterScript, true); - - if(!spawnDatatable.empty()) - { - // Creature spawning has to be done in script. - ScriptParams params; - params.addParam(regionObject->getNetworkId()); - params.addParam(spawnDatatable.c_str()); - params.addParam(centerX); - params.addParam(centerY); - params.addParam(centerZ); - - IGNORE_RETURN(regionObject->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DYNAMIC_SPAWN_REGION_CREATED, params)); - } - - return regionObject->getNetworkId(); -} - -bool RegionMaster::setDynamicSpawnRegionObjectData(UniverseObject & object, - const Unicode::String & name, const std::string & planet, int geometry, - float minX, float minZ, float maxX, float maxZ, int pvp, int buildable, - int municipal, int geography, int minDifficulty, int maxDifficulty, int spawnable, - int mission, bool visible, bool notify, std::string spawntable, int duration) -{ - time_t const birthEpoch = ::time(NULL); - time_t const endEpoch = birthEpoch + (duration * 60); // Duration is in minutes. - - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NAME, name); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PLANET, Unicode::narrowToWide(planet)); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOMETRY, geometry); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINX, minX); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINY, minZ); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXX, maxX); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXY, maxZ); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PVP, pvp); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOGRAPHY, geography); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWN, spawnable); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MISSION, mission); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BUILDABLE, buildable); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MUNICIPAL, municipal); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_VISIBLE, static_cast(visible)); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NOTIFY, static_cast(notify)); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWNTABLE, spawntable); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BIRTH, static_cast(birthEpoch)); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_DURATION, duration); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXDURATION, duration + (duration/3)); // Max duration is an extra 30% of the time. - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_READABLE_BIRTH, CalendarTime::convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(birthEpoch)); - object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_READABLE_DEATH, CalendarTime::convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(endEpoch)); - return true; -} // RegionMaster::setDynamicRegionObjectData - -//---------------------------------------------------------------------- - +//======================================================================== +// +// RegionMaster.cpp +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/RegionMaster.h" + +#include "serverGame/ConfigServerGame.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/PlanetObject.h" +#include "serverGame/Region.h" +#include "serverGame/RegionPvp.h" +#include "serverGame/ServerUniverse.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/UniverseObject.h" +#include "serverNetworkMessages/CreateDynamicRegionCircleMessage.h" +#include "serverNetworkMessages/CreateDynamicRegionRectangleMessage.h" +#include "serverNetworkMessages/CreateDynamicSpawnRegionCircleMessage.h" +#include "sharedFoundation/CalendarTime.h" +#include "sharedFoundation/DynamicVariableList.h" +#include "sharedFoundation/FloatMath.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedMath/MxCifQuadTree.h" +#include "sharedMath/MxCifQuadTreeBounds.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptParameters.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" +#include +#include +#include + + +// objvars for dynamic regions +const static std::string OBJVAR_DYNAMIC_REGION("dynamic_region"); +const static std::string OBJVAR_DYNAMIC_REGION_PLANET("planet"); +const static std::string OBJVAR_DYNAMIC_REGION_NAME("name"); +const static std::string OBJVAR_DYNAMIC_REGION_GEOMETRY("geometry"); +const static std::string OBJVAR_DYNAMIC_REGION_MINX("minX"); +const static std::string OBJVAR_DYNAMIC_REGION_MINY("minY"); +const static std::string OBJVAR_DYNAMIC_REGION_MAXX("maxX"); +const static std::string OBJVAR_DYNAMIC_REGION_MAXY("maxY"); +const static std::string OBJVAR_DYNAMIC_REGION_PVP("pvp"); +const static std::string OBJVAR_DYNAMIC_REGION_GEOGRAPHY("geography"); +const static std::string OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY("minDifficulty"); +const static std::string OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY("maxDifficulty"); +const static std::string OBJVAR_DYNAMIC_REGION_SPAWN("spawn"); +const static std::string OBJVAR_DYNAMIC_REGION_MISSION("mission"); +const static std::string OBJVAR_DYNAMIC_REGION_BUILDABLE("buildable"); +const static std::string OBJVAR_DYNAMIC_REGION_MUNICIPAL("municipal"); +const static std::string OBJVAR_DYNAMIC_REGION_VISIBLE("visible"); +const static std::string OBJVAR_DYNAMIC_REGION_BATTLEFIELD_MARKER("_battlefield"); +const static std::string OBJVAR_DYNAMIC_REGION_NOTIFY("notify"); +const static std::string OBJVAR_DYNAMIC_REGION_SPAWNTABLE("spawntable"); +const static std::string OBJVAR_DYNAMIC_REGION_DURATION("duration"); +const static std::string OBJVAR_DYNAMIC_REGION_MAXDURATION("maxDuration"); +const static std::string OBJVAR_DYNAMIC_REGION_BIRTH("birth"); +const static std::string OBJVAR_DYNAMIC_REGION_READABLE_BIRTH("calendarBirth"); +const static std::string OBJVAR_DYNAMIC_REGION_READABLE_DEATH("calenderDeath"); +const static std::string OBJVAR_DYNAMIC_REGION_CREATURE_LIST("creatureList"); + +// template used to make dynamic regions +const static std::string DYNAMIC_REGION_TEMPLATE_NAME("object/universe/dynamic_region.iff"); + + + +enum RegionGeometry +{ + RG_rectagle, + RG_circle +}; + +//---------------------------------------------------------------------- + +struct RegionMaster::RegionData +{ + MxCifQuadTree * tree; + RegionsMappedByName nameMap; + + RegionData() : tree(NULL), nameMap() {} +}; + +namespace RegionMasterNamspace +{ + EnvironmentInfo convertFromStringToEnvironmentInfo(std::string const & stringList); + + std::string s_environmentFlagsDataTable = "datatables/region/region_environment_flags.iff"; + std::map s_conversionMap; + + std::string s_dynamicMasterScript = "systems.regions.dynamic_region_master"; +} + +using namespace RegionMasterNamspace; +//======================================================================== +// static member vars + +std::map RegionMaster::ms_planetRegions; +std::vector RegionMaster::ms_staticRegions; +std::vector RegionMaster::ms_dynamicRegions; +bool RegionMaster::ms_installed = false; + +//======================================================================== + +/** + * Called on program startup. Creates the RegionMaster. + */ +void RegionMaster::install() +{ + if (!ms_installed) + { + ms_installed = true; + readRegionDataTables(); + ExitChain::add(exit, "RegionMaster"); + } +} + +//----------------------------------------------------------------------- + +/** + * Called on program shutdown. Deletes the RegionMaster. + */ +void RegionMaster::exit() +{ + if (ms_installed) + { + { + for (std::map::iterator i1 = ms_planetRegions.begin(); + i1 != ms_planetRegions.end(); ++i1) + { + delete (*i1).second.tree; + (*i1).second.tree = NULL; + } + ms_planetRegions.clear(); + } + + { + for (std::vector::iterator i2 = ms_staticRegions.begin(); + i2 != ms_staticRegions.end(); ++i2) + { + delete const_cast(*i2); + *i2 = NULL; + } + ms_staticRegions.clear(); + } + + { + for (std::vector::iterator i2 = ms_dynamicRegions.begin(); + i2 != ms_dynamicRegions.end(); ++i2) + { + delete const_cast(*i2); + *i2 = NULL; + } + ms_dynamicRegions.clear(); + } + + ms_installed = false; + } +} + +//----------------------------------------------------------------------- + +/** + * Reads the static region info from the planets' region datatables. + */ +void RegionMaster::readRegionDataTables() +{ + if (!ms_installed) + { + WARNING(true, ("RegionMaster::readRegionDataTables, not installed")); + return; + } + + const char * regionFilesName = ConfigServerGame::getRegionFilesName(); + + DataTable * const regionFilesTable = DataTableManager::getTable(regionFilesName, true); + if (regionFilesTable == NULL) + { + WARNING(true, ("RegionMaster::readRegionDataTables could not open file %s, static regions will not be read!", regionFilesName)); + return; + } + + { + const int numRegionFiles = regionFilesTable->getNumRows(); + for (int i = 0; i < numRegionFiles; ++i) + { + // get the region table from the filename table + const std::string & planetName = regionFilesTable->getStringValue(0, i); + const std::string & regionFileName = regionFilesTable->getStringValue(1, i); + float regionMinX = regionFilesTable->getFloatValue (2, i); + float regionMinY = regionFilesTable->getFloatValue (3, i); + float regionMaxX = regionFilesTable->getFloatValue (4, i); + float regionMaxY = regionFilesTable->getFloatValue (5, i); + + DataTable * const regionTable = DataTableManager::getTable(regionFileName, true); + if (regionTable == NULL) + { + WARNING(true, ("RegionMaster::readRegionDataTables could not open region file %s.", regionFileName.c_str())); + continue; + } + + RegionData & regionData = ms_planetRegions[planetName]; + if (regionData.tree == NULL) + { + regionData.tree = new MxCifQuadTree(regionMinX, regionMinY, regionMaxX, regionMaxY, ConfigServerGame::getRegionTreeDepth()); + } + + int numRegions = regionTable->getNumRows(); + for (int j = 0; j < numRegions; ++j) + { + // read the region data from the table + const Unicode::String name(Unicode::narrowToWide(regionTable->getStringValue( 0, j))); + int geometry = regionTable->getIntValue ( 1, j); + float minX = regionTable->getFloatValue ( 2, j); + float minY = regionTable->getFloatValue ( 3, j); + float maxX = regionTable->getFloatValue ( 4, j); + float maxY = regionTable->getFloatValue ( 5, j); + int pvp = regionTable->getIntValue ( 6, j); + int geography = regionTable->getIntValue ( 7, j); + int minDifficulty = regionTable->getIntValue ( 8, j); + int maxDifficulty = regionTable->getIntValue ( 9, j); + int spawn = regionTable->getIntValue (10, j); + int mission = regionTable->getIntValue (11, j); + int buildable = regionTable->getIntValue (12, j); + int municipal = regionTable->getIntValue (13, j); + int visible = regionTable->getIntValue (14, j); + int notify = regionTable->getIntValue (15, j); + EnvironmentInfo envFlags = convertFromStringToEnvironmentInfo( regionTable->getStringValue(16, j) ); + + // make sure the region has a unique name + if (name.empty()) + { + WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s has no region name", + j, regionFileName.c_str())); + continue; + } + else if (regionData.nameMap.find(name) != regionData.nameMap.end()) + { + WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s is trying to add duplicate region %s", + j, regionFileName.c_str(), Unicode::wideToNarrow(name).c_str())); + continue; + } + + // create a rectangular or circular region and add it to the region tree + Region * region = NULL; + switch (geometry) + { + case RG_rectagle: + { + RegionRectangle * const rectangle = new RegionRectangle(minX, minY, maxX, maxY); + if (regionData.tree->addObject(rectangle->getBounds())) + region = rectangle; + else + delete rectangle; + } + break; + case RG_circle: + { + if (pvp == PR_battlefieldPvp || pvp == PR_battlefieldPve) + { + RegionPvp * battlefield = new RegionPvp(minX, minY, maxX); + if (regionData.tree->addObject(battlefield->getBounds())) + region = battlefield; + else + delete battlefield; + } + else + { + RegionCircle * circle = new RegionCircle(minX, minY, maxX); + if (regionData.tree->addObject(circle->getBounds())) + region = circle; + else + delete circle; + } + } + break; + default: + WARNING(true, ("RegionMaster::readRegionDataTables row %d of table %s has invalid geometry parameter %d", + j, regionFileName.c_str(), geometry)); + continue; + } + // set the rest of the region's data + if (region != NULL) + { + region->setName(name); + region->setPlanet(planetName); + region->setPvp(pvp); + region->setGeography(geography); + region->setMinDifficulty(minDifficulty); + region->setMaxDifficulty(maxDifficulty); + region->setSpawn(spawn); + region->setMission(mission); + region->setBuildable(buildable); + region->setMunicipal(municipal); + region->setVisible(visible); + region->setNotify(notify); + region->setEnvironmentFlags(envFlags); + ms_staticRegions.push_back(region); + regionData.nameMap[name] = region; + } + else + { + FATAL(true, ("RegionMaster::readRegionDataTables could not add row %d (%s) of table %s to region tree", + j, Unicode::wideToNarrow(name).c_str(), regionFileName.c_str())); + } + } + DataTableManager::close(regionFileName); + } + } + DataTableManager::close(regionFilesName); +} // RegionMaster::readRegionDataTables + +//----------------------------------------------------------------------- + +/** + * Creates a new rectangular dynamic region. + * + * @param minX min x coordinate + * @param minZ min z coordinate + * @param maxX max x coordinate + * @param maxZ max z coordinate + * @param name region name + * @param planet region planet name + * @param pvp pvp state + * @param buildable buildable state + * @param municipal municipal state + * @param geography geography state + * @param minDifficulty min difficulty state + * @param maxDifficulty max difficulty state + * @param spawnable spawnable state + * @param mission mission state + * @param visible visible flag + * @param notify notify flag + */ +void RegionMaster::createNewDynamicRegion(float minX, float minZ, + float maxX, float maxZ, const Unicode::String & name, const std::string & planet, + int pvp, int buildable, int municipal, int geography, int minDifficulty, + int maxDifficulty, int spawnable, int mission, bool visible, bool notify) +{ + // no creating duplicate regions + if (getRegionByName(planet, name)) + return; + + // only the universe process may create universe objects + if (!ServerUniverse::getInstance().isAuthoritative()) + { + CreateDynamicRegionRectangleMessage const createMessage(minX, minZ, maxX, maxZ, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify); + GameServer::getInstance().sendToCentralServer(createMessage); + return; + } + + // create a new UniverseObject that will be used to hold the region data + Transform tr; + tr.setPosition_p(Vector::xyz111); + UniverseObject *regionObject = safe_cast(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false)); + + if (!regionObject) + return; + + if (!setDynamicRegionObjectData(*regionObject, name, planet, RG_rectagle, minX, + minZ, maxX, maxZ, pvp, buildable, municipal, geography, minDifficulty, + maxDifficulty, spawnable, mission, visible, notify)) + { + regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); + return; + } + + const Region * region = addDynamicRegion(*regionObject); + if (region) + regionObject->persist(); + else + { + regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION); + regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); + } +} + +//---------------------------------------------------------------------- + +/** + * Creates a new circlular dynamic region. + * + * @param centerX x coordinate of circle center + * @param centerZ z coordinate of circle center + * @param radius circle radius + * @param name region name + * @param planet region planet name + * @param pvp pvp state + * @param buildable buildable state + * @param municipal municipal state + * @param geography geography state + * @param minDifficulty min difficulty state + * @param maxDifficulty max difficulty state + * @param spawnable spawnable state + * @param mission mission state + * @param visible visible flag + * @param notify notify flag + * + * @return the new region, or NULL on error + */ +void RegionMaster::createNewDynamicRegion(float centerX, float centerZ, + float radius, const Unicode::String & name, const std::string & planet, int pvp, + int buildable, int municipal, int geography, int minDifficulty, int maxDifficulty, + int spawnable, int mission, bool visible, bool notify) +{ + // no creating duplicate regions + if (getRegionByName(planet, name)) + return; + + // only the universe process may create universe objects + if (!ServerUniverse::getInstance().isAuthoritative()) + { + CreateDynamicRegionCircleMessage const createMessage(centerX, centerZ, radius, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify); + GameServer::getInstance().sendToCentralServer(createMessage); + return; + } + + // create a new UniverseObject that will be used to hold the region data + Transform tr; + tr.setPosition_p(Vector::xyz111); + UniverseObject *regionObject = safe_cast(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false)); + + if (!regionObject) + return; + + if (!setDynamicRegionObjectData(*regionObject, name, planet, RG_circle, centerX, + centerZ, radius, 0, pvp, buildable, municipal, geography, minDifficulty, + maxDifficulty, spawnable, mission, visible, notify)) + { + regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); + return; + } + + regionObject->addToWorld(); + + const Region * region = addDynamicRegion(*regionObject); + if (region) + regionObject->persist(); + else + { + regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION); + regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); + } +} + +//---------------------------------------------------------------------- + +/** + * Sets the objvars on a universe object to turn it into a dynamic region + * object. + * + * @param object the object + * @param name region name + * @param planet region planet name + * @param geometry region geometry (rect or circle) + * @param minX min x coordinate/center x + * @param minZ min z coordinate/center z + * @param maxX max x coordinate/radius + * @param maxZ max z coordinate/ignored + * @param pvp pvp state + * @param buildable buildable state + * @param municipal municipal state + * @param geography geography state + * @param minDifficulty min difficulty state + * @param maxDifficulty max difficulty state + * @param spawnable spawnable state + * @param mission mission state + * @param visible visible flag + * @param notify notify flag + * + * @return true on success, false if there was an error + */ +bool RegionMaster::setDynamicRegionObjectData(UniverseObject & object, + const Unicode::String & name, const std::string & planet, int geometry, + float minX, float minZ, float maxX, float maxZ, int pvp, int buildable, + int municipal, int geography, int minDifficulty, int maxDifficulty, int spawnable, + int mission, bool visible, bool notify) +{ + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NAME, name); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PLANET, Unicode::narrowToWide(planet)); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOMETRY, geometry); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINX, minX); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINY, minZ); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXX, maxX); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXY, maxZ); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PVP, pvp); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOGRAPHY, geography); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWN, spawnable); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MISSION, mission); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BUILDABLE, buildable); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MUNICIPAL, municipal); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_VISIBLE, static_cast(visible)); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NOTIFY, static_cast(notify)); + return true; +} // RegionMaster::setDynamicRegionObjectData + +//---------------------------------------------------------------------- + +/** + * Adds a dynamic region to the world. + * + * @param source the source of the region + */ +const Region * RegionMaster::addDynamicRegion(const UniverseObject & source) +{ + if (!ms_installed) + { + WARNING(true, ("RegionMaster::addDynamicRegion, not installed")); + return NULL; + } + + DynamicVariableList::NestedList regionObjvars(source.getObjVars(),OBJVAR_DYNAMIC_REGION); + + Unicode::String planet; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no planet data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + Unicode::String name; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no name data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + if (name.empty()) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has empty " + "name data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int geometry = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_GEOMETRY,geometry)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "geometry data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + float minX; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MINX,minX)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "minX data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + float minY; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MINY,minY)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "minY data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + float maxX; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAXX,maxX)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "maxX data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + float maxY; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAXY,maxY)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "maxY data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int pvp=0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PVP,pvp)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "pvp data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int geography=0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_GEOGRAPHY,geography)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "geography data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int minDifficulty = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "min difficulty data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int maxDifficulty = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "max difficulty data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int spawn = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_SPAWN,spawn)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "spawn data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int mission = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MISSION,mission)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "mission data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int buildable = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_BUILDABLE,buildable)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "buildable data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int municipal = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_MUNICIPAL,municipal)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "municipal data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int visible = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_VISIBLE,visible)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "visible data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + int notify = 0; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NOTIFY,notify)) + { + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has no " + "notify data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + + // find the appropriate region data for the planet + // note that dynamic regions cannot define new planets + std::map::iterator result = ms_planetRegions.find( + Unicode::wideToNarrow(planet)); + if (result == ms_planetRegions.end()) + { + WARNING(true, ("RegionMaster::addDynamicRegion object %s gave unknown " + "planet %s for its region", source.getNetworkId().getValueString().c_str(), + Unicode::wideToNarrow(planet).c_str())); + return NULL; + } + RegionData & regionData = (*result).second; + if (regionData.tree == NULL) + { + WARNING_STRICT_FATAL(true, ("RegionMaster::addDynamicRegion planet %s " + "has no tree defined!", Unicode::wideToNarrow(planet).c_str())); + return NULL; + } + + // make sure the region name is unique + if (regionData.nameMap.find(name) != regionData.nameMap.end()) + { + WARNING(true, ("RegionMaster::addDynamicRegion object %s is trying " + "to add duplicate region %s", source.getNetworkId().getValueString().c_str(), + Unicode::wideToNarrow(name).c_str())); + return NULL; + } + + // create a rectangular or circular region and add it to the region tree + Region * region = NULL; + switch (geometry) + { + case RG_rectagle: + { + RegionRectangle * rectangle = new RegionRectangle(minX, minY, maxX, maxY, CachedNetworkId(source)); + if (regionData.tree->addObject(rectangle->getBounds())) + region = rectangle; + else + delete rectangle; + } + break; + case RG_circle: + { + if (pvp == PR_battlefieldPvp || pvp == PR_battlefieldPve) + { + RegionPvp * battlefield = new RegionPvp(minX, minY, maxX, CachedNetworkId(source)); + if (regionData.tree->addObject(battlefield->getBounds())) + region = battlefield; + else + delete battlefield; + } + else + { + RegionCircle * circle = new RegionCircle(minX, minY, maxX, CachedNetworkId(source)); + if (regionData.tree->addObject(circle->getBounds())) + region = circle; + else + delete circle; + } + } + break; + default: + DEBUG_WARNING(true, ("RegionMaster::addDynamicRegion object %s has unknown " + "geometry type", source.getNetworkId().getValueString().c_str(), + geometry)); + return NULL; + } + if (region == NULL) + { + WARNING(true, ("RegionMaster::readRegionDataTables could " + "not add region defined by object %s to region tree", + source.getNetworkId().getValueString().c_str())); + return NULL; + } + + // set the rest of the region's data + region->setName(name); + region->setPlanet(Unicode::wideToNarrow(planet)); + region->setPvp(pvp); + region->setGeography(geography); + region->setMinDifficulty(minDifficulty); + region->setMaxDifficulty(maxDifficulty); + region->setSpawn(spawn); + region->setMission(mission); + region->setBuildable(buildable); + region->setMunicipal(municipal); + region->setVisible(visible); + region->setNotify(notify); + ms_dynamicRegions.push_back(region); + regionData.nameMap[name] = region; + + if (region->asRegionPvp()) + region->asRegionPvp()->checkBattlefieldMarker(); + + // if the region is a notify region, force checkNotifyRegions() to be + // called on all character creatures in the region as soon as possible so + // notifications will be sent that the creature has entered the region + if (notify) + { + std::vector regions; + + CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures(); + for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i) + { + CreatureObject *creatureObj = const_cast(*i); + if (creatureObj->isInitialized() && creatureObj->isAuthoritative() && creatureObj->isPlayerControlled() && creatureObj->isInWorld()) + { + regions.clear(); + getRegionsAtPoint(ServerWorld::getSceneId(), creatureObj->getPosition_w().x, creatureObj->getPosition_w().z, regions); + if (std::find(regions.begin(), regions.end(), region) != regions.end()) + creatureObj->forceNotifyRegionsCheck(); + } + } + } + + return region; +} // RegionMaster::addDynamicRegion + +//---------------------------------------------------------------------- + +/** + * Removes a dynamic region from the world. + * + * @param source the source of the region + */ +void RegionMaster::removeDynamicRegion(const UniverseObject & source) +{ + if (!ms_installed) + { + WARNING(true, ("RegionMaster::removeDynamicRegion, not installed")); + return; + } + + DynamicVariableList::NestedList regionObjvars(source.getObjVars(),OBJVAR_DYNAMIC_REGION); + + Unicode::String planet; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet)) + { + DEBUG_WARNING(true, ("RegionMaster::removeDynamicRegion object %s has no " + "planet data", source.getNetworkId().getValueString().c_str())); + return; + } + Unicode::String name; + if (!regionObjvars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name)) + { + DEBUG_WARNING(true, ("RegionMaster::removeDynamicRegion object %s has no " + "name data", source.getNetworkId().getValueString().c_str())); + return; + } + + // find the appropriate region data for the planet + // note that dynamic regions cannot define new planets + std::map::iterator dataResult = ms_planetRegions.find( + Unicode::wideToNarrow(planet)); + if (dataResult == ms_planetRegions.end()) + { + WARNING(true, ("RegionMaster::removeDynamicRegion object %s gave unknown " + "planet %s for its region", source.getNetworkId().getValueString().c_str(), + Unicode::wideToNarrow(planet).c_str())); + return; + } + RegionData & regionData = (*dataResult).second; + if (regionData.tree == NULL) + { + WARNING_STRICT_FATAL(true, ("RegionMaster::addDynamicRegion planet %s " + "has no tree defined!", Unicode::wideToNarrow(planet).c_str())); + return; + } + + // find the region by its name + RegionsMappedByName::iterator regionResult = regionData.nameMap.find(name); + if (regionResult == regionData.nameMap.end()) + { + WARNING(true, ("RegionMaster::removeDynamicRegion object %s gave unknown " + "name %s for its region", source.getNetworkId().getValueString().c_str(), + Unicode::wideToNarrow(name).c_str())); + return; + } + const Region * region = (*regionResult).second; + if (region && !region->isDynamic()) + { + WARNING(true, ("RegionMaster::removeDynamicRegion object %s tried to remove static region %s", + source.getNetworkId().getValueString().c_str(), Unicode::wideToNarrow(name).c_str())); + return; + } + + // if the region is a notify region, force checkNotifyRegions() to be + // called on all character creatures in the region as soon as possible so + // notifications will be sent that the creature has left the region + if (region->getNotify()) + { + std::vector regions; + + CreatureObject::AllCreaturesSet const &creatureList = CreatureObject::getAllCreatures(); + for (CreatureObject::AllCreaturesSet::const_iterator i = creatureList.begin(); i != creatureList.end(); ++i) + { + CreatureObject *creatureObj = const_cast(*i); + if (creatureObj->isInitialized() && creatureObj->isAuthoritative() && creatureObj->isPlayerControlled() && creatureObj->isInWorld()) + { + regions.clear(); + getRegionsAtPoint(ServerWorld::getSceneId(), creatureObj->getPosition_w().x, creatureObj->getPosition_w().z, regions); + if (std::find(regions.begin(), regions.end(), region) != regions.end()) + creatureObj->forceNotifyRegionsCheck(); + } + } + } + + regionData.nameMap.erase(regionResult); + + // remove the region from the tree + if (!regionData.tree->removeObject(region->getBounds())) + { + WARNING(true, ("RegionMaster::removeDynamicRegion error removing dynamic " + "region %s from region tree, continuing anyway", + source.getNetworkId().getValueString().c_str())); + } + + // remove the region from the dynamic region list + std::vector::iterator removeResult = std::find( + ms_dynamicRegions.begin(), ms_dynamicRegions.end(), region); + if (removeResult != ms_dynamicRegions.end()) + { + ms_dynamicRegions.erase(removeResult); + } + else + { + WARNING(true, ("RegionMaster::removeDynamicRegion dynamic region %s was " + "not in the dynamic region list, continuing anyway", + source.getNetworkId().getValueString().c_str())); + } + + // remove the region + delete region; +} // RegionMaster::removeDynamicRegion + +//---------------------------------------------------------------------- + +/** + * Returns the dynamic region associated with a UniverseObject. + * + * @param source the object to get the region from + */ +const Region * RegionMaster::getDynamicRegionFromObject(const UniverseObject & source) +{ + if (!ms_installed) + { + WARNING(true, ("RegionMaster::getDynamicRegionFromObject, not installed")); + return NULL; + } + + DynamicVariableList::NestedList regionObjVars(source.getObjVars(),OBJVAR_DYNAMIC_REGION); + + Unicode::String planet; + if (!regionObjVars.getItem(OBJVAR_DYNAMIC_REGION_PLANET,planet)) + { + DEBUG_WARNING(true, ("RegionMaster::getDynamicRegionFromObject object %s has no " + "planet data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + Unicode::String name; + if (!regionObjVars.getItem(OBJVAR_DYNAMIC_REGION_NAME,name)) + { + DEBUG_WARNING(true, ("RegionMaster::getDynamicRegionFromObject object %s has no " + "name data", source.getNetworkId().getValueString().c_str())); + return NULL; + } + + return getRegionByName(Unicode::wideToNarrow(planet), name); +} // RegionMaster::getDynamicRegionFromObject + +//---------------------------------------------------------------------- + +/** + * Returns the region with the given name. + */ +Region * RegionMaster::getRegionByName(const std::string & planetName, const Unicode::String & regionName) +{ + if (!ms_installed) + { + WARNING(true, ("RegionMaster::getRegionByName, not installed")); + return NULL; + } + + const RegionData & regionData = ms_planetRegions[planetName]; + if (regionData.tree != NULL) + { + RegionsMappedByName::const_iterator result = regionData.nameMap.find(regionName); + if (result != regionData.nameMap.end()) + return (*result).second; + } + return NULL; +} // RegionMaster::getRegionByName + +//---------------------------------------------------------------------- + +/** + * Finds the region with the smallest area at a given point. + */ +const Region * RegionMaster::getSmallestRegionAtPoint(const std::string & planet, float x, float z) +{ + if (!ms_installed) + { + WARNING(true, ("RegionMaster::getSmallestRegionAtPoint, not installed")); + return NULL; + } + + std::vector regions; + getRegionsAtPoint(planet, x, z, regions); + + float area = 0; + const Region * region = NULL; + for (std::vector::const_iterator iter = regions.begin(); + iter != regions.end(); ++iter) + { + if (region == NULL) + { + region = *iter; + area = region->getArea(); + } + else + { + float testArea = (*iter)->getArea(); + if (testArea < area) + { + area = testArea; + region = *iter; + } + } + } + return region; +} // RegionMaster::getSmallestRegionAtPoint + +//---------------------------------------------------------------------- + +/** + * Same as getSmallestRegionAtPoint, but the region must be marked as visible. + */ +const Region * RegionMaster::getSmallestVisibleRegionAtPoint(const std::string & planet, float x, float z) +{ + if (!ms_installed) + { + WARNING(true, ("RegionMaster::getSmallestRegionAtPoint, not installed")); + return NULL; + } + + std::vector regions; + getRegionsAtPoint(planet, x, z, regions); + + float area = 0; + const Region * region = NULL; + for (std::vector::const_iterator iter = regions.begin(); iter != regions.end(); ++iter) + { + if ((*iter)->isVisible()) + { + if (region == NULL) + { + region = *iter; + area = region->getArea(); + } + else + { + float testArea = (*iter)->getArea(); + if (testArea < area) + { + area = testArea; + region = *iter; + } + } + } + } + return region; +} // RegionMaster::getSmallestVisibleRegionAtPoint + +//---------------------------------------------------------------------- + +/** + * Finds the regions at a given point. + * + * @param planet planet name of region to get + * @param x x coordinate of point + * @param z z coordinate of point + * @param regions vector to be filled in with list of regions at the point + */ +void RegionMaster::getRegionsAtPoint(const std::string & planet, float x, float z, + std::vector & regions) +{ + regions.clear(); + + if (!ms_installed) + { + WARNING(true, ("RegionMaster::getRegionsAtPoint, not installed")); + return; + } + + const RegionData & regionData = ms_planetRegions[planet]; + if (regionData.tree != NULL) + { + std::vector objects; + regionData.tree->getObjectsAt(x, z, objects); + for (std::vector::const_iterator iter = objects.begin(); + iter != objects.end(); ++iter) + { + regions.push_back(static_cast((*iter)->getData())); + } + } +} // RegionMaster::getRegionsAtPoint + +//---------------------------------------------------------------------- + +/** + * Returns all the regions for a given planet. + */ +void RegionMaster::getRegionsForPlanet(const std::string & planetName, + std::vector & regions) +{ + regions.clear(); + + if (!ms_installed) + { + WARNING(true, ("RegionMaster::getRegionsForPlanet, not installed")); + return; + } + + const RegionData & regionData = ms_planetRegions[planetName]; + if (regionData.tree != NULL) + { + std::vector objects; + regionData.tree->getAllObjects(objects); + for (std::vector::const_iterator iter = objects.begin(); + iter != objects.end(); ++iter) + { + regions.push_back(static_cast((*iter)->getData())); + } + } +} // RegionMaster::getRegionsForPlanet + +//---------------------------------------------------------------------- + +void RegionMaster::registerBattlefieldMarker(const std::string ®ionName, BattlefieldMarkerObject *marker) +{ + Region *region = getRegionByName(ServerWorld::getSceneId(), Unicode::narrowToWide(regionName)); + if (region) + { + RegionPvp *regionPvp = region->asRegionPvp(); + if (regionPvp) + regionPvp->setBattlefieldMarker(marker); + } +} + +EnvironmentInfo RegionMasterNamspace::convertFromStringToEnvironmentInfo(std::string const & stringList) +{ + if(stringList.empty()) + return 0; + + if(s_conversionMap.empty()) + { + // Fill the Datatable with values from our environment flags datatable. + DataTable * const environmentFlagTable = DataTableManager::getTable(s_environmentFlagsDataTable, true); + for(int i = 0; i < environmentFlagTable->getNumRows(); ++i) + { + s_conversionMap.insert( std::pair(environmentFlagTable->getStringValue(0,i), static_cast(1 << i) ) ); + } + } + + std::string parserList = stringList; + const char delimiter = ','; + EnvironmentInfo outputValue = 0; + + // Parse the input string using , as the delimiter. + std::vector parsedStringVector; + std::string::size_type loc = parserList.find(delimiter); + + if (std::string::npos != loc) // We found a comma + { + std::vector locations; + locations.push_back(loc); + while (std::string::npos != (loc = parserList.find(delimiter, loc+1))) + { + locations.push_back(loc); + } + + for(std::vector::size_type i = 0; i < locations.size(); ++i) + { + std::string subString; + + if(i == 0) + subString = parserList.substr(0, locations[i]); + else + subString = parserList.substr(locations[i - 1], locations[i]); + + parsedStringVector.push_back(subString); + } + + } + else + parsedStringVector.push_back(parserList); // No comma, must be one item in the list. + + // Now we just search our map for the strings we just read in. If we find it, we add that flag to our output value. + for(std::vector::size_type i = 0; i < parsedStringVector.size(); ++i) + { + std::map::iterator searchIter = s_conversionMap.find(parsedStringVector[i]); + + if( searchIter != s_conversionMap.end()) + { + outputValue |= searchIter->second; + } + } + + + return outputValue; +} + +NetworkId RegionMaster::createNewDynamicRegionWithSpawn(float centerX, float centerY, float centerZ, + float radius, const Unicode::String & name, const std::string & planet, int pvp, + int buildable, int municipal, int geography, int minDifficulty, int maxDifficulty, + int spawnable, int mission, bool visible, bool notify, std::string spawnDatatable, int duration) +{ + // no creating duplicate regions + if (getRegionByName(planet, name)) + return NetworkId(); + + // only the universe process may create universe objects + if (!ServerUniverse::getInstance().isAuthoritative()) + { + CreateDynamicSpawnRegionCircleMessage const createMessage(centerX, centerY, centerZ, radius, name, planet, pvp, buildable, municipal, geography, minDifficulty, maxDifficulty, spawnable, mission, visible, notify, spawnDatatable, duration); + GameServer::getInstance().sendToCentralServer(createMessage); + return NetworkId(); + } + + // create a new UniverseObject that will be used to hold the region data + Transform tr; + tr.setPosition_p(Vector::xyz111); + UniverseObject *regionObject = safe_cast(ServerWorld::createNewObject(DYNAMIC_REGION_TEMPLATE_NAME, tr, 0, false)); + + if (!regionObject || !regionObject->getScriptObject()) + return NetworkId(); + + if (!setDynamicSpawnRegionObjectData(*regionObject, name, planet, RG_circle, centerX, + centerZ, radius, 0, pvp, buildable, municipal, geography, minDifficulty, + maxDifficulty, spawnable, mission, visible, notify, spawnDatatable, duration)) + { + regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); + return NetworkId(); + } + + regionObject->addToWorld(); + + const Region * region = addDynamicRegion(*regionObject); + if (region) + regionObject->persist(); + else + { + regionObject->removeObjVarItem(OBJVAR_DYNAMIC_REGION); + regionObject->permanentlyDestroy(DeleteReasons::SetupFailed); + } + + // Everything went okay. Add dynamic spawn script and other objvars. + regionObject->getScriptObject()->attachScript(s_dynamicMasterScript, true); + + if(!spawnDatatable.empty()) + { + // Creature spawning has to be done in script. + ScriptParams params; + params.addParam(regionObject->getNetworkId()); + params.addParam(spawnDatatable.c_str()); + params.addParam(centerX); + params.addParam(centerY); + params.addParam(centerZ); + + IGNORE_RETURN(regionObject->getScriptObject()->trigAllScripts(Scripting::TRIG_ON_DYNAMIC_SPAWN_REGION_CREATED, params)); + } + + return regionObject->getNetworkId(); +} + +bool RegionMaster::setDynamicSpawnRegionObjectData(UniverseObject & object, + const Unicode::String & name, const std::string & planet, int geometry, + float minX, float minZ, float maxX, float maxZ, int pvp, int buildable, + int municipal, int geography, int minDifficulty, int maxDifficulty, int spawnable, + int mission, bool visible, bool notify, std::string spawntable, int duration) +{ + time_t const birthEpoch = ::time(NULL); + time_t const endEpoch = birthEpoch + (duration * 60); // Duration is in minutes. + + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NAME, name); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PLANET, Unicode::narrowToWide(planet)); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOMETRY, geometry); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINX, minX); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MINY, minZ); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXX, maxX); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXY, maxZ); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_PVP, pvp); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_GEOGRAPHY, geography); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MIN_DIFFICULTY, minDifficulty); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAX_DIFFICULTY, maxDifficulty); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWN, spawnable); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MISSION, mission); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BUILDABLE, buildable); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MUNICIPAL, municipal); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_VISIBLE, static_cast(visible)); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_NOTIFY, static_cast(notify)); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_SPAWNTABLE, spawntable); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_BIRTH, static_cast(birthEpoch)); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_DURATION, duration); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_MAXDURATION, duration + (duration/3)); // Max duration is an extra 30% of the time. + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_READABLE_BIRTH, CalendarTime::convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(birthEpoch)); + object.setObjVarItem(OBJVAR_DYNAMIC_REGION + "." + OBJVAR_DYNAMIC_REGION_READABLE_DEATH, CalendarTime::convertEpochToTimeStringGMT_YYYYMMDDHHMMSS(endEpoch)); + return true; +} // RegionMaster::setDynamicRegionObjectData + +//---------------------------------------------------------------------- + diff --git a/src/engine/server/library/serverGame/src/shared/space/ShipInternalDamageOverTimeManager.cpp b/src/engine/server/library/serverGame/src/shared/space/ShipInternalDamageOverTimeManager.cpp index e4ab942f0..3cc0f54f6 100644 --- a/src/engine/server/library/serverGame/src/shared/space/ShipInternalDamageOverTimeManager.cpp +++ b/src/engine/server/library/serverGame/src/shared/space/ShipInternalDamageOverTimeManager.cpp @@ -1,256 +1,256 @@ -//====================================================================== -// -// ShipInternalDamageOverTimeManager.cpp -// copyright (c) 2004 Sony Online Entertainment -// -//====================================================================== - -#include "serverGame/FirstServerGame.h" -#include "serverGame/ShipInternalDamageOverTimeManager.h" - -#include "serverGame/ShipInternalDamageOverTime.h" -#include "serverGame/ShipObject.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptFunctionTable.h" -#include "serverScript/ScriptParameters.h" -#include "sharedFoundation/ExitChain.h" -#include -#include - -//====================================================================== - -namespace ShipInternalDamageOverTimeManagerNamespace -{ - typedef ShipInternalDamageOverTimeManager::IdotVector IdotVector; - typedef std::pair IdotDamage; - typedef stdvector::fwd IdotDamageVector; - - IdotVector s_idotVector; - IdotVector s_temporaryIdotVector; - IdotDamageVector s_temporaryIdotDamageVector; - - float ms_timeSinceUpdate = 0.0f; - - float const ms_updateTime = 2.0f; - - //---------------------------------------------------------------------- - - void notifyIdotRemoval(ShipObject & ship, ShipInternalDamageOverTime const & idot) - { - GameScriptObject * const gameScriptObject = ship.getScriptObject(); - - if (gameScriptObject != NULL) - { - ScriptParams p; - p.addParam(idot.getChassisSlot()); - p.addParam(idot.getDamageRate()); - p.addParam(idot.getDamageThreshold()); - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SHIP_INTERNAL_DAMAGE_OVER_TIME_REMOVED, p)); - } - } - - //---------------------------------------------------------------------- - - void notifyIdotDamage(ShipObject & ship, ShipInternalDamageOverTime const & idot, float damageApplied) - { - GameScriptObject * const gameScriptObject = ship.getScriptObject(); - - if (gameScriptObject != NULL) - { - ScriptParams p; - p.addParam(idot.getChassisSlot()); - p.addParam(idot.getDamageRate()); - p.addParam(idot.getDamageThreshold()); - p.addParam(damageApplied); - - IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SHIP_DAMAGED_BY_INTERNAL_DAMAGE_OVER_TIME, p)); - } - } -} - -using namespace ShipInternalDamageOverTimeManagerNamespace; - -//---------------------------------------------------------------------- - -void ShipInternalDamageOverTimeManager::install() -{ - ExitChain::add(ShipInternalDamageOverTimeManager::remove, "ShipInternalDamageOverTimeManager::remove"); -} - -//---------------------------------------------------------------------- - -void ShipInternalDamageOverTimeManager::remove() -{ - s_temporaryIdotVector.clear(); - s_idotVector.clear(); -} - -//---------------------------------------------------------------------- - -void ShipInternalDamageOverTimeManager::update(float elapsedTime) -{ - ms_timeSinceUpdate += elapsedTime; - - if (ms_timeSinceUpdate < ms_updateTime) - return; - - bool hasExpired = false; - - { - s_temporaryIdotDamageVector.clear(); - - IdotVector::const_iterator const end = s_idotVector.end(); - for (IdotVector::const_iterator it = s_idotVector.begin(); it != end; ++it) - { - ShipInternalDamageOverTime const & idot = *it; - - float damageApplied = 0.0f; - if (idot.isExpired() || !idot.applyDamage(ms_timeSinceUpdate, damageApplied)) - { - idot.setExpired(true); - hasExpired = true; - } - - if (damageApplied != 0.0f) - s_temporaryIdotDamageVector.push_back(IdotDamage(idot, damageApplied)); - } - } - - //-- process queued damage notifications - //-- this is done outside the update loop so that script triggers can be allowed to add/remove idots - { - for (IdotDamageVector::const_iterator it = s_temporaryIdotDamageVector.begin(); it != s_temporaryIdotDamageVector.end(); ++it) - { - IdotDamage const & idotDamage = *it; - ShipInternalDamageOverTime const & idot = idotDamage.first; - float const damageApplied = idotDamage.second; - - ShipObject * const shipObject = idot.getShipObject(); - - if (NULL != shipObject) - notifyIdotDamage(*shipObject, idot, damageApplied); - } - } - - //-- process any expired idots - //-- this is done outside the update loop so that script triggers can be allowed to add/remove idots - if (hasExpired) - { - IdotVector::iterator const expired_begin = std::remove_if(s_idotVector.begin(), s_idotVector.end(), ShipInternalDamageOverTime::ExpiredRemoveFunctor()); - - s_temporaryIdotVector.clear(); - s_temporaryIdotVector.insert(s_temporaryIdotVector.end(), expired_begin, s_idotVector.end()); - IGNORE_RETURN(s_idotVector.erase(expired_begin, s_idotVector.end())); - - { - IdotVector::const_iterator const end = s_temporaryIdotVector.end(); - for (IdotVector::const_iterator it = s_temporaryIdotVector.begin(); it != end; ++it) - { - ShipInternalDamageOverTime const & expiredIdot = *it; - ShipObject * const shipObject = expiredIdot.getShipObject(); - - if (shipObject != NULL) - notifyIdotRemoval(*shipObject, expiredIdot); - } - } - - s_temporaryIdotVector.clear(); - } - - ms_timeSinceUpdate = 0.0f; -} - -//---------------------------------------------------------------------- - -bool ShipInternalDamageOverTimeManager::setEntry(ShipObject const & ship, int chassisSlot, float damageRate, float damageThreshold) -{ - ShipInternalDamageOverTime const idot(ship, chassisSlot, damageRate, damageThreshold); - - if (!idot.checkValidity()) - return false; - - IdotVector::iterator const lowerBound = std::lower_bound(s_idotVector.begin(), s_idotVector.end(), idot); - - //-- there is no lower bound, just stick it at the end - if (lowerBound == s_idotVector.end()) - { - s_idotVector.push_back(idot); - } - else - { - ShipInternalDamageOverTime & lowerBoundIdot = *lowerBound; - - //-- the lower bound sorts greater than the new idot, therefore this is a new insertion - if (idot < lowerBoundIdot) - { - IGNORE_RETURN(s_idotVector.insert(lowerBound, idot)); - } - else - { - //-- otherwise we are overriding an existing value - - lowerBoundIdot.setDamageRate(damageRate); - lowerBoundIdot.setDamageThreshold(damageThreshold); - } - } - - return true; -} - -//---------------------------------------------------------------------- - -bool ShipInternalDamageOverTimeManager::removeEntry(ShipObject const & ship, int chassisSlot) -{ - ShipInternalDamageOverTime const idot(ship, chassisSlot, 0.0f, 0.0f); - - IdotVector::iterator const lowerBound = std::lower_bound(s_idotVector.begin(), s_idotVector.end(), idot); - - //-- there is no lower bound, the idot is not in the vector - if (lowerBound == s_idotVector.end()) - return false; - - ShipInternalDamageOverTime const lowerBoundIdot = *lowerBound; - - //-- the lower bound sorts greater than the new idot, therefore this is a new insertion - if (idot < lowerBoundIdot) - return false; - - IGNORE_RETURN(s_idotVector.erase(lowerBound)); - - ShipObject * const shipObject = lowerBoundIdot.getShipObject(); - if (shipObject != NULL) - notifyIdotRemoval(*shipObject, lowerBoundIdot); - - return true; -} - -//---------------------------------------------------------------------- - -ShipInternalDamageOverTime const * const ShipInternalDamageOverTimeManager::findEntry(ShipObject const & ship, int chassisSlot) -{ - ShipInternalDamageOverTime const idot(ship, chassisSlot, 0.0f, 0.0f); - - IdotVector::iterator const lowerBound = std::lower_bound(s_idotVector.begin(), s_idotVector.end(), idot); - - //-- there is no lower bound, the idot is not in the vector - if (lowerBound == s_idotVector.end()) - return NULL; - - ShipInternalDamageOverTime & lowerBoundIdot = *lowerBound; - - //-- the lower bound sorts greater than the new idot, therefore this is a new insertion - if (idot < lowerBoundIdot) - return NULL; - - return &lowerBoundIdot; -} - -//---------------------------------------------------------------------- - -ShipInternalDamageOverTimeManager::IdotVector const & ShipInternalDamageOverTimeManager::getActiveShipInternalDamageOverTime() -{ - return s_idotVector; -} - -//====================================================================== +//====================================================================== +// +// ShipInternalDamageOverTimeManager.cpp +// copyright (c) 2004 Sony Online Entertainment +// +//====================================================================== + +#include "serverGame/FirstServerGame.h" +#include "serverGame/ShipInternalDamageOverTimeManager.h" + +#include "serverGame/ShipInternalDamageOverTime.h" +#include "serverGame/ShipObject.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptFunctionTable.h" +#include "serverScript/ScriptParameters.h" +#include "sharedFoundation/ExitChain.h" +#include +#include + +//====================================================================== + +namespace ShipInternalDamageOverTimeManagerNamespace +{ + typedef ShipInternalDamageOverTimeManager::IdotVector IdotVector; + typedef std::pair IdotDamage; + typedef stdvector::fwd IdotDamageVector; + + IdotVector s_idotVector; + IdotVector s_temporaryIdotVector; + IdotDamageVector s_temporaryIdotDamageVector; + + float ms_timeSinceUpdate = 0.0f; + + float const ms_updateTime = 2.0f; + + //---------------------------------------------------------------------- + + void notifyIdotRemoval(ShipObject & ship, ShipInternalDamageOverTime const & idot) + { + GameScriptObject * const gameScriptObject = ship.getScriptObject(); + + if (gameScriptObject != NULL) + { + ScriptParams p; + p.addParam(idot.getChassisSlot()); + p.addParam(idot.getDamageRate()); + p.addParam(idot.getDamageThreshold()); + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SHIP_INTERNAL_DAMAGE_OVER_TIME_REMOVED, p)); + } + } + + //---------------------------------------------------------------------- + + void notifyIdotDamage(ShipObject & ship, ShipInternalDamageOverTime const & idot, float damageApplied) + { + GameScriptObject * const gameScriptObject = ship.getScriptObject(); + + if (gameScriptObject != NULL) + { + ScriptParams p; + p.addParam(idot.getChassisSlot()); + p.addParam(idot.getDamageRate()); + p.addParam(idot.getDamageThreshold()); + p.addParam(damageApplied); + + IGNORE_RETURN(gameScriptObject->trigAllScripts(Scripting::TRIG_SHIP_DAMAGED_BY_INTERNAL_DAMAGE_OVER_TIME, p)); + } + } +} + +using namespace ShipInternalDamageOverTimeManagerNamespace; + +//---------------------------------------------------------------------- + +void ShipInternalDamageOverTimeManager::install() +{ + ExitChain::add(ShipInternalDamageOverTimeManager::remove, "ShipInternalDamageOverTimeManager::remove"); +} + +//---------------------------------------------------------------------- + +void ShipInternalDamageOverTimeManager::remove() +{ + s_temporaryIdotVector.clear(); + s_idotVector.clear(); +} + +//---------------------------------------------------------------------- + +void ShipInternalDamageOverTimeManager::update(float elapsedTime) +{ + ms_timeSinceUpdate += elapsedTime; + + if (ms_timeSinceUpdate < ms_updateTime) + return; + + bool hasExpired = false; + + { + s_temporaryIdotDamageVector.clear(); + + IdotVector::const_iterator const end = s_idotVector.end(); + for (IdotVector::const_iterator it = s_idotVector.begin(); it != end; ++it) + { + ShipInternalDamageOverTime const & idot = *it; + + float damageApplied = 0.0f; + if (idot.isExpired() || !idot.applyDamage(ms_timeSinceUpdate, damageApplied)) + { + idot.setExpired(true); + hasExpired = true; + } + + if (damageApplied != 0.0f) + s_temporaryIdotDamageVector.push_back(IdotDamage(idot, damageApplied)); + } + } + + //-- process queued damage notifications + //-- this is done outside the update loop so that script triggers can be allowed to add/remove idots + { + for (IdotDamageVector::const_iterator it = s_temporaryIdotDamageVector.begin(); it != s_temporaryIdotDamageVector.end(); ++it) + { + IdotDamage const & idotDamage = *it; + ShipInternalDamageOverTime const & idot = idotDamage.first; + float const damageApplied = idotDamage.second; + + ShipObject * const shipObject = idot.getShipObject(); + + if (NULL != shipObject) + notifyIdotDamage(*shipObject, idot, damageApplied); + } + } + + //-- process any expired idots + //-- this is done outside the update loop so that script triggers can be allowed to add/remove idots + if (hasExpired) + { + IdotVector::iterator const expired_begin = std::remove_if(s_idotVector.begin(), s_idotVector.end(), ShipInternalDamageOverTime::ExpiredRemoveFunctor()); + + s_temporaryIdotVector.clear(); + s_temporaryIdotVector.insert(s_temporaryIdotVector.end(), expired_begin, s_idotVector.end()); + IGNORE_RETURN(s_idotVector.erase(expired_begin, s_idotVector.end())); + + { + IdotVector::const_iterator const end = s_temporaryIdotVector.end(); + for (IdotVector::const_iterator it = s_temporaryIdotVector.begin(); it != end; ++it) + { + ShipInternalDamageOverTime const & expiredIdot = *it; + ShipObject * const shipObject = expiredIdot.getShipObject(); + + if (shipObject != NULL) + notifyIdotRemoval(*shipObject, expiredIdot); + } + } + + s_temporaryIdotVector.clear(); + } + + ms_timeSinceUpdate = 0.0f; +} + +//---------------------------------------------------------------------- + +bool ShipInternalDamageOverTimeManager::setEntry(ShipObject const & ship, int chassisSlot, float damageRate, float damageThreshold) +{ + ShipInternalDamageOverTime const idot(ship, chassisSlot, damageRate, damageThreshold); + + if (!idot.checkValidity()) + return false; + + IdotVector::iterator const lowerBound = std::lower_bound(s_idotVector.begin(), s_idotVector.end(), idot); + + //-- there is no lower bound, just stick it at the end + if (lowerBound == s_idotVector.end()) + { + s_idotVector.push_back(idot); + } + else + { + ShipInternalDamageOverTime & lowerBoundIdot = *lowerBound; + + //-- the lower bound sorts greater than the new idot, therefore this is a new insertion + if (idot < lowerBoundIdot) + { + IGNORE_RETURN(s_idotVector.insert(lowerBound, idot)); + } + else + { + //-- otherwise we are overriding an existing value + + lowerBoundIdot.setDamageRate(damageRate); + lowerBoundIdot.setDamageThreshold(damageThreshold); + } + } + + return true; +} + +//---------------------------------------------------------------------- + +bool ShipInternalDamageOverTimeManager::removeEntry(ShipObject const & ship, int chassisSlot) +{ + ShipInternalDamageOverTime const idot(ship, chassisSlot, 0.0f, 0.0f); + + IdotVector::iterator const lowerBound = std::lower_bound(s_idotVector.begin(), s_idotVector.end(), idot); + + //-- there is no lower bound, the idot is not in the vector + if (lowerBound == s_idotVector.end()) + return false; + + ShipInternalDamageOverTime const lowerBoundIdot = *lowerBound; + + //-- the lower bound sorts greater than the new idot, therefore this is a new insertion + if (idot < lowerBoundIdot) + return false; + + IGNORE_RETURN(s_idotVector.erase(lowerBound)); + + ShipObject * const shipObject = lowerBoundIdot.getShipObject(); + if (shipObject != NULL) + notifyIdotRemoval(*shipObject, lowerBoundIdot); + + return true; +} + +//---------------------------------------------------------------------- + +ShipInternalDamageOverTime const * const ShipInternalDamageOverTimeManager::findEntry(ShipObject const & ship, int chassisSlot) +{ + ShipInternalDamageOverTime const idot(ship, chassisSlot, 0.0f, 0.0f); + + IdotVector::iterator const lowerBound = std::lower_bound(s_idotVector.begin(), s_idotVector.end(), idot); + + //-- there is no lower bound, the idot is not in the vector + if (lowerBound == s_idotVector.end()) + return NULL; + + ShipInternalDamageOverTime & lowerBoundIdot = *lowerBound; + + //-- the lower bound sorts greater than the new idot, therefore this is a new insertion + if (idot < lowerBoundIdot) + return NULL; + + return &lowerBoundIdot; +} + +//---------------------------------------------------------------------- + +ShipInternalDamageOverTimeManager::IdotVector const & ShipInternalDamageOverTimeManager::getActiveShipInternalDamageOverTime() +{ + return s_idotVector; +} + +//====================================================================== diff --git a/src/engine/server/library/serverMetrics/src/shared/ConfigServerMetrics.cpp b/src/engine/server/library/serverMetrics/src/shared/ConfigServerMetrics.cpp index 29059c7e9..1ce30451c 100644 --- a/src/engine/server/library/serverMetrics/src/shared/ConfigServerMetrics.cpp +++ b/src/engine/server/library/serverMetrics/src/shared/ConfigServerMetrics.cpp @@ -1,47 +1,47 @@ -// ConfigServerMetrics.cpp -// copyright 2000 Verant Interactive -// Author: Justin Randall - - -//----------------------------------------------------------------------- - -#include "serverMetrics/FirstServerMetrics.h" -#include "sharedFoundation/ConfigFile.h" -#include "ConfigServerMetrics.h" - -//----------------------------------------------------------------------- - -ConfigServerMetrics::Data * ConfigServerMetrics::data = 0; - -#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("ServerMetrics", #a, b)) -#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("ServerMetrics", #a, b)) -#define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("ServerMetrics", #a, b)) -#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("ServerMetrics", #a, b)) - -//----------------------------------------------------------------------- - -void ConfigServerMetrics::install(void) -{ - data = new ConfigServerMetrics::Data; - - KEY_STRING(metricsServerAddress, "localhost"); - - data->secondsBetweenUpdates = static_cast(ConfigFile::getKeyInt("ServerMetrics", "secondsBetweenUpdates", 5)); - data->metricsServerPort = static_cast(ConfigFile::getKeyInt("ServerMetrics", "metricsServerPort", 44480)); - - KEY_STRING(primaryName, "unknownProcess"); - KEY_STRING(secondaryName, ""); - KEY_INT(frameTimeAveragingSize, 11); - -} - -//----------------------------------------------------------------------- - -void ConfigServerMetrics::remove(void) -{ - delete data; - data = 0; -} - -//----------------------------------------------------------------------- - +// ConfigServerMetrics.cpp +// copyright 2000 Verant Interactive +// Author: Justin Randall + + +//----------------------------------------------------------------------- + +#include "serverMetrics/FirstServerMetrics.h" +#include "sharedFoundation/ConfigFile.h" +#include "ConfigServerMetrics.h" + +//----------------------------------------------------------------------- + +ConfigServerMetrics::Data * ConfigServerMetrics::data = 0; + +#define KEY_INT(a,b) (data->a = ConfigFile::getKeyInt("ServerMetrics", #a, b)) +#define KEY_BOOL(a,b) (data->a = ConfigFile::getKeyBool("ServerMetrics", #a, b)) +#define KEY_REAL(a,b) (data->a = ConfigFile::getKeyReal("ServerMetrics", #a, b)) +#define KEY_STRING(a,b) (data->a = ConfigFile::getKeyString("ServerMetrics", #a, b)) + +//----------------------------------------------------------------------- + +void ConfigServerMetrics::install(void) +{ + data = new ConfigServerMetrics::Data; + + KEY_STRING(metricsServerAddress, "localhost"); + + data->secondsBetweenUpdates = static_cast(ConfigFile::getKeyInt("ServerMetrics", "secondsBetweenUpdates", 5)); + data->metricsServerPort = static_cast(ConfigFile::getKeyInt("ServerMetrics", "metricsServerPort", 44480)); + + KEY_STRING(primaryName, "unknownProcess"); + KEY_STRING(secondaryName, ""); + KEY_INT(frameTimeAveragingSize, 11); + +} + +//----------------------------------------------------------------------- + +void ConfigServerMetrics::remove(void) +{ + delete data; + data = 0; +} + +//----------------------------------------------------------------------- + diff --git a/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiCreatureStateMessage.h b/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiCreatureStateMessage.h index 9addbd87f..11d831771 100644 --- a/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiCreatureStateMessage.h +++ b/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiCreatureStateMessage.h @@ -30,7 +30,7 @@ class AiCreatureStateMessage : public MessageQueue::Data { CONTROLLER_MESSAGE_INTERFACE; - friend void Archive::get(ReadIterator & source, AiCreatureStateMessage & target); + friend void Archive::get(Archive::ReadIterator & source, AiCreatureStateMessage & target); public: diff --git a/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiMovementMessage.h b/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiMovementMessage.h index 7cec0cf41..7cc7d9d4d 100644 --- a/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiMovementMessage.h +++ b/src/engine/server/library/serverNetworkMessages/src/shared/gameGameServer/AiMovementMessage.h @@ -35,7 +35,7 @@ class AiMovementMessage : public MessageQueue::Data { CONTROLLER_MESSAGE_INTERFACE; - friend void Archive::get(ReadIterator & source, AiMovementMessage & target); + friend void Archive::get(Archive::ReadIterator & source, AiMovementMessage & target); public: AiMovementMessage(); diff --git a/src/engine/server/library/serverScript/src/shared/JavaLibrary.cpp b/src/engine/server/library/serverScript/src/shared/JavaLibrary.cpp index f2c3ad701..2ae597df5 100644 --- a/src/engine/server/library/serverScript/src/shared/JavaLibrary.cpp +++ b/src/engine/server/library/serverScript/src/shared/JavaLibrary.cpp @@ -1232,7 +1232,7 @@ void JavaLibrary::initializeJavaThread() } #ifdef JNI_VERSION_1_4 - if (!ms_javaVmType == JV_ibm) + if ((!ms_javaVmType) == JV_ibm) { tempOption.optionString = "-Xrs"; options.push_back(tempOption); @@ -1243,14 +1243,6 @@ void JavaLibrary::initializeJavaThread() { tempOption.optionString = "-Xloggc:javagc.log"; options.push_back(tempOption); -// tempOption.optionString = "-Xrunpri"; -// options.push_back(tempOption); -// tempOption.optionString = "-Xbootclasspath/a:/home/sjakab/temp/OptimizeitSuiteDemo/lib/oibcp.jar"; -// options.push_back(tempOption); -// tempOption.optionString = "-Xboundthreads"; -// options.push_back(tempOption); -// tempOption.optionString = "-Xrunhprof:heap=format=b"; -// options.push_back(tempOption); } #endif diff --git a/src/engine/server/library/serverScript/src/shared/ScriptMethodsCrafting.cpp b/src/engine/server/library/serverScript/src/shared/ScriptMethodsCrafting.cpp index cf44ff22b..45860e439 100644 --- a/src/engine/server/library/serverScript/src/shared/ScriptMethodsCrafting.cpp +++ b/src/engine/server/library/serverScript/src/shared/ScriptMethodsCrafting.cpp @@ -1,2808 +1,2808 @@ -//======================================================================== -// -// ScriptMethodsCrafting.cpp - implements script methods dealing with crafting -// and manufacturing. -// -// copyright 2001 Sony Online Entertainment -// -//======================================================================== - -#include "serverScript/FirstServerScript.h" -#include "serverScript/JavaLibrary.h" - -#include "UnicodeUtils.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/DraftSchematicObject.h" -#include "serverGame/FactoryObject.h" -#include "serverGame/ManufactureInstallationObject.h" -#include "serverGame/ManufactureObjectInterface.h" -#include "serverGame/ManufactureSchematicObject.h" -#include "serverGame/ObserveTracker.h" -#include "serverGame/PlayerCreatureController.h" -#include "serverGame/PlayerObject.h" -#include "serverGame/ResourceContainerObject.h" -#include "serverGame/ServerWorld.h" -#include "serverScript/GameScriptObject.h" -#include "serverScript/ScriptParameters.h" -#include "sharedFoundation/TemporaryCrcString.h" -#include "sharedGame/AssetCustomizationManager.h" -#include "sharedLog/Log.h" -#include "sharedObject/CustomizationData.h" -#include "sharedObject/MemoryBlockManagedObject.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedObject/PaletteColorCustomizationVariable.h" -#include "sharedObject/RangedIntCustomizationVariable.h" -#include "sharedObject/VolumeContainer.h" - -#include - -using namespace JNIWrappersNamespace; - - -// ====================================================================== - -namespace ScriptMethodsCraftingNamespace -{ - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struct VariableInfo - { - VariableInfo(std::string const &newName, int newMinValueInclusive, int newSetValue, int newMaxValueExclusive); - - std::string name; - int minValueInclusive; - int value; - int maxValueExclusive; - }; - - typedef std::vector VariableInfoVector; - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool install(); - void collectRangedIntVariableCallback(const std::string &fullVariablePathName, const CustomizationVariable *customizationVariable, void *context); - - jboolean JNICALL startCraftingSession(JNIEnv *env, jobject self, jlong player, jlong station); - jboolean JNICALL endCraftingSession(JNIEnv *env, jobject self, jlong crafter, jlong tool, jlong prototype); - jboolean JNICALL setCraftingLevelAndStation(JNIEnv *env, jobject self, jlong player, jint craftingLevel, jlong station); - jint JNICALL getCraftingLevel(JNIEnv *env, jobject self, jlong player); - jlong JNICALL getCraftingStation(JNIEnv *env, jobject self, jlong player); - jboolean JNICALL sendUseableDraftSchematics(JNIEnv *env, jobject self, jlong player, jintArray schematics); - jboolean JNICALL setSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject attribute, jboolean experiment); - jboolean JNICALL setSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributes, jboolean experiment); - jobject JNICALL getSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject name, jboolean experiment); - jobjectArray JNICALL getSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray names, jboolean experiment); - jobjectArray JNICALL getAllSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jboolean experiment); - jobject JNICALL getSchematicForExperimentalAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributeNames); - jboolean JNICALL setSchematicExperimentMod(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat experimentMod); - jboolean JNICALL setSchematicAppearances(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray appearances); - jboolean JNICALL setSchematicCustomizations(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray customizations); - jint JNICALL getSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic); - jboolean JNICALL setSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count); - jint JNICALL getSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic); - jboolean JNICALL setSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count); - jfloat JNICALL getSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic); - jboolean JNICALL setSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat time); - jboolean JNICALL setCreatorXp(JNIEnv *env, jobject self, jlong object, jint xp); - void JNICALL getIngredientsForManufactureStation(JNIEnv *env, jobject self, jlong station, jobjectArray ingredients); - jlong JNICALL getManufactureStationInputHopper(JNIEnv *env, jobject self, jlong station); - jlong JNICALL getManufactureStationOutputHopper(JNIEnv *env, jobject self, jlong station); - jstring JNICALL getManufactureStationSchematic(JNIEnv *env, jobject self, jlong station); - void JNICALL getValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station, jobjectArray schematics); - jboolean JNICALL hasValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station); - jboolean JNICALL transferManufactureSchematicToPlayer(JNIEnv *env, jobject self, jlong station, jlong player); - jboolean JNICALL transferManufactureSchematicToStation(JNIEnv *env, jobject self, jlong schematic, jlong station); - void JNICALL getRepairableObjectsForTool(JNIEnv *env, jobject self, jlong player, jlong tool, jobjectArray objects); - jintArray JNICALL getAttributeBonuses(JNIEnv *env, jobject self, jlong target); - jint JNICALL getAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute); - jboolean JNICALL setAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute, jint bonus); - jboolean JNICALL setAttributeBonuses(JNIEnv *env, jobject self, jlong target, jintArray bonuses); - jobject JNICALL getSkillModBonuses(JNIEnv *env, jobject self, jlong target); - jint JNICALL getSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod); - jboolean JNICALL setSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod, jint bonus); - jboolean JNICALL setSkillModBonuses(JNIEnv *env, jobject self, jlong target, jobjectArray skillMod, jintArray bonus); - jboolean JNICALL setCategorizedSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring category, jstring skillMod, jint bonus); - void JNICALL removeCategorizedSkillModBonuses(JNIEnv *env, jobject self, jlong target, jstring category); - jint JNICALL getSkillModSockets(JNIEnv *env, jobject self, jlong target); - jboolean JNICALL setSkillModSockets(JNIEnv *env, jobject self, jlong target, jint sockets); - jlong JNICALL makeCraftedItem(JNIEnv *env, jobject self, jstring draftSchematic, jfloat qualityPercent, jlong container); - jobject JNICALL getSchematicData(JNIEnv *env, jobject self, jlong manufacturingSchematic); - jobject JNICALL getDraftSchematicData(JNIEnv *env, jobject self, jstring draftSchematic); - jobject JNICALL getDraftSchematicDataCrc(JNIEnv *env, jobject self, jint draftSchematicCrc); - void JNICALL recomputeCrateAttributes(JNIEnv *env, jobject self, jlong crate); -} - -using namespace ScriptMethodsCraftingNamespace; - - -//======================================================================== -// install -//======================================================================== - -bool ScriptMethodsCraftingNamespace::install() -{ -const JNINativeMethod NATIVES[] = { - #define JF(a,b,c) {a,b,(void*)(ScriptMethodsCraftingNamespace::c)} - JF("_startCraftingSession", "(JJ)Z", startCraftingSession), - JF("_endCraftingSession", "(JJJ)Z", endCraftingSession), - JF("_setCraftingLevelAndStation", "(JIJ)Z", setCraftingLevelAndStation), - JF("_getCraftingLevel", "(J)I", getCraftingLevel), - JF("_getCraftingStation", "(J)J", getCraftingStation), - JF("_sendUseableDraftSchematics", "(J[I)Z", sendUseableDraftSchematics), - JF("__setSchematicAttribute", "(JLscript/draft_schematic$attribute;Z)Z", setSchematicAttribute), - JF("__setSchematicAttributes", "(J[Lscript/draft_schematic$attribute;Z)Z", setSchematicAttributes), - JF("__getSchematicAttribute", "(JLscript/string_id;Z)Lscript/draft_schematic$attribute;", getSchematicAttribute), - JF("__getSchematicAttributes", "(J[Lscript/string_id;Z)[Lscript/draft_schematic$attribute;", getSchematicAttributes), - JF("__getAllSchematicAttributes", "(JZ)[Lscript/draft_schematic$attribute;", getAllSchematicAttributes), - JF("_getSchematicForExperimentalAttributes", "(J[Lscript/string_id;)Lscript/draft_schematic;", getSchematicForExperimentalAttributes), - JF("_setSchematicExperimentMod", "(JF)Z", setSchematicExperimentMod), - JF("_setSchematicAppearances", "(J[Ljava/lang/String;)Z", setSchematicAppearances), - JF("_setSchematicCustomizations", "(J[Lscript/draft_schematic$custom;)Z", setSchematicCustomizations), - JF("_getSchematicItemCount", "(J)I", getSchematicItemCount), - JF("_setSchematicItemCount", "(JI)Z", setSchematicItemCount), - JF("_getSchematicItemsPerContainer", "(J)I", getSchematicItemsPerContainer), - JF("_setSchematicItemsPerContainer", "(JI)Z", setSchematicItemsPerContainer), - JF("_getSchematicManufactureTime", "(J)F", getSchematicManufactureTime), - JF("_setSchematicManufactureTime", "(JF)Z", setSchematicManufactureTime), - JF("_setCreatorXp", "(JI)Z", setCreatorXp), - JF("_getIngredientsForManufactureStation", "(J[[Ljava/lang/String;)V", getIngredientsForManufactureStation), - JF("_getManufactureStationInputHopper", "(J)J", getManufactureStationInputHopper), - JF("_getManufactureStationOutputHopper", "(J)J", getManufactureStationOutputHopper), - JF("_getManufactureStationSchematic", "(J)Ljava/lang/String;", getManufactureStationSchematic), - JF("_getValidManufactureSchematicsForStation", "(JJ[[Ljava/lang/String;)V", getValidManufactureSchematicsForStation), - JF("_hasValidManufactureSchematicsForStation", "(JJ)Z", hasValidManufactureSchematicsForStation), - JF("_transferManufactureSchematicToPlayer", "(JJ)Z", transferManufactureSchematicToPlayer), - JF("_transferManufactureSchematicToStation", "(JJ)Z", transferManufactureSchematicToStation), - JF("_getRepairableObjectsForTool", "(JJ[[Ljava/lang/String;)V", getRepairableObjectsForTool), - JF("_getAttributeBonuses", "(J)[I", getAttributeBonuses), - JF("_getAttributeBonus", "(JI)I", getAttributeBonus), - JF("_setAttributeBonus", "(JII)Z", setAttributeBonus), - JF("_setAttributeBonuses", "(J[I)Z", setAttributeBonuses), - JF("_getSkillModBonuses", "(J)Lscript/dictionary;", getSkillModBonuses), - JF("_getSkillModBonus", "(JLjava/lang/String;)I", getSkillModBonus), - JF("_setSkillModBonus", "(JLjava/lang/String;I)Z", setSkillModBonus), - JF("_setSkillModBonuses", "(J[Ljava/lang/String;[I)Z", setSkillModBonuses), - JF("_setCategorizedSkillModBonus", "(JLjava/lang/String;Ljava/lang/String;I)Z", setCategorizedSkillModBonus), - JF("_removeCategorizedSkillModBonuses", "(JLjava/lang/String;)V", removeCategorizedSkillModBonuses), - JF("_getSkillModSockets", "(J)I", getSkillModSockets), - JF("_setSkillModSockets", "(JI)Z", setSkillModSockets), - JF("_makeCraftedItem", "(Ljava/lang/String;FJ)J", makeCraftedItem), - JF("_getSchematicData", "(J)Lscript/draft_schematic;", getSchematicData), - JF("getSchematicData", "(Ljava/lang/String;)Lscript/draft_schematic;", getDraftSchematicData), - JF("getSchematicData", "(I)Lscript/draft_schematic;", getDraftSchematicDataCrc), - JF("_recomputeCrateAttributes", "(J)V", recomputeCrateAttributes), -}; - - return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); -} - - -// ====================================================================== -// namespace ScriptMethodsCraftingNamespace -// ====================================================================== - -ScriptMethodsCraftingNamespace::VariableInfo::VariableInfo(std::string const &newName, int newMinValueInclusive, int newSetValue, int newMaxValueExclusive): - name(newName), - minValueInclusive(newMinValueInclusive), - value(newSetValue), - maxValueExclusive(newMaxValueExclusive) -{ -} - -// ---------------------------------------------------------------------- - -void ScriptMethodsCraftingNamespace::collectRangedIntVariableCallback(const std::string &fullVariablePathName, const CustomizationVariable *customizationVariable, void *context) -{ - //-- Check if variable is a palette-color style variable. If not, ignore for now. - // NOTE: replace PaletteColorCustomizationVariable with RangedIntCustomizatoinVariable - // if you want any ranged int (including texture choice ranges and palette colors) to be - // passed to crafting. - PaletteColorCustomizationVariable const *const paletteColorVariable = dynamic_cast(customizationVariable); - if (!paletteColorVariable) - { - // Nothing to do. - return; - } - - //-- Check if variable is a ranged int style variable. - RangedIntCustomizationVariable const *const rangedIntVariable = paletteColorVariable; - - //-- Get variable info list from context. - NOT_NULL(context); - VariableInfoVector *const variableInfoVector = static_cast(context); - - //-- Add variable info to vector. - int minValueInclusive = 0; - int maxValueExclusive = 0; - - rangedIntVariable->getRange(minValueInclusive, maxValueExclusive); - variableInfoVector->push_back(VariableInfo(fullVariablePathName, minValueInclusive, rangedIntVariable->getValue(), maxValueExclusive)); -} - -//======================================================================== -// class JavaLibrary crafting utility functions -//======================================================================== - -/** - * Creates a Java draft_schematic.attribute instance from an object attribute. - * - * @param manfSchematic manufacture schematic the attribute belongs to - * @param draftSchematic draft schematic the attribute belongs to - * @param attribIndex index of the attribute - * - * @return the attribute instance, or NULL on error - */ -LocalRefPtr JavaLibrary::createObjectAttribute(const ManufactureObjectInterface & manfSchematic, - const DraftSchematicObject & draftSchematic, int attribIndex) -{ - if (attribIndex < 0 || attribIndex >= draftSchematic.getAttribsCount()) - return LocalRef::cms_nullPtr; - - const SharedDraftSchematicObjectTemplate::SchematicAttribute & - minAttrib = draftSchematic.getAttribMin(attribIndex); - const SharedDraftSchematicObjectTemplate::SchematicAttribute & - maxAttrib = draftSchematic.getAttribMax(attribIndex); - - if (minAttrib.name.getTable().empty() || minAttrib.name.getText().empty()) - return LocalRef::cms_nullPtr; - - // create the attribute object - LocalRefPtr attribute = allocObject(JavaLibrary::getClsDraftSchematicAttrib()); - if (attribute == LocalRef::cms_nullPtr) - return LocalRef::cms_nullPtr; - - // set the name - LocalRefPtr name; - if (!ScriptConversion::convert(minAttrib.name, name)) - return LocalRef::cms_nullPtr; - - setObjectField(*attribute, JavaLibrary::getFidDraftSchematicAttribName(), *name); - - // get the resourceMax and current values - float minValue = static_cast(minAttrib.value); - float maxValue = static_cast(maxAttrib.value); - float resourceMaxValue = maxValue; - float currentValue = minValue; - - std::map::const_iterator result = manfSchematic.getAttributes().find( - minAttrib.name); - if (result != manfSchematic.getAttributes().end()) - currentValue = (*result).second; - - result = manfSchematic.getResourceMaxAttributes().find( - minAttrib.name); - if (result != manfSchematic.getResourceMaxAttributes().end()) - resourceMaxValue = (*result).second; - - // set the other fields - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMinValue(), minValue); - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue(), maxValue); - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue(), resourceMaxValue); - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue(), currentValue); - - return attribute; -} // JavaLibrary::createObjectAttribute - -/** - * Creates a Java draft_schematic.attribute instance from an experimental attribute. - * - * @param manfSchematic manufacture schematic the attribute belongs to - * @param attribName name of the attribute - * - * @return the attribute instance, or NULL on error - */ -LocalRefPtr JavaLibrary::createExperimentAttribute(const ManufactureObjectInterface & manfSchematic, - const StringId & attribName) -{ - if (attribName.getTable().empty() || attribName.getText().empty()) - return LocalRef::cms_nullPtr; - - // create the attribute object - LocalRefPtr attribute = allocObject(JavaLibrary::getClsDraftSchematicAttrib()); - if (attribute == LocalRef::cms_nullPtr) - return LocalRef::cms_nullPtr; - - // set the name - LocalRefPtr name; - if (!ScriptConversion::convert(attribName, name)) - return LocalRef::cms_nullPtr; - - setObjectField(*attribute, JavaLibrary::getFidDraftSchematicAttribName(), *name); - - // set the other fields - float value, minValue, maxValue, resourceValue; - manfSchematic.getAllExperimentAttributeValues(attribName, value, minValue, maxValue, - resourceValue); - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue(), value); - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMinValue(), minValue); - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue(), maxValue); - setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue(), resourceValue); - - return attribute; -} // JavaLibrary::createExperimentAttribute - - -//======================================================================== -// class JavaLibrary JNI conversion methods -//======================================================================== - -/** - * Converts a C++ ManufactureSchematicObject to a Java draft_schematic. - * - * @param source the ManufactureSchematicObject to convert - * - * @return a new draft_schematic object - */ -LocalRefPtr JavaLibrary::convert(const ManufactureObjectInterface & source) -{ -int i; - - const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( - source.getDraftSchematic()); - if (draft == NULL) - return LocalRef::cms_nullPtr; - - LocalRefPtr target = allocObject(ms_clsDraftSchematic); - if (target == LocalRef::cms_nullPtr) - return LocalRef::cms_nullPtr; - - // set the ingredients - int numSlots = source.getSlotsCount(); - LocalObjectArrayRefPtr slots = createNewObjectArray(numSlots, ms_clsDraftSchematicSlot); - if (slots == LocalObjectArrayRef::cms_nullPtr) - return LocalRef::cms_nullPtr; - - Crafting::IngredientSlot sourceSlot; - ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; - for (i = 0; i < numSlots; ++i) - { - if (!source.getSlot(i, sourceSlot, true)) - { - WARNING(true, ("JavaLibrary::convert manf data: unable to get slot %d " - "from manf schematic %s", i, source.getDerivedNetworkId().getValueString().c_str())); - break; - } - - // get the amount of ingredient required from the draft schematic - if (!draft->getSlot(draftSlot, sourceSlot.name)) - { - WARNING(true, ("JavaLibrary::convert manf data: unable to get slot %s " - "from draft schematic %s", sourceSlot.name.getCanonicalRepresentation().c_str(), - draft->getObjectTemplateName())); - break; - } - int amountRequired = draftSlot.options[sourceSlot.draftSlotOption]. - ingredients[0].count; - - // create the ingredient object - LocalRefPtr slot = convert(source, sourceSlot, amountRequired, - draftSlot.appearance, draftSlot.options[0].ingredients[0].ingredient); - if (slot == LocalRef::cms_nullPtr) - { - WARNING(true, ("Unable to convert schematic slot %s to Java data", - sourceSlot.name.getCanonicalRepresentation().c_str())); - break; - } - - setObjectArrayElement(*slots, i, *slot); - } - if (i != numSlots) - { - return LocalRef::cms_nullPtr; - } - setObjectField(*target, ms_fidDraftSchematicSlots, *slots); - - // if we are converting the schematic in order to manufacture an object, - // just convert the object attributes and ingredient sources and exit - if (source.isMakingObject()) - { - int numObjectAttribs = draft->getAttribsCount(); - LocalObjectArrayRefPtr attributes = createNewObjectArray(numObjectAttribs, JavaLibrary::getClsDraftSchematicAttrib()); - if (attributes == LocalObjectArrayRef::cms_nullPtr) - { - return LocalRef::cms_nullPtr; - } - for (i = 0; i < numObjectAttribs; ++i) - { - // create the attribute object - LocalRefPtr attribute = JavaLibrary::createObjectAttribute(source, *draft, i); - if (attribute == LocalRef::cms_nullPtr) - break; - setObjectArrayElement(*attributes, i, *attribute); - } - if (i != numObjectAttribs) - { - return LocalRef::cms_nullPtr; - } - setObjectField(*target, ms_fidDraftSchematicAttribs, *attributes); - return target; - } - - // set the crafting category - setIntField(*target, ms_fidDraftSchematicCategory, draft->getCategory()); - // set the base complexity - setFloatField(*target, ms_fidDraftSchematicComplexity, draft->getComplexity()); - - // - // set the attributes, the experimental attributes, and the mapping between them - // - - LocalRefPtr attribMap = createNewObject(ms_clsHashtable, ms_midHashtable); - if (attribMap == LocalRef::cms_nullPtr) - return LocalRef::cms_nullPtr; - - // create a local frame reference big enough so we can keep around the - // references to the object attributes and experiment attributes - const std::vector & experimentNames = source.getExperimentAttributeNames(); - int numExperimentAttribs = experimentNames.size(); - int numObjectAttribs = draft->getAttribsCount(); - - // set the experimental attributes - std::vector experimentAttribRefs; - LocalObjectArrayRefPtr attributes = createNewObjectArray(numExperimentAttribs, JavaLibrary::getClsDraftSchematicAttrib()); - if (attributes == LocalObjectArrayRef::cms_nullPtr) - { - return LocalRef::cms_nullPtr; - } - for (i = 0; i < numExperimentAttribs; ++i) - { - // create the attribute object - LocalRefPtr attribute = JavaLibrary::createExperimentAttribute(source, experimentNames[i]); - if (attribute == LocalRef::cms_nullPtr) - break; - - setObjectArrayElement(*attributes, i, *attribute); - experimentAttribRefs.push_back(attribute); - } - if (i != numExperimentAttribs) - { - return LocalRef::cms_nullPtr; - } - setObjectField(*target, ms_fidDraftSchematicExperimentalAttribs, *attributes); - - // set the object attributes - attributes = createNewObjectArray(numObjectAttribs, JavaLibrary::getClsDraftSchematicAttrib()); - if (attributes == LocalObjectArrayRef::cms_nullPtr) - { - return LocalRef::cms_nullPtr; - } - for (i = 0; i < numObjectAttribs; ++i) - { - // create the attribute object - LocalRefPtr attribute = JavaLibrary::createObjectAttribute(source, *draft, i); - if (attribute == LocalRef::cms_nullPtr) - break; - setObjectArrayElement(*attributes, i, *attribute); - - // find the experimental attribute associated with the object attibute - // and add it to the attribute map - StringId expAttrib(draft->getExperimentalAttributeFromAttribute(i)); - for (int j = 0; j < numExperimentAttribs; ++j) - { - if (expAttrib == experimentNames[j]) - { - callObjectMethod(*attribMap, ms_midMapPut, - attribute->getValue(), experimentAttribRefs[j]->getValue()); - break; - } - } - } - if (i != numObjectAttribs) - { - return LocalRef::cms_nullPtr; - } - setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribs(), *attributes); - setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribMap(), *attribMap); - - // restore our frame reference - experimentAttribRefs.clear(); - - // set the customization info from the shared object template - const ServerObjectTemplate * objectTemplate = draft->getCraftedObjectTemplate(); - if (objectTemplate == NULL) - { - return LocalRef::cms_nullPtr; - } - const SharedObjectTemplate * sharedTemplate = safe_cast( - ObjectTemplateList::fetch(objectTemplate->getSharedTemplate())); - const SharedTangibleObjectTemplate * sharedTangibleTemplate = dynamic_cast< - const SharedTangibleObjectTemplate *>(sharedTemplate); - if (sharedTangibleTemplate != NULL) - { - // New method using the AssetCustomizationManager mechanism. - - //-- Retrieve customization declarations for the appearance asset associated with - // the crafted object's shared object template. - - // Create a dummy object. - Object *dummyObject = new MemoryBlockManagedObject(); - NOT_NULL(dummyObject); - - // Create a CustomizationData instance. - CustomizationData *customizationData = new CustomizationData(*dummyObject); - NOT_NULL(customizationData); - customizationData->fetch(); - - // Retrieve CustomizationData for crafted object's appearance template name. - bool const skipSharedOwnerVariables = true; - AssetCustomizationManager::addCustomizationVariablesForAsset(TemporaryCrcString(sharedTangibleTemplate->getAppearanceFilename().c_str(), true), *customizationData, skipSharedOwnerVariables); - - // Retrieve all ranged int customization variables from CusotmizationData. - VariableInfoVector variableInfoList; - bool const includeRemoveVariables = false; - customizationData->iterateOverConstVariables(collectRangedIntVariableCallback, &variableInfoList, includeRemoveVariables); - - int const count = static_cast(variableInfoList.size()); -#ifdef _DEBUG - LOG("crafting-customizations", ("customization variable count: %d for (%s)", count, sharedTangibleTemplate->getAppearanceFilename().c_str())); -#endif - - //-- Create the Java array to hold the ranged int customization entries. - LocalObjectArrayRefPtr customizations = createNewObjectArray(count, ms_clsDraftSchematicCustom); - if (customizations == LocalObjectArrayRef::cms_nullPtr) - { - customizationData->release(); - delete dummyObject; - return LocalRef::cms_nullPtr; - } - - //-- Fill in the Java array with customization entries. - int i; - - for (i = 0; i < count; ++i) - { - VariableInfo const &info = variableInfoList[static_cast(i)]; - - // create the customization object - LocalRefPtr customization = allocObject(ms_clsDraftSchematicCustom); - if (customization == LocalRef::cms_nullPtr) - break; - - // set the name - JavaString name(info.name.c_str()); - setObjectField(*customization, JavaLibrary::getFidDraftSchematicCustomName(), name); - - // set the values - setIntField(*customization, JavaLibrary::getFidDraftSchematicCustomValue(), info.value); - setIntField(*customization, JavaLibrary::getFidDraftSchematicCustomMinValue(), info.minValueInclusive); - setIntField(*customization, JavaLibrary::getFidDraftSchematicCustomMaxValue(), info.maxValueExclusive - 1); -// setBooleanField(*customization, ms_fidDraftSchematicCustomLocked, -// JNI_FALSE); - - setObjectArrayElement(*customizations, i, *customization); - } - if (i != count) - { - customizationData->release(); - delete dummyObject; - return LocalRef::cms_nullPtr; - } - setObjectField(*target, ms_fidDraftSchematicCustomizations, *customizations); - - //-- Cleanup. - customizationData->release(); - delete dummyObject; - } - else - setObjectField(*target, ms_fidDraftSchematicCustomizations, LocalRef(0)); - - return target; -} // JavaLibrary::convert(const ManufactureObjectInterface &) - -/** - * Converts a C++ Crafting::IngredientSlot to a Java draft_schematic$slot. - * - * @param schematic the manf schematic the slot belongs to - * @param source the IngredientSlot to convert - * @param amountRequired amount of ingredients required to fill the slot - * @param appearance appearance data associated with the slot - * @param requiredIngredient name of the ingredient needed for the slot - * - * @return a new draft_schematic object - */ -LocalRefPtr JavaLibrary::convert(const ManufactureObjectInterface & schematic, - const Crafting::IngredientSlot & source, int amountRequired, - const std::string & appearance, const std::string & requiredIngredient) -{ - int i; - - // create the slot object - LocalRefPtr slot = allocObject(ms_clsDraftSchematicSlot); - if (slot == LocalRef::cms_nullPtr) - return LocalRef::cms_nullPtr; - - // set the slot name - LocalRefPtr slotName; - if (!ScriptConversion::convert(source.name, slotName)) - { - return LocalRef::cms_nullPtr; - } - setObjectField(*slot, ms_fidDraftSchematicSlotName, *slotName); - - // set the slot appearance data - JavaString appearanceName(appearance.c_str()); - setObjectField(*slot, ms_fidDraftSchematicSlotAppearance, appearanceName); - - JavaString ingredientName(requiredIngredient); - if (ingredientName.getValue() == 0) - return LocalRef::cms_nullPtr; - - // set the slot data - setIntField(*slot, ms_fidDraftSchematicSlotOption, source.draftSlotOption); - setIntField(*slot, ms_fidDraftSchematicSlotIngredientType, source.ingredientType); - setFloatField(*slot, ms_fidDraftSchematicSlotComplexity, source.complexity); - setIntField(*slot, ms_fidDraftSchematicSlotAmountRequired, amountRequired); - setObjectField(*slot, ms_fidDraftSchematicSlotIngredientName, ingredientName); - - // create the ingredients array - int count = source.ingredients.size(); - LocalObjectArrayRefPtr ingredients = createNewObjectArray(count, ms_clsDraftSchematicSimpleIngredient); - if (ingredients == LocalObjectArrayRef::cms_nullPtr) - { - return LocalRef::cms_nullPtr; - } - for (i = 0; i < count; ++i) - { - // create the ingredient object - LocalRefPtr ingredient = allocObject(ms_clsDraftSchematicSimpleIngredient); - if (ingredient == LocalRef::cms_nullPtr) - { - WARNING(true, ("Unable to allocate Java memory for simple ingredient data")); - break; - } - - // set the ingredient source and xp type - LocalRefPtr sourceId = getObjId(source.ingredients[i]->source); - setObjectField(*ingredient, ms_fidDraftSchematicSimpleIngredientSource, - *sourceId); - setIntField(*ingredient, ms_fidDraftSchematicSimpleIngredientXpType, - source.ingredients[i]->xpType); - - - // set the ingredient id - if (source.ingredientType == Crafting::IT_resourceType || - source.ingredientType == Crafting::IT_resourceClass) - { - LocalRefPtr ingredientId = getObjId(source.ingredients[i]->ingredient); - if (ingredientId == LocalRef::cms_nullPtr) - { - WARNING(true, ("Unable to convert ingredient resource network id " - "%s to a Java obj_id", source.ingredients[i]->ingredient.getValueString().c_str())); - break; - } - setObjectField(*ingredient, ms_fidDraftSchematicSimpleIngredientIngredient, - *ingredientId); - } - else - { - const Crafting::ComponentIngredient * componentData = safe_cast< - const Crafting::ComponentIngredient *>(source.ingredients[i].get()); -// TangibleObject * component = schematic.getComponent(*componentData); -// NOT_NULL(component); -// LocalRef ingredientId(getObjId(component->getNetworkId())); - LocalRefPtr componentId = getObjId(componentData->ingredient); - if (componentId == LocalRef::cms_nullPtr) - { - WARNING(true, ("Unable to convert ingredient component network id " - "%s to a Java obj_id", componentData->ingredient.getValueString().c_str())); - break; - } - setObjectField(*ingredient, ms_fidDraftSchematicSimpleIngredientIngredient, - *componentId); - setIntField(*ingredient, ms_fidDraftSchematicSimpleIngredientXpAmount, - componentData->sourceXp); - } - - // set the ingredient count - setIntField(*ingredient, ms_fidDraftSchematicSimpleIngredientCount, - source.ingredients[i]->count); - - setObjectArrayElement(*ingredients, i, *ingredient); - } - if (i != count) - { - return LocalRef::cms_nullPtr; - } - setObjectField(*slot, ms_fidDraftSchematicSlotIngredients, *ingredients); - - return slot; -} // JavaLibrary::convert(const Crafting::IngredientSlot &) - -/** - * Converts a C++ DraftSchematicObject to a Java draft_schematic. - * - * @param source the DraftSchematicObject to convert - * - * @return a new draft_schematic object - */ -jobject JavaLibrary::convert(const DraftSchematicObject & source) -{ -int i; - - LocalRefPtr target = allocObject(ms_clsDraftSchematic); - if (target == LocalRef::cms_nullPtr) - return 0; - - // set the ingredients/slots - int numSlots = source.getSlotsCount(); - LocalObjectArrayRefPtr slots = createNewObjectArray(numSlots, ms_clsDraftSchematicSlot); - if (slots == LocalObjectArrayRef::cms_nullPtr) - return 0; - - ServerDraftSchematicObjectTemplate::IngredientSlot slot; - for (i = 0; i < numSlots; ++i) - { - if (!source.getSlot(slot, i)) - { - WARNING(true, ("JavaLibrary::convert draft data: unable to get slot %d " - "from draft schematic %s", i, source.getObjectTemplateName())); - break; - } - - if (slot.options.empty()) - { - WARNING(true, ("JavaLibrary::convert draft data: slot %d in draft " - "schematic %s has no options", i, source.getObjectTemplateName())); - break; - } - if (slot.options[0].ingredients.empty()) - { - WARNING(true, ("JavaLibrary::convert draft data: slot %d in draft " - "schematic %s has no ingredients", i, source.getObjectTemplateName())); - break; - } - - JavaString appearanceName(slot.appearance); - if (appearanceName.getValue() == 0) - break; - JavaString ingredientName(slot.options[0].ingredients[0].ingredient); - if (ingredientName.getValue() == 0) - break; - LocalRefPtr slotName; - if (!ScriptConversion::convert(slot.name, slotName)) - break; - - LocalRefPtr jslot = allocObject(ms_clsDraftSchematicSlot); - if (jslot == LocalRef::cms_nullPtr) - break; - - setObjectField(*jslot, ms_fidDraftSchematicSlotName, *slotName); - setObjectField(*jslot, ms_fidDraftSchematicSlotIngredientName, ingredientName); - setObjectField(*jslot, ms_fidDraftSchematicSlotIngredients, LocalRef(0)); - setObjectField(*jslot, ms_fidDraftSchematicSlotAppearance, appearanceName); - setIntField(*jslot, ms_fidDraftSchematicSlotOption, 0); - setIntField(*jslot, ms_fidDraftSchematicSlotIngredientType, slot.options[0].ingredientType); - setIntField(*jslot, ms_fidDraftSchematicSlotAmountRequired, slot.options[0].ingredients[0].count); - setFloatField(*jslot, ms_fidDraftSchematicSlotComplexity, slot.complexity); - setObjectArrayElement(*slots, i, *jslot); - } - if (i != numSlots) - { - return 0; - } - setObjectField(*target, ms_fidDraftSchematicSlots, *slots); - - // set the attributes - int numAttributes = source.getAttribsCount(); - LocalObjectArrayRefPtr attribs = createNewObjectArray(numAttributes, JavaLibrary::getClsDraftSchematicAttrib()); - if (attribs == LocalObjectArrayRef::cms_nullPtr) - return 0; - int minValue = 0; - int maxValue = 0; - for (i = 0; i < numAttributes; ++i) - { - const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = - source.getAttrib(i); - source.getAttribMinMax(i, minValue, maxValue); - - LocalRefPtr attribName; - if (!ScriptConversion::convert(attrib.name, attribName)) - break; - - LocalRefPtr jattrib = allocObject(JavaLibrary::getClsDraftSchematicAttrib()); - if (jattrib == LocalRef::cms_nullPtr) - break; - - setObjectField(*jattrib, JavaLibrary::getFidDraftSchematicAttribName(), *attribName); - setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribMinValue(), static_cast(minValue)); - setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribMaxValue(), static_cast(maxValue)); - setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue(), 0); - setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribCurrentValue(), 0); - setObjectArrayElement(*attribs, i, *jattrib); - } - if (i != numAttributes) - { - return 0; - } - setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribs(), *attribs); - - // set the created item template crc value - const ServerObjectTemplate * craftedTemplate = source.getCraftedObjectTemplate(); - if (craftedTemplate == NULL) - { - WARNING(true, ("JavaLibrary::convert DraftSchematicObject got null crafted " - "template for draft schematic %s", source.getObjectTemplateName())); - return 0; - } - setIntField(*target, ms_fidDraftSchematicObjectTemplateCreated, craftedTemplate->getCrcName().getCrc()); - - // set the script value - const ServerDraftSchematicObjectTemplate * const sourceSchematicTemplate = - safe_cast(source.getObjectTemplate()); - NOT_NULL(sourceSchematicTemplate); - if (sourceSchematicTemplate == NULL) - { - // emergency case for release mode - return 0; - } - const int numScripts = sourceSchematicTemplate->getManufactureScriptsCount(); - LocalObjectArrayRefPtr scripts = createNewObjectArray(numScripts, JavaLibrary::getClsString()); - if (scripts == LocalObjectArrayRef::cms_nullPtr) - { - WARNING(true, ("JavaLibrary::convert DraftSchematicObject could not allocate " - "script array for draft schematic %s", source.getObjectTemplateName())); - return 0; - } - for (i = 0; i < numScripts; ++i) - { - JavaString script(sourceSchematicTemplate->getManufactureScripts(i)); - setObjectArrayElement(*scripts, i, script); - } - setObjectField(*target, ms_fidDraftSchematicScripts, *scripts); - - return target->getReturnValue(); -} // JavaLibrary::convert(const DraftSchematicObject &) - - -//======================================================================== -// class JavaLibrary JNI crafting callback methods -//======================================================================== - -/** - * Starts a crafting session. - * - * @param env Java environment - * @param self class calling this function - * @param player the player who will be crafting - * @param station the design station a player will be using - * - * @return true on success, false on fail - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::startCraftingSession(JNIEnv *env, jobject self, jlong player, jlong station) -{ - UNREF(env); - UNREF(self); - - CreatureObject* playerObj = NULL; - if (!JavaLibrary::getObject(player, playerObj)) - return JNI_FALSE; - - TangibleObject* stationObj = NULL; - if (!JavaLibrary::getObject(station, stationObj)) - return JNI_FALSE; - - if (!stationObj->startCraftingSession(*playerObj)) - return JNI_FALSE; - - return JNI_TRUE; -} // JavaLibrary::startCraftingSession - -/** - * Ends a crafting session. - * - * @param env Java environment - * @param self class calling this function - * @param crafter the player that was crafting - * @param tool the crafting tool that was being used - * @param prototype the prototype that was created (may be null) - * - * @return true on success, false on fail - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::endCraftingSession(JNIEnv *env, jobject self, jlong crafter, jlong tool, jlong prototype) -{ - UNREF(env); - UNREF(self); - UNREF(tool); - - // we're only do things if there's a prototype - if (prototype == 0) - return JNI_TRUE; - - CreatureObject * crafterObj = NULL; - if (!JavaLibrary::getObject(crafter, crafterObj)) - return JNI_FALSE; - - TangibleObject * prototypeObj = NULL; - if (!JavaLibrary::getObject(prototype, prototypeObj)) - return JNI_FALSE; - - // tell the crafter to create the prototype - ObserveTracker::onCraftingEndCraftingSession(*crafterObj, *prototypeObj); - - return JNI_TRUE; -} // JavaLibrary::endCraftingSession - -/** - * Sets the crafting level and station of a player's crafting session. - * - * @param env Java environment - * @param self class calling this function - * @param player the player who's crafting - * @param craftingLevel the crafting level of the session - * @param station the crafting station of the session - * - * @return true if the data was set, false on error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setCraftingLevelAndStation(JNIEnv *env, jobject self, jlong player, jint craftingLevel, jlong station) -{ - UNREF(self); - - CreatureObject* creatureObject = NULL; - if (!JavaLibrary::getObject(player, creatureObject)) - return JNI_FALSE; - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if (playerObject == NULL) - return JNI_FALSE; - - if (craftingLevel >= 0 && craftingLevel <= Crafting::MAX_CRAFTING_LEVEL) - playerObject->setCraftingLevel(craftingLevel); - - if (station != 0) - { - const TangibleObject * stationObject = NULL; - const NetworkId stationId(station); - if (stationId != NetworkId::cms_invalid) - { - stationObject = dynamic_cast(ServerWorld::findObjectByNetworkId(stationId)); - if (stationObject == NULL) - return JNI_FALSE; - } - playerObject->setCraftingStation(stationObject); - } - - return JNI_TRUE; -} // JavaLibrary::setCraftingLevelAndStation - -/** - * Gets the crafting level of a player's crafting session. - * - * @param env Java environment - * @param self class calling this function - * @param player the player who's crafting - * - * @return the crafting level, or -1 on error - */ -jint JNICALL ScriptMethodsCraftingNamespace::getCraftingLevel(JNIEnv *env, jobject self, jlong player) -{ - UNREF(self); - - const CreatureObject* creatureObject = NULL; - if (!JavaLibrary::getObject(player, creatureObject)) - return -1; - const PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if (playerObject == NULL) - return -1; - - return playerObject->getCraftingLevel(); -} // JavaLibrary::getCraftingLevel - -/** - * Gets the crafting station of a player's crafting session. - * - * @param env Java environment - * @param self class calling this function - * @param player the player who's crafting - * - * @return the crafting station, or 0 on error - */ -jlong JNICALL ScriptMethodsCraftingNamespace::getCraftingStation(JNIEnv *env, jobject self, jlong player) -{ - UNREF(self); - - const CreatureObject* creatureObject = NULL; - if (!JavaLibrary::getObject(player, creatureObject)) - return 0; - const PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if (playerObject == NULL) - return 0; - - return (playerObject->getCraftingStation()).getValue(); -} // JavaLibrary::getCraftingStation - -/** - * Sends a list of draft schematics to a player that he may select to craft an item. - * - * @param env Java environment - * @param self class calling this function - * @param player the player trying to use the station - * @param schematics list of schematic template name crcs the player may use to craft an item - * - * @return true on success, false if there was an error - **/ -jboolean JNICALL ScriptMethodsCraftingNamespace::sendUseableDraftSchematics(JNIEnv *env, jobject self, jlong player, jintArray schematics) -{ - UNREF(self); - - CreatureObject* creatureObject = NULL; - if (!JavaLibrary::getObject(player, creatureObject)) - return JNI_FALSE; - PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); - if (playerObject == NULL) - { - DEBUG_WARNING(true, ("JavaLibrary::sendUseableDraftSchematics non-player " - "object %s\n", creatureObject->getNetworkId().getValueString().c_str())); - return JNI_FALSE; - } - - int count = env->GetArrayLength(schematics); - if (count == 0) - return JNI_FALSE; - - jint * schematicsArray = env->GetIntArrayElements(schematics, NULL); - if (schematicsArray != NULL) - { - std::vector schematicCrcs(schematicsArray, &schematicsArray[count]); - playerObject->sendUseableDraftSchematics(schematicCrcs); - env->ReleaseIntArrayElements(schematics, schematicsArray, JNI_ABORT); - } - else - { - std::vector schematicCrcs; - playerObject->sendUseableDraftSchematics(schematicCrcs); - } - - return JNI_TRUE; -} // JavaLibrary::sendUseableDraftSchematics - -/** - * Sets an attribute for a manufacturing schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param attribute the attribute info to set - * @param experiment flag that these are experimental attributes - * - * @return true on success, false if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject attribute, jboolean experiment) -{ - UNREF(self); - - if (manufacturingSchematic == 0 || attribute == 0) - return JNI_FALSE; - - ManufactureObjectInterface * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - LocalRefPtr attrName = getObjectField(LocalRefParam(attribute), JavaLibrary::getFidDraftSchematicAttribName()); - jfloat value = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue()); - jfloat resourceValue = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue()); - - if (attrName == LocalRef::cms_nullPtr) - return JNI_FALSE; - - StringId name; - if (!ScriptConversion::convert(*attrName, name)) - return JNI_FALSE; - - if (experiment) - { - schematic->setExperimentAttribute(name, value); - jfloat minValue = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribMinValue()); - jfloat maxValue = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue()); - schematic->setExperimentAttributeLimits(name, minValue, maxValue, resourceValue); - } - else - { - schematic->setAttribute(name, value); - schematic->setResourceMaxAttribute(name, resourceValue); - } - return JNI_TRUE; -} // JavaLibrary::setSchematicAttribute - -/** - * Sets attributes for a manufacturing schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param attributes list of attribute info to set - * @param experiment flag that these are experimental attributes - * - * @return true on success, false if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributes, jboolean experiment) -{ - UNREF(self); - - if (manufacturingSchematic == 0 || attributes == 0) - return JNI_FALSE; - - ManufactureObjectInterface * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - StringId name; - int count = env->GetArrayLength(attributes); - for (int i = 0; i < count; ++i) - { - LocalRefPtr attribute = getObjectArrayElement(LocalObjectArrayRefParam(attributes), i); - if (attribute != LocalRef::cms_nullPtr) - { - LocalRefPtr attrName = getObjectField(*attribute, JavaLibrary::getFidDraftSchematicAttribName()); - jfloat value = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue()); - jfloat resourceValue = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue()); - - if (attrName != LocalRef::cms_nullPtr) - { - if (ScriptConversion::convert(*attrName, name)) - { - if (experiment) - { - schematic->setExperimentAttribute(name, value); - jfloat minValue = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMinValue()); - jfloat maxValue = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue()); - schematic->setExperimentAttributeLimits(name, - minValue, maxValue, resourceValue); - } - else - { - schematic->setAttribute(name, value); - schematic->setResourceMaxAttribute(name, resourceValue); - } - } - } - } - } - - return JNI_TRUE; -} // JavaLibrary::setSchematicAttributes - -/** - * Gets an attribute of a manufacturing schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param name name of the attribute to get - * @param experiment flag that these are experimental attributes - * - * @return the attribute, or null on error - */ -jobject JNICALL ScriptMethodsCraftingNamespace::getSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject name, jboolean experiment) -{ - UNREF(self); - - if (manufacturingSchematic == 0 || name == 0) - return 0; - - ManufactureObjectInterface * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return 0; - - const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( - schematic->getDraftSchematic()); - if (draft == NULL) - return 0; - - StringId nameId; - if (!ScriptConversion::convert(name, nameId)) - return 0; - - if (experiment) - { - return JavaLibrary::createExperimentAttribute(*schematic, nameId)->getReturnValue(); - } - else - { - return JavaLibrary::createObjectAttribute(*schematic, *draft, draft->getAttribIndex(nameId))->getReturnValue(); - } -} // JavaLibrary::getSchematicAttribute - -/** - * Gets a select list of the attributes of a manufacturing schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param names names of the attributes to get - * @param experiment flag that these are experimental attributes - * - * @return the attributes, or null on error - */ -jobjectArray JNICALL ScriptMethodsCraftingNamespace::getSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray names, jboolean experiment) -{ - UNREF(self); - - if (manufacturingSchematic == 0) - return 0; - - ManufactureObjectInterface * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return 0; - - const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( - schematic->getDraftSchematic()); - if (draft == NULL) - return 0; - - int numAttribs = env->GetArrayLength(names); - - // create the attribute array - LocalObjectArrayRefPtr attributes = createNewObjectArray(numAttribs, JavaLibrary::getClsDraftSchematicAttrib()); - if (attributes == LocalObjectArrayRef::cms_nullPtr) - return 0; - - int i; - StringId attribName; - for (i = 0; i < numAttribs; ++i) - { - LocalRefPtr name = getObjectArrayElement(LocalObjectArrayRefParam(names), i); - if (!ScriptConversion::convert(*name, attribName)) - break; - - // create the attribute object - LocalRefPtr attribute; - if (experiment) - { - attribute = JavaLibrary::createExperimentAttribute(*schematic, attribName); - } - else - { - attribute = JavaLibrary::createObjectAttribute(*schematic, *draft, draft->getAttribIndex( - attribName)); - } - if (attribute == LocalRef::cms_nullPtr) - break; - - setObjectArrayElement(*attributes, i, *attribute); - } - - if (i != numAttribs) - { - attributes = LocalObjectArrayRef::cms_nullPtr; - } - - return attributes->getReturnValue(); -} // JavaLibrary::getSchematicAttributes - -/** - * Gets all the attributes of a manufacturing schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param experiment flag that these are experimental attributes - * - * @return the attributes, or null on error - */ -jobjectArray JNICALL ScriptMethodsCraftingNamespace::getAllSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jboolean experiment) -{ - UNREF(env); - UNREF(self); - - if (manufacturingSchematic == 0) - return 0; - - ManufactureObjectInterface * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return 0; - - const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( - schematic->getDraftSchematic()); - if (draft == NULL) - return 0; - - // set the attributes - int numAttribs = 0; - const std::vector & experimentNames = schematic->getExperimentAttributeNames(); - if (experiment) - numAttribs = experimentNames.size(); - else - numAttribs = draft->getAttribsCount(); - LocalObjectArrayRefPtr attributes = createNewObjectArray(numAttribs, JavaLibrary::getClsDraftSchematicAttrib()); - if (attributes == LocalObjectArrayRef::cms_nullPtr) - return 0; - - for (int i = 0; i < numAttribs; ++i) - { - // create the attribute object - LocalRefPtr attribute; - if (experiment) - { - attribute = JavaLibrary::createExperimentAttribute(*schematic, experimentNames[i]); - } - else - { - attribute = JavaLibrary::createObjectAttribute(*schematic, *draft, i); - } - - setObjectArrayElement(*attributes, i, *attribute); - } - - return attributes->getReturnValue(); -} // JavaLibrary::getAllSchematicAttributes - -//---------------------------------------------------------------------- - -/** - * Returns a draft_schematic structure filled in with info about requested - * experimental attributes. The info will consist of the experimentation attribute - * data, the object attributes associated with them, and a mapping between the two. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic to get the data from - * @param attributeNames the experimental attributes we're interested about - * - * @return the draft_schematic object, or null on error - */ -jobject JNICALL ScriptMethodsCraftingNamespace::getSchematicForExperimentalAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributeNames) -{ -int i; - - UNREF(self); - - if (manufacturingSchematic == 0 || attributeNames == 0) - return 0; - - const ManufactureObjectInterface * manfSchematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, manfSchematic)) - return 0; - - const DraftSchematicObject * draftSchematic = DraftSchematicObject::getSchematic( - manfSchematic->getDraftSchematic()); - if (draftSchematic == NULL) - return 0; - - // create a draft_schematic object to return - LocalRefPtr target = allocObject(JavaLibrary::getClsDraftSchematic()); - if (target == LocalRef::cms_nullPtr) - return 0; - - // create the experimental attributes array - int numExperimentAttribs = env->GetArrayLength(attributeNames); - LocalObjectArrayRefPtr experimentalAttribs = createNewObjectArray(numExperimentAttribs, - JavaLibrary::getClsDraftSchematicAttrib()); - if (experimentalAttribs == LocalObjectArrayRef::cms_nullPtr) - return 0; - - // create the object attributes array - int numObjectAttribs = draftSchematic->getAttribsCount(); - LocalObjectArrayRefPtr objectAttribs = createNewObjectArray(numObjectAttribs, - JavaLibrary::getClsDraftSchematicAttrib()); - if (objectAttribs == LocalObjectArrayRef::cms_nullPtr) - return 0; - - // create a map of experimental attributes to object attributes - LocalRefPtr attribMap = createNewObject(JavaLibrary::getClsHashtable(), JavaLibrary::getMidHashtable()); - if (attribMap == LocalRef::cms_nullPtr) - return 0; - - std::vector objectAttribRefs; - - // create the object attributes objects - for (i = 0; i < numObjectAttribs; ++i) - { - // create the attribute object - LocalRefPtr attribute = JavaLibrary::createObjectAttribute(*manfSchematic, *draftSchematic, i); - if (attribute == LocalRef::cms_nullPtr) - { - objectAttribRefs.clear(); - return 0; - } - - setObjectArrayElement(*objectAttribs, i, *attribute); - objectAttribRefs.push_back(attribute); - } - setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribs(), *objectAttribs); - - // create the experimental attribute objects - StringId experimentAttribName; - for (i = 0; i < numExperimentAttribs; ++i) - { - // get the experimental attribute name - LocalRefPtr name = getObjectArrayElement(LocalObjectArrayRefParam(attributeNames), i); - if (name == LocalRef::cms_nullPtr) - { - objectAttribRefs.clear(); - return 0; - } - - if (!ScriptConversion::convert(*name, experimentAttribName)) - { - objectAttribRefs.clear(); - return 0; - } - - // get the data for the experimental attribute - LocalRefPtr attribute = JavaLibrary::createExperimentAttribute(*manfSchematic, - experimentAttribName); - if (attribute == LocalRef::cms_nullPtr) - { - objectAttribRefs.clear(); - return 0; - } - - setObjectArrayElement(*experimentalAttribs, i, *attribute); - - // find all the object attributes associated with this experimental - // attribute and map them to each other - LocalObjectArrayRefPtr mappedObjectAttribs = createNewObjectArray(numObjectAttribs, - JavaLibrary::getClsDraftSchematicAttrib()); - if (mappedObjectAttribs == LocalObjectArrayRef::cms_nullPtr) - { - objectAttribRefs.clear(); - return 0; - } - - int j; - int mappedObjectIndex = 0; - for (j = 0; j < numObjectAttribs; ++j) - { - if (draftSchematic->getAttribMin(j).value != draftSchematic->getAttribMax(j).value) - { - const SharedDraftSchematicObjectTemplate::SchematicAttribute & - objectAttrib = draftSchematic->getAttribMin(j); - if (objectAttrib.experiment == experimentAttribName) - { - setObjectArrayElement(*mappedObjectAttribs, mappedObjectIndex++, *objectAttribRefs[j]); - } - } - } - for (j = mappedObjectIndex; j < numObjectAttribs; ++j) - { - setObjectArrayElement(*mappedObjectAttribs, j, LocalRef(0)); - } - callObjectMethod(*attribMap, JavaLibrary::getMidMapPut(), attribute->getValue(), mappedObjectAttribs->getValue()); - } - setObjectField(*target, JavaLibrary::getFidDraftSchematicExperimentalAttribs(), *experimentalAttribs); - setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribMap(), *attribMap); - - objectAttribRefs.clear(); - - return target->getReturnValue(); -} // JavaLibrary::getSchematicForExperimentalAttributes - -//---------------------------------------------------------------------- - -/** - * Sets an approximate experiment mod for an assembled schematic so the player will have some idea of - * the risk experimenting with an item. - * - * @param manufacturingSchematic the schematic - * @param experimentMod approximent mod that will be applied during experimentation - * - * @return true on success, false if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicExperimentMod(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat experimentMod) -{ - UNREF(self); - - ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - schematic->setExperimentMod(experimentMod); - - return JNI_TRUE; -} // JavaLibrary::setSchematicExperimentMod - -//---------------------------------------------------------------------- - -/** - * Sets the appearances that will be available to the player during customization. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic that will create the - * customized object - * @param appearances appearance filenames that the player may choose - * - * @return JNI_TRUE on success, JNI_FALSE on error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicAppearances(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray appearances) -{ - UNREF(self); - - if (manufacturingSchematic == 0 || appearances == 0) - return JNI_FALSE; - - ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - std::string appearance; - int count = env->GetArrayLength(appearances); - for (int i = 0; i < count; ++i) - { - JavaString appearanceString(static_cast(env->GetObjectArrayElement( - appearances, i))); - if (JavaLibrary::convert(appearanceString, appearance)) - { - schematic->addAppearance(appearance); - } - } - return JNI_TRUE; -} // JavaLibrary::setSchematicAppearances - -//---------------------------------------------------------------------- - -/** - * Sets the customization parameters that a player is allowed to change, or - * differ in their default value from the template. You do not have to set - * fixed customization parameters that use their default value. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic that will create the - * customized object - * @param customizations customization info - * - * @return JNI_TRUE on success, JNI_FALSE if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicCustomizations(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray customizations) -{ - UNREF(self); - - if (manufacturingSchematic == 0 || customizations == 0) - return JNI_FALSE; - - ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - std::string name; - int count = env->GetArrayLength(customizations); - for (int i = 0; i < count; ++i) - { - LocalRefPtr custom = getObjectArrayElement(LocalObjectArrayRefParam(customizations), i); - if (custom == LocalRef::cms_nullPtr) - continue; - - JavaStringPtr jname = getStringField(*custom, JavaLibrary::getFidDraftSchematicCustomName()); - if (jname == JavaString::cms_nullPtr) - continue; - if (!JavaLibrary::convert(*jname, name)) - return JNI_FALSE; - - int value = getIntField(*custom, JavaLibrary::getFidDraftSchematicCustomValue()); - int minValue = getIntField(*custom, JavaLibrary::getFidDraftSchematicCustomMinValue()); - int maxValue = getIntField(*custom, JavaLibrary::getFidDraftSchematicCustomMaxValue()); - - schematic->setCustomization(name, value, minValue, maxValue); - } - - return JNI_TRUE; -} // JavaLibrary::setSchematicCustomizations - -//---------------------------------------------------------------------- - -/** - * Returns the number of items a manufacturing schematic can create. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * - * @return the number of items, or -1 on error - */ -jint JNICALL ScriptMethodsCraftingNamespace::getSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic) -{ - UNREF(self); - - if (manufacturingSchematic == 0) - return -1; - - const ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return -1; - - return schematic->getCount(); -} // JavaLibrary::getSchematicItemCount - -//---------------------------------------------------------------------- - -/** - * Sets the number of items a manufacturing schematic can create. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param count the number of items - * - * @return true on success, false if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count) -{ - UNREF(self); - - if (manufacturingSchematic == 0) - return JNI_FALSE; - - ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - schematic->setCount(count); - return JNI_TRUE; -} // JavaLibrary::setSchematicItemCount - -//---------------------------------------------------------------------- - -/** - * Returns the numer of items per container a manufacturing schematic will - * create. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * - * @return the number of items, or -1 on error - */ -jint JNICALL ScriptMethodsCraftingNamespace::getSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic) -{ - UNREF(self); - - if (manufacturingSchematic == 0) - return -1; - - const ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return -1; - - return schematic->getItemsPerContainer(); -} // JavaLibrary::getSchematicItemsPerContainer - -//---------------------------------------------------------------------- - -/** - * Sets the numer of items per container a manufacturing schematic will - * create. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param count the number of items - * - * @return true on success, false if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count) -{ - UNREF(self); - - if (manufacturingSchematic == 0) - return JNI_FALSE; - - ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - schematic->setItemsPerContainer(count); - return JNI_TRUE; -} // JavaLibrary::setSchematicItemsPerContainer - -//---------------------------------------------------------------------- - -/** - * Returns the time per complexity point it takes to manufacture an item with - * a manufacturing schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * - * @return the time, or -1 on error - */ -jfloat JNICALL ScriptMethodsCraftingNamespace::getSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic) -{ - UNREF(self); - - if (manufacturingSchematic == 0) - return -1.0f; - - const ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return -1.0f; - - return schematic->getManufactureTime(); -} // JavaLibrary::getSchematicManufactureTime - -//---------------------------------------------------------------------- - -/** - * Sets the time per complexity point it takes to manufacture an item with - * a manufacturing schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic - * @param time the manufacturing time per complexity - * - * @return true on success, false if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat time) -{ - UNREF(self); - - if (manufacturingSchematic == 0) - return JNI_FALSE; - - ManufactureSchematicObject * schematic = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) - return JNI_FALSE; - - schematic->setManufactureTime(time); - return JNI_TRUE; -} // JavaLibrary::setSchematicManufactureTime - -//---------------------------------------------------------------------- - -/** - * Sets the amount of xp the creator of an object will get when an object is "used". - * - * @param env Java environment - * @param self class calling this function - * @param object the object that will grant the xp - * @param xp the amount of xp to grant - * - * @return true on success, false if there was an error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setCreatorXp(JNIEnv *env, jobject self, jlong object, jint xp) -{ - UNREF(self); - - TangibleObject * target = NULL; - if (!JavaLibrary::getObject(object, target)) - return JNI_FALSE; - - target->setCreatorXp(xp); - return JNI_TRUE; -} // JavaLibrary::setCreatorXp - -/** - * Gets a list of ingredients needed to craft using the current manufacturing - * schematic in a manufacturing station. - * - * @param env Java environment - * @param self class calling this function - * @param station the manufacturing station id - * @param ingredients array to be filled in with a string array of ingredients - */ -void JNICALL ScriptMethodsCraftingNamespace::getIngredientsForManufactureStation(JNIEnv *env, jobject self, jlong station, jobjectArray ingredients) -{ - UNREF(self); - - if (station == 0 || ingredients == 0) - return; - - const ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return; - - if (env->GetArrayLength(ingredients) != 1) - return; - - const ManufactureSchematicObject * const schematic = manfStation->getSchematic(); - if (schematic == NULL) - return; - - static ManufactureSchematicObject::IngredientInfoVector iiv; - iiv.clear (); - - schematic->getIngredientInfo (iiv); - - if (iiv.empty ()) - return; - - const size_t count = iiv.size(); - - LocalObjectArrayRefPtr ingredientList = createNewObjectArray(count, JavaLibrary::getClsString()); - if (ingredientList == LocalObjectArrayRef::cms_nullPtr) - return; - - char buf [128]; - const size_t buf_size = sizeof (buf); - - for (size_t i = 0; i < count; ++i) - { - const ManufactureSchematicObject::IngredientInfo & info = iiv [i]; - - const Unicode::String & name = info.first; - const int numPerItem = info.second.second; - - if (name.empty ()) - continue; - - snprintf (buf, buf_size, ":\\>200%d", numPerItem); - - Unicode::String element = name; - - if (name [0] == '@') - element.push_back ('\0'); - - element += Unicode::narrowToWide (buf); - - JavaString jelement(element); - setObjectArrayElement(*ingredientList, i, jelement); - } - - setObjectArrayElement(LocalObjectArrayRefParam(ingredients), 0, *ingredientList); -} // JavaLibrary::getIngredientsForManufactureStation - -//---------------------------------------------------------------------- - -/** - * Gets the id of a manufacture station's input hopper. - * - * @param env Java environment - * @param self class calling this function - * @param station the station id - * - * @return the hopper id, or null on error - */ -jlong JNICALL ScriptMethodsCraftingNamespace::getManufactureStationInputHopper(JNIEnv *env, jobject self, jlong station) -{ - UNREF(self); - - if (station == 0) - return 0; - - const ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return 0; - - ServerObject * hopper = manfStation->getInputHopper(); - if (hopper == NULL) - return 0; - - return (hopper->getNetworkId()).getValue(); -} // JavaLibrary::getManufactureStationInputHopper - -//---------------------------------------------------------------------- - -/** - * Gets the id of a manufacture station's output hopper. - * - * @param env Java environment - * @param self class calling this function - * @param station the station id - * - * @return the hopper id, or null on error - */ -jlong JNICALL ScriptMethodsCraftingNamespace::getManufactureStationOutputHopper(JNIEnv *env, jobject self, jlong station) -{ - UNREF(self); - - if (station == 0) - return 0; - - const ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return 0; - - ServerObject * hopper = manfStation->getOutputHopper(); - if (hopper == NULL) - return 0; - - return (hopper->getNetworkId()).getValue(); -} // JavaLibrary::getManufactureStationOutputHopper - -//---------------------------------------------------------------------- - -/** - * Gets the id and name of the schematic in a manufacture station. - * - * @param env Java environment - * @param self class calling this function - * @param station the station id - * - * @return a string of the form "*" , or null if the station has no schematic - */ -jstring JNICALL ScriptMethodsCraftingNamespace::getManufactureStationSchematic(JNIEnv *env, jobject self, jlong station) -{ - static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); - - UNREF(self); - - const ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return 0; - - const ManufactureSchematicObject * manfSchematic = manfStation->getSchematic(); - if (manfSchematic == NULL) - return 0; - - return JavaString( - Unicode::narrowToWide(manfSchematic->getNetworkId().getValueString()) + - SEPARATOR + - manfSchematic->getObjectName() - ).getReturnValue(); -} // JavaLibrary::getManufactureStationSchematic - -//---------------------------------------------------------------------- - -/** - * Gets a list of manufacture schematics that could be used at a given manufacturing - * station. - * - * @param env Java environment - * @param self class calling this function - * @param player the player whose schematics to get - * @param station the manufacturing station - * @param schematics array to be filled in with a string array of schematics - */ -void JNICALL ScriptMethodsCraftingNamespace::getValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station, jobjectArray schematics) -{ - static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); - - UNREF(self); - - if (player == 0 || station == 0 || schematics == 0) - return; - - CreatureObject * playerCreature = NULL; - if (!JavaLibrary::getObject(player, playerCreature)) - return; - - const ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return; - - if (env->GetArrayLength(schematics) != 1) - return; - - std::vector manfSchematics; - uint32 stationTypes = manfStation->getValidSchematicTypes(); - playerCreature->getManufactureSchematics(manfSchematics, stationTypes); - - int count = manfSchematics.size(); - LocalObjectArrayRefPtr schematicList = createNewObjectArray(count, JavaLibrary::getClsString()); - if (schematicList == LocalObjectArrayRef::cms_nullPtr) - return; - - for (int i = 0; i < count; ++i) - { - const ManufactureSchematicObject * manfSchematic = manfSchematics[i]; - setObjectArrayElement(*schematicList, i, - JavaString( - Unicode::narrowToWide(manfSchematic->getNetworkId().getValueString()) + - SEPARATOR + - manfSchematic->getObjectName() - )); - } - - setObjectArrayElement(LocalObjectArrayRefParam(schematics), 0, *schematicList); -} // JavaLibrary::getValidManufactureSchematicsForStation - -//---------------------------------------------------------------------- - -/** - * Checks if a player has any manufacture schematics that could be used at a - * given manufacturing station. - * - * @param env Java environment - * @param self class calling this function - * @param player the player whose schematics to check - * @param station the manufacturing station - * - * @return true if the player has any schematics, false if not - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::hasValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station) -{ - static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); - - UNREF(self); - - if (player == 0 || station == 0) - return JNI_FALSE; - - CreatureObject * playerCreature = NULL; - if (!JavaLibrary::getObject(player, playerCreature)) - return JNI_FALSE; - - const ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return JNI_FALSE; - - std::vector manfSchematics; - playerCreature->getManufactureSchematics(manfSchematics, - manfStation->getValidSchematicTypes()); - - if (manfSchematics.empty()) - return JNI_FALSE; - return JNI_TRUE; -} // JavaLibrary::hasValidManufactureSchematicsForStation - -//---------------------------------------------------------------------- - -/** - * Transfers the manufacture schematic in a manufacturing station to a player. - * - * @param env Java environment - * @param self class calling this function - * @param station the manufacturing station id - * @param player the the player to transfer to - * - * @return true if the schematic was transferred, false if not - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::transferManufactureSchematicToPlayer(JNIEnv *env, jobject self, jlong station, jlong player) -{ - UNREF(self); - - const ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return JNI_FALSE; - - ManufactureSchematicObject * schematic = manfStation->getSchematic(); - if (schematic == NULL) - return JNI_TRUE; - - CreatureObject * playerCreature = NULL; - if (!JavaLibrary::getObject(player, playerCreature)) - return JNI_FALSE; - - ServerObject * datapad = playerCreature->getDatapad(); - if (datapad == NULL) - return JNI_FALSE; - - Container::ContainerErrorCode tmp = Container::CEC_Success; - if (ContainerInterface::transferItemToVolumeContainer(*datapad, *schematic, NULL, tmp)) - return JNI_TRUE; - return JNI_FALSE; -} // JavaLibrary::transferManufactureSchematicToPlayer - -//---------------------------------------------------------------------- - -/** - * Transfers a manufacture schematic to a manufacturing station. - * - * @param env Java environment - * @param self class calling this function - * @param schematic the schematic id - * @param station the manufacturing station id - * - * @return true if the schematic was transferred, false if not - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::transferManufactureSchematicToStation(JNIEnv *env, jobject self, jlong schematic, jlong station) -{ - UNREF(self); - - ManufactureSchematicObject * manfSchematic = NULL; - if (!JavaLibrary::getObject(schematic, manfSchematic)) - return JNI_FALSE; - - ManufactureInstallationObject * manfStation = NULL; - if (!JavaLibrary::getObject(station, manfStation)) - return JNI_FALSE; - - if (manfStation->addSchematic(*manfSchematic, NULL)) - return JNI_TRUE; - return JNI_FALSE; -} // JavaLibrary::transferManufactureSchematicToStation - -//---------------------------------------------------------------------- - -/** - * Gets a list of objects that can be repaired by a given repair tool. - * - * @param env Java environment - * @param self class calling this function - * @param player the player whose objects to get - * @param tool the repair tool - * @param objects array to be filled in with a string array of objects - */ -void JNICALL ScriptMethodsCraftingNamespace::getRepairableObjectsForTool(JNIEnv *env, jobject self, jlong player, jlong tool, jobjectArray objects) -{ - static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); - - if (player == 0 || tool == 0 || objects == 0) - return; - - CreatureObject * playerCreature = NULL; - if (!JavaLibrary::getObject(player, playerCreature)) - return; - - const TangibleObject * toolObject = NULL; - if (!JavaLibrary::getObject(tool, toolObject)) - return; - if (!toolObject->isRepairTool()) - return; - int toolType = toolObject->getCraftingType(); - - // determine if the repair tool repairs a specific GOT or a category - bool genericTool = false; - if ((toolType & 0x000000ff) == 0) - genericTool = true; - - if (env->GetArrayLength(objects) != 1) - return; - - // @todo: we need to get a list of things the player owns that are loaded, - // so non-inventory objects can be repaired. For now, just repair inventory - // objects - - const ServerObject * inventory = playerCreature->getInventory(); - if (inventory == NULL) - return; - - const VolumeContainer * inventoryContainer = ContainerInterface::getVolumeContainer(*inventory); - if (inventoryContainer == NULL) - return; - - std::vector objList; - for (ContainerConstIterator iter(inventoryContainer->begin()); - iter != inventoryContainer->end(); ++iter) - { - const CachedNetworkId & objId = (*iter); - const TangibleObject * obj = safe_cast(objId.getObject()); - if (obj != NULL && !obj->isCraftingTool() && !obj->isRepairTool() && - obj->getDamageTaken() > 0) - { - if ((genericTool && (toolType & obj->getGameObjectType()) != 0) || - (!genericTool && toolType == obj->getGameObjectType())) - { - objList.push_back( - Unicode::narrowToWide(obj->getNetworkId().getValueString()) + - SEPARATOR + - obj->getEncodedObjectName ()); - } - } - } - - int count = objList.size(); - LocalObjectArrayRefPtr objectStringList = createNewObjectArray(count, JavaLibrary::getClsString()); - if (objectStringList == LocalObjectArrayRef::cms_nullPtr) - return; - - for (int i = 0; i < count; ++i) - { - setObjectArrayElement(*objectStringList, i, JavaString(objList[i])); - } - - setObjectArrayElement(LocalObjectArrayRefParam(objects), 0, *objectStringList); -} // JavaLibrary::getRepairableObjectsForTool - -//---------------------------------------------------------------------- - -/** - * Returns the attribute bonuses an object grants when equipped. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * - * @return an array with the bonus for each attribute, or null on error - */ -jintArray JNICALL ScriptMethodsCraftingNamespace::getAttributeBonuses(JNIEnv *env, jobject self, jlong target) -{ - UNREF(self); - - const ServerObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return 0; - - std::vector > bonuses; - if (object->asTangibleObject() != NULL) - { - object->asTangibleObject()->getAttribBonuses(bonuses); - } - else if (object->asManufactureSchematicObject() != NULL) - { - object->asManufactureSchematicObject()->getAttribBonuses(bonuses); - } - else - return 0; - - jint bonusesArray[Attributes::NumberOfAttributes]; - { - for (int i = 0; i < Attributes::NumberOfAttributes; ++i) - bonusesArray[i] = 0; - } - { - for (std::vector >::const_iterator i = bonuses.begin(); - i != bonuses.end(); ++i) - { - if ((*i).first >= 0 && (*i).first < Attributes::NumberOfAttributes) - bonusesArray[(*i).first] = (*i).second; - } - } - - LocalIntArrayRefPtr jbonuses = createNewIntArray(Attributes::NumberOfAttributes); - if (jbonuses == LocalIntArrayRef::cms_nullPtr) - return 0; - - setIntArrayRegion(*jbonuses, 0, Attributes::NumberOfAttributes, &bonusesArray[0]); - return jbonuses->getReturnValue(); -} // JavaLibrary::getAttributeBonuses - -//---------------------------------------------------------------------- - -/** - * Returns the attribute bonus of an object for a given attribute. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * @param attribute the attribute to get - * - * @return the attribute bonus - */ -jint JNICALL ScriptMethodsCraftingNamespace::getAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute) -{ - UNREF(self); - - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - return 0; - - const ServerObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return 0; - - jint bonus = 0; - if (object->asTangibleObject() != NULL) - { - bonus = object->asTangibleObject()->getAttribBonus(attribute); - } - else if (object->asManufactureSchematicObject() != NULL) - { - bonus = object->asManufactureSchematicObject()->getAttribBonus(attribute); - } - return bonus; -} // JavaLibrary::getAttributeBonus - -//---------------------------------------------------------------------- - -/** - * Sets the attribute bonus an object applies when equipped. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * @param attribute the attribute to set - * @param bonus the attribute bonus value - * - * @return true on success, false on error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute, jint bonus) -{ - UNREF(self); - - if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) - return JNI_FALSE; - - ServerObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return JNI_FALSE; - - if (object->asTangibleObject() != NULL) - { - object->asTangibleObject()->setAttribBonus(attribute, bonus); - } - else if (object->asManufactureSchematicObject() != NULL) - { - object->asManufactureSchematicObject()->setAttribBonus(attribute, bonus); - } - else - return JNI_FALSE; - return JNI_TRUE; -} // JavaLibrary::setAttributeBonus - -//---------------------------------------------------------------------- - -/** - * Sets the attribute bonuses an object applies when equipped. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * @param bonuses the attribute bonus values - * - * @return true on success, false on error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setAttributeBonuses(JNIEnv *env, jobject self, jlong target, jintArray bonuses) -{ - UNREF(self); - - if (bonuses == 0) - return JNI_FALSE; - - ServerObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return JNI_FALSE; - - jsize count = env->GetArrayLength(bonuses); - if (count != Attributes::NumberOfAttributes) - { - WARNING(true, ("JavaLibrary::setAttributeBonuses passed bad array of " - "size %u", count)); - return JNI_FALSE; - } - - jint buffer[Attributes::NumberOfAttributes]; - env->GetIntArrayRegion(bonuses, 0, count, buffer); - - if (object->asTangibleObject() != NULL) - { - TangibleObject * tangibleObject = object->asTangibleObject(); - for (jsize i = 0; i < count; ++i) - tangibleObject->setAttribBonus(i, buffer[i]); - } - else if (object->asManufactureSchematicObject() != NULL) - { - ManufactureSchematicObject * manufactureSchematicObject = object->asManufactureSchematicObject(); - for (jsize i = 0; i < count; ++i) - manufactureSchematicObject->setAttribBonus(i, buffer[i]); - } - else - return JNI_FALSE; - - return JNI_TRUE; -} // JavaLibrary::setAttributeBonus - -//---------------------------------------------------------------------- - -/** - * Returns the skill mod bonuses an object grants when equipped. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * - * @return a dictionary of skill mod names -> mod values, or null on error - */ -jobject JNICALL ScriptMethodsCraftingNamespace::getSkillModBonuses(JNIEnv *env, jobject self, jlong target) -{ - UNREF(self); - - const TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return 0; - - std::vector > skillModBonuses; - object->getSkillModBonuses(skillModBonuses); - - // put the bonuses into ScriptParams, and then convert to a dictionary - ScriptParams params; - int count = skillModBonuses.size(); - for (int i = 0; i < count; ++i) - { - params.addParam(skillModBonuses[i].second, skillModBonuses[i].first); - } - JavaDictionaryPtr dictionary; - JavaLibrary::instance()->convert(params, dictionary); - - return dictionary->getReturnValue(); -} // JavaLibrary::getSkillModBonuses - -//---------------------------------------------------------------------- - -/** - * Returns the skill mod bonus of an object for a given skill mod. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * @param skillMod the skill mod to get - * - * @return the skill mod value - */ -jint JNICALL ScriptMethodsCraftingNamespace::getSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod) -{ - UNREF(self); - - JavaStringParam jskillMod(skillMod); - - const TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return 0; - - std::string skillModName; - if (!JavaLibrary::convert(jskillMod, skillModName)) - return 0; - - return object->getSkillModBonus(skillModName); -} // JavaLibrary::getSkillModBonus - -//---------------------------------------------------------------------- - -/** - * Sets the base skill mod bonus an object applies when equipped. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * @param skillMod the skill mod to set - * @param bonus the skill mod bonus value - * - * @return true on success, false on error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod, jint bonus) -{ - UNREF(self); - - JavaStringParam jskillMod(skillMod); - - TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return JNI_FALSE; - - std::string skillModName; - if (!JavaLibrary::convert(jskillMod, skillModName)) - return JNI_FALSE; - - object->setSkillModBonus(skillModName, bonus); - return JNI_TRUE; -} // JavaLibrary::setSkillModBonus - -//---------------------------------------------------------------------- - -/** - * Sets the base skill mod bonuses an object applies when equipped. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * @param skillMod the skill mods to set - * @param bonus the skill mod bonus values - * - * @return true on success, false on error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSkillModBonuses(JNIEnv *env, jobject self, jlong target, jobjectArray skillMod, jintArray bonus) -{ - UNREF(self); - - TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return JNI_FALSE; - - if (skillMod == 0 || bonus == 0) - return JNI_FALSE; - - int skillModCount = env->GetArrayLength(skillMod); - int bonusCount = env->GetArrayLength(bonus); - if (skillModCount != bonusCount) - { - DEBUG_WARNING(true, ("[designer bug] setSkillModBonuses called with unequal " - "array sizes")); - return JNI_FALSE; - } - - std::string skillName; - const jint * bonusArray = env->GetIntArrayElements(bonus, NULL); - for (int i = 0; i < skillModCount; ++i) - { - JavaStringParam jskillName(static_cast(env->GetObjectArrayElement(skillMod, i))); - JavaLibrary::convert(jskillName, skillName); - object->setSkillModBonus(skillName, bonusArray[i]); - } - env->ReleaseIntArrayElements(bonus, const_cast(bonusArray), JNI_ABORT); - - return JNI_TRUE; -} // JavaLibrary::setSkillModBonuses - -//---------------------------------------------------------------------- - -/** -* Sets the base skill mod bonus an object applies when equipped. -* -* @param env Java environment -* @param self class calling this function -* @param target the object -* @param category the category of the skill mod bonus -* multiple/independent bonuses can be granted -* for a particular skill mod by putting them -* into different categories -* @param skillMod the skill mod to set -* @param bonus the skill mod bonus value -* -* @return true on success, false on error -*/ -jboolean JNICALL ScriptMethodsCraftingNamespace::setCategorizedSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring category, jstring skillMod, jint bonus) -{ - UNREF(self); - - JavaStringParam jcategory(category); - JavaStringParam jskillMod(skillMod); - - TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return JNI_FALSE; - - std::string categoryName; - if (!JavaLibrary::convert(jcategory, categoryName)) - return JNI_FALSE; - - std::string skillModName; - if (!JavaLibrary::convert(jskillMod, skillModName)) - return JNI_FALSE; - - object->setSkillModBonus(categoryName, skillModName, bonus); - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -/** -* Removes all skill mod bonuses in a particular category on an object. -* -* @param env Java environment -* @param self class calling this function -* @param target the object -* @param category the category of the skill mod bonus -* multiple/independent bonuses can be granted -* for a particular skill mod by putting them -* into different categories -*/ -void JNICALL ScriptMethodsCraftingNamespace::removeCategorizedSkillModBonuses(JNIEnv *env, jobject self, jlong target, jstring category) -{ - UNREF(self); - - JavaStringParam jcategory(category); - - TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return; - - std::string categoryName; - if (!JavaLibrary::convert(jcategory, categoryName)) - return; - - object->removeCategorizedSkillModBonuses(categoryName); -} - -//---------------------------------------------------------------------- - -/** - * Returns the number of available skill mod sockets of an object. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * - * @return the number of sockets - */ -jint JNICALL ScriptMethodsCraftingNamespace::getSkillModSockets(JNIEnv *env, jobject self, jlong target) -{ - UNREF(self); - - const TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return 0; - - return object->getSkillModSockets(); -} // JavaLibrary::getSkillModSockets - -//---------------------------------------------------------------------- - -/** - * Sets the number of available skill mod sockets for an object. - * - * @param env Java environment - * @param self class calling this function - * @param target the object - * @param sockets the number of sockets - * - * @return true on success, false on error - */ -jboolean JNICALL ScriptMethodsCraftingNamespace::setSkillModSockets(JNIEnv *env, jobject self, jlong target, jint sockets) -{ - UNREF(self); - - TangibleObject * object = NULL; - if (!JavaLibrary::getObject(target, object)) - return JNI_FALSE; - - object->setSkillModSockets(sockets); - return JNI_TRUE; -} // JavaLibrary::setSkillModSockets - -//---------------------------------------------------------------------- - -/** - * Creates a new item based on a draft schematic. The item will have stats - * based on a % value passed in (0 = worst possible stats, 100 = best possible - * stats). - * - * @param env Java environment - * @param self class calling this function - * @param draftSchematic draft schematic to make the object from - * @param qualityPercent % stat adjustment - * @param container the container to create the item in - * - * @return the item, or null on error - */ -jlong JNICALL ScriptMethodsCraftingNamespace::makeCraftedItem(JNIEnv *env, jobject self, jstring draftSchematic, jfloat qualityPercent, jlong container) -{ - UNREF(self); - - if (draftSchematic == 0 || container == 0) - { - WARNING(true, ("[script bug] null schematic or container passed to " - "makeCraftedItem")); - return 0; - } - - JavaStringParam jDraftSchematic(draftSchematic); - std::string draftSchematicName; - if (!JavaLibrary::convert(jDraftSchematic, draftSchematicName)) - { - WARNING(true, ("JavaLibrary::makeCraftedItem can't convert schematic " - "name to string")); - return 0; - } - - const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic( - draftSchematicName); - if (schematic == NULL) - { - WARNING(true, ("[script bug] bad schematic name %s passed to " - "makeCraftedItem", draftSchematicName.c_str())); - return 0; - } - - ServerObject * target = NULL; - if (!JavaLibrary::getObject(container, target)) - { - WARNING(true, ("[script bug] bad container id passed to makeCraftedItem")); - return 0; - } - Object * targetParent = ContainerInterface::getFirstParentInWorld(*target); - if (targetParent == NULL) - { - WARNING(true, ("JavaLibrary::makeCraftedItem can't find parent in world " - "for container %s", target->getNetworkId().getValueString().c_str())); - return 0; - } - Vector createPos(targetParent->getPosition_w()); - createPos.y = -100000.0f; - - // create a manf schematic and prototype - ManufactureSchematicObject * manfSchematic = ServerWorld::createNewManufacturingSchematic( - *schematic, createPos, false); - if (manfSchematic == NULL) - { - WARNING(true, ("JavaLibrary::makeCraftedItem: error creating manf " - "schematic!")); - return 0; - } - ServerObject * prototype = manfSchematic->manufactureObject(createPos); - if (prototype == NULL) - { - WARNING(true, ("JavaLibrary::makeCraftedItem: error creating " - "prototype!")); - manfSchematic->permanentlyDestroy(DeleteReasons::SetupFailed); - return false; - } - - if (qualityPercent < 0.0f) - qualityPercent = 0.0f; - else if (qualityPercent > 100.0f) - qualityPercent = 100.0f; - - ScriptParams params; - params.addParam(prototype->getNetworkId()); - params.addParam(*manfSchematic); - params.addParam(qualityPercent); - IGNORE_RETURN(manfSchematic->getScriptObject()->trigAllScripts( - Scripting::TRIG_MAKE_CRAFTED_ITEM, params)); - - manfSchematic->permanentlyDestroy(DeleteReasons::Consumed); - Container::ContainerErrorCode error; - if (!ContainerInterface::transferItemToVolumeContainer (*target, *prototype, - NULL, error, true)) - { - WARNING(true, ("JavaLibrary::makeCraftedItem: error can't store prototype " - "in container, error = %d", error)); - prototype->permanentlyDestroy(DeleteReasons::BadContainerTransfer); - return 0; - } - - return (prototype->getNetworkId()).getValue(); -} // JavaLibrary::makeCraftedItem - -//---------------------------------------------------------------------- - -/** - * Returns a draft_schematic structure filled in with info used by a manufacturing - * schematic. - * - * @param env Java environment - * @param self class calling this function - * @param manufacturingSchematic the schematic to get the data from - * - * @return the draft_schematic object, or null on error - */ -jobject JNICALL ScriptMethodsCraftingNamespace::getSchematicData(JNIEnv *env, jobject self, jlong manufacturingSchematic) -{ - if (manufacturingSchematic == 0) - return 0; - - const ManufactureSchematicObject * schematicObject = NULL; - if (!JavaLibrary::getObject(manufacturingSchematic, schematicObject)) - return 0; - - return JavaLibrary::convert(*schematicObject)->getReturnValue(); -} // JavaLibrary::getSchematicData - -//---------------------------------------------------------------------- - -/** - * Returns a draft_schematic structure filled in with info used by a draft - * schematic. - * - * @param env Java environment - * @param self class calling this function - * @param draftSchematic the schematic to get the data from - * - * @return the draft_schematic object, or null on error - */ -jobject JNICALL ScriptMethodsCraftingNamespace::getDraftSchematicData(JNIEnv *env, jobject self, - jstring draftSchematic) -{ - if (draftSchematic == 0) - return 0; - - JavaStringParam jdraftSchematic(draftSchematic); - std::string schematicName; - if (!JavaLibrary::convert(jdraftSchematic, schematicName)) - return 0; - - const DraftSchematicObject * schematicObject = DraftSchematicObject::getSchematic(schematicName); - if (schematicObject == NULL) - return 0; - - return JavaLibrary::convert(*schematicObject); -} // JavaLibrary::getSchematicData - -//---------------------------------------------------------------------- - -/** - * Returns a draft_schematic structure filled in with info used by a draft - * schematic. - * - * @param env Java environment - * @param self class calling this function - * @param draftSchematicCrc the schematic to get the data from - * - * @return the draft_schematic object, or null on error - */ -jobject JNICALL ScriptMethodsCraftingNamespace::getDraftSchematicDataCrc(JNIEnv *env, jobject self, - jint draftSchematicCrc) -{ - if (draftSchematicCrc == 0) - return 0; - - const DraftSchematicObject * schematicObject = DraftSchematicObject::getSchematic(draftSchematicCrc); - if (schematicObject == NULL) - return 0; - - return JavaLibrary::convert(*schematicObject); -} // JavaLibrary::getSchematicDataCrc - -//---------------------------------------------------------------------- - -/** - * Causes the stats of a crate of manufactured objects to get recomputed from the - * crate's objvars. - * IMPORTANT: This only affects the stats of new objects that get pulled out of the - * crate! It is up to the caller to modify the "examine" item stored in the crate. - * - * @param env Java environment - * @param self class calling this function - * @param crate the crate to recompute the stats of - */ -void JNICALL ScriptMethodsCraftingNamespace::recomputeCrateAttributes(JNIEnv *env, jobject self, jlong crate) -{ - FactoryObject * factory = NULL; - if (!JavaLibrary::getObject(crate, factory)) - return; - - factory->calculateAttributes(); -} - -//---------------------------------------------------------------------- +//======================================================================== +// +// ScriptMethodsCrafting.cpp - implements script methods dealing with crafting +// and manufacturing. +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#include "serverScript/FirstServerScript.h" +#include "serverScript/JavaLibrary.h" + +#include "UnicodeUtils.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/DraftSchematicObject.h" +#include "serverGame/FactoryObject.h" +#include "serverGame/ManufactureInstallationObject.h" +#include "serverGame/ManufactureObjectInterface.h" +#include "serverGame/ManufactureSchematicObject.h" +#include "serverGame/ObserveTracker.h" +#include "serverGame/PlayerCreatureController.h" +#include "serverGame/PlayerObject.h" +#include "serverGame/ResourceContainerObject.h" +#include "serverGame/ServerWorld.h" +#include "serverScript/GameScriptObject.h" +#include "serverScript/ScriptParameters.h" +#include "sharedFoundation/TemporaryCrcString.h" +#include "sharedGame/AssetCustomizationManager.h" +#include "sharedLog/Log.h" +#include "sharedObject/CustomizationData.h" +#include "sharedObject/MemoryBlockManagedObject.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedObject/PaletteColorCustomizationVariable.h" +#include "sharedObject/RangedIntCustomizationVariable.h" +#include "sharedObject/VolumeContainer.h" + +#include + +using namespace JNIWrappersNamespace; + + +// ====================================================================== + +namespace ScriptMethodsCraftingNamespace +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + struct VariableInfo + { + VariableInfo(std::string const &newName, int newMinValueInclusive, int newSetValue, int newMaxValueExclusive); + + std::string name; + int minValueInclusive; + int value; + int maxValueExclusive; + }; + + typedef std::vector VariableInfoVector; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + bool install(); + void collectRangedIntVariableCallback(const std::string &fullVariablePathName, const CustomizationVariable *customizationVariable, void *context); + + jboolean JNICALL startCraftingSession(JNIEnv *env, jobject self, jlong player, jlong station); + jboolean JNICALL endCraftingSession(JNIEnv *env, jobject self, jlong crafter, jlong tool, jlong prototype); + jboolean JNICALL setCraftingLevelAndStation(JNIEnv *env, jobject self, jlong player, jint craftingLevel, jlong station); + jint JNICALL getCraftingLevel(JNIEnv *env, jobject self, jlong player); + jlong JNICALL getCraftingStation(JNIEnv *env, jobject self, jlong player); + jboolean JNICALL sendUseableDraftSchematics(JNIEnv *env, jobject self, jlong player, jintArray schematics); + jboolean JNICALL setSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject attribute, jboolean experiment); + jboolean JNICALL setSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributes, jboolean experiment); + jobject JNICALL getSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject name, jboolean experiment); + jobjectArray JNICALL getSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray names, jboolean experiment); + jobjectArray JNICALL getAllSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jboolean experiment); + jobject JNICALL getSchematicForExperimentalAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributeNames); + jboolean JNICALL setSchematicExperimentMod(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat experimentMod); + jboolean JNICALL setSchematicAppearances(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray appearances); + jboolean JNICALL setSchematicCustomizations(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray customizations); + jint JNICALL getSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic); + jboolean JNICALL setSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count); + jint JNICALL getSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic); + jboolean JNICALL setSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count); + jfloat JNICALL getSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic); + jboolean JNICALL setSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat time); + jboolean JNICALL setCreatorXp(JNIEnv *env, jobject self, jlong object, jint xp); + void JNICALL getIngredientsForManufactureStation(JNIEnv *env, jobject self, jlong station, jobjectArray ingredients); + jlong JNICALL getManufactureStationInputHopper(JNIEnv *env, jobject self, jlong station); + jlong JNICALL getManufactureStationOutputHopper(JNIEnv *env, jobject self, jlong station); + jstring JNICALL getManufactureStationSchematic(JNIEnv *env, jobject self, jlong station); + void JNICALL getValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station, jobjectArray schematics); + jboolean JNICALL hasValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station); + jboolean JNICALL transferManufactureSchematicToPlayer(JNIEnv *env, jobject self, jlong station, jlong player); + jboolean JNICALL transferManufactureSchematicToStation(JNIEnv *env, jobject self, jlong schematic, jlong station); + void JNICALL getRepairableObjectsForTool(JNIEnv *env, jobject self, jlong player, jlong tool, jobjectArray objects); + jintArray JNICALL getAttributeBonuses(JNIEnv *env, jobject self, jlong target); + jint JNICALL getAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute); + jboolean JNICALL setAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute, jint bonus); + jboolean JNICALL setAttributeBonuses(JNIEnv *env, jobject self, jlong target, jintArray bonuses); + jobject JNICALL getSkillModBonuses(JNIEnv *env, jobject self, jlong target); + jint JNICALL getSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod); + jboolean JNICALL setSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod, jint bonus); + jboolean JNICALL setSkillModBonuses(JNIEnv *env, jobject self, jlong target, jobjectArray skillMod, jintArray bonus); + jboolean JNICALL setCategorizedSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring category, jstring skillMod, jint bonus); + void JNICALL removeCategorizedSkillModBonuses(JNIEnv *env, jobject self, jlong target, jstring category); + jint JNICALL getSkillModSockets(JNIEnv *env, jobject self, jlong target); + jboolean JNICALL setSkillModSockets(JNIEnv *env, jobject self, jlong target, jint sockets); + jlong JNICALL makeCraftedItem(JNIEnv *env, jobject self, jstring draftSchematic, jfloat qualityPercent, jlong container); + jobject JNICALL getSchematicData(JNIEnv *env, jobject self, jlong manufacturingSchematic); + jobject JNICALL getDraftSchematicData(JNIEnv *env, jobject self, jstring draftSchematic); + jobject JNICALL getDraftSchematicDataCrc(JNIEnv *env, jobject self, jint draftSchematicCrc); + void JNICALL recomputeCrateAttributes(JNIEnv *env, jobject self, jlong crate); +} + +using namespace ScriptMethodsCraftingNamespace; + + +//======================================================================== +// install +//======================================================================== + +bool ScriptMethodsCraftingNamespace::install() +{ +const JNINativeMethod NATIVES[] = { + #define JF(a,b,c) {a,b,(void*)(ScriptMethodsCraftingNamespace::c)} + JF("_startCraftingSession", "(JJ)Z", startCraftingSession), + JF("_endCraftingSession", "(JJJ)Z", endCraftingSession), + JF("_setCraftingLevelAndStation", "(JIJ)Z", setCraftingLevelAndStation), + JF("_getCraftingLevel", "(J)I", getCraftingLevel), + JF("_getCraftingStation", "(J)J", getCraftingStation), + JF("_sendUseableDraftSchematics", "(J[I)Z", sendUseableDraftSchematics), + JF("__setSchematicAttribute", "(JLscript/draft_schematic$attribute;Z)Z", setSchematicAttribute), + JF("__setSchematicAttributes", "(J[Lscript/draft_schematic$attribute;Z)Z", setSchematicAttributes), + JF("__getSchematicAttribute", "(JLscript/string_id;Z)Lscript/draft_schematic$attribute;", getSchematicAttribute), + JF("__getSchematicAttributes", "(J[Lscript/string_id;Z)[Lscript/draft_schematic$attribute;", getSchematicAttributes), + JF("__getAllSchematicAttributes", "(JZ)[Lscript/draft_schematic$attribute;", getAllSchematicAttributes), + JF("_getSchematicForExperimentalAttributes", "(J[Lscript/string_id;)Lscript/draft_schematic;", getSchematicForExperimentalAttributes), + JF("_setSchematicExperimentMod", "(JF)Z", setSchematicExperimentMod), + JF("_setSchematicAppearances", "(J[Ljava/lang/String;)Z", setSchematicAppearances), + JF("_setSchematicCustomizations", "(J[Lscript/draft_schematic$custom;)Z", setSchematicCustomizations), + JF("_getSchematicItemCount", "(J)I", getSchematicItemCount), + JF("_setSchematicItemCount", "(JI)Z", setSchematicItemCount), + JF("_getSchematicItemsPerContainer", "(J)I", getSchematicItemsPerContainer), + JF("_setSchematicItemsPerContainer", "(JI)Z", setSchematicItemsPerContainer), + JF("_getSchematicManufactureTime", "(J)F", getSchematicManufactureTime), + JF("_setSchematicManufactureTime", "(JF)Z", setSchematicManufactureTime), + JF("_setCreatorXp", "(JI)Z", setCreatorXp), + JF("_getIngredientsForManufactureStation", "(J[[Ljava/lang/String;)V", getIngredientsForManufactureStation), + JF("_getManufactureStationInputHopper", "(J)J", getManufactureStationInputHopper), + JF("_getManufactureStationOutputHopper", "(J)J", getManufactureStationOutputHopper), + JF("_getManufactureStationSchematic", "(J)Ljava/lang/String;", getManufactureStationSchematic), + JF("_getValidManufactureSchematicsForStation", "(JJ[[Ljava/lang/String;)V", getValidManufactureSchematicsForStation), + JF("_hasValidManufactureSchematicsForStation", "(JJ)Z", hasValidManufactureSchematicsForStation), + JF("_transferManufactureSchematicToPlayer", "(JJ)Z", transferManufactureSchematicToPlayer), + JF("_transferManufactureSchematicToStation", "(JJ)Z", transferManufactureSchematicToStation), + JF("_getRepairableObjectsForTool", "(JJ[[Ljava/lang/String;)V", getRepairableObjectsForTool), + JF("_getAttributeBonuses", "(J)[I", getAttributeBonuses), + JF("_getAttributeBonus", "(JI)I", getAttributeBonus), + JF("_setAttributeBonus", "(JII)Z", setAttributeBonus), + JF("_setAttributeBonuses", "(J[I)Z", setAttributeBonuses), + JF("_getSkillModBonuses", "(J)Lscript/dictionary;", getSkillModBonuses), + JF("_getSkillModBonus", "(JLjava/lang/String;)I", getSkillModBonus), + JF("_setSkillModBonus", "(JLjava/lang/String;I)Z", setSkillModBonus), + JF("_setSkillModBonuses", "(J[Ljava/lang/String;[I)Z", setSkillModBonuses), + JF("_setCategorizedSkillModBonus", "(JLjava/lang/String;Ljava/lang/String;I)Z", setCategorizedSkillModBonus), + JF("_removeCategorizedSkillModBonuses", "(JLjava/lang/String;)V", removeCategorizedSkillModBonuses), + JF("_getSkillModSockets", "(J)I", getSkillModSockets), + JF("_setSkillModSockets", "(JI)Z", setSkillModSockets), + JF("_makeCraftedItem", "(Ljava/lang/String;FJ)J", makeCraftedItem), + JF("_getSchematicData", "(J)Lscript/draft_schematic;", getSchematicData), + JF("getSchematicData", "(Ljava/lang/String;)Lscript/draft_schematic;", getDraftSchematicData), + JF("getSchematicData", "(I)Lscript/draft_schematic;", getDraftSchematicDataCrc), + JF("_recomputeCrateAttributes", "(J)V", recomputeCrateAttributes), +}; + + return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); +} + + +// ====================================================================== +// namespace ScriptMethodsCraftingNamespace +// ====================================================================== + +ScriptMethodsCraftingNamespace::VariableInfo::VariableInfo(std::string const &newName, int newMinValueInclusive, int newSetValue, int newMaxValueExclusive): + name(newName), + minValueInclusive(newMinValueInclusive), + value(newSetValue), + maxValueExclusive(newMaxValueExclusive) +{ +} + +// ---------------------------------------------------------------------- + +void ScriptMethodsCraftingNamespace::collectRangedIntVariableCallback(const std::string &fullVariablePathName, const CustomizationVariable *customizationVariable, void *context) +{ + //-- Check if variable is a palette-color style variable. If not, ignore for now. + // NOTE: replace PaletteColorCustomizationVariable with RangedIntCustomizatoinVariable + // if you want any ranged int (including texture choice ranges and palette colors) to be + // passed to crafting. + PaletteColorCustomizationVariable const *const paletteColorVariable = dynamic_cast(customizationVariable); + if (!paletteColorVariable) + { + // Nothing to do. + return; + } + + //-- Check if variable is a ranged int style variable. + RangedIntCustomizationVariable const *const rangedIntVariable = paletteColorVariable; + + //-- Get variable info list from context. + NOT_NULL(context); + VariableInfoVector *const variableInfoVector = static_cast(context); + + //-- Add variable info to vector. + int minValueInclusive = 0; + int maxValueExclusive = 0; + + rangedIntVariable->getRange(minValueInclusive, maxValueExclusive); + variableInfoVector->push_back(VariableInfo(fullVariablePathName, minValueInclusive, rangedIntVariable->getValue(), maxValueExclusive)); +} + +//======================================================================== +// class JavaLibrary crafting utility functions +//======================================================================== + +/** + * Creates a Java draft_schematic.attribute instance from an object attribute. + * + * @param manfSchematic manufacture schematic the attribute belongs to + * @param draftSchematic draft schematic the attribute belongs to + * @param attribIndex index of the attribute + * + * @return the attribute instance, or NULL on error + */ +LocalRefPtr JavaLibrary::createObjectAttribute(const ManufactureObjectInterface & manfSchematic, + const DraftSchematicObject & draftSchematic, int attribIndex) +{ + if (attribIndex < 0 || attribIndex >= draftSchematic.getAttribsCount()) + return LocalRef::cms_nullPtr; + + const SharedDraftSchematicObjectTemplate::SchematicAttribute & + minAttrib = draftSchematic.getAttribMin(attribIndex); + const SharedDraftSchematicObjectTemplate::SchematicAttribute & + maxAttrib = draftSchematic.getAttribMax(attribIndex); + + if (minAttrib.name.getTable().empty() || minAttrib.name.getText().empty()) + return LocalRef::cms_nullPtr; + + // create the attribute object + LocalRefPtr attribute = allocObject(JavaLibrary::getClsDraftSchematicAttrib()); + if (attribute == LocalRef::cms_nullPtr) + return LocalRef::cms_nullPtr; + + // set the name + LocalRefPtr name; + if (!ScriptConversion::convert(minAttrib.name, name)) + return LocalRef::cms_nullPtr; + + setObjectField(*attribute, JavaLibrary::getFidDraftSchematicAttribName(), *name); + + // get the resourceMax and current values + float minValue = static_cast(minAttrib.value); + float maxValue = static_cast(maxAttrib.value); + float resourceMaxValue = maxValue; + float currentValue = minValue; + + std::map::const_iterator result = manfSchematic.getAttributes().find( + minAttrib.name); + if (result != manfSchematic.getAttributes().end()) + currentValue = (*result).second; + + result = manfSchematic.getResourceMaxAttributes().find( + minAttrib.name); + if (result != manfSchematic.getResourceMaxAttributes().end()) + resourceMaxValue = (*result).second; + + // set the other fields + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMinValue(), minValue); + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue(), maxValue); + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue(), resourceMaxValue); + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue(), currentValue); + + return attribute; +} // JavaLibrary::createObjectAttribute + +/** + * Creates a Java draft_schematic.attribute instance from an experimental attribute. + * + * @param manfSchematic manufacture schematic the attribute belongs to + * @param attribName name of the attribute + * + * @return the attribute instance, or NULL on error + */ +LocalRefPtr JavaLibrary::createExperimentAttribute(const ManufactureObjectInterface & manfSchematic, + const StringId & attribName) +{ + if (attribName.getTable().empty() || attribName.getText().empty()) + return LocalRef::cms_nullPtr; + + // create the attribute object + LocalRefPtr attribute = allocObject(JavaLibrary::getClsDraftSchematicAttrib()); + if (attribute == LocalRef::cms_nullPtr) + return LocalRef::cms_nullPtr; + + // set the name + LocalRefPtr name; + if (!ScriptConversion::convert(attribName, name)) + return LocalRef::cms_nullPtr; + + setObjectField(*attribute, JavaLibrary::getFidDraftSchematicAttribName(), *name); + + // set the other fields + float value, minValue, maxValue, resourceValue; + manfSchematic.getAllExperimentAttributeValues(attribName, value, minValue, maxValue, + resourceValue); + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue(), value); + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMinValue(), minValue); + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue(), maxValue); + setFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue(), resourceValue); + + return attribute; +} // JavaLibrary::createExperimentAttribute + + +//======================================================================== +// class JavaLibrary JNI conversion methods +//======================================================================== + +/** + * Converts a C++ ManufactureSchematicObject to a Java draft_schematic. + * + * @param source the ManufactureSchematicObject to convert + * + * @return a new draft_schematic object + */ +LocalRefPtr JavaLibrary::convert(const ManufactureObjectInterface & source) +{ +int i; + + const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( + source.getDraftSchematic()); + if (draft == NULL) + return LocalRef::cms_nullPtr; + + LocalRefPtr target = allocObject(ms_clsDraftSchematic); + if (target == LocalRef::cms_nullPtr) + return LocalRef::cms_nullPtr; + + // set the ingredients + int numSlots = source.getSlotsCount(); + LocalObjectArrayRefPtr slots = createNewObjectArray(numSlots, ms_clsDraftSchematicSlot); + if (slots == LocalObjectArrayRef::cms_nullPtr) + return LocalRef::cms_nullPtr; + + Crafting::IngredientSlot sourceSlot; + ServerDraftSchematicObjectTemplate::IngredientSlot draftSlot; + for (i = 0; i < numSlots; ++i) + { + if (!source.getSlot(i, sourceSlot, true)) + { + WARNING(true, ("JavaLibrary::convert manf data: unable to get slot %d " + "from manf schematic %s", i, source.getDerivedNetworkId().getValueString().c_str())); + break; + } + + // get the amount of ingredient required from the draft schematic + if (!draft->getSlot(draftSlot, sourceSlot.name)) + { + WARNING(true, ("JavaLibrary::convert manf data: unable to get slot %s " + "from draft schematic %s", sourceSlot.name.getCanonicalRepresentation().c_str(), + draft->getObjectTemplateName())); + break; + } + int amountRequired = draftSlot.options[sourceSlot.draftSlotOption]. + ingredients[0].count; + + // create the ingredient object + LocalRefPtr slot = convert(source, sourceSlot, amountRequired, + draftSlot.appearance, draftSlot.options[0].ingredients[0].ingredient); + if (slot == LocalRef::cms_nullPtr) + { + WARNING(true, ("Unable to convert schematic slot %s to Java data", + sourceSlot.name.getCanonicalRepresentation().c_str())); + break; + } + + setObjectArrayElement(*slots, i, *slot); + } + if (i != numSlots) + { + return LocalRef::cms_nullPtr; + } + setObjectField(*target, ms_fidDraftSchematicSlots, *slots); + + // if we are converting the schematic in order to manufacture an object, + // just convert the object attributes and ingredient sources and exit + if (source.isMakingObject()) + { + int numObjectAttribs = draft->getAttribsCount(); + LocalObjectArrayRefPtr attributes = createNewObjectArray(numObjectAttribs, JavaLibrary::getClsDraftSchematicAttrib()); + if (attributes == LocalObjectArrayRef::cms_nullPtr) + { + return LocalRef::cms_nullPtr; + } + for (i = 0; i < numObjectAttribs; ++i) + { + // create the attribute object + LocalRefPtr attribute = JavaLibrary::createObjectAttribute(source, *draft, i); + if (attribute == LocalRef::cms_nullPtr) + break; + setObjectArrayElement(*attributes, i, *attribute); + } + if (i != numObjectAttribs) + { + return LocalRef::cms_nullPtr; + } + setObjectField(*target, ms_fidDraftSchematicAttribs, *attributes); + return target; + } + + // set the crafting category + setIntField(*target, ms_fidDraftSchematicCategory, draft->getCategory()); + // set the base complexity + setFloatField(*target, ms_fidDraftSchematicComplexity, draft->getComplexity()); + + // + // set the attributes, the experimental attributes, and the mapping between them + // + + LocalRefPtr attribMap = createNewObject(ms_clsHashtable, ms_midHashtable); + if (attribMap == LocalRef::cms_nullPtr) + return LocalRef::cms_nullPtr; + + // create a local frame reference big enough so we can keep around the + // references to the object attributes and experiment attributes + const std::vector & experimentNames = source.getExperimentAttributeNames(); + int numExperimentAttribs = experimentNames.size(); + int numObjectAttribs = draft->getAttribsCount(); + + // set the experimental attributes + std::vector experimentAttribRefs; + LocalObjectArrayRefPtr attributes = createNewObjectArray(numExperimentAttribs, JavaLibrary::getClsDraftSchematicAttrib()); + if (attributes == LocalObjectArrayRef::cms_nullPtr) + { + return LocalRef::cms_nullPtr; + } + for (i = 0; i < numExperimentAttribs; ++i) + { + // create the attribute object + LocalRefPtr attribute = JavaLibrary::createExperimentAttribute(source, experimentNames[i]); + if (attribute == LocalRef::cms_nullPtr) + break; + + setObjectArrayElement(*attributes, i, *attribute); + experimentAttribRefs.push_back(attribute); + } + if (i != numExperimentAttribs) + { + return LocalRef::cms_nullPtr; + } + setObjectField(*target, ms_fidDraftSchematicExperimentalAttribs, *attributes); + + // set the object attributes + attributes = createNewObjectArray(numObjectAttribs, JavaLibrary::getClsDraftSchematicAttrib()); + if (attributes == LocalObjectArrayRef::cms_nullPtr) + { + return LocalRef::cms_nullPtr; + } + for (i = 0; i < numObjectAttribs; ++i) + { + // create the attribute object + LocalRefPtr attribute = JavaLibrary::createObjectAttribute(source, *draft, i); + if (attribute == LocalRef::cms_nullPtr) + break; + setObjectArrayElement(*attributes, i, *attribute); + + // find the experimental attribute associated with the object attibute + // and add it to the attribute map + StringId expAttrib(draft->getExperimentalAttributeFromAttribute(i)); + for (int j = 0; j < numExperimentAttribs; ++j) + { + if (expAttrib == experimentNames[j]) + { + callObjectMethod(*attribMap, ms_midMapPut, + attribute->getValue(), experimentAttribRefs[j]->getValue()); + break; + } + } + } + if (i != numObjectAttribs) + { + return LocalRef::cms_nullPtr; + } + setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribs(), *attributes); + setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribMap(), *attribMap); + + // restore our frame reference + experimentAttribRefs.clear(); + + // set the customization info from the shared object template + const ServerObjectTemplate * objectTemplate = draft->getCraftedObjectTemplate(); + if (objectTemplate == NULL) + { + return LocalRef::cms_nullPtr; + } + const SharedObjectTemplate * sharedTemplate = safe_cast( + ObjectTemplateList::fetch(objectTemplate->getSharedTemplate())); + const SharedTangibleObjectTemplate * sharedTangibleTemplate = dynamic_cast< + const SharedTangibleObjectTemplate *>(sharedTemplate); + if (sharedTangibleTemplate != NULL) + { + // New method using the AssetCustomizationManager mechanism. + + //-- Retrieve customization declarations for the appearance asset associated with + // the crafted object's shared object template. + + // Create a dummy object. + Object *dummyObject = new MemoryBlockManagedObject(); + NOT_NULL(dummyObject); + + // Create a CustomizationData instance. + CustomizationData *customizationData = new CustomizationData(*dummyObject); + NOT_NULL(customizationData); + customizationData->fetch(); + + // Retrieve CustomizationData for crafted object's appearance template name. + bool const skipSharedOwnerVariables = true; + AssetCustomizationManager::addCustomizationVariablesForAsset(TemporaryCrcString(sharedTangibleTemplate->getAppearanceFilename().c_str(), true), *customizationData, skipSharedOwnerVariables); + + // Retrieve all ranged int customization variables from CusotmizationData. + VariableInfoVector variableInfoList; + bool const includeRemoveVariables = false; + customizationData->iterateOverConstVariables(collectRangedIntVariableCallback, &variableInfoList, includeRemoveVariables); + + int const count = static_cast(variableInfoList.size()); +#ifdef _DEBUG + LOG("crafting-customizations", ("customization variable count: %d for (%s)", count, sharedTangibleTemplate->getAppearanceFilename().c_str())); +#endif + + //-- Create the Java array to hold the ranged int customization entries. + LocalObjectArrayRefPtr customizations = createNewObjectArray(count, ms_clsDraftSchematicCustom); + if (customizations == LocalObjectArrayRef::cms_nullPtr) + { + customizationData->release(); + delete dummyObject; + return LocalRef::cms_nullPtr; + } + + //-- Fill in the Java array with customization entries. + int i; + + for (i = 0; i < count; ++i) + { + VariableInfo const &info = variableInfoList[static_cast(i)]; + + // create the customization object + LocalRefPtr customization = allocObject(ms_clsDraftSchematicCustom); + if (customization == LocalRef::cms_nullPtr) + break; + + // set the name + JavaString name(info.name.c_str()); + setObjectField(*customization, JavaLibrary::getFidDraftSchematicCustomName(), name); + + // set the values + setIntField(*customization, JavaLibrary::getFidDraftSchematicCustomValue(), info.value); + setIntField(*customization, JavaLibrary::getFidDraftSchematicCustomMinValue(), info.minValueInclusive); + setIntField(*customization, JavaLibrary::getFidDraftSchematicCustomMaxValue(), info.maxValueExclusive - 1); +// setBooleanField(*customization, ms_fidDraftSchematicCustomLocked, +// JNI_FALSE); + + setObjectArrayElement(*customizations, i, *customization); + } + if (i != count) + { + customizationData->release(); + delete dummyObject; + return LocalRef::cms_nullPtr; + } + setObjectField(*target, ms_fidDraftSchematicCustomizations, *customizations); + + //-- Cleanup. + customizationData->release(); + delete dummyObject; + } + else + setObjectField(*target, ms_fidDraftSchematicCustomizations, LocalRef(0)); + + return target; +} // JavaLibrary::convert(const ManufactureObjectInterface &) + +/** + * Converts a C++ Crafting::IngredientSlot to a Java draft_schematic$slot. + * + * @param schematic the manf schematic the slot belongs to + * @param source the IngredientSlot to convert + * @param amountRequired amount of ingredients required to fill the slot + * @param appearance appearance data associated with the slot + * @param requiredIngredient name of the ingredient needed for the slot + * + * @return a new draft_schematic object + */ +LocalRefPtr JavaLibrary::convert(const ManufactureObjectInterface & schematic, + const Crafting::IngredientSlot & source, int amountRequired, + const std::string & appearance, const std::string & requiredIngredient) +{ + int i; + + // create the slot object + LocalRefPtr slot = allocObject(ms_clsDraftSchematicSlot); + if (slot == LocalRef::cms_nullPtr) + return LocalRef::cms_nullPtr; + + // set the slot name + LocalRefPtr slotName; + if (!ScriptConversion::convert(source.name, slotName)) + { + return LocalRef::cms_nullPtr; + } + setObjectField(*slot, ms_fidDraftSchematicSlotName, *slotName); + + // set the slot appearance data + JavaString appearanceName(appearance.c_str()); + setObjectField(*slot, ms_fidDraftSchematicSlotAppearance, appearanceName); + + JavaString ingredientName(requiredIngredient); + if (ingredientName.getValue() == 0) + return LocalRef::cms_nullPtr; + + // set the slot data + setIntField(*slot, ms_fidDraftSchematicSlotOption, source.draftSlotOption); + setIntField(*slot, ms_fidDraftSchematicSlotIngredientType, source.ingredientType); + setFloatField(*slot, ms_fidDraftSchematicSlotComplexity, source.complexity); + setIntField(*slot, ms_fidDraftSchematicSlotAmountRequired, amountRequired); + setObjectField(*slot, ms_fidDraftSchematicSlotIngredientName, ingredientName); + + // create the ingredients array + int count = source.ingredients.size(); + LocalObjectArrayRefPtr ingredients = createNewObjectArray(count, ms_clsDraftSchematicSimpleIngredient); + if (ingredients == LocalObjectArrayRef::cms_nullPtr) + { + return LocalRef::cms_nullPtr; + } + for (i = 0; i < count; ++i) + { + // create the ingredient object + LocalRefPtr ingredient = allocObject(ms_clsDraftSchematicSimpleIngredient); + if (ingredient == LocalRef::cms_nullPtr) + { + WARNING(true, ("Unable to allocate Java memory for simple ingredient data")); + break; + } + + // set the ingredient source and xp type + LocalRefPtr sourceId = getObjId(source.ingredients[i]->source); + setObjectField(*ingredient, ms_fidDraftSchematicSimpleIngredientSource, + *sourceId); + setIntField(*ingredient, ms_fidDraftSchematicSimpleIngredientXpType, + source.ingredients[i]->xpType); + + + // set the ingredient id + if (source.ingredientType == Crafting::IT_resourceType || + source.ingredientType == Crafting::IT_resourceClass) + { + LocalRefPtr ingredientId = getObjId(source.ingredients[i]->ingredient); + if (ingredientId == LocalRef::cms_nullPtr) + { + WARNING(true, ("Unable to convert ingredient resource network id " + "%s to a Java obj_id", source.ingredients[i]->ingredient.getValueString().c_str())); + break; + } + setObjectField(*ingredient, ms_fidDraftSchematicSimpleIngredientIngredient, + *ingredientId); + } + else + { + const Crafting::ComponentIngredient * componentData = safe_cast< + const Crafting::ComponentIngredient *>(source.ingredients[i].get()); +// TangibleObject * component = schematic.getComponent(*componentData); +// NOT_NULL(component); +// LocalRef ingredientId(getObjId(component->getNetworkId())); + LocalRefPtr componentId = getObjId(componentData->ingredient); + if (componentId == LocalRef::cms_nullPtr) + { + WARNING(true, ("Unable to convert ingredient component network id " + "%s to a Java obj_id", componentData->ingredient.getValueString().c_str())); + break; + } + setObjectField(*ingredient, ms_fidDraftSchematicSimpleIngredientIngredient, + *componentId); + setIntField(*ingredient, ms_fidDraftSchematicSimpleIngredientXpAmount, + componentData->sourceXp); + } + + // set the ingredient count + setIntField(*ingredient, ms_fidDraftSchematicSimpleIngredientCount, + source.ingredients[i]->count); + + setObjectArrayElement(*ingredients, i, *ingredient); + } + if (i != count) + { + return LocalRef::cms_nullPtr; + } + setObjectField(*slot, ms_fidDraftSchematicSlotIngredients, *ingredients); + + return slot; +} // JavaLibrary::convert(const Crafting::IngredientSlot &) + +/** + * Converts a C++ DraftSchematicObject to a Java draft_schematic. + * + * @param source the DraftSchematicObject to convert + * + * @return a new draft_schematic object + */ +jobject JavaLibrary::convert(const DraftSchematicObject & source) +{ +int i; + + LocalRefPtr target = allocObject(ms_clsDraftSchematic); + if (target == LocalRef::cms_nullPtr) + return 0; + + // set the ingredients/slots + int numSlots = source.getSlotsCount(); + LocalObjectArrayRefPtr slots = createNewObjectArray(numSlots, ms_clsDraftSchematicSlot); + if (slots == LocalObjectArrayRef::cms_nullPtr) + return 0; + + ServerDraftSchematicObjectTemplate::IngredientSlot slot; + for (i = 0; i < numSlots; ++i) + { + if (!source.getSlot(slot, i)) + { + WARNING(true, ("JavaLibrary::convert draft data: unable to get slot %d " + "from draft schematic %s", i, source.getObjectTemplateName())); + break; + } + + if (slot.options.empty()) + { + WARNING(true, ("JavaLibrary::convert draft data: slot %d in draft " + "schematic %s has no options", i, source.getObjectTemplateName())); + break; + } + if (slot.options[0].ingredients.empty()) + { + WARNING(true, ("JavaLibrary::convert draft data: slot %d in draft " + "schematic %s has no ingredients", i, source.getObjectTemplateName())); + break; + } + + JavaString appearanceName(slot.appearance); + if (appearanceName.getValue() == 0) + break; + JavaString ingredientName(slot.options[0].ingredients[0].ingredient); + if (ingredientName.getValue() == 0) + break; + LocalRefPtr slotName; + if (!ScriptConversion::convert(slot.name, slotName)) + break; + + LocalRefPtr jslot = allocObject(ms_clsDraftSchematicSlot); + if (jslot == LocalRef::cms_nullPtr) + break; + + setObjectField(*jslot, ms_fidDraftSchematicSlotName, *slotName); + setObjectField(*jslot, ms_fidDraftSchematicSlotIngredientName, ingredientName); + setObjectField(*jslot, ms_fidDraftSchematicSlotIngredients, LocalRef(0)); + setObjectField(*jslot, ms_fidDraftSchematicSlotAppearance, appearanceName); + setIntField(*jslot, ms_fidDraftSchematicSlotOption, 0); + setIntField(*jslot, ms_fidDraftSchematicSlotIngredientType, slot.options[0].ingredientType); + setIntField(*jslot, ms_fidDraftSchematicSlotAmountRequired, slot.options[0].ingredients[0].count); + setFloatField(*jslot, ms_fidDraftSchematicSlotComplexity, slot.complexity); + setObjectArrayElement(*slots, i, *jslot); + } + if (i != numSlots) + { + return 0; + } + setObjectField(*target, ms_fidDraftSchematicSlots, *slots); + + // set the attributes + int numAttributes = source.getAttribsCount(); + LocalObjectArrayRefPtr attribs = createNewObjectArray(numAttributes, JavaLibrary::getClsDraftSchematicAttrib()); + if (attribs == LocalObjectArrayRef::cms_nullPtr) + return 0; + int minValue = 0; + int maxValue = 0; + for (i = 0; i < numAttributes; ++i) + { + const SharedDraftSchematicObjectTemplate::SchematicAttribute & attrib = + source.getAttrib(i); + source.getAttribMinMax(i, minValue, maxValue); + + LocalRefPtr attribName; + if (!ScriptConversion::convert(attrib.name, attribName)) + break; + + LocalRefPtr jattrib = allocObject(JavaLibrary::getClsDraftSchematicAttrib()); + if (jattrib == LocalRef::cms_nullPtr) + break; + + setObjectField(*jattrib, JavaLibrary::getFidDraftSchematicAttribName(), *attribName); + setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribMinValue(), static_cast(minValue)); + setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribMaxValue(), static_cast(maxValue)); + setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue(), 0); + setFloatField(*jattrib, JavaLibrary::getFidDraftSchematicAttribCurrentValue(), 0); + setObjectArrayElement(*attribs, i, *jattrib); + } + if (i != numAttributes) + { + return 0; + } + setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribs(), *attribs); + + // set the created item template crc value + const ServerObjectTemplate * craftedTemplate = source.getCraftedObjectTemplate(); + if (craftedTemplate == NULL) + { + WARNING(true, ("JavaLibrary::convert DraftSchematicObject got null crafted " + "template for draft schematic %s", source.getObjectTemplateName())); + return 0; + } + setIntField(*target, ms_fidDraftSchematicObjectTemplateCreated, craftedTemplate->getCrcName().getCrc()); + + // set the script value + const ServerDraftSchematicObjectTemplate * const sourceSchematicTemplate = + safe_cast(source.getObjectTemplate()); + NOT_NULL(sourceSchematicTemplate); + if (sourceSchematicTemplate == NULL) + { + // emergency case for release mode + return 0; + } + const int numScripts = sourceSchematicTemplate->getManufactureScriptsCount(); + LocalObjectArrayRefPtr scripts = createNewObjectArray(numScripts, JavaLibrary::getClsString()); + if (scripts == LocalObjectArrayRef::cms_nullPtr) + { + WARNING(true, ("JavaLibrary::convert DraftSchematicObject could not allocate " + "script array for draft schematic %s", source.getObjectTemplateName())); + return 0; + } + for (i = 0; i < numScripts; ++i) + { + JavaString script(sourceSchematicTemplate->getManufactureScripts(i)); + setObjectArrayElement(*scripts, i, script); + } + setObjectField(*target, ms_fidDraftSchematicScripts, *scripts); + + return target->getReturnValue(); +} // JavaLibrary::convert(const DraftSchematicObject &) + + +//======================================================================== +// class JavaLibrary JNI crafting callback methods +//======================================================================== + +/** + * Starts a crafting session. + * + * @param env Java environment + * @param self class calling this function + * @param player the player who will be crafting + * @param station the design station a player will be using + * + * @return true on success, false on fail + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::startCraftingSession(JNIEnv *env, jobject self, jlong player, jlong station) +{ + UNREF(env); + UNREF(self); + + CreatureObject* playerObj = NULL; + if (!JavaLibrary::getObject(player, playerObj)) + return JNI_FALSE; + + TangibleObject* stationObj = NULL; + if (!JavaLibrary::getObject(station, stationObj)) + return JNI_FALSE; + + if (!stationObj->startCraftingSession(*playerObj)) + return JNI_FALSE; + + return JNI_TRUE; +} // JavaLibrary::startCraftingSession + +/** + * Ends a crafting session. + * + * @param env Java environment + * @param self class calling this function + * @param crafter the player that was crafting + * @param tool the crafting tool that was being used + * @param prototype the prototype that was created (may be null) + * + * @return true on success, false on fail + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::endCraftingSession(JNIEnv *env, jobject self, jlong crafter, jlong tool, jlong prototype) +{ + UNREF(env); + UNREF(self); + UNREF(tool); + + // we're only do things if there's a prototype + if (prototype == 0) + return JNI_TRUE; + + CreatureObject * crafterObj = NULL; + if (!JavaLibrary::getObject(crafter, crafterObj)) + return JNI_FALSE; + + TangibleObject * prototypeObj = NULL; + if (!JavaLibrary::getObject(prototype, prototypeObj)) + return JNI_FALSE; + + // tell the crafter to create the prototype + ObserveTracker::onCraftingEndCraftingSession(*crafterObj, *prototypeObj); + + return JNI_TRUE; +} // JavaLibrary::endCraftingSession + +/** + * Sets the crafting level and station of a player's crafting session. + * + * @param env Java environment + * @param self class calling this function + * @param player the player who's crafting + * @param craftingLevel the crafting level of the session + * @param station the crafting station of the session + * + * @return true if the data was set, false on error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setCraftingLevelAndStation(JNIEnv *env, jobject self, jlong player, jint craftingLevel, jlong station) +{ + UNREF(self); + + CreatureObject* creatureObject = NULL; + if (!JavaLibrary::getObject(player, creatureObject)) + return JNI_FALSE; + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if (playerObject == NULL) + return JNI_FALSE; + + if (craftingLevel >= 0 && craftingLevel <= Crafting::MAX_CRAFTING_LEVEL) + playerObject->setCraftingLevel(craftingLevel); + + if (station != 0) + { + const TangibleObject * stationObject = NULL; + const NetworkId stationId(station); + if (stationId != NetworkId::cms_invalid) + { + stationObject = dynamic_cast(ServerWorld::findObjectByNetworkId(stationId)); + if (stationObject == NULL) + return JNI_FALSE; + } + playerObject->setCraftingStation(stationObject); + } + + return JNI_TRUE; +} // JavaLibrary::setCraftingLevelAndStation + +/** + * Gets the crafting level of a player's crafting session. + * + * @param env Java environment + * @param self class calling this function + * @param player the player who's crafting + * + * @return the crafting level, or -1 on error + */ +jint JNICALL ScriptMethodsCraftingNamespace::getCraftingLevel(JNIEnv *env, jobject self, jlong player) +{ + UNREF(self); + + const CreatureObject* creatureObject = NULL; + if (!JavaLibrary::getObject(player, creatureObject)) + return -1; + const PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if (playerObject == NULL) + return -1; + + return playerObject->getCraftingLevel(); +} // JavaLibrary::getCraftingLevel + +/** + * Gets the crafting station of a player's crafting session. + * + * @param env Java environment + * @param self class calling this function + * @param player the player who's crafting + * + * @return the crafting station, or 0 on error + */ +jlong JNICALL ScriptMethodsCraftingNamespace::getCraftingStation(JNIEnv *env, jobject self, jlong player) +{ + UNREF(self); + + const CreatureObject* creatureObject = NULL; + if (!JavaLibrary::getObject(player, creatureObject)) + return 0; + const PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if (playerObject == NULL) + return 0; + + return (playerObject->getCraftingStation()).getValue(); +} // JavaLibrary::getCraftingStation + +/** + * Sends a list of draft schematics to a player that he may select to craft an item. + * + * @param env Java environment + * @param self class calling this function + * @param player the player trying to use the station + * @param schematics list of schematic template name crcs the player may use to craft an item + * + * @return true on success, false if there was an error + **/ +jboolean JNICALL ScriptMethodsCraftingNamespace::sendUseableDraftSchematics(JNIEnv *env, jobject self, jlong player, jintArray schematics) +{ + UNREF(self); + + CreatureObject* creatureObject = NULL; + if (!JavaLibrary::getObject(player, creatureObject)) + return JNI_FALSE; + PlayerObject * playerObject = PlayerCreatureController::getPlayerObject(creatureObject); + if (playerObject == NULL) + { + DEBUG_WARNING(true, ("JavaLibrary::sendUseableDraftSchematics non-player " + "object %s\n", creatureObject->getNetworkId().getValueString().c_str())); + return JNI_FALSE; + } + + int count = env->GetArrayLength(schematics); + if (count == 0) + return JNI_FALSE; + + jint * schematicsArray = env->GetIntArrayElements(schematics, NULL); + if (schematicsArray != NULL) + { + std::vector schematicCrcs(schematicsArray, &schematicsArray[count]); + playerObject->sendUseableDraftSchematics(schematicCrcs); + env->ReleaseIntArrayElements(schematics, schematicsArray, JNI_ABORT); + } + else + { + std::vector schematicCrcs; + playerObject->sendUseableDraftSchematics(schematicCrcs); + } + + return JNI_TRUE; +} // JavaLibrary::sendUseableDraftSchematics + +/** + * Sets an attribute for a manufacturing schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param attribute the attribute info to set + * @param experiment flag that these are experimental attributes + * + * @return true on success, false if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject attribute, jboolean experiment) +{ + UNREF(self); + + if (manufacturingSchematic == 0 || attribute == 0) + return JNI_FALSE; + + ManufactureObjectInterface * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + LocalRefPtr attrName = getObjectField(LocalRefParam(attribute), JavaLibrary::getFidDraftSchematicAttribName()); + jfloat value = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue()); + jfloat resourceValue = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue()); + + if (attrName == LocalRef::cms_nullPtr) + return JNI_FALSE; + + StringId name; + if (!ScriptConversion::convert(*attrName, name)) + return JNI_FALSE; + + if (experiment) + { + schematic->setExperimentAttribute(name, value); + jfloat minValue = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribMinValue()); + jfloat maxValue = env->GetFloatField(attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue()); + schematic->setExperimentAttributeLimits(name, minValue, maxValue, resourceValue); + } + else + { + schematic->setAttribute(name, value); + schematic->setResourceMaxAttribute(name, resourceValue); + } + return JNI_TRUE; +} // JavaLibrary::setSchematicAttribute + +/** + * Sets attributes for a manufacturing schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param attributes list of attribute info to set + * @param experiment flag that these are experimental attributes + * + * @return true on success, false if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributes, jboolean experiment) +{ + UNREF(self); + + if (manufacturingSchematic == 0 || attributes == 0) + return JNI_FALSE; + + ManufactureObjectInterface * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + StringId name; + int count = env->GetArrayLength(attributes); + for (int i = 0; i < count; ++i) + { + LocalRefPtr attribute = getObjectArrayElement(LocalObjectArrayRefParam(attributes), i); + if (attribute != LocalRef::cms_nullPtr) + { + LocalRefPtr attrName = getObjectField(*attribute, JavaLibrary::getFidDraftSchematicAttribName()); + jfloat value = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribCurrentValue()); + jfloat resourceValue = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribResourceMaxValue()); + + if (attrName != LocalRef::cms_nullPtr) + { + if (ScriptConversion::convert(*attrName, name)) + { + if (experiment) + { + schematic->setExperimentAttribute(name, value); + jfloat minValue = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMinValue()); + jfloat maxValue = getFloatField(*attribute, JavaLibrary::getFidDraftSchematicAttribMaxValue()); + schematic->setExperimentAttributeLimits(name, + minValue, maxValue, resourceValue); + } + else + { + schematic->setAttribute(name, value); + schematic->setResourceMaxAttribute(name, resourceValue); + } + } + } + } + } + + return JNI_TRUE; +} // JavaLibrary::setSchematicAttributes + +/** + * Gets an attribute of a manufacturing schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param name name of the attribute to get + * @param experiment flag that these are experimental attributes + * + * @return the attribute, or null on error + */ +jobject JNICALL ScriptMethodsCraftingNamespace::getSchematicAttribute(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobject name, jboolean experiment) +{ + UNREF(self); + + if (manufacturingSchematic == 0 || name == 0) + return 0; + + ManufactureObjectInterface * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return 0; + + const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( + schematic->getDraftSchematic()); + if (draft == NULL) + return 0; + + StringId nameId; + if (!ScriptConversion::convert(name, nameId)) + return 0; + + if (experiment) + { + return JavaLibrary::createExperimentAttribute(*schematic, nameId)->getReturnValue(); + } + else + { + return JavaLibrary::createObjectAttribute(*schematic, *draft, draft->getAttribIndex(nameId))->getReturnValue(); + } +} // JavaLibrary::getSchematicAttribute + +/** + * Gets a select list of the attributes of a manufacturing schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param names names of the attributes to get + * @param experiment flag that these are experimental attributes + * + * @return the attributes, or null on error + */ +jobjectArray JNICALL ScriptMethodsCraftingNamespace::getSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray names, jboolean experiment) +{ + UNREF(self); + + if (manufacturingSchematic == 0) + return 0; + + ManufactureObjectInterface * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return 0; + + const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( + schematic->getDraftSchematic()); + if (draft == NULL) + return 0; + + int numAttribs = env->GetArrayLength(names); + + // create the attribute array + LocalObjectArrayRefPtr attributes = createNewObjectArray(numAttribs, JavaLibrary::getClsDraftSchematicAttrib()); + if (attributes == LocalObjectArrayRef::cms_nullPtr) + return 0; + + int i; + StringId attribName; + for (i = 0; i < numAttribs; ++i) + { + LocalRefPtr name = getObjectArrayElement(LocalObjectArrayRefParam(names), i); + if (!ScriptConversion::convert(*name, attribName)) + break; + + // create the attribute object + LocalRefPtr attribute; + if (experiment) + { + attribute = JavaLibrary::createExperimentAttribute(*schematic, attribName); + } + else + { + attribute = JavaLibrary::createObjectAttribute(*schematic, *draft, draft->getAttribIndex( + attribName)); + } + if (attribute == LocalRef::cms_nullPtr) + break; + + setObjectArrayElement(*attributes, i, *attribute); + } + + if (i != numAttribs) + { + attributes = LocalObjectArrayRef::cms_nullPtr; + } + + return attributes->getReturnValue(); +} // JavaLibrary::getSchematicAttributes + +/** + * Gets all the attributes of a manufacturing schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param experiment flag that these are experimental attributes + * + * @return the attributes, or null on error + */ +jobjectArray JNICALL ScriptMethodsCraftingNamespace::getAllSchematicAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jboolean experiment) +{ + UNREF(env); + UNREF(self); + + if (manufacturingSchematic == 0) + return 0; + + ManufactureObjectInterface * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return 0; + + const DraftSchematicObject * draft = DraftSchematicObject::getSchematic( + schematic->getDraftSchematic()); + if (draft == NULL) + return 0; + + // set the attributes + int numAttribs = 0; + const std::vector & experimentNames = schematic->getExperimentAttributeNames(); + if (experiment) + numAttribs = experimentNames.size(); + else + numAttribs = draft->getAttribsCount(); + LocalObjectArrayRefPtr attributes = createNewObjectArray(numAttribs, JavaLibrary::getClsDraftSchematicAttrib()); + if (attributes == LocalObjectArrayRef::cms_nullPtr) + return 0; + + for (int i = 0; i < numAttribs; ++i) + { + // create the attribute object + LocalRefPtr attribute; + if (experiment) + { + attribute = JavaLibrary::createExperimentAttribute(*schematic, experimentNames[i]); + } + else + { + attribute = JavaLibrary::createObjectAttribute(*schematic, *draft, i); + } + + setObjectArrayElement(*attributes, i, *attribute); + } + + return attributes->getReturnValue(); +} // JavaLibrary::getAllSchematicAttributes + +//---------------------------------------------------------------------- + +/** + * Returns a draft_schematic structure filled in with info about requested + * experimental attributes. The info will consist of the experimentation attribute + * data, the object attributes associated with them, and a mapping between the two. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic to get the data from + * @param attributeNames the experimental attributes we're interested about + * + * @return the draft_schematic object, or null on error + */ +jobject JNICALL ScriptMethodsCraftingNamespace::getSchematicForExperimentalAttributes(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray attributeNames) +{ +int i; + + UNREF(self); + + if (manufacturingSchematic == 0 || attributeNames == 0) + return 0; + + const ManufactureObjectInterface * manfSchematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, manfSchematic)) + return 0; + + const DraftSchematicObject * draftSchematic = DraftSchematicObject::getSchematic( + manfSchematic->getDraftSchematic()); + if (draftSchematic == NULL) + return 0; + + // create a draft_schematic object to return + LocalRefPtr target = allocObject(JavaLibrary::getClsDraftSchematic()); + if (target == LocalRef::cms_nullPtr) + return 0; + + // create the experimental attributes array + int numExperimentAttribs = env->GetArrayLength(attributeNames); + LocalObjectArrayRefPtr experimentalAttribs = createNewObjectArray(numExperimentAttribs, + JavaLibrary::getClsDraftSchematicAttrib()); + if (experimentalAttribs == LocalObjectArrayRef::cms_nullPtr) + return 0; + + // create the object attributes array + int numObjectAttribs = draftSchematic->getAttribsCount(); + LocalObjectArrayRefPtr objectAttribs = createNewObjectArray(numObjectAttribs, + JavaLibrary::getClsDraftSchematicAttrib()); + if (objectAttribs == LocalObjectArrayRef::cms_nullPtr) + return 0; + + // create a map of experimental attributes to object attributes + LocalRefPtr attribMap = createNewObject(JavaLibrary::getClsHashtable(), JavaLibrary::getMidHashtable()); + if (attribMap == LocalRef::cms_nullPtr) + return 0; + + std::vector objectAttribRefs; + + // create the object attributes objects + for (i = 0; i < numObjectAttribs; ++i) + { + // create the attribute object + LocalRefPtr attribute = JavaLibrary::createObjectAttribute(*manfSchematic, *draftSchematic, i); + if (attribute == LocalRef::cms_nullPtr) + { + objectAttribRefs.clear(); + return 0; + } + + setObjectArrayElement(*objectAttribs, i, *attribute); + objectAttribRefs.push_back(attribute); + } + setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribs(), *objectAttribs); + + // create the experimental attribute objects + StringId experimentAttribName; + for (i = 0; i < numExperimentAttribs; ++i) + { + // get the experimental attribute name + LocalRefPtr name = getObjectArrayElement(LocalObjectArrayRefParam(attributeNames), i); + if (name == LocalRef::cms_nullPtr) + { + objectAttribRefs.clear(); + return 0; + } + + if (!ScriptConversion::convert(*name, experimentAttribName)) + { + objectAttribRefs.clear(); + return 0; + } + + // get the data for the experimental attribute + LocalRefPtr attribute = JavaLibrary::createExperimentAttribute(*manfSchematic, + experimentAttribName); + if (attribute == LocalRef::cms_nullPtr) + { + objectAttribRefs.clear(); + return 0; + } + + setObjectArrayElement(*experimentalAttribs, i, *attribute); + + // find all the object attributes associated with this experimental + // attribute and map them to each other + LocalObjectArrayRefPtr mappedObjectAttribs = createNewObjectArray(numObjectAttribs, + JavaLibrary::getClsDraftSchematicAttrib()); + if (mappedObjectAttribs == LocalObjectArrayRef::cms_nullPtr) + { + objectAttribRefs.clear(); + return 0; + } + + int j; + int mappedObjectIndex = 0; + for (j = 0; j < numObjectAttribs; ++j) + { + if (draftSchematic->getAttribMin(j).value != draftSchematic->getAttribMax(j).value) + { + const SharedDraftSchematicObjectTemplate::SchematicAttribute & + objectAttrib = draftSchematic->getAttribMin(j); + if (objectAttrib.experiment == experimentAttribName) + { + setObjectArrayElement(*mappedObjectAttribs, mappedObjectIndex++, *objectAttribRefs[j]); + } + } + } + for (j = mappedObjectIndex; j < numObjectAttribs; ++j) + { + setObjectArrayElement(*mappedObjectAttribs, j, LocalRef(0)); + } + callObjectMethod(*attribMap, JavaLibrary::getMidMapPut(), attribute->getValue(), mappedObjectAttribs->getValue()); + } + setObjectField(*target, JavaLibrary::getFidDraftSchematicExperimentalAttribs(), *experimentalAttribs); + setObjectField(*target, JavaLibrary::getFidDraftSchematicAttribMap(), *attribMap); + + objectAttribRefs.clear(); + + return target->getReturnValue(); +} // JavaLibrary::getSchematicForExperimentalAttributes + +//---------------------------------------------------------------------- + +/** + * Sets an approximate experiment mod for an assembled schematic so the player will have some idea of + * the risk experimenting with an item. + * + * @param manufacturingSchematic the schematic + * @param experimentMod approximent mod that will be applied during experimentation + * + * @return true on success, false if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicExperimentMod(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat experimentMod) +{ + UNREF(self); + + ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + schematic->setExperimentMod(experimentMod); + + return JNI_TRUE; +} // JavaLibrary::setSchematicExperimentMod + +//---------------------------------------------------------------------- + +/** + * Sets the appearances that will be available to the player during customization. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic that will create the + * customized object + * @param appearances appearance filenames that the player may choose + * + * @return JNI_TRUE on success, JNI_FALSE on error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicAppearances(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray appearances) +{ + UNREF(self); + + if (manufacturingSchematic == 0 || appearances == 0) + return JNI_FALSE; + + ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + std::string appearance; + int count = env->GetArrayLength(appearances); + for (int i = 0; i < count; ++i) + { + JavaString appearanceString(static_cast(env->GetObjectArrayElement( + appearances, i))); + if (JavaLibrary::convert(appearanceString, appearance)) + { + schematic->addAppearance(appearance); + } + } + return JNI_TRUE; +} // JavaLibrary::setSchematicAppearances + +//---------------------------------------------------------------------- + +/** + * Sets the customization parameters that a player is allowed to change, or + * differ in their default value from the template. You do not have to set + * fixed customization parameters that use their default value. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic that will create the + * customized object + * @param customizations customization info + * + * @return JNI_TRUE on success, JNI_FALSE if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicCustomizations(JNIEnv *env, jobject self, jlong manufacturingSchematic, jobjectArray customizations) +{ + UNREF(self); + + if (manufacturingSchematic == 0 || customizations == 0) + return JNI_FALSE; + + ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + std::string name; + int count = env->GetArrayLength(customizations); + for (int i = 0; i < count; ++i) + { + LocalRefPtr custom = getObjectArrayElement(LocalObjectArrayRefParam(customizations), i); + if (custom == LocalRef::cms_nullPtr) + continue; + + JavaStringPtr jname = getStringField(*custom, JavaLibrary::getFidDraftSchematicCustomName()); + if (jname == JavaString::cms_nullPtr) + continue; + if (!JavaLibrary::convert(*jname, name)) + return JNI_FALSE; + + int value = getIntField(*custom, JavaLibrary::getFidDraftSchematicCustomValue()); + int minValue = getIntField(*custom, JavaLibrary::getFidDraftSchematicCustomMinValue()); + int maxValue = getIntField(*custom, JavaLibrary::getFidDraftSchematicCustomMaxValue()); + + schematic->setCustomization(name, value, minValue, maxValue); + } + + return JNI_TRUE; +} // JavaLibrary::setSchematicCustomizations + +//---------------------------------------------------------------------- + +/** + * Returns the number of items a manufacturing schematic can create. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * + * @return the number of items, or -1 on error + */ +jint JNICALL ScriptMethodsCraftingNamespace::getSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic) +{ + UNREF(self); + + if (manufacturingSchematic == 0) + return -1; + + const ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return -1; + + return schematic->getCount(); +} // JavaLibrary::getSchematicItemCount + +//---------------------------------------------------------------------- + +/** + * Sets the number of items a manufacturing schematic can create. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param count the number of items + * + * @return true on success, false if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicItemCount(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count) +{ + UNREF(self); + + if (manufacturingSchematic == 0) + return JNI_FALSE; + + ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + schematic->setCount(count); + return JNI_TRUE; +} // JavaLibrary::setSchematicItemCount + +//---------------------------------------------------------------------- + +/** + * Returns the numer of items per container a manufacturing schematic will + * create. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * + * @return the number of items, or -1 on error + */ +jint JNICALL ScriptMethodsCraftingNamespace::getSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic) +{ + UNREF(self); + + if (manufacturingSchematic == 0) + return -1; + + const ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return -1; + + return schematic->getItemsPerContainer(); +} // JavaLibrary::getSchematicItemsPerContainer + +//---------------------------------------------------------------------- + +/** + * Sets the numer of items per container a manufacturing schematic will + * create. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param count the number of items + * + * @return true on success, false if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicItemsPerContainer(JNIEnv *env, jobject self, jlong manufacturingSchematic, jint count) +{ + UNREF(self); + + if (manufacturingSchematic == 0) + return JNI_FALSE; + + ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + schematic->setItemsPerContainer(count); + return JNI_TRUE; +} // JavaLibrary::setSchematicItemsPerContainer + +//---------------------------------------------------------------------- + +/** + * Returns the time per complexity point it takes to manufacture an item with + * a manufacturing schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * + * @return the time, or -1 on error + */ +jfloat JNICALL ScriptMethodsCraftingNamespace::getSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic) +{ + UNREF(self); + + if (manufacturingSchematic == 0) + return -1.0f; + + const ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return -1.0f; + + return schematic->getManufactureTime(); +} // JavaLibrary::getSchematicManufactureTime + +//---------------------------------------------------------------------- + +/** + * Sets the time per complexity point it takes to manufacture an item with + * a manufacturing schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic + * @param time the manufacturing time per complexity + * + * @return true on success, false if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSchematicManufactureTime(JNIEnv *env, jobject self, jlong manufacturingSchematic, jfloat time) +{ + UNREF(self); + + if (manufacturingSchematic == 0) + return JNI_FALSE; + + ManufactureSchematicObject * schematic = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematic)) + return JNI_FALSE; + + schematic->setManufactureTime(time); + return JNI_TRUE; +} // JavaLibrary::setSchematicManufactureTime + +//---------------------------------------------------------------------- + +/** + * Sets the amount of xp the creator of an object will get when an object is "used". + * + * @param env Java environment + * @param self class calling this function + * @param object the object that will grant the xp + * @param xp the amount of xp to grant + * + * @return true on success, false if there was an error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setCreatorXp(JNIEnv *env, jobject self, jlong object, jint xp) +{ + UNREF(self); + + TangibleObject * target = NULL; + if (!JavaLibrary::getObject(object, target)) + return JNI_FALSE; + + target->setCreatorXp(xp); + return JNI_TRUE; +} // JavaLibrary::setCreatorXp + +/** + * Gets a list of ingredients needed to craft using the current manufacturing + * schematic in a manufacturing station. + * + * @param env Java environment + * @param self class calling this function + * @param station the manufacturing station id + * @param ingredients array to be filled in with a string array of ingredients + */ +void JNICALL ScriptMethodsCraftingNamespace::getIngredientsForManufactureStation(JNIEnv *env, jobject self, jlong station, jobjectArray ingredients) +{ + UNREF(self); + + if (station == 0 || ingredients == 0) + return; + + const ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return; + + if (env->GetArrayLength(ingredients) != 1) + return; + + const ManufactureSchematicObject * const schematic = manfStation->getSchematic(); + if (schematic == NULL) + return; + + static ManufactureSchematicObject::IngredientInfoVector iiv; + iiv.clear (); + + schematic->getIngredientInfo (iiv); + + if (iiv.empty ()) + return; + + const size_t count = iiv.size(); + + LocalObjectArrayRefPtr ingredientList = createNewObjectArray(count, JavaLibrary::getClsString()); + if (ingredientList == LocalObjectArrayRef::cms_nullPtr) + return; + + char buf [128]; + const size_t buf_size = sizeof (buf); + + for (size_t i = 0; i < count; ++i) + { + const ManufactureSchematicObject::IngredientInfo & info = iiv [i]; + + const Unicode::String & name = info.first; + const int numPerItem = info.second.second; + + if (name.empty ()) + continue; + + snprintf (buf, buf_size, ":\\>200%d", numPerItem); + + Unicode::String element = name; + + if (name [0] == '@') + element.push_back ('\0'); + + element += Unicode::narrowToWide (buf); + + JavaString jelement(element); + setObjectArrayElement(*ingredientList, i, jelement); + } + + setObjectArrayElement(LocalObjectArrayRefParam(ingredients), 0, *ingredientList); +} // JavaLibrary::getIngredientsForManufactureStation + +//---------------------------------------------------------------------- + +/** + * Gets the id of a manufacture station's input hopper. + * + * @param env Java environment + * @param self class calling this function + * @param station the station id + * + * @return the hopper id, or null on error + */ +jlong JNICALL ScriptMethodsCraftingNamespace::getManufactureStationInputHopper(JNIEnv *env, jobject self, jlong station) +{ + UNREF(self); + + if (station == 0) + return 0; + + const ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return 0; + + ServerObject * hopper = manfStation->getInputHopper(); + if (hopper == NULL) + return 0; + + return (hopper->getNetworkId()).getValue(); +} // JavaLibrary::getManufactureStationInputHopper + +//---------------------------------------------------------------------- + +/** + * Gets the id of a manufacture station's output hopper. + * + * @param env Java environment + * @param self class calling this function + * @param station the station id + * + * @return the hopper id, or null on error + */ +jlong JNICALL ScriptMethodsCraftingNamespace::getManufactureStationOutputHopper(JNIEnv *env, jobject self, jlong station) +{ + UNREF(self); + + if (station == 0) + return 0; + + const ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return 0; + + ServerObject * hopper = manfStation->getOutputHopper(); + if (hopper == NULL) + return 0; + + return (hopper->getNetworkId()).getValue(); +} // JavaLibrary::getManufactureStationOutputHopper + +//---------------------------------------------------------------------- + +/** + * Gets the id and name of the schematic in a manufacture station. + * + * @param env Java environment + * @param self class calling this function + * @param station the station id + * + * @return a string of the form "*" , or null if the station has no schematic + */ +jstring JNICALL ScriptMethodsCraftingNamespace::getManufactureStationSchematic(JNIEnv *env, jobject self, jlong station) +{ + static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); + + UNREF(self); + + const ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return 0; + + const ManufactureSchematicObject * manfSchematic = manfStation->getSchematic(); + if (manfSchematic == NULL) + return 0; + + return JavaString( + Unicode::narrowToWide(manfSchematic->getNetworkId().getValueString()) + + SEPARATOR + + manfSchematic->getObjectName() + ).getReturnValue(); +} // JavaLibrary::getManufactureStationSchematic + +//---------------------------------------------------------------------- + +/** + * Gets a list of manufacture schematics that could be used at a given manufacturing + * station. + * + * @param env Java environment + * @param self class calling this function + * @param player the player whose schematics to get + * @param station the manufacturing station + * @param schematics array to be filled in with a string array of schematics + */ +void JNICALL ScriptMethodsCraftingNamespace::getValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station, jobjectArray schematics) +{ + static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); + + UNREF(self); + + if (player == 0 || station == 0 || schematics == 0) + return; + + CreatureObject * playerCreature = NULL; + if (!JavaLibrary::getObject(player, playerCreature)) + return; + + const ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return; + + if (env->GetArrayLength(schematics) != 1) + return; + + std::vector manfSchematics; + uint32 stationTypes = manfStation->getValidSchematicTypes(); + playerCreature->getManufactureSchematics(manfSchematics, stationTypes); + + int count = manfSchematics.size(); + LocalObjectArrayRefPtr schematicList = createNewObjectArray(count, JavaLibrary::getClsString()); + if (schematicList == LocalObjectArrayRef::cms_nullPtr) + return; + + for (int i = 0; i < count; ++i) + { + const ManufactureSchematicObject * manfSchematic = manfSchematics[i]; + setObjectArrayElement(*schematicList, i, + JavaString( + Unicode::narrowToWide(manfSchematic->getNetworkId().getValueString()) + + SEPARATOR + + manfSchematic->getObjectName() + )); + } + + setObjectArrayElement(LocalObjectArrayRefParam(schematics), 0, *schematicList); +} // JavaLibrary::getValidManufactureSchematicsForStation + +//---------------------------------------------------------------------- + +/** + * Checks if a player has any manufacture schematics that could be used at a + * given manufacturing station. + * + * @param env Java environment + * @param self class calling this function + * @param player the player whose schematics to check + * @param station the manufacturing station + * + * @return true if the player has any schematics, false if not + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::hasValidManufactureSchematicsForStation(JNIEnv *env, jobject self, jlong player, jlong station) +{ + static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); + + UNREF(self); + + if (player == 0 || station == 0) + return JNI_FALSE; + + CreatureObject * playerCreature = NULL; + if (!JavaLibrary::getObject(player, playerCreature)) + return JNI_FALSE; + + const ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return JNI_FALSE; + + std::vector manfSchematics; + playerCreature->getManufactureSchematics(manfSchematics, + manfStation->getValidSchematicTypes()); + + if (manfSchematics.empty()) + return JNI_FALSE; + return JNI_TRUE; +} // JavaLibrary::hasValidManufactureSchematicsForStation + +//---------------------------------------------------------------------- + +/** + * Transfers the manufacture schematic in a manufacturing station to a player. + * + * @param env Java environment + * @param self class calling this function + * @param station the manufacturing station id + * @param player the the player to transfer to + * + * @return true if the schematic was transferred, false if not + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::transferManufactureSchematicToPlayer(JNIEnv *env, jobject self, jlong station, jlong player) +{ + UNREF(self); + + const ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return JNI_FALSE; + + ManufactureSchematicObject * schematic = manfStation->getSchematic(); + if (schematic == NULL) + return JNI_TRUE; + + CreatureObject * playerCreature = NULL; + if (!JavaLibrary::getObject(player, playerCreature)) + return JNI_FALSE; + + ServerObject * datapad = playerCreature->getDatapad(); + if (datapad == NULL) + return JNI_FALSE; + + Container::ContainerErrorCode tmp = Container::CEC_Success; + if (ContainerInterface::transferItemToVolumeContainer(*datapad, *schematic, NULL, tmp)) + return JNI_TRUE; + return JNI_FALSE; +} // JavaLibrary::transferManufactureSchematicToPlayer + +//---------------------------------------------------------------------- + +/** + * Transfers a manufacture schematic to a manufacturing station. + * + * @param env Java environment + * @param self class calling this function + * @param schematic the schematic id + * @param station the manufacturing station id + * + * @return true if the schematic was transferred, false if not + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::transferManufactureSchematicToStation(JNIEnv *env, jobject self, jlong schematic, jlong station) +{ + UNREF(self); + + ManufactureSchematicObject * manfSchematic = NULL; + if (!JavaLibrary::getObject(schematic, manfSchematic)) + return JNI_FALSE; + + ManufactureInstallationObject * manfStation = NULL; + if (!JavaLibrary::getObject(station, manfStation)) + return JNI_FALSE; + + if (manfStation->addSchematic(*manfSchematic, NULL)) + return JNI_TRUE; + return JNI_FALSE; +} // JavaLibrary::transferManufactureSchematicToStation + +//---------------------------------------------------------------------- + +/** + * Gets a list of objects that can be repaired by a given repair tool. + * + * @param env Java environment + * @param self class calling this function + * @param player the player whose objects to get + * @param tool the repair tool + * @param objects array to be filled in with a string array of objects + */ +void JNICALL ScriptMethodsCraftingNamespace::getRepairableObjectsForTool(JNIEnv *env, jobject self, jlong player, jlong tool, jobjectArray objects) +{ + static const Unicode::String SEPARATOR(Unicode::narrowToWide("*")); + + if (player == 0 || tool == 0 || objects == 0) + return; + + CreatureObject * playerCreature = NULL; + if (!JavaLibrary::getObject(player, playerCreature)) + return; + + const TangibleObject * toolObject = NULL; + if (!JavaLibrary::getObject(tool, toolObject)) + return; + if (!toolObject->isRepairTool()) + return; + int toolType = toolObject->getCraftingType(); + + // determine if the repair tool repairs a specific GOT or a category + bool genericTool = false; + if ((toolType & 0x000000ff) == 0) + genericTool = true; + + if (env->GetArrayLength(objects) != 1) + return; + + // @todo: we need to get a list of things the player owns that are loaded, + // so non-inventory objects can be repaired. For now, just repair inventory + // objects + + const ServerObject * inventory = playerCreature->getInventory(); + if (inventory == NULL) + return; + + const VolumeContainer * inventoryContainer = ContainerInterface::getVolumeContainer(*inventory); + if (inventoryContainer == NULL) + return; + + std::vector objList; + for (ContainerConstIterator iter(inventoryContainer->begin()); + iter != inventoryContainer->end(); ++iter) + { + const CachedNetworkId & objId = (*iter); + const TangibleObject * obj = safe_cast(objId.getObject()); + if (obj != NULL && !obj->isCraftingTool() && !obj->isRepairTool() && + obj->getDamageTaken() > 0) + { + if ((genericTool && (toolType & obj->getGameObjectType()) != 0) || + (!genericTool && toolType == obj->getGameObjectType())) + { + objList.push_back( + Unicode::narrowToWide(obj->getNetworkId().getValueString()) + + SEPARATOR + + obj->getEncodedObjectName ()); + } + } + } + + int count = objList.size(); + LocalObjectArrayRefPtr objectStringList = createNewObjectArray(count, JavaLibrary::getClsString()); + if (objectStringList == LocalObjectArrayRef::cms_nullPtr) + return; + + for (int i = 0; i < count; ++i) + { + setObjectArrayElement(*objectStringList, i, JavaString(objList[i])); + } + + setObjectArrayElement(LocalObjectArrayRefParam(objects), 0, *objectStringList); +} // JavaLibrary::getRepairableObjectsForTool + +//---------------------------------------------------------------------- + +/** + * Returns the attribute bonuses an object grants when equipped. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * + * @return an array with the bonus for each attribute, or null on error + */ +jintArray JNICALL ScriptMethodsCraftingNamespace::getAttributeBonuses(JNIEnv *env, jobject self, jlong target) +{ + UNREF(self); + + const ServerObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return 0; + + std::vector > bonuses; + if (object->asTangibleObject() != NULL) + { + object->asTangibleObject()->getAttribBonuses(bonuses); + } + else if (object->asManufactureSchematicObject() != NULL) + { + object->asManufactureSchematicObject()->getAttribBonuses(bonuses); + } + else + return 0; + + jint bonusesArray[Attributes::NumberOfAttributes]; + { + for (int i = 0; i < Attributes::NumberOfAttributes; ++i) + bonusesArray[i] = 0; + } + { + for (std::vector >::const_iterator i = bonuses.begin(); + i != bonuses.end(); ++i) + { + if ((*i).first >= 0 && (*i).first < Attributes::NumberOfAttributes) + bonusesArray[(*i).first] = (*i).second; + } + } + + LocalIntArrayRefPtr jbonuses = createNewIntArray(Attributes::NumberOfAttributes); + if (jbonuses == LocalIntArrayRef::cms_nullPtr) + return 0; + + setIntArrayRegion(*jbonuses, 0, Attributes::NumberOfAttributes, &bonusesArray[0]); + return jbonuses->getReturnValue(); +} // JavaLibrary::getAttributeBonuses + +//---------------------------------------------------------------------- + +/** + * Returns the attribute bonus of an object for a given attribute. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * @param attribute the attribute to get + * + * @return the attribute bonus + */ +jint JNICALL ScriptMethodsCraftingNamespace::getAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute) +{ + UNREF(self); + + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + return 0; + + const ServerObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return 0; + + jint bonus = 0; + if (object->asTangibleObject() != NULL) + { + bonus = object->asTangibleObject()->getAttribBonus(attribute); + } + else if (object->asManufactureSchematicObject() != NULL) + { + bonus = object->asManufactureSchematicObject()->getAttribBonus(attribute); + } + return bonus; +} // JavaLibrary::getAttributeBonus + +//---------------------------------------------------------------------- + +/** + * Sets the attribute bonus an object applies when equipped. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * @param attribute the attribute to set + * @param bonus the attribute bonus value + * + * @return true on success, false on error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setAttributeBonus(JNIEnv *env, jobject self, jlong target, jint attribute, jint bonus) +{ + UNREF(self); + + if (attribute < 0 || attribute >= Attributes::NumberOfAttributes) + return JNI_FALSE; + + ServerObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return JNI_FALSE; + + if (object->asTangibleObject() != NULL) + { + object->asTangibleObject()->setAttribBonus(attribute, bonus); + } + else if (object->asManufactureSchematicObject() != NULL) + { + object->asManufactureSchematicObject()->setAttribBonus(attribute, bonus); + } + else + return JNI_FALSE; + return JNI_TRUE; +} // JavaLibrary::setAttributeBonus + +//---------------------------------------------------------------------- + +/** + * Sets the attribute bonuses an object applies when equipped. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * @param bonuses the attribute bonus values + * + * @return true on success, false on error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setAttributeBonuses(JNIEnv *env, jobject self, jlong target, jintArray bonuses) +{ + UNREF(self); + + if (bonuses == 0) + return JNI_FALSE; + + ServerObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return JNI_FALSE; + + jsize count = env->GetArrayLength(bonuses); + if (count != Attributes::NumberOfAttributes) + { + WARNING(true, ("JavaLibrary::setAttributeBonuses passed bad array of " + "size %u", count)); + return JNI_FALSE; + } + + jint buffer[Attributes::NumberOfAttributes]; + env->GetIntArrayRegion(bonuses, 0, count, buffer); + + if (object->asTangibleObject() != NULL) + { + TangibleObject * tangibleObject = object->asTangibleObject(); + for (jsize i = 0; i < count; ++i) + tangibleObject->setAttribBonus(i, buffer[i]); + } + else if (object->asManufactureSchematicObject() != NULL) + { + ManufactureSchematicObject * manufactureSchematicObject = object->asManufactureSchematicObject(); + for (jsize i = 0; i < count; ++i) + manufactureSchematicObject->setAttribBonus(i, buffer[i]); + } + else + return JNI_FALSE; + + return JNI_TRUE; +} // JavaLibrary::setAttributeBonus + +//---------------------------------------------------------------------- + +/** + * Returns the skill mod bonuses an object grants when equipped. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * + * @return a dictionary of skill mod names -> mod values, or null on error + */ +jobject JNICALL ScriptMethodsCraftingNamespace::getSkillModBonuses(JNIEnv *env, jobject self, jlong target) +{ + UNREF(self); + + const TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return 0; + + std::vector > skillModBonuses; + object->getSkillModBonuses(skillModBonuses); + + // put the bonuses into ScriptParams, and then convert to a dictionary + ScriptParams params; + int count = skillModBonuses.size(); + for (int i = 0; i < count; ++i) + { + params.addParam(skillModBonuses[i].second, skillModBonuses[i].first); + } + JavaDictionaryPtr dictionary; + JavaLibrary::instance()->convert(params, dictionary); + + return dictionary->getReturnValue(); +} // JavaLibrary::getSkillModBonuses + +//---------------------------------------------------------------------- + +/** + * Returns the skill mod bonus of an object for a given skill mod. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * @param skillMod the skill mod to get + * + * @return the skill mod value + */ +jint JNICALL ScriptMethodsCraftingNamespace::getSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod) +{ + UNREF(self); + + JavaStringParam jskillMod(skillMod); + + const TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return 0; + + std::string skillModName; + if (!JavaLibrary::convert(jskillMod, skillModName)) + return 0; + + return object->getSkillModBonus(skillModName); +} // JavaLibrary::getSkillModBonus + +//---------------------------------------------------------------------- + +/** + * Sets the base skill mod bonus an object applies when equipped. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * @param skillMod the skill mod to set + * @param bonus the skill mod bonus value + * + * @return true on success, false on error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring skillMod, jint bonus) +{ + UNREF(self); + + JavaStringParam jskillMod(skillMod); + + TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return JNI_FALSE; + + std::string skillModName; + if (!JavaLibrary::convert(jskillMod, skillModName)) + return JNI_FALSE; + + object->setSkillModBonus(skillModName, bonus); + return JNI_TRUE; +} // JavaLibrary::setSkillModBonus + +//---------------------------------------------------------------------- + +/** + * Sets the base skill mod bonuses an object applies when equipped. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * @param skillMod the skill mods to set + * @param bonus the skill mod bonus values + * + * @return true on success, false on error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSkillModBonuses(JNIEnv *env, jobject self, jlong target, jobjectArray skillMod, jintArray bonus) +{ + UNREF(self); + + TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return JNI_FALSE; + + if (skillMod == 0 || bonus == 0) + return JNI_FALSE; + + int skillModCount = env->GetArrayLength(skillMod); + int bonusCount = env->GetArrayLength(bonus); + if (skillModCount != bonusCount) + { + DEBUG_WARNING(true, ("[designer bug] setSkillModBonuses called with unequal " + "array sizes")); + return JNI_FALSE; + } + + std::string skillName; + const jint * bonusArray = env->GetIntArrayElements(bonus, NULL); + for (int i = 0; i < skillModCount; ++i) + { + JavaStringParam jskillName(static_cast(env->GetObjectArrayElement(skillMod, i))); + JavaLibrary::convert(jskillName, skillName); + object->setSkillModBonus(skillName, bonusArray[i]); + } + env->ReleaseIntArrayElements(bonus, const_cast(bonusArray), JNI_ABORT); + + return JNI_TRUE; +} // JavaLibrary::setSkillModBonuses + +//---------------------------------------------------------------------- + +/** +* Sets the base skill mod bonus an object applies when equipped. +* +* @param env Java environment +* @param self class calling this function +* @param target the object +* @param category the category of the skill mod bonus +* multiple/independent bonuses can be granted +* for a particular skill mod by putting them +* into different categories +* @param skillMod the skill mod to set +* @param bonus the skill mod bonus value +* +* @return true on success, false on error +*/ +jboolean JNICALL ScriptMethodsCraftingNamespace::setCategorizedSkillModBonus(JNIEnv *env, jobject self, jlong target, jstring category, jstring skillMod, jint bonus) +{ + UNREF(self); + + JavaStringParam jcategory(category); + JavaStringParam jskillMod(skillMod); + + TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return JNI_FALSE; + + std::string categoryName; + if (!JavaLibrary::convert(jcategory, categoryName)) + return JNI_FALSE; + + std::string skillModName; + if (!JavaLibrary::convert(jskillMod, skillModName)) + return JNI_FALSE; + + object->setSkillModBonus(categoryName, skillModName, bonus); + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +/** +* Removes all skill mod bonuses in a particular category on an object. +* +* @param env Java environment +* @param self class calling this function +* @param target the object +* @param category the category of the skill mod bonus +* multiple/independent bonuses can be granted +* for a particular skill mod by putting them +* into different categories +*/ +void JNICALL ScriptMethodsCraftingNamespace::removeCategorizedSkillModBonuses(JNIEnv *env, jobject self, jlong target, jstring category) +{ + UNREF(self); + + JavaStringParam jcategory(category); + + TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return; + + std::string categoryName; + if (!JavaLibrary::convert(jcategory, categoryName)) + return; + + object->removeCategorizedSkillModBonuses(categoryName); +} + +//---------------------------------------------------------------------- + +/** + * Returns the number of available skill mod sockets of an object. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * + * @return the number of sockets + */ +jint JNICALL ScriptMethodsCraftingNamespace::getSkillModSockets(JNIEnv *env, jobject self, jlong target) +{ + UNREF(self); + + const TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return 0; + + return object->getSkillModSockets(); +} // JavaLibrary::getSkillModSockets + +//---------------------------------------------------------------------- + +/** + * Sets the number of available skill mod sockets for an object. + * + * @param env Java environment + * @param self class calling this function + * @param target the object + * @param sockets the number of sockets + * + * @return true on success, false on error + */ +jboolean JNICALL ScriptMethodsCraftingNamespace::setSkillModSockets(JNIEnv *env, jobject self, jlong target, jint sockets) +{ + UNREF(self); + + TangibleObject * object = NULL; + if (!JavaLibrary::getObject(target, object)) + return JNI_FALSE; + + object->setSkillModSockets(sockets); + return JNI_TRUE; +} // JavaLibrary::setSkillModSockets + +//---------------------------------------------------------------------- + +/** + * Creates a new item based on a draft schematic. The item will have stats + * based on a % value passed in (0 = worst possible stats, 100 = best possible + * stats). + * + * @param env Java environment + * @param self class calling this function + * @param draftSchematic draft schematic to make the object from + * @param qualityPercent % stat adjustment + * @param container the container to create the item in + * + * @return the item, or null on error + */ +jlong JNICALL ScriptMethodsCraftingNamespace::makeCraftedItem(JNIEnv *env, jobject self, jstring draftSchematic, jfloat qualityPercent, jlong container) +{ + UNREF(self); + + if (draftSchematic == 0 || container == 0) + { + WARNING(true, ("[script bug] null schematic or container passed to " + "makeCraftedItem")); + return 0; + } + + JavaStringParam jDraftSchematic(draftSchematic); + std::string draftSchematicName; + if (!JavaLibrary::convert(jDraftSchematic, draftSchematicName)) + { + WARNING(true, ("JavaLibrary::makeCraftedItem can't convert schematic " + "name to string")); + return 0; + } + + const DraftSchematicObject * schematic = DraftSchematicObject::getSchematic( + draftSchematicName); + if (schematic == NULL) + { + WARNING(true, ("[script bug] bad schematic name %s passed to " + "makeCraftedItem", draftSchematicName.c_str())); + return 0; + } + + ServerObject * target = NULL; + if (!JavaLibrary::getObject(container, target)) + { + WARNING(true, ("[script bug] bad container id passed to makeCraftedItem")); + return 0; + } + Object * targetParent = ContainerInterface::getFirstParentInWorld(*target); + if (targetParent == NULL) + { + WARNING(true, ("JavaLibrary::makeCraftedItem can't find parent in world " + "for container %s", target->getNetworkId().getValueString().c_str())); + return 0; + } + Vector createPos(targetParent->getPosition_w()); + createPos.y = -100000.0f; + + // create a manf schematic and prototype + ManufactureSchematicObject * manfSchematic = ServerWorld::createNewManufacturingSchematic( + *schematic, createPos, false); + if (manfSchematic == NULL) + { + WARNING(true, ("JavaLibrary::makeCraftedItem: error creating manf " + "schematic!")); + return 0; + } + ServerObject * prototype = manfSchematic->manufactureObject(createPos); + if (prototype == NULL) + { + WARNING(true, ("JavaLibrary::makeCraftedItem: error creating " + "prototype!")); + manfSchematic->permanentlyDestroy(DeleteReasons::SetupFailed); + return false; + } + + if (qualityPercent < 0.0f) + qualityPercent = 0.0f; + else if (qualityPercent > 100.0f) + qualityPercent = 100.0f; + + ScriptParams params; + params.addParam(prototype->getNetworkId()); + params.addParam(*manfSchematic); + params.addParam(qualityPercent); + IGNORE_RETURN(manfSchematic->getScriptObject()->trigAllScripts( + Scripting::TRIG_MAKE_CRAFTED_ITEM, params)); + + manfSchematic->permanentlyDestroy(DeleteReasons::Consumed); + Container::ContainerErrorCode error; + if (!ContainerInterface::transferItemToVolumeContainer (*target, *prototype, + NULL, error, true)) + { + WARNING(true, ("JavaLibrary::makeCraftedItem: error can't store prototype " + "in container, error = %d", error)); + prototype->permanentlyDestroy(DeleteReasons::BadContainerTransfer); + return 0; + } + + return (prototype->getNetworkId()).getValue(); +} // JavaLibrary::makeCraftedItem + +//---------------------------------------------------------------------- + +/** + * Returns a draft_schematic structure filled in with info used by a manufacturing + * schematic. + * + * @param env Java environment + * @param self class calling this function + * @param manufacturingSchematic the schematic to get the data from + * + * @return the draft_schematic object, or null on error + */ +jobject JNICALL ScriptMethodsCraftingNamespace::getSchematicData(JNIEnv *env, jobject self, jlong manufacturingSchematic) +{ + if (manufacturingSchematic == 0) + return 0; + + const ManufactureSchematicObject * schematicObject = NULL; + if (!JavaLibrary::getObject(manufacturingSchematic, schematicObject)) + return 0; + + return JavaLibrary::convert(*schematicObject)->getReturnValue(); +} // JavaLibrary::getSchematicData + +//---------------------------------------------------------------------- + +/** + * Returns a draft_schematic structure filled in with info used by a draft + * schematic. + * + * @param env Java environment + * @param self class calling this function + * @param draftSchematic the schematic to get the data from + * + * @return the draft_schematic object, or null on error + */ +jobject JNICALL ScriptMethodsCraftingNamespace::getDraftSchematicData(JNIEnv *env, jobject self, + jstring draftSchematic) +{ + if (draftSchematic == 0) + return 0; + + JavaStringParam jdraftSchematic(draftSchematic); + std::string schematicName; + if (!JavaLibrary::convert(jdraftSchematic, schematicName)) + return 0; + + const DraftSchematicObject * schematicObject = DraftSchematicObject::getSchematic(schematicName); + if (schematicObject == NULL) + return 0; + + return JavaLibrary::convert(*schematicObject); +} // JavaLibrary::getSchematicData + +//---------------------------------------------------------------------- + +/** + * Returns a draft_schematic structure filled in with info used by a draft + * schematic. + * + * @param env Java environment + * @param self class calling this function + * @param draftSchematicCrc the schematic to get the data from + * + * @return the draft_schematic object, or null on error + */ +jobject JNICALL ScriptMethodsCraftingNamespace::getDraftSchematicDataCrc(JNIEnv *env, jobject self, + jint draftSchematicCrc) +{ + if (draftSchematicCrc == 0) + return 0; + + const DraftSchematicObject * schematicObject = DraftSchematicObject::getSchematic(draftSchematicCrc); + if (schematicObject == NULL) + return 0; + + return JavaLibrary::convert(*schematicObject); +} // JavaLibrary::getSchematicDataCrc + +//---------------------------------------------------------------------- + +/** + * Causes the stats of a crate of manufactured objects to get recomputed from the + * crate's objvars. + * IMPORTANT: This only affects the stats of new objects that get pulled out of the + * crate! It is up to the caller to modify the "examine" item stored in the crate. + * + * @param env Java environment + * @param self class calling this function + * @param crate the crate to recompute the stats of + */ +void JNICALL ScriptMethodsCraftingNamespace::recomputeCrateAttributes(JNIEnv *env, jobject self, jlong crate) +{ + FactoryObject * factory = NULL; + if (!JavaLibrary::getObject(crate, factory)) + return; + + factory->calculateAttributes(); +} + +//---------------------------------------------------------------------- diff --git a/src/engine/server/library/serverScript/src/shared/ScriptMethodsDataTable.cpp b/src/engine/server/library/serverScript/src/shared/ScriptMethodsDataTable.cpp index faf8bdb00..e84b0de64 100644 --- a/src/engine/server/library/serverScript/src/shared/ScriptMethodsDataTable.cpp +++ b/src/engine/server/library/serverScript/src/shared/ScriptMethodsDataTable.cpp @@ -1,1591 +1,1591 @@ -// ScriptMethodsDataTable.cpp -// -// copyright 2001 Sony Online Entertainment -// -//======================================================================== - -#include "serverScript/FirstServerScript.h" -#include "serverScript/JavaLibrary.h" - -#include "fileInterface/StdioFile.h" -#include "sharedDebug/Profiler.h" -#include "sharedUtility/DataTable.h" -#include "sharedUtility/DataTableManager.h" - -using namespace JNIWrappersNamespace; - - -//------------------------------------------------------------------------ -//lint -e818 //env could be declared const - -// ====================================================================== - -#ifdef _DEBUG -static char const *findNextChar(char const *s, char c) -{ - char const *tmp = s; - while (tmp && *tmp != '\0') - { - if (*tmp == c) - return tmp; - ++tmp; - } - return 0; -} -#endif - -// ---------------------------------------------------------------------- - -//ifdef out because this is currently only used in debug builds, and breaks the release build -#ifdef _DEBUG -static void parseTabbedLine(char const *line, int length, std::vector &results) -{ - char const *currentPos = line; - char const *tab = findNextChar(currentPos, '\t'); - char const *lineEnd = line+length; - if (lineEnd > line && *(lineEnd-1) == '\r') - --lineEnd; - while (tab && tab < lineEnd) - { - results.push_back(std::string(currentPos, tab-currentPos)); - currentPos = tab+1; - tab = findNextChar(currentPos, '\t'); - } - results.push_back(std::string(currentPos, lineEnd-currentPos)); -} -#endif - -// ====================================================================== -// ScriptMethodsDataTableNamespace -// ====================================================================== - -namespace ScriptMethodsDataTableNamespace -{ - bool install(); - - jint JNICALL dataTableGetInt(JNIEnv *env, jobject self, jstring table, jint row, jstring column); - jfloat JNICALL dataTableGetFloat(JNIEnv *env, jobject self, jstring table, jint row, jstring column); - jstring JNICALL dataTableGetString(JNIEnv *env, jobject self, jstring table, jint row, jstring column); - jintArray JNICALL dataTableGetIntColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults); - jintArray JNICALL dataTableGetIntColumn(JNIEnv *env, jobject self, jstring table, jstring column); - jintArray JNICALL dataTableGetIntColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column); - jfloatArray JNICALL dataTableGetFloatColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults); - jfloatArray JNICALL dataTableGetFloatColumn(JNIEnv *env, jobject self, jstring table, jstring column); - jfloatArray JNICALL dataTableGetFloatColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column); - jobjectArray JNICALL dataTableGetStringColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults); - jobjectArray JNICALL dataTableGetStringColumn(JNIEnv *env, jobject self, jstring table, jstring column); - jobjectArray JNICALL dataTableGetStringColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column); - jint JNICALL dataTableGetIntA(JNIEnv *env, jobject self, jstring table, jint row, jint column); - jfloat JNICALL dataTableGetFloatA(JNIEnv *env, jobject self, jstring table, jint row, jint column); - jstring JNICALL dataTableGetStringA(JNIEnv *env, jobject self, jstring table, jint row, jint column); - jintArray JNICALL dataTableGetIntColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults); - jintArray JNICALL dataTableGetIntColumnA(JNIEnv *env, jobject self, jstring table, jint column); - jintArray JNICALL dataTableGetIntColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column); - jfloatArray JNICALL dataTableGetFloatColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults); - jfloatArray JNICALL dataTableGetFloatColumnA(JNIEnv *env, jobject self, jstring table, jint column); - jfloatArray JNICALL dataTableGetFloatColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column); - jobjectArray JNICALL dataTableGetStringColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults); - jobjectArray JNICALL dataTableGetStringColumnA(JNIEnv *env, jobject self, jstring table, jint column); - jobjectArray JNICALL dataTableGetStringColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column); - jboolean JNICALL dataTableOpen(JNIEnv *env, jobject self, jstring table); - jint JNICALL dataTableGetColumnType(JNIEnv *env, jobject self, jstring table, jstring column); - jint JNICALL dataTableGetColumnTypeA(JNIEnv *env, jobject self, jstring table, jint column); - jboolean JNICALL dataTableHasColumn(JNIEnv *env, jobject self, jstring table, jstring column); - jint JNICALL dataTableGetNumColumns (JNIEnv *env, jobject self, jstring table); - jint JNICALL dataTableGetNumRows (JNIEnv *env, jobject self, jstring table); - jobject JNICALL dataTableGetRow(JNIEnv *env, jobject self, jstring table, jint row); - jstring JNICALL dataTableGetColumnName(JNIEnv *env, jobject self, jstring table, jint column); - jobjectArray JNICALL dataTableGetColumnNames(JNIEnv *env, jobject self, jstring table); - jint JNICALL dataTableSearchColumnForString(JNIEnv *env, jobject self, jstring entry, jstring column, jstring table); - jint JNICALL dataTableSearchColumnForInt(JNIEnv *env, jobject self, jint entry, jstring column, jstring table); - jint JNICALL dataTableSearchColumnForStringA(JNIEnv *env, jobject self, jstring entry, jint column, jstring table); - jint JNICALL dataTableSearchColumnForIntA(JNIEnv *env, jobject self, jint entry, jint column, jstring table); - jint JNICALL dataTableFindColumnNumber(JNIEnv *env, jobject self, jstring table, jstring column); - void JNICALL dataTableAddRow(JNIEnv *env, jobject self, jstring table, jobject row); -} - - -//======================================================================== -// install -//======================================================================== - -bool ScriptMethodsDataTableNamespace::install() -{ -const JNINativeMethod NATIVES[] = { - #define JF(a,b,c) {a,b,(void*)(ScriptMethodsDataTableNamespace::c)} - JF("dataTableGetInt", "(Ljava/lang/String;ILjava/lang/String;)I", dataTableGetInt), - JF("dataTableGetFloat", "(Ljava/lang/String;ILjava/lang/String;)F", dataTableGetFloat), - JF("dataTableGetString", "(Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;", dataTableGetString), - JF("dataTableGetInt", "(Ljava/lang/String;II)I", dataTableGetIntA), - JF("dataTableGetFloat", "(Ljava/lang/String;II)F", dataTableGetFloatA), - JF("dataTableGetString", "(Ljava/lang/String;II)Ljava/lang/String;", dataTableGetStringA), - JF("dataTableGetIntColumn", "(Ljava/lang/String;Ljava/lang/String;)[I", dataTableGetIntColumn), - JF("dataTableGetIntColumnNoDefaults", "(Ljava/lang/String;Ljava/lang/String;)[I", dataTableGetIntColumnNoDefaults), - JF("dataTableGetFloatColumn", "(Ljava/lang/String;Ljava/lang/String;)[F", dataTableGetFloatColumn), - JF("dataTableGetFloatColumnNoDefaults", "(Ljava/lang/String;Ljava/lang/String;)[F", dataTableGetFloatColumnNoDefaults), - JF("dataTableGetStringColumn", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;", dataTableGetStringColumn), - JF("dataTableGetStringColumnNoDefaults", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;", dataTableGetStringColumnNoDefaults), - JF("dataTableGetIntColumn", "(Ljava/lang/String;I)[I", dataTableGetIntColumnA), - JF("dataTableGetIntColumnNoDefaults", "(Ljava/lang/String;I)[I", dataTableGetIntColumnANoDefaults), - JF("dataTableGetFloatColumn", "(Ljava/lang/String;I)[F", dataTableGetFloatColumnA), - JF("dataTableGetFloatColumnNoDefaults", "(Ljava/lang/String;I)[F", dataTableGetFloatColumnANoDefaults), - JF("dataTableGetStringColumn", "(Ljava/lang/String;I)[Ljava/lang/String;", dataTableGetStringColumnA), - JF("dataTableGetStringColumnNoDefaults", "(Ljava/lang/String;I)[Ljava/lang/String;", dataTableGetStringColumnANoDefaults), - JF("dataTableOpen", "(Ljava/lang/String;)Z", dataTableOpen), - JF("dataTableGetColumnType", "(Ljava/lang/String;Ljava/lang/String;)I", dataTableGetColumnType), - JF("dataTableGetColumnType", "(Ljava/lang/String;I)I", dataTableGetColumnTypeA), - JF("dataTableHasColumn", "(Ljava/lang/String;Ljava/lang/String;)Z", dataTableHasColumn), - JF("dataTableGetNumRows", "(Ljava/lang/String;)I", dataTableGetNumRows), - JF("dataTableGetNumColumns", "(Ljava/lang/String;)I", dataTableGetNumColumns), - JF("dataTableGetRow", "(Ljava/lang/String;I)Lscript/dictionary;", dataTableGetRow), - JF("dataTableGetColumnName", "(Ljava/lang/String;I)Ljava/lang/String;", dataTableGetColumnName), - JF("dataTableGetColumnNames", "(Ljava/lang/String;)[Ljava/lang/String;", dataTableGetColumnNames), - JF("dataTableSearchColumnForString", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", dataTableSearchColumnForString), - JF("dataTableSearchColumnForInt", "(ILjava/lang/String;Ljava/lang/String;)I", dataTableSearchColumnForInt), - JF("dataTableSearchColumnForString", "(Ljava/lang/String;ILjava/lang/String;)I", dataTableSearchColumnForStringA), - JF("dataTableSearchColumnForInt", "(IILjava/lang/String;)I", dataTableSearchColumnForIntA), - JF("dataTableFindColumnNumber", "(Ljava/lang/String;Ljava/lang/String;)I", dataTableFindColumnNumber), - JF("dataTableAddRow", "(Ljava/lang/String;Lscript/dictionary;)V", dataTableAddRow), -}; - - return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); -} - - -// ====================================================================== - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetInt(JNIEnv *env, jobject self, jstring table, jint row, jstring column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetInt"); - - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetInt - Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (row < 0 || dt->getNumRows() <= row) - { - DEBUG_WARNING(true, ("JavaLibaray::dataTableGetInt [%s] - Invalid row %d of table %s.", dt->getName().c_str(), row, tableNameString.c_str())); - return 0; - } - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetInt [%s] - Invalid column name <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); - return 0; - } - - if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Int) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetInt [%s] - Invalid type (not an int), column <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); - return 0; - } - - return dt->getIntValue(columnNameString, row); -} - -//------------------------------------------------------------------------ - -jfloat JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloat(JNIEnv *env, jobject self, jstring table, jint row, jstring column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloat"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetFloat - Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (row < 0 || dt->getNumRows() <= row) - { - DEBUG_WARNING(true, ("JavaLibaray::dataTableGetFloat [%s] - Invalid row %d of table %s.", dt->getName().c_str(), row, tableNameString.c_str())); - return 0; - } - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetFloat [%s] - Invalid column name <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); - return 0; - } - - if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Float) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetFloat [%s] - Invalid type (not a float), column <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); - return 0; - } - - return dt->getFloatValue(columnNameString, row); -} - -//------------------------------------------------------------------------ - -jstring JNICALL ScriptMethodsDataTableNamespace::dataTableGetString(JNIEnv *env, jobject self, jstring table, jint row, jstring column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetString"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetString - Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (row < 0 || dt->getNumRows() <= row) - { - DEBUG_WARNING(true, ("JavaLibaray::dataTableGetString [%s] - Invalid row %d of table %s.", dt->getName().c_str(), row, tableNameString.c_str())); - return 0; - } - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetString [%s] - Invalid column name <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); - return 0; - } - - if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_String) - { - DEBUG_WARNING(true, ("JavaLibrary::dataTableGetString [%s] - Invalid type (not a string), column <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); - return 0; - } - - JavaString javaString(dt->getStringValue(columnNameString, row)); - return javaString.getReturnValue(); -} - -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntA(JNIEnv *env, jobject self, jstring table, jint row, jint column) -{ - UNREF(env); - UNREF(self); - - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetIntA"); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (row < 0 || dt->getNumRows() <= row) - { - DEBUG_WARNING(true, ("Invalid row %d.", row)); - return 0; - } - if (column < 0 || dt->getNumColumns() <= column) - { - DEBUG_WARNING(true, ("Invalid column %d.", column)); - return 0; - } - - if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Int) - { - DEBUG_WARNING(true, ("Invalid type (not an int).")); - return 0; - } - - return dt->getIntValue(column, row); -} - -//------------------------------------------------------------------------ - -jfloat JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatA(JNIEnv *env, jobject self, jstring table, jint row, jint column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloatA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (row < 0 || dt->getNumRows() <= row) - { - DEBUG_WARNING(true, ("Invalid row %d.", row)); - return 0; - } - if (column < 0 || dt->getNumColumns() <= column) - { - DEBUG_WARNING(true, ("Invalid column %d.", column)); - return 0; - } - if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Float) - { - DEBUG_WARNING(true, ("Invalid type (not an float).")); - return 0; - } - return dt->getFloatValue(column, row); -} - -//------------------------------------------------------------------------ - -jstring JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringA(JNIEnv *env, jobject self, jstring table, jint row, jint column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetStringA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (row < 0 || dt->getNumRows() <= row) - { - DEBUG_WARNING(true, ("Invalid row %d.", row)); - return 0; - } - if (column < 0 || dt->getNumColumns() <= column) - { - DEBUG_WARNING(true, ("Invalid column %d.", column)); - return 0; - } - if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_String) - { - DEBUG_WARNING(true, ("Invalid type (not a string).")); - return 0; - } - JavaString javaString(dt->getStringValue(column, row)); - return javaString.getReturnValue(); -} - -//------------------------------------------------------------------------ - -jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetIntColInt"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); - return 0; - } - - if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Int) - { - DEBUG_WARNING(true, ("[%s] DataTable: Invalid type (not a int).", dt->getName().c_str())); - return 0; - } - - std::vector ret; - if (withDefaults) - { - dt->getIntColumn(columnNameString, ret); - } - else - { - int defaultValue = dt->getIntDefaultForColumn(columnNameString); - std::vector v; - dt->getIntColumn(columnNameString, v); - for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) - if ((*i) != defaultValue) - ret.push_back(*i); - } - - LocalIntArrayRefPtr valueArray = createNewIntArray(static_cast(ret.size())); - if (ret.size() > 0) - { - setIntArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast - (const_cast(&ret[0]))); - } - return valueArray->getReturnValue(); -} - -//------------------------------------------------------------------------ - -jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumn(JNIEnv *env, jobject self, jstring table, jstring column) -{ - return dataTableGetIntColumnInternal(env, self, table, column, true); -} - -//------------------------------------------------------------------------ - -jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column) -{ - return dataTableGetIntColumnInternal(env, self, table, column, false); -} - -//------------------------------------------------------------------------ - -jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloatColInt"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); - return 0; - } - - if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Float) - { - DEBUG_WARNING(true, ("[%s] Wrong type (not an float column)", dt->getName().c_str())); - return 0; - } - - std::vector ret; - if (withDefaults) - { - dt->getFloatColumn(columnNameString, ret); - } - else - { - float defaultValue = dt->getFloatDefaultForColumn(columnNameString); - std::vector v; - dt->getFloatColumn(columnNameString, v); - for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) - if ((*i) != defaultValue) //lint !e777 //testing floats for equality - ret.push_back(*i); - } - - LocalFloatArrayRefPtr valueArray = createNewFloatArray(static_cast(ret.size())); - if (ret.size() > 0 && valueArray != LocalFloatArrayRef::cms_nullPtr) - { - setFloatArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast - (const_cast(&ret[0]))); - } - return valueArray->getReturnValue(); - -} - -//------------------------------------------------------------------------ - -jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumn(JNIEnv *env, jobject self, jstring table, jstring column) -{ - return dataTableGetFloatColumnInternal(env, self, table, column, true); -} - -//------------------------------------------------------------------------ - -jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column) -{ - return dataTableGetFloatColumnInternal(env, self, table, column, false); -} - -//------------------------------------------------------------------------ - -jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetStringColInt"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableGetStringColumnInternal: could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableGetStringColumnInternal: could not convert column name from java string to string for table %s.", tableNameString.c_str())); - return 0; - } - - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); - return 0; - } - - if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_String) - { - DEBUG_WARNING(true, ("[%s] Wrong type (not an string column)", dt->getName().c_str())); - return 0; - } - - std::vector ret; - if (withDefaults) - { - dt->getStringColumn(columnNameString, ret); - } - else - { - std::string defaultValue(dt->getStringDefaultForColumn(columnNameString)); - std::vector v; - dt->getStringColumn(columnNameString, v); - for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) - { - const char *const string = *i; - - if (strcmp(string, defaultValue.c_str())!=0) - { - ret.push_back(*i); - } - } - } - - size_t count = ret.size(); - LocalObjectArrayRefPtr valueArray = createNewObjectArray(static_cast(count), JavaLibrary::getClsString()); - for (size_t i = 0; i < count; ++i) - { - const char *const string = ret[i]; - JavaString jval(string); - setObjectArrayElement(*valueArray, static_cast(i), jval); - } - return valueArray->getReturnValue(); -} - -//------------------------------------------------------------------------ - -jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumn(JNIEnv *env, jobject self, jstring table, jstring column) -{ - return dataTableGetStringColumnInternal(env, self, table, column, true); -} - -//------------------------------------------------------------------------ - -jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column) -{ - return dataTableGetStringColumnInternal(env, self, table, column, false); -} - -//------------------------------------------------------------------------ - -jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetIntColIntA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (column < 0 || dt->getNumColumns() < column) - { - DEBUG_WARNING(true, ("Invalid column %d", column)); - return 0; - } - if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Int) - { - DEBUG_WARNING(true, ("Wrong type (not an int column)")); - return 0; - } - - std::vector ret; - if (withDefaults) - { - dt->getIntColumn(column, ret); - } - else - { - int defaultValue = dt->getIntDefaultForColumn(column); - std::vector v; - dt->getIntColumn(column, v); - for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) - if ((*i) != defaultValue) - ret.push_back(*i); - } - - LocalIntArrayRefPtr valueArray = createNewIntArray(static_cast(ret.size())); - if (ret.size() > 0) - { - setIntArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast - (const_cast(&ret[0]))); - } - return valueArray->getReturnValue(); -} - -//------------------------------------------------------------------------ - -jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnA(JNIEnv *env, jobject self, jstring table, jint column) -{ - return dataTableGetIntColumnAInternal(env, self, table, column, true); -} - -//------------------------------------------------------------------------ - -jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column) -{ - return dataTableGetIntColumnAInternal(env, self, table, column, false); -} - -//------------------------------------------------------------------------ - -jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloatColIntA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (column < 0 || dt->getNumColumns() < column) - { - DEBUG_WARNING(true, ("Invalid column %d", column)); - return 0; - } - if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Float) - { - DEBUG_WARNING(true, ("Wrong type (not an float column)")); - return 0; - } - - std::vector ret; - if (withDefaults) - { - dt->getFloatColumn(column, ret); - } - else - { - float defaultValue = dt->getFloatDefaultForColumn(column); - std::vector v; - dt->getFloatColumn(column, v); - for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) - if ((*i) != defaultValue) //lint !e777 //testing floats for equality - ret.push_back(*i); - } - - LocalFloatArrayRefPtr valueArray = createNewFloatArray(static_cast(ret.size())); - if (ret.size() > 0 && valueArray != LocalFloatArrayRef::cms_nullPtr) - { - setFloatArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast - (const_cast(&ret[0]))); - } - return valueArray->getReturnValue(); -} - -//------------------------------------------------------------------------ - -jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnA(JNIEnv *env, jobject self, jstring table, jint column) -{ - return dataTableGetFloatColumnAInternal(env, self, table, column, true); -} - -//------------------------------------------------------------------------ - -jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column) -{ - return dataTableGetFloatColumnAInternal(env, self, table, column, false); -} - -//------------------------------------------------------------------------ - -jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetStringColIntA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (column < 0 || dt->getNumColumns() < column) - { - DEBUG_WARNING(true, ("Invalid column %d", column)); - return 0; - } - if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_String) - { - DEBUG_WARNING(true, ("Wrong type (not an string column)")); - return 0; - } - - std::vector ret; - if (withDefaults) - { - dt->getStringColumn(column, ret); - } - else - { - std::string defaultValue(dt->getStringDefaultForColumn(column)); - std::vector v; - dt->getStringColumn(column, v); - for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) - { - const char *const string = *i; - if (strcmp(string, defaultValue.c_str())!=0) - { - ret.push_back(*i); - } - } - } - - size_t count = ret.size(); - LocalObjectArrayRefPtr valueArray = createNewObjectArray(static_cast(count), JavaLibrary::getClsString()); - for (size_t i = 0; i < count; ++i) - { - const char *const string = ret[i]; - JavaString jval(string); - setObjectArrayElement(*valueArray, static_cast(i), jval); - } - return valueArray->getReturnValue(); -} - -//------------------------------------------------------------------------ - -jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnA(JNIEnv *env, jobject self, jstring table, jint column) -{ - return dataTableGetStringColumnAInternal(env, self, table, column, true); -} - -//------------------------------------------------------------------------ - -jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column) -{ - return dataTableGetStringColumnAInternal(env, self, table, column, false); -} - -//------------------------------------------------------------------------ - -jboolean JNICALL ScriptMethodsDataTableNamespace::dataTableOpen(JNIEnv *env, jobject self, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableOpen"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return JNI_FALSE; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return JNI_FALSE; - } - return JNI_TRUE; -} - -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnType(JNIEnv *env, jobject self, jstring table, jstring column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColType"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); - return 0; - } - return static_cast(dt->getDataTypeForColumn(columnNameString).getBasicType()); -} - -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnTypeA(JNIEnv *env, jobject self, jstring table, jint column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColTypeA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - if (column < 0 || dt->getNumColumns() < column) - { - DEBUG_WARNING(true, ("Invalid column %d", column)); - return -1; - } - return static_cast(dt->getDataTypeForColumn(column).getBasicType()); -} -//------------------------------------------------------------------------ - -jboolean JNICALL ScriptMethodsDataTableNamespace::dataTableHasColumn(JNIEnv *env, jobject self, jstring table, jstring column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableHasCol"); - UNREF(env); - UNREF(self); - - JavaStringParam localTable(table); - JavaStringParam localColumn(column); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - return dt->doesColumnExist(columnNameString); -} -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetNumColumns (JNIEnv *env, jobject self, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetNumColumns"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - return dt->getNumColumns(); -} -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetNumRows (JNIEnv *env, jobject self, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetNumRows"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - return dt->getNumRows(); - -} -//------------------------------------------------------------------------ - -jobject JNICALL ScriptMethodsDataTableNamespace::dataTableGetRow(JNIEnv *env, jobject self, jstring table, jint row) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetRow"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (row < 0 || dt->getNumRows() <= row) - { - DEBUG_WARNING(true, ("Invalid row %d passed to dataTableGetInt.", row)); - JavaLibrary::throwInternalScriptError("Java script attempted to get an invalid row from a datatable"); - return 0; - } - - - LocalRefPtr target = createNewObject(JavaLibrary::getClsDictionary(), JavaLibrary::getMidDictionary()); - if (target == LocalRef::cms_nullPtr) - return JNI_FALSE; - - for (int i = 0; i < dt->getNumColumns(); ++i) - { - JavaString jcolumnName(dt->getColumnName(i).c_str()); - switch (dt->getDataTypeForColumn(i).getBasicType()) - { - case DataTableColumnType::DT_HashString: - case DataTableColumnType::DT_Enum: - case DataTableColumnType::DT_Bool: - case DataTableColumnType::DT_Int: - case DataTableColumnType::DT_BitVector: - IGNORE_RETURN( callObjectMethod(*target, JavaLibrary::getMidDictionaryPutInt(), jcolumnName.getValue(), dt->getIntValue(i, row)) ); - break; - case DataTableColumnType::DT_Float: - IGNORE_RETURN( callObjectMethod(*target, JavaLibrary::getMidDictionaryPutFloat(), jcolumnName.getValue(), dt->getFloatValue(i, row)) ); - break; - case DataTableColumnType::DT_String: - { - JavaString jtmpString(dt->getStringValue(i, row)); - IGNORE_RETURN ( callObjectMethod(*target, JavaLibrary::getMidDictionaryPut(), jcolumnName.getValue(), jtmpString.getValue()) ); - break; - } - case DataTableColumnType::DT_Unknown: - case DataTableColumnType::DT_Comment: - default: - WARNING_STRICT_FATAL(true, ("Unhandled type in table %s row %d col %d", tableNameString.c_str(), row, i)); - return 0; - break; //lint !e527 //-- unreachable statement - } - } - return target->getReturnValue(); -} - -//------------------------------------------------------------------------ - -jstring JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnName(JNIEnv *env, jobject self, jstring table, jint column) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColName"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - if (column < 0 || dt->getNumColumns() <= column) - { - DEBUG_WARNING(true, ("Invalid column %d", column)); - return 0; - } - JavaString javaString(dt->getColumnName(column).c_str()); - return javaString.getReturnValue(); -} - -//------------------------------------------------------------------------ - -jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnNames(JNIEnv *env, jobject self, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColNames"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return 0; - } - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return 0; - } - - int numColumns = dt->getNumColumns(); - LocalObjectArrayRefPtr valueArray = createNewObjectArray(numColumns, JavaLibrary::getClsString()); - for (int i = 0; i < numColumns; ++i) - { - const std::string & string = dt->getColumnName(i); - JavaString jval(string.c_str()); - setObjectArrayElement(*valueArray, i, jval); - } - return valueArray->getReturnValue(); -} - -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForString(JNIEnv *env, jobject self, jstring entry, jstring column, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetSearchForString"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return -1; - } - - JavaStringParam localColumn(column); - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return -1; - } - - JavaStringParam localEntry(entry); - std::string target; - if (!JavaLibrary::convert(localEntry, target)) - { - DEBUG_WARNING(true, ("Could not convert search name from java string to string.")); - return -1; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return -1; - } - - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); - return -1; - } - - return dt->searchColumnString(dt->findColumnNumber(columnNameString), target); -} - -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForStringA(JNIEnv *env, jobject self, jstring entry, jint column, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableSearchForStringA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return -1; - } - - JavaStringParam localEntry(entry); - std::string target; - if (!JavaLibrary::convert(localEntry, target)) - { - DEBUG_WARNING(true, ("Could not convert search name from java string to string.")); - return -1; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return -1; - } - - return dt->searchColumnString(column, target); -} - -//------------------------------------------------------------------------ -jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForInt(JNIEnv *env, jobject self, jint entry, jstring column, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableSearchForInt"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return -1; - } - - JavaStringParam localColumn(column); - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return -1; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return -1; - } - - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); - return -1; - } - - return dt->searchColumnInt(dt->findColumnNumber(columnNameString), entry); -} - -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForIntA(JNIEnv *env, jobject self, jint entry, jint column, jstring table) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableSearchForIntA"); - UNREF(env); - UNREF(self); - JavaStringParam localTable(table); - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return -1; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return -1; - } - - return dt->searchColumnInt(column, entry); -} - -//------------------------------------------------------------------------ - -jint JNICALL ScriptMethodsDataTableNamespace::dataTableFindColumnNumber(JNIEnv *env, jobject self, jstring table, jstring column) -{ - JavaStringParam localTable(table); - std::string tableNameString; - if (!JavaLibrary::convert(localTable, tableNameString)) - { - DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); - return -1; - } - - JavaStringParam localColumn(column); - std::string columnNameString; - if (!JavaLibrary::convert(localColumn, columnNameString)) - { - DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); - return -1; - } - - DataTable* dt = DataTableManager::getTable(tableNameString, true); - if (!dt) - { - DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); - return -1; - } - - if (!dt->doesColumnExist(columnNameString)) - { - DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); - return -1; - } - - return dt->findColumnNumber(columnNameString); -} - -//------------------------------------------------------------------------ - -void JNICALL ScriptMethodsDataTableNamespace::dataTableAddRow(JNIEnv *env, jobject self, jstring table, jobject row) -{ -#ifndef _DEBUG - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow is not allowed except in debug mode!")); - return; -#else - JavaStringParam localTable(table); - std::string tableNameStr; - if (!JavaLibrary::convert(localTable, tableNameStr)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow bad table name")); - return; - } - if (!env->IsInstanceOf(row, JavaLibrary::getClsDictionary())) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow bad row dictionary, table %s", tableNameStr.c_str())); - return; - } - - std::vector columnNames; - std::vector columnTypes; - - std::string fileName(tableNameStr); - bool dosLinefeeds = false; - - // locate the table file and load column names and types - { - StdioFile inputFile(fileName.c_str(), "r"); - if (!inputFile.isOpen()) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow failed to open datatable file %s for reading", fileName.c_str())); - return; - } - int fileLength = inputFile.length(); - char *buffer = new char[fileLength+2]; // assure at least 2 '\0's on the end so we always have 2 strings - memset(buffer, 0, fileLength+2); - int bytes_read = inputFile.read(buffer, fileLength); - memset(buffer + bytes_read, 0, fileLength - bytes_read + 2); - char const *namesLineEnd = findNextChar(buffer, '\n'); - if (namesLineEnd > buffer && *(namesLineEnd-1) == '\r') - dosLinefeeds = true; - if (!namesLineEnd) - { - delete [] buffer; - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow malformed column names row in datatable %s", tableNameStr.c_str())); - return; - } - parseTabbedLine(buffer, namesLineEnd-buffer, columnNames); - char const *typesLineEnd = findNextChar(namesLineEnd+1, '\n'); - if (!typesLineEnd) - { - delete [] buffer; - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow malformed column types row in datatable %s", tableNameStr.c_str())); - return; - } - parseTabbedLine(namesLineEnd+1, typesLineEnd-namesLineEnd-1, columnTypes); - delete [] buffer; - } - - // pull the column names and types from the table file - std::vector addRowValues; - - if (columnNames.size() != columnTypes.size()) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow datatable column name or type is missing, table %s", tableNameStr.c_str())); - return; - } - - // resize the row values appropriately to account for the real number of columns - addRowValues.resize(columnNames.size()); - - LocalRefPtr keyEnumeration = callObjectMethod(LocalRefParam(row), JavaLibrary::getMidDictionaryKeys()); - while (callBooleanMethod(*keyEnumeration, JavaLibrary::getMidEnumerationHasMoreElements())) - { - LocalRefPtr key = callObjectMethod(*keyEnumeration, JavaLibrary::getMidEnumerationNextElement()); - if (!isInstanceOf(*key, JavaLibrary::getClsString())) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow dictionary has bad key, table %s", tableNameStr.c_str())); - return; - } - JavaStringParam localKeyStr(*key); - std::string keyStr; - JavaLibrary::convert(localKeyStr, keyStr); - // find the column - unsigned int column; - for (column = 0; column < columnNames.size(); ++column) - if (columnNames[column] == keyStr) - break; - if (column == columnNames.size()) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow unknown column %s for datatable %s", keyStr.c_str(), tableNameStr.c_str())); - return; - } - LocalRefPtr value = callObjectMethod(LocalRefParam(row), JavaLibrary::getMidDictionaryGet(), key->getValue()); - // verify the value is of an appropriate type, and set appropriately in the new row - switch (columnTypes[column].c_str()[0]) - { - case 'e': - // TODO: validate enumerations here if desired - case 'i': - { - if (!isInstanceOf(*value, JavaLibrary::getClsInteger())) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-int value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); - return; - } - jint intValue = callIntMethod(*value, JavaLibrary::getMidIntegerIntValue()); - char buf[64]; - snprintf(buf, sizeof(buf)-1, "%d", intValue); - buf[sizeof(buf)-1] = '\0'; - addRowValues[column] = buf; - } - break; - case 'f': - { - if (!isInstanceOf(*value, JavaLibrary::getClsFloat())) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-float value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); - return; - } - jfloat floatValue = callFloatMethod(*value, JavaLibrary::getMidFloatFloatValue()); - char buf[64]; - snprintf(buf, sizeof(buf)-1, "%12g", static_cast(floatValue)); - buf[sizeof(buf)-1] = '\0'; - addRowValues[column] = buf; - } - break; - case 'b': - { - if (!isInstanceOf(*value, JavaLibrary::getClsBoolean())) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-float value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); - return; - } - jboolean booleanValue = callBooleanMethod(*value, JavaLibrary::getMidBooleanBooleanValue()); - addRowValues[column] = booleanValue ? "1" : "0"; - } - break; - case 's': - case 'h': - case 'c': - case 'p': - { - if (!isInstanceOf(*value, JavaLibrary::getClsString())) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-string value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); - return; - } - JavaStringParam localValueStr(*value); - std::string valueStr; - JavaLibrary::convert(localValueStr, valueStr); - addRowValues[column] = valueStr; - } - break; - default: - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow unsupported type %s for column %s of datatable %s", columnTypes[column].c_str(), keyStr.c_str(), tableNameStr.c_str())); - } - return; - } - } - - // append the new row to the datatable - { - StdioFile outputFile(fileName.c_str(), "a"); - if (!outputFile.isOpen()) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow failed to open datatable file %s for appending", fileName.c_str())); - return; - } - - for (unsigned int i = 0; i < addRowValues.size(); ++i) - { - int len = addRowValues[i].length(); - if (len) - outputFile.write(len, addRowValues[i].c_str()); - if (i < addRowValues.size()-1) - outputFile.write(1, "\t"); - } - if (dosLinefeeds) - outputFile.write(1, "\r"); - outputFile.write(1, "\n"); - } -#endif -} - -//------------------------------------------------------------------------ - +// ScriptMethodsDataTable.cpp +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#include "serverScript/FirstServerScript.h" +#include "serverScript/JavaLibrary.h" + +#include "fileInterface/StdioFile.h" +#include "sharedDebug/Profiler.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" + +using namespace JNIWrappersNamespace; + + +//------------------------------------------------------------------------ +//lint -e818 //env could be declared const + +// ====================================================================== + +#ifdef _DEBUG +static char const *findNextChar(char const *s, char c) +{ + char const *tmp = s; + while (tmp && *tmp != '\0') + { + if (*tmp == c) + return tmp; + ++tmp; + } + return 0; +} +#endif + +// ---------------------------------------------------------------------- + +//ifdef out because this is currently only used in debug builds, and breaks the release build +#ifdef _DEBUG +static void parseTabbedLine(char const *line, int length, std::vector &results) +{ + char const *currentPos = line; + char const *tab = findNextChar(currentPos, '\t'); + char const *lineEnd = line+length; + if (lineEnd > line && *(lineEnd-1) == '\r') + --lineEnd; + while (tab && tab < lineEnd) + { + results.push_back(std::string(currentPos, tab-currentPos)); + currentPos = tab+1; + tab = findNextChar(currentPos, '\t'); + } + results.push_back(std::string(currentPos, lineEnd-currentPos)); +} +#endif + +// ====================================================================== +// ScriptMethodsDataTableNamespace +// ====================================================================== + +namespace ScriptMethodsDataTableNamespace +{ + bool install(); + + jint JNICALL dataTableGetInt(JNIEnv *env, jobject self, jstring table, jint row, jstring column); + jfloat JNICALL dataTableGetFloat(JNIEnv *env, jobject self, jstring table, jint row, jstring column); + jstring JNICALL dataTableGetString(JNIEnv *env, jobject self, jstring table, jint row, jstring column); + jintArray JNICALL dataTableGetIntColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults); + jintArray JNICALL dataTableGetIntColumn(JNIEnv *env, jobject self, jstring table, jstring column); + jintArray JNICALL dataTableGetIntColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column); + jfloatArray JNICALL dataTableGetFloatColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults); + jfloatArray JNICALL dataTableGetFloatColumn(JNIEnv *env, jobject self, jstring table, jstring column); + jfloatArray JNICALL dataTableGetFloatColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column); + jobjectArray JNICALL dataTableGetStringColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults); + jobjectArray JNICALL dataTableGetStringColumn(JNIEnv *env, jobject self, jstring table, jstring column); + jobjectArray JNICALL dataTableGetStringColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column); + jint JNICALL dataTableGetIntA(JNIEnv *env, jobject self, jstring table, jint row, jint column); + jfloat JNICALL dataTableGetFloatA(JNIEnv *env, jobject self, jstring table, jint row, jint column); + jstring JNICALL dataTableGetStringA(JNIEnv *env, jobject self, jstring table, jint row, jint column); + jintArray JNICALL dataTableGetIntColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults); + jintArray JNICALL dataTableGetIntColumnA(JNIEnv *env, jobject self, jstring table, jint column); + jintArray JNICALL dataTableGetIntColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column); + jfloatArray JNICALL dataTableGetFloatColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults); + jfloatArray JNICALL dataTableGetFloatColumnA(JNIEnv *env, jobject self, jstring table, jint column); + jfloatArray JNICALL dataTableGetFloatColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column); + jobjectArray JNICALL dataTableGetStringColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults); + jobjectArray JNICALL dataTableGetStringColumnA(JNIEnv *env, jobject self, jstring table, jint column); + jobjectArray JNICALL dataTableGetStringColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column); + jboolean JNICALL dataTableOpen(JNIEnv *env, jobject self, jstring table); + jint JNICALL dataTableGetColumnType(JNIEnv *env, jobject self, jstring table, jstring column); + jint JNICALL dataTableGetColumnTypeA(JNIEnv *env, jobject self, jstring table, jint column); + jboolean JNICALL dataTableHasColumn(JNIEnv *env, jobject self, jstring table, jstring column); + jint JNICALL dataTableGetNumColumns (JNIEnv *env, jobject self, jstring table); + jint JNICALL dataTableGetNumRows (JNIEnv *env, jobject self, jstring table); + jobject JNICALL dataTableGetRow(JNIEnv *env, jobject self, jstring table, jint row); + jstring JNICALL dataTableGetColumnName(JNIEnv *env, jobject self, jstring table, jint column); + jobjectArray JNICALL dataTableGetColumnNames(JNIEnv *env, jobject self, jstring table); + jint JNICALL dataTableSearchColumnForString(JNIEnv *env, jobject self, jstring entry, jstring column, jstring table); + jint JNICALL dataTableSearchColumnForInt(JNIEnv *env, jobject self, jint entry, jstring column, jstring table); + jint JNICALL dataTableSearchColumnForStringA(JNIEnv *env, jobject self, jstring entry, jint column, jstring table); + jint JNICALL dataTableSearchColumnForIntA(JNIEnv *env, jobject self, jint entry, jint column, jstring table); + jint JNICALL dataTableFindColumnNumber(JNIEnv *env, jobject self, jstring table, jstring column); + void JNICALL dataTableAddRow(JNIEnv *env, jobject self, jstring table, jobject row); +} + + +//======================================================================== +// install +//======================================================================== + +bool ScriptMethodsDataTableNamespace::install() +{ +const JNINativeMethod NATIVES[] = { + #define JF(a,b,c) {a,b,(void*)(ScriptMethodsDataTableNamespace::c)} + JF("dataTableGetInt", "(Ljava/lang/String;ILjava/lang/String;)I", dataTableGetInt), + JF("dataTableGetFloat", "(Ljava/lang/String;ILjava/lang/String;)F", dataTableGetFloat), + JF("dataTableGetString", "(Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;", dataTableGetString), + JF("dataTableGetInt", "(Ljava/lang/String;II)I", dataTableGetIntA), + JF("dataTableGetFloat", "(Ljava/lang/String;II)F", dataTableGetFloatA), + JF("dataTableGetString", "(Ljava/lang/String;II)Ljava/lang/String;", dataTableGetStringA), + JF("dataTableGetIntColumn", "(Ljava/lang/String;Ljava/lang/String;)[I", dataTableGetIntColumn), + JF("dataTableGetIntColumnNoDefaults", "(Ljava/lang/String;Ljava/lang/String;)[I", dataTableGetIntColumnNoDefaults), + JF("dataTableGetFloatColumn", "(Ljava/lang/String;Ljava/lang/String;)[F", dataTableGetFloatColumn), + JF("dataTableGetFloatColumnNoDefaults", "(Ljava/lang/String;Ljava/lang/String;)[F", dataTableGetFloatColumnNoDefaults), + JF("dataTableGetStringColumn", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;", dataTableGetStringColumn), + JF("dataTableGetStringColumnNoDefaults", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;", dataTableGetStringColumnNoDefaults), + JF("dataTableGetIntColumn", "(Ljava/lang/String;I)[I", dataTableGetIntColumnA), + JF("dataTableGetIntColumnNoDefaults", "(Ljava/lang/String;I)[I", dataTableGetIntColumnANoDefaults), + JF("dataTableGetFloatColumn", "(Ljava/lang/String;I)[F", dataTableGetFloatColumnA), + JF("dataTableGetFloatColumnNoDefaults", "(Ljava/lang/String;I)[F", dataTableGetFloatColumnANoDefaults), + JF("dataTableGetStringColumn", "(Ljava/lang/String;I)[Ljava/lang/String;", dataTableGetStringColumnA), + JF("dataTableGetStringColumnNoDefaults", "(Ljava/lang/String;I)[Ljava/lang/String;", dataTableGetStringColumnANoDefaults), + JF("dataTableOpen", "(Ljava/lang/String;)Z", dataTableOpen), + JF("dataTableGetColumnType", "(Ljava/lang/String;Ljava/lang/String;)I", dataTableGetColumnType), + JF("dataTableGetColumnType", "(Ljava/lang/String;I)I", dataTableGetColumnTypeA), + JF("dataTableHasColumn", "(Ljava/lang/String;Ljava/lang/String;)Z", dataTableHasColumn), + JF("dataTableGetNumRows", "(Ljava/lang/String;)I", dataTableGetNumRows), + JF("dataTableGetNumColumns", "(Ljava/lang/String;)I", dataTableGetNumColumns), + JF("dataTableGetRow", "(Ljava/lang/String;I)Lscript/dictionary;", dataTableGetRow), + JF("dataTableGetColumnName", "(Ljava/lang/String;I)Ljava/lang/String;", dataTableGetColumnName), + JF("dataTableGetColumnNames", "(Ljava/lang/String;)[Ljava/lang/String;", dataTableGetColumnNames), + JF("dataTableSearchColumnForString", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", dataTableSearchColumnForString), + JF("dataTableSearchColumnForInt", "(ILjava/lang/String;Ljava/lang/String;)I", dataTableSearchColumnForInt), + JF("dataTableSearchColumnForString", "(Ljava/lang/String;ILjava/lang/String;)I", dataTableSearchColumnForStringA), + JF("dataTableSearchColumnForInt", "(IILjava/lang/String;)I", dataTableSearchColumnForIntA), + JF("dataTableFindColumnNumber", "(Ljava/lang/String;Ljava/lang/String;)I", dataTableFindColumnNumber), + JF("dataTableAddRow", "(Ljava/lang/String;Lscript/dictionary;)V", dataTableAddRow), +}; + + return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); +} + + +// ====================================================================== + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetInt(JNIEnv *env, jobject self, jstring table, jint row, jstring column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetInt"); + + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetInt - Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (row < 0 || dt->getNumRows() <= row) + { + DEBUG_WARNING(true, ("JavaLibaray::dataTableGetInt [%s] - Invalid row %d of table %s.", dt->getName().c_str(), row, tableNameString.c_str())); + return 0; + } + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetInt [%s] - Invalid column name <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); + return 0; + } + + if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Int) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetInt [%s] - Invalid type (not an int), column <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); + return 0; + } + + return dt->getIntValue(columnNameString, row); +} + +//------------------------------------------------------------------------ + +jfloat JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloat(JNIEnv *env, jobject self, jstring table, jint row, jstring column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloat"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetFloat - Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (row < 0 || dt->getNumRows() <= row) + { + DEBUG_WARNING(true, ("JavaLibaray::dataTableGetFloat [%s] - Invalid row %d of table %s.", dt->getName().c_str(), row, tableNameString.c_str())); + return 0; + } + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetFloat [%s] - Invalid column name <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); + return 0; + } + + if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Float) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetFloat [%s] - Invalid type (not a float), column <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); + return 0; + } + + return dt->getFloatValue(columnNameString, row); +} + +//------------------------------------------------------------------------ + +jstring JNICALL ScriptMethodsDataTableNamespace::dataTableGetString(JNIEnv *env, jobject self, jstring table, jint row, jstring column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetString"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetString - Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (row < 0 || dt->getNumRows() <= row) + { + DEBUG_WARNING(true, ("JavaLibaray::dataTableGetString [%s] - Invalid row %d of table %s.", dt->getName().c_str(), row, tableNameString.c_str())); + return 0; + } + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetString [%s] - Invalid column name <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); + return 0; + } + + if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_String) + { + DEBUG_WARNING(true, ("JavaLibrary::dataTableGetString [%s] - Invalid type (not a string), column <%s> of table %s.", dt->getName().c_str(), columnNameString.c_str(), tableNameString.c_str())); + return 0; + } + + JavaString javaString(dt->getStringValue(columnNameString, row)); + return javaString.getReturnValue(); +} + +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntA(JNIEnv *env, jobject self, jstring table, jint row, jint column) +{ + UNREF(env); + UNREF(self); + + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetIntA"); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (row < 0 || dt->getNumRows() <= row) + { + DEBUG_WARNING(true, ("Invalid row %d.", row)); + return 0; + } + if (column < 0 || dt->getNumColumns() <= column) + { + DEBUG_WARNING(true, ("Invalid column %d.", column)); + return 0; + } + + if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Int) + { + DEBUG_WARNING(true, ("Invalid type (not an int).")); + return 0; + } + + return dt->getIntValue(column, row); +} + +//------------------------------------------------------------------------ + +jfloat JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatA(JNIEnv *env, jobject self, jstring table, jint row, jint column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloatA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (row < 0 || dt->getNumRows() <= row) + { + DEBUG_WARNING(true, ("Invalid row %d.", row)); + return 0; + } + if (column < 0 || dt->getNumColumns() <= column) + { + DEBUG_WARNING(true, ("Invalid column %d.", column)); + return 0; + } + if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Float) + { + DEBUG_WARNING(true, ("Invalid type (not an float).")); + return 0; + } + return dt->getFloatValue(column, row); +} + +//------------------------------------------------------------------------ + +jstring JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringA(JNIEnv *env, jobject self, jstring table, jint row, jint column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetStringA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (row < 0 || dt->getNumRows() <= row) + { + DEBUG_WARNING(true, ("Invalid row %d.", row)); + return 0; + } + if (column < 0 || dt->getNumColumns() <= column) + { + DEBUG_WARNING(true, ("Invalid column %d.", column)); + return 0; + } + if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_String) + { + DEBUG_WARNING(true, ("Invalid type (not a string).")); + return 0; + } + JavaString javaString(dt->getStringValue(column, row)); + return javaString.getReturnValue(); +} + +//------------------------------------------------------------------------ + +jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetIntColInt"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); + return 0; + } + + if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Int) + { + DEBUG_WARNING(true, ("[%s] DataTable: Invalid type (not a int).", dt->getName().c_str())); + return 0; + } + + std::vector ret; + if (withDefaults) + { + dt->getIntColumn(columnNameString, ret); + } + else + { + int defaultValue = dt->getIntDefaultForColumn(columnNameString); + std::vector v; + dt->getIntColumn(columnNameString, v); + for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + if ((*i) != defaultValue) + ret.push_back(*i); + } + + LocalIntArrayRefPtr valueArray = createNewIntArray(static_cast(ret.size())); + if (ret.size() > 0) + { + setIntArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast + (const_cast(&ret[0]))); + } + return valueArray->getReturnValue(); +} + +//------------------------------------------------------------------------ + +jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumn(JNIEnv *env, jobject self, jstring table, jstring column) +{ + return dataTableGetIntColumnInternal(env, self, table, column, true); +} + +//------------------------------------------------------------------------ + +jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column) +{ + return dataTableGetIntColumnInternal(env, self, table, column, false); +} + +//------------------------------------------------------------------------ + +jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloatColInt"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); + return 0; + } + + if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_Float) + { + DEBUG_WARNING(true, ("[%s] Wrong type (not an float column)", dt->getName().c_str())); + return 0; + } + + std::vector ret; + if (withDefaults) + { + dt->getFloatColumn(columnNameString, ret); + } + else + { + float defaultValue = dt->getFloatDefaultForColumn(columnNameString); + std::vector v; + dt->getFloatColumn(columnNameString, v); + for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + if ((*i) != defaultValue) //lint !e777 //testing floats for equality + ret.push_back(*i); + } + + LocalFloatArrayRefPtr valueArray = createNewFloatArray(static_cast(ret.size())); + if (ret.size() > 0 && valueArray != LocalFloatArrayRef::cms_nullPtr) + { + setFloatArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast + (const_cast(&ret[0]))); + } + return valueArray->getReturnValue(); + +} + +//------------------------------------------------------------------------ + +jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumn(JNIEnv *env, jobject self, jstring table, jstring column) +{ + return dataTableGetFloatColumnInternal(env, self, table, column, true); +} + +//------------------------------------------------------------------------ + +jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column) +{ + return dataTableGetFloatColumnInternal(env, self, table, column, false); +} + +//------------------------------------------------------------------------ + +jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnInternal(JNIEnv *env, jobject self, jstring table, jstring column, bool withDefaults) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetStringColInt"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableGetStringColumnInternal: could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableGetStringColumnInternal: could not convert column name from java string to string for table %s.", tableNameString.c_str())); + return 0; + } + + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); + return 0; + } + + if (dt->getDataTypeForColumn(columnNameString).getBasicType() != DataTableColumnType::DT_String) + { + DEBUG_WARNING(true, ("[%s] Wrong type (not an string column)", dt->getName().c_str())); + return 0; + } + + std::vector ret; + if (withDefaults) + { + dt->getStringColumn(columnNameString, ret); + } + else + { + std::string defaultValue(dt->getStringDefaultForColumn(columnNameString)); + std::vector v; + dt->getStringColumn(columnNameString, v); + for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + { + const char *const string = *i; + + if (strcmp(string, defaultValue.c_str())!=0) + { + ret.push_back(*i); + } + } + } + + size_t count = ret.size(); + LocalObjectArrayRefPtr valueArray = createNewObjectArray(static_cast(count), JavaLibrary::getClsString()); + for (size_t i = 0; i < count; ++i) + { + const char *const string = ret[i]; + JavaString jval(string); + setObjectArrayElement(*valueArray, static_cast(i), jval); + } + return valueArray->getReturnValue(); +} + +//------------------------------------------------------------------------ + +jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumn(JNIEnv *env, jobject self, jstring table, jstring column) +{ + return dataTableGetStringColumnInternal(env, self, table, column, true); +} + +//------------------------------------------------------------------------ + +jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnNoDefaults(JNIEnv *env, jobject self, jstring table, jstring column) +{ + return dataTableGetStringColumnInternal(env, self, table, column, false); +} + +//------------------------------------------------------------------------ + +jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetIntColIntA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (column < 0 || dt->getNumColumns() < column) + { + DEBUG_WARNING(true, ("Invalid column %d", column)); + return 0; + } + if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Int) + { + DEBUG_WARNING(true, ("Wrong type (not an int column)")); + return 0; + } + + std::vector ret; + if (withDefaults) + { + dt->getIntColumn(column, ret); + } + else + { + int defaultValue = dt->getIntDefaultForColumn(column); + std::vector v; + dt->getIntColumn(column, v); + for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + if ((*i) != defaultValue) + ret.push_back(*i); + } + + LocalIntArrayRefPtr valueArray = createNewIntArray(static_cast(ret.size())); + if (ret.size() > 0) + { + setIntArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast + (const_cast(&ret[0]))); + } + return valueArray->getReturnValue(); +} + +//------------------------------------------------------------------------ + +jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnA(JNIEnv *env, jobject self, jstring table, jint column) +{ + return dataTableGetIntColumnAInternal(env, self, table, column, true); +} + +//------------------------------------------------------------------------ + +jintArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetIntColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column) +{ + return dataTableGetIntColumnAInternal(env, self, table, column, false); +} + +//------------------------------------------------------------------------ + +jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetFloatColIntA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (column < 0 || dt->getNumColumns() < column) + { + DEBUG_WARNING(true, ("Invalid column %d", column)); + return 0; + } + if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_Float) + { + DEBUG_WARNING(true, ("Wrong type (not an float column)")); + return 0; + } + + std::vector ret; + if (withDefaults) + { + dt->getFloatColumn(column, ret); + } + else + { + float defaultValue = dt->getFloatDefaultForColumn(column); + std::vector v; + dt->getFloatColumn(column, v); + for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + if ((*i) != defaultValue) //lint !e777 //testing floats for equality + ret.push_back(*i); + } + + LocalFloatArrayRefPtr valueArray = createNewFloatArray(static_cast(ret.size())); + if (ret.size() > 0 && valueArray != LocalFloatArrayRef::cms_nullPtr) + { + setFloatArrayRegion(*valueArray, 0, static_cast(ret.size()), reinterpret_cast + (const_cast(&ret[0]))); + } + return valueArray->getReturnValue(); +} + +//------------------------------------------------------------------------ + +jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnA(JNIEnv *env, jobject self, jstring table, jint column) +{ + return dataTableGetFloatColumnAInternal(env, self, table, column, true); +} + +//------------------------------------------------------------------------ + +jfloatArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetFloatColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column) +{ + return dataTableGetFloatColumnAInternal(env, self, table, column, false); +} + +//------------------------------------------------------------------------ + +jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnAInternal(JNIEnv *env, jobject self, jstring table, jint column, bool withDefaults) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetStringColIntA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (column < 0 || dt->getNumColumns() < column) + { + DEBUG_WARNING(true, ("Invalid column %d", column)); + return 0; + } + if (dt->getDataTypeForColumn(column).getBasicType() != DataTableColumnType::DT_String) + { + DEBUG_WARNING(true, ("Wrong type (not an string column)")); + return 0; + } + + std::vector ret; + if (withDefaults) + { + dt->getStringColumn(column, ret); + } + else + { + std::string defaultValue(dt->getStringDefaultForColumn(column)); + std::vector v; + dt->getStringColumn(column, v); + for (std::vector::const_iterator i = v.begin(); i != v.end(); ++i) + { + const char *const string = *i; + if (strcmp(string, defaultValue.c_str())!=0) + { + ret.push_back(*i); + } + } + } + + size_t count = ret.size(); + LocalObjectArrayRefPtr valueArray = createNewObjectArray(static_cast(count), JavaLibrary::getClsString()); + for (size_t i = 0; i < count; ++i) + { + const char *const string = ret[i]; + JavaString jval(string); + setObjectArrayElement(*valueArray, static_cast(i), jval); + } + return valueArray->getReturnValue(); +} + +//------------------------------------------------------------------------ + +jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnA(JNIEnv *env, jobject self, jstring table, jint column) +{ + return dataTableGetStringColumnAInternal(env, self, table, column, true); +} + +//------------------------------------------------------------------------ + +jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetStringColumnANoDefaults(JNIEnv *env, jobject self, jstring table, jint column) +{ + return dataTableGetStringColumnAInternal(env, self, table, column, false); +} + +//------------------------------------------------------------------------ + +jboolean JNICALL ScriptMethodsDataTableNamespace::dataTableOpen(JNIEnv *env, jobject self, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableOpen"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return JNI_FALSE; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return JNI_FALSE; + } + return JNI_TRUE; +} + +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnType(JNIEnv *env, jobject self, jstring table, jstring column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColType"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); + return 0; + } + return static_cast(dt->getDataTypeForColumn(columnNameString).getBasicType()); +} + +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnTypeA(JNIEnv *env, jobject self, jstring table, jint column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColTypeA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + if (column < 0 || dt->getNumColumns() < column) + { + DEBUG_WARNING(true, ("Invalid column %d", column)); + return -1; + } + return static_cast(dt->getDataTypeForColumn(column).getBasicType()); +} +//------------------------------------------------------------------------ + +jboolean JNICALL ScriptMethodsDataTableNamespace::dataTableHasColumn(JNIEnv *env, jobject self, jstring table, jstring column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableHasCol"); + UNREF(env); + UNREF(self); + + JavaStringParam localTable(table); + JavaStringParam localColumn(column); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + return dt->doesColumnExist(columnNameString); +} +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetNumColumns (JNIEnv *env, jobject self, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetNumColumns"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + return dt->getNumColumns(); +} +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableGetNumRows (JNIEnv *env, jobject self, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetNumRows"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + return dt->getNumRows(); + +} +//------------------------------------------------------------------------ + +jobject JNICALL ScriptMethodsDataTableNamespace::dataTableGetRow(JNIEnv *env, jobject self, jstring table, jint row) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetRow"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (row < 0 || dt->getNumRows() <= row) + { + DEBUG_WARNING(true, ("Invalid row %d passed to dataTableGetInt.", row)); + JavaLibrary::throwInternalScriptError("Java script attempted to get an invalid row from a datatable"); + return 0; + } + + + LocalRefPtr target = createNewObject(JavaLibrary::getClsDictionary(), JavaLibrary::getMidDictionary()); + if (target == LocalRef::cms_nullPtr) + return JNI_FALSE; + + for (int i = 0; i < dt->getNumColumns(); ++i) + { + JavaString jcolumnName(dt->getColumnName(i).c_str()); + switch (dt->getDataTypeForColumn(i).getBasicType()) + { + case DataTableColumnType::DT_HashString: + case DataTableColumnType::DT_Enum: + case DataTableColumnType::DT_Bool: + case DataTableColumnType::DT_Int: + case DataTableColumnType::DT_BitVector: + IGNORE_RETURN( callObjectMethod(*target, JavaLibrary::getMidDictionaryPutInt(), jcolumnName.getValue(), dt->getIntValue(i, row)) ); + break; + case DataTableColumnType::DT_Float: + IGNORE_RETURN( callObjectMethod(*target, JavaLibrary::getMidDictionaryPutFloat(), jcolumnName.getValue(), dt->getFloatValue(i, row)) ); + break; + case DataTableColumnType::DT_String: + { + JavaString jtmpString(dt->getStringValue(i, row)); + IGNORE_RETURN ( callObjectMethod(*target, JavaLibrary::getMidDictionaryPut(), jcolumnName.getValue(), jtmpString.getValue()) ); + break; + } + case DataTableColumnType::DT_Unknown: + case DataTableColumnType::DT_Comment: + default: + WARNING_STRICT_FATAL(true, ("Unhandled type in table %s row %d col %d", tableNameString.c_str(), row, i)); + return 0; + break; //lint !e527 //-- unreachable statement + } + } + return target->getReturnValue(); +} + +//------------------------------------------------------------------------ + +jstring JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnName(JNIEnv *env, jobject self, jstring table, jint column) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColName"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + if (column < 0 || dt->getNumColumns() <= column) + { + DEBUG_WARNING(true, ("Invalid column %d", column)); + return 0; + } + JavaString javaString(dt->getColumnName(column).c_str()); + return javaString.getReturnValue(); +} + +//------------------------------------------------------------------------ + +jobjectArray JNICALL ScriptMethodsDataTableNamespace::dataTableGetColumnNames(JNIEnv *env, jobject self, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetColNames"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return 0; + } + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return 0; + } + + int numColumns = dt->getNumColumns(); + LocalObjectArrayRefPtr valueArray = createNewObjectArray(numColumns, JavaLibrary::getClsString()); + for (int i = 0; i < numColumns; ++i) + { + const std::string & string = dt->getColumnName(i); + JavaString jval(string.c_str()); + setObjectArrayElement(*valueArray, i, jval); + } + return valueArray->getReturnValue(); +} + +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForString(JNIEnv *env, jobject self, jstring entry, jstring column, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableGetSearchForString"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return -1; + } + + JavaStringParam localColumn(column); + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return -1; + } + + JavaStringParam localEntry(entry); + std::string target; + if (!JavaLibrary::convert(localEntry, target)) + { + DEBUG_WARNING(true, ("Could not convert search name from java string to string.")); + return -1; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return -1; + } + + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); + return -1; + } + + return dt->searchColumnString(dt->findColumnNumber(columnNameString), target); +} + +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForStringA(JNIEnv *env, jobject self, jstring entry, jint column, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableSearchForStringA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return -1; + } + + JavaStringParam localEntry(entry); + std::string target; + if (!JavaLibrary::convert(localEntry, target)) + { + DEBUG_WARNING(true, ("Could not convert search name from java string to string.")); + return -1; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return -1; + } + + return dt->searchColumnString(column, target); +} + +//------------------------------------------------------------------------ +jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForInt(JNIEnv *env, jobject self, jint entry, jstring column, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableSearchForInt"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return -1; + } + + JavaStringParam localColumn(column); + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return -1; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return -1; + } + + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); + return -1; + } + + return dt->searchColumnInt(dt->findColumnNumber(columnNameString), entry); +} + +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableSearchColumnForIntA(JNIEnv *env, jobject self, jint entry, jint column, jstring table) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::dataTableSearchForIntA"); + UNREF(env); + UNREF(self); + JavaStringParam localTable(table); + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return -1; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return -1; + } + + return dt->searchColumnInt(column, entry); +} + +//------------------------------------------------------------------------ + +jint JNICALL ScriptMethodsDataTableNamespace::dataTableFindColumnNumber(JNIEnv *env, jobject self, jstring table, jstring column) +{ + JavaStringParam localTable(table); + std::string tableNameString; + if (!JavaLibrary::convert(localTable, tableNameString)) + { + DEBUG_WARNING(true, ("Could not convert table name from java string to string.")); + return -1; + } + + JavaStringParam localColumn(column); + std::string columnNameString; + if (!JavaLibrary::convert(localColumn, columnNameString)) + { + DEBUG_WARNING(true, ("Could not convert column name from java string to string.")); + return -1; + } + + DataTable* dt = DataTableManager::getTable(tableNameString, true); + if (!dt) + { + DEBUG_WARNING(true, ("Could not find table %s.", tableNameString.c_str())); + return -1; + } + + if (!dt->doesColumnExist(columnNameString)) + { + DEBUG_WARNING(true, ("[%s] Invalid column name <%s>.", dt->getName().c_str(), columnNameString.c_str())); + return -1; + } + + return dt->findColumnNumber(columnNameString); +} + +//------------------------------------------------------------------------ + +void JNICALL ScriptMethodsDataTableNamespace::dataTableAddRow(JNIEnv *env, jobject self, jstring table, jobject row) +{ +#ifndef _DEBUG + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow is not allowed except in debug mode!")); + return; +#else + JavaStringParam localTable(table); + std::string tableNameStr; + if (!JavaLibrary::convert(localTable, tableNameStr)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow bad table name")); + return; + } + if (!env->IsInstanceOf(row, JavaLibrary::getClsDictionary())) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow bad row dictionary, table %s", tableNameStr.c_str())); + return; + } + + std::vector columnNames; + std::vector columnTypes; + + std::string fileName(tableNameStr); + bool dosLinefeeds = false; + + // locate the table file and load column names and types + { + StdioFile inputFile(fileName.c_str(), "r"); + if (!inputFile.isOpen()) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow failed to open datatable file %s for reading", fileName.c_str())); + return; + } + int fileLength = inputFile.length(); + char *buffer = new char[fileLength+2]; // assure at least 2 '\0's on the end so we always have 2 strings + memset(buffer, 0, fileLength+2); + int bytes_read = inputFile.read(buffer, fileLength); + memset(buffer + bytes_read, 0, fileLength - bytes_read + 2); + char const *namesLineEnd = findNextChar(buffer, '\n'); + if (namesLineEnd > buffer && *(namesLineEnd-1) == '\r') + dosLinefeeds = true; + if (!namesLineEnd) + { + delete [] buffer; + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow malformed column names row in datatable %s", tableNameStr.c_str())); + return; + } + parseTabbedLine(buffer, namesLineEnd-buffer, columnNames); + char const *typesLineEnd = findNextChar(namesLineEnd+1, '\n'); + if (!typesLineEnd) + { + delete [] buffer; + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow malformed column types row in datatable %s", tableNameStr.c_str())); + return; + } + parseTabbedLine(namesLineEnd+1, typesLineEnd-namesLineEnd-1, columnTypes); + delete [] buffer; + } + + // pull the column names and types from the table file + std::vector addRowValues; + + if (columnNames.size() != columnTypes.size()) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow datatable column name or type is missing, table %s", tableNameStr.c_str())); + return; + } + + // resize the row values appropriately to account for the real number of columns + addRowValues.resize(columnNames.size()); + + LocalRefPtr keyEnumeration = callObjectMethod(LocalRefParam(row), JavaLibrary::getMidDictionaryKeys()); + while (callBooleanMethod(*keyEnumeration, JavaLibrary::getMidEnumerationHasMoreElements())) + { + LocalRefPtr key = callObjectMethod(*keyEnumeration, JavaLibrary::getMidEnumerationNextElement()); + if (!isInstanceOf(*key, JavaLibrary::getClsString())) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow dictionary has bad key, table %s", tableNameStr.c_str())); + return; + } + JavaStringParam localKeyStr(*key); + std::string keyStr; + JavaLibrary::convert(localKeyStr, keyStr); + // find the column + unsigned int column; + for (column = 0; column < columnNames.size(); ++column) + if (columnNames[column] == keyStr) + break; + if (column == columnNames.size()) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow unknown column %s for datatable %s", keyStr.c_str(), tableNameStr.c_str())); + return; + } + LocalRefPtr value = callObjectMethod(LocalRefParam(row), JavaLibrary::getMidDictionaryGet(), key->getValue()); + // verify the value is of an appropriate type, and set appropriately in the new row + switch (columnTypes[column].c_str()[0]) + { + case 'e': + // TODO: validate enumerations here if desired + case 'i': + { + if (!isInstanceOf(*value, JavaLibrary::getClsInteger())) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-int value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); + return; + } + jint intValue = callIntMethod(*value, JavaLibrary::getMidIntegerIntValue()); + char buf[64]; + snprintf(buf, sizeof(buf)-1, "%d", intValue); + buf[sizeof(buf)-1] = '\0'; + addRowValues[column] = buf; + } + break; + case 'f': + { + if (!isInstanceOf(*value, JavaLibrary::getClsFloat())) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-float value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); + return; + } + jfloat floatValue = callFloatMethod(*value, JavaLibrary::getMidFloatFloatValue()); + char buf[64]; + snprintf(buf, sizeof(buf)-1, "%12g", static_cast(floatValue)); + buf[sizeof(buf)-1] = '\0'; + addRowValues[column] = buf; + } + break; + case 'b': + { + if (!isInstanceOf(*value, JavaLibrary::getClsBoolean())) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-float value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); + return; + } + jboolean booleanValue = callBooleanMethod(*value, JavaLibrary::getMidBooleanBooleanValue()); + addRowValues[column] = booleanValue ? "1" : "0"; + } + break; + case 's': + case 'h': + case 'c': + case 'p': + { + if (!isInstanceOf(*value, JavaLibrary::getClsString())) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow non-string value for column %s of datatable %s", keyStr.c_str(), tableNameStr.c_str())); + return; + } + JavaStringParam localValueStr(*value); + std::string valueStr; + JavaLibrary::convert(localValueStr, valueStr); + addRowValues[column] = valueStr; + } + break; + default: + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow unsupported type %s for column %s of datatable %s", columnTypes[column].c_str(), keyStr.c_str(), tableNameStr.c_str())); + } + return; + } + } + + // append the new row to the datatable + { + StdioFile outputFile(fileName.c_str(), "a"); + if (!outputFile.isOpen()) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::dataTableAddRow failed to open datatable file %s for appending", fileName.c_str())); + return; + } + + for (unsigned int i = 0; i < addRowValues.size(); ++i) + { + int len = addRowValues[i].length(); + if (len) + outputFile.write(len, addRowValues[i].c_str()); + if (i < addRowValues.size()-1) + outputFile.write(1, "\t"); + } + if (dosLinefeeds) + outputFile.write(1, "\r"); + outputFile.write(1, "\n"); + } +#endif +} + +//------------------------------------------------------------------------ + diff --git a/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectCreate.cpp b/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectCreate.cpp index ea707e316..37ab2bac1 100644 --- a/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectCreate.cpp +++ b/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectCreate.cpp @@ -1123,8 +1123,11 @@ jboolean JNICALL ScriptMethodsObjectCreateNamespace::persistObject(JNIEnv *env, ServerObject* object = NULL; if (!JavaLibrary::getObject(target, object)) return JNI_FALSE; - object->persist(); - return JNI_TRUE; + if (object->persist()) { + return JNI_TRUE; + } else { + return JNI_FALSE; + } } // JavaLibrary::persistObject /** diff --git a/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectInfo.cpp b/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectInfo.cpp index 9c4fb1da5..8d03185d9 100644 --- a/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectInfo.cpp +++ b/src/engine/server/library/serverScript/src/shared/ScriptMethodsObjectInfo.cpp @@ -2699,58 +2699,6 @@ namespace //----------------------------------------------------------------------- - bool DebugDumpCustomVar(JNIEnv *env, LocalRefPtr customVar) - { - NOT_NULL(env); - NOT_NULL(customVar.get()); - NOT_NULL(customVar->getValue()); - - //-- get class for custom_var - const jclass customVarClass = env->FindClass("custom_var"); - - DEBUG_REPORT_LOG(!customVarClass, ("FindClass() failed for custom_var.\n")); - if (!customVarClass) - return false; - - //-- invoke "String getVarName()" method - const jmethodID getVarNameMid = env->GetMethodID(customVarClass, "getVarName", "()Ljava/lang/String;"); - - DEBUG_REPORT_LOG(!getVarNameMid , ("GetMethodId() failed for getVarName().\n")); - if (!getVarNameMid) - { - env->DeleteLocalRef(customVarClass); - return false; - } - - std::string nativeCustomVarName; - - JavaStringPtr javaCustomVarName = callStringMethod(*customVar, getVarNameMid); - JavaLibrary::convert(*javaCustomVarName, nativeCustomVarName); - - //-- invoke "int getTypeId()" method - const jmethodID getTypeIdMid = env->GetMethodID(customVarClass, "getTypeId", "()I"); - - DEBUG_REPORT_LOG(!getTypeIdMid, ("GetMethodId() failed for getTypeId().\n")); - if (!getTypeIdMid) - { - env->DeleteLocalRef(customVarClass); - return false; - } - - const int nativeCustomVarTypeId = callIntMethod(*customVar, getTypeIdMid); - - //-- cleanup - env->DeleteLocalRef(customVarClass); - - //-- print results - REPORT_LOG(true, ("<*> (customizationVariable); - if (!variable) - return; - - //-- convert context to customization variable collection - CustomizationVariableIteratorData *const iteratorData = reinterpret_cast(context); - - //-- add CustomizationVariable to the container - iteratorData->m_variableNames.push_back(fullVariablePathName); - iteratorData->m_customizationVariables.push_back(customizationVariable); - } - - // ---------------------------------------------------------------------- - - void PalcolorCustomizationVariableCollector(const std::string &fullVariablePathName, CustomizationVariable *customizationVariable, void *context) - { - //-- validate arguments - if (!customizationVariable || !context) - { - DEBUG_FATAL(true, ("programmer error: callback made with NULL arguments.\n")); - return; - } - - //-- check if this is a PaletteColorCustomizationVariable - PaletteColorCustomizationVariable *const variable = dynamic_cast(customizationVariable); - if (!variable) - return; - - //-- convert context to customization variable collection - CustomizationVariableIteratorData *const iteratorData = reinterpret_cast(context); - - //-- add CustomizationVariable to the container - iteratorData->m_variableNames.push_back(fullVariablePathName); - iteratorData->m_customizationVariables.push_back(customizationVariable); - } } // ---------------------------------------------------------------------- diff --git a/src/engine/server/library/serverScript/src/shared/ScriptMethodsShip.cpp b/src/engine/server/library/serverScript/src/shared/ScriptMethodsShip.cpp index f8ab4d93f..8c40cd6cc 100644 --- a/src/engine/server/library/serverScript/src/shared/ScriptMethodsShip.cpp +++ b/src/engine/server/library/serverScript/src/shared/ScriptMethodsShip.cpp @@ -1,4162 +1,4162 @@ -// ====================================================================== -// -// ScriptMethodsShip.cpp -// Copyright 2003, Sony Online Entertainment, Inc. -// All rights reserved. -// -// ====================================================================== - -#include "serverScript/FirstServerScript.h" -#include "serverScript/JavaLibrary.h" - -#include "UnicodeUtils.h" -#include "serverGame/AiShipController.h" -#include "serverGame/ConfigServerGame.h" -#include "serverGame/ConnectionServerConnection.h" -#include "serverGame/ContainerInterface.h" -#include "serverGame/CreatureObject.h" -#include "serverGame/GameServer.h" -#include "serverGame/MiningAsteroidController.h" -#include "serverGame/Missile.h" -#include "serverGame/MissileManager.h" -#include "serverGame/Pvp.h" -#include "serverGame/ServerObjectTemplate.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/ShipInternalDamageOverTime.h" -#include "serverGame/ShipInternalDamageOverTimeManager.h" -#include "serverGame/ShipObject.h" -#include "serverGame/SpaceVisibilityManager.h" -#include "serverNetworkMessages/GameConnectionServerMessages.h" -#include "sharedNetworkMessages/MessageQueueShipHit.h" -#include "sharedFoundation/ConstCharCrcLowerString.h" -#include "sharedFoundation/ConstCharCrcString.h" -#include "sharedFoundation/Crc.h" -#include "sharedFoundation/GameControllerMessage.h" -#include "sharedGame/Nebula.h" -#include "sharedGame/NebulaManager.h" -#include "sharedGame/ShipChassis.h" -#include "sharedGame/ShipChassisSlot.h" -#include "sharedGame/ShipComponentData.h" -#include "sharedGame/ShipComponentDescriptor.h" -#include "sharedGame/ShipComponentWeaponManager.h" -#include "sharedNetworkMessages/DestroyShipComponentMessage.h" -#include "sharedNetworkMessages/DestroyShipMessage.h" -#include "sharedNetworkMessages/GameNetworkMessage.h" -#include "sharedNetworkMessages/GenericValueTypeMessage.h" -#include "sharedNetworkMessages/MessageQueueGenericValueType.h" -#include "sharedNetworkMessages/ShipDamageMessage.h" -#include "sharedObject/Appearance.h" -#include "sharedObject/CellProperty.h" -#include "sharedObject/Controller.h" -#include "sharedObject/NetworkIdManager.h" -#include "sharedObject/ObjectTemplateList.h" - -using namespace JNIWrappersNamespace; - - -// ====================================================================== - -namespace ScriptMethodsShipNamespace -{ - bool verifyShipsEnabled() - { - if (!ConfigServerGame::getShipsEnabled()) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("Ship support is not enabled. Make sure [GameServer] shipsEnabled=1 is in your config file.")); - return false; - } - - return true; - } - - ShipChassisSlotType::Type getSlotType(int slotType) - { - if(slotType < ShipChassisSlotType::SCST_first || slotType > ShipChassisSlotType::SCST_num_types) - return ShipChassisSlotType::SCST_num_types; - else - return static_cast(slotType); - } - - //---------------------------------------------------------------------- - - ShipObject * const getShipThrowTestSlot(JNIEnv * env, jlong jobject_shipId, char const * const functionName, bool throwIfNotOnServer, int chassisSlot) - { - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return NULL; - - char buf[256]; - snprintf(buf, sizeof(buf), "JavaLibrary::%s: ship obj_id did not resolve to a ShipObject", functionName); - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, buf, throwIfNotOnServer); - if (!shipObject) - return NULL; - - if (chassisSlot != ShipChassisSlotType::SCST_num_types && !shipObject->isSlotInstalled(chassisSlot)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::%s chassisSlot [%d] not installed", functionName, chassisSlot)); - - return shipObject; - } - - //---------------------------------------------------------------------- - - void sendGameNetworkMessageToObservers(ServerObject const & sourceObject, GameNetworkMessage const & message, bool sendToSourceObject) - { - // send the projectile to all clients observing the owner except the owner - // time is in the context of the connection server's sync stamp, so we need a unique message per connection server - typedef std::map > DistributionList; - DistributionList distributionList; - - //-- Build distribution list of clients observing object, but don't include the client doing the firing - { - typedef std::set ObserverList; - ObserverList const & observers = sourceObject.getObservers(); - for (ObserverList::const_iterator iter = observers.begin(); iter != observers.end(); ++iter) - { - Client * const client = *iter; - if (sendToSourceObject || client != sourceObject.getClient()) - distributionList[client->getConnection()].push_back(client->getCharacterObjectId()); - } - } - - //-- Send message to distribution list - { - for (DistributionList::const_iterator iter = distributionList.begin(); iter != distributionList.end(); ++iter) - { - GameClientMessage const gameClientMessage(iter->second, true, message); - iter->first->send(gameClientMessage, true); - } - } - } - - bool install(); - - jboolean JNICALL pilotShip(JNIEnv *env, jobject self, jlong pilotId, jlong shipIdId); - jboolean JNICALL unpilotShip(JNIEnv *env, jobject self, jlong pilotId); - jlong JNICALL getShipPilot(JNIEnv * env, jobject self, jlong shipId); - jlong JNICALL getPilotedShip(JNIEnv * env, jobject self, jlong pilotId); - jboolean JNICALL getShipHasWings(JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipCurrentSpeed(JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL setShipSlideDampener(JNIEnv * env, jobject self, jlong shipId, jfloat slideDampener); - jfloat JNICALL getShipSlideDampener(JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL setShipCurrentYaw(JNIEnv * env, jobject self, jlong shipId, jfloat currentYaw); - jfloat JNICALL getShipCurrentYaw(JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL setShipCurrentPitch(JNIEnv * env, jobject self, jlong shipId, jfloat currentPitch); - jfloat JNICALL getShipCurrentPitch(JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL setShipCurrentRoll(JNIEnv * env, jobject self, jlong shipId, jfloat currentRoll); - jfloat JNICALL getShipCurrentRoll(JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL setShipCurrentChassisHitPoints(JNIEnv * env, jobject self, jlong shipId, jfloat currentChassisHitPoints); - jfloat JNICALL getShipCurrentChassisHitPoints(JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL setShipMaximumChassisHitPoints(JNIEnv * env, jobject self, jlong shipId, jfloat maximumChassisHitPoints); - jfloat JNICALL getShipMaximumChassisHitPoints(JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL launchMissile(JNIEnv * env, jobject self, jlong player, jlong ship, jlong target, jint missileInfo, jint targetedComponent); - jboolean JNICALL launchCountermeasure(JNIEnv * env, jobject self, jlong ship, jint targettedMissile, jboolean successful, jint countermeasureType); - jint JNICALL getNearestUnlockedMissileForTarget(JNIEnv * env, jobject self, jlong target); - jintArray JNICALL getAllUnlockedMissilesForTarget(JNIEnv * env, jobject self, jlong jtarget); - jboolean JNICALL destroyMissile(JNIEnv * env, jobject self, jint missileId); - jint JNICALL getTypeByMissile(JNIEnv * env, jobject self, jint missileId); - jint JNICALL getWeaponIndexByMissile(JNIEnv * env, jobject self, jint missileId); - jint JNICALL getTimeSinceFiredByMissile(JNIEnv * env, jobject self, jint missileId); - jint JNICALL getTotalTimeByMissile(JNIEnv * env, jobject self, jint missileId); - jlong JNICALL getWhoFiredByMissile(JNIEnv * env, jobject self, jint missileId); - jboolean JNICALL setLookAtTargetShipComponent(JNIEnv * env, jobject self, jlong ship, jint targetedComponent); - jint JNICALL getLookAtTargetShipComponent(JNIEnv * env, jobject self, jlong ship); - jlongArray JNICALL getObservedShips(JNIEnv *env, jobject self, jlong jsource, jboolean excludeSource); - jlongArray JNICALL getObservedPlayerShips(JNIEnv *env, jobject self, jlong jsource, jboolean excludeSource); - jlongArray JNICALL getObservedEnemyShips(JNIEnv *env, jobject self, jlong jsource); - jlongArray JNICALL getObservedEnemyPlayerShips(JNIEnv *env, jobject self, jlong jsource); - void JNICALL notifyShipDamage(JNIEnv * env, jobject self, jlong victim, jlong attacker, jfloat totalDamage); - jfloat JNICALL getShipChassisSpeedMaximumModifier (JNIEnv * env, jobject self, jlong shipId); - void JNICALL setShipChassisSpeedMaximumModifier (JNIEnv * env, jobject self, jlong shipId, jfloat value); - jfloat JNICALL getShipActualAccelerationRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualDecelerationRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualPitchAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualYawAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualRollAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualPitchRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualYawRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualRollRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipActualSpeedMaximum (JNIEnv * env, jobject self, jlong shipId); - jstring JNICALL getShipChassisType (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getChassisComponentMassCurrent (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getChassisComponentMassMaximum (JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL setChassisComponentMassMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat chassisComponentMassMaximum); - jboolean JNICALL isShipSlotInstalled (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jboolean JNICALL isShipComponentDisabled (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jboolean JNICALL isShipComponentLowPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jboolean JNICALL isShipComponentDisabledNeedsPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentArmorHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentArmorHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentEfficiencyGeneral (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentEfficiencyEnergy (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentEnergyMaintenanceRequirement (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentMass (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jint JNICALL getShipComponentCrc (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipComponentHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jint JNICALL getShipComponentFlags (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jstring JNICALL getShipComponentName (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponDamageMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponDamageMinimum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponEffectivenessShields (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponEffectivenessArmor (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponEnergyPerShot (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponActualRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipWeaponEfficiencyRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jint JNICALL getShipWeaponAmmoCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jint JNICALL getShipWeaponAmmoMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jint JNICALL getShipWeaponAmmoType (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jfloat JNICALL getShipShieldHitpointsFrontCurrent (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipShieldHitpointsFrontMaximum (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipShieldHitpointsBackCurrent (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipShieldHitpointsBackMaximum (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipShieldRechargeRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipCapacitorEnergyCurrent (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipCapacitorEnergyMaximum (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipCapacitorEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineAccelerationRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineDecelerationRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEnginePitchAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineYawAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineRollAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEnginePitchRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineYawRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineRollRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineSpeedMaximum (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineSpeedRotationFactorMaximum (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineSpeedRotationFactorMinimum (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipEngineSpeedRotationFactorOptimal (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipReactorEnergyGenerationRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipBoosterEnergyCurrent (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipBoosterEnergyMaximum (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipBoosterEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipBoosterEnergyConsumptionRate (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipBoosterAcceleration (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipBoosterSpeedMaximum (JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL isShipBoosterActive (JNIEnv * env, jobject self, jlong shipId); - jfloat JNICALL getShipDroidInterfaceCommandSpeed (JNIEnv * env, jobject self, jlong shipId); - int JNICALL getShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong shipId); - int JNICALL getShipCargoHoldContentsCurrent (JNIEnv * env, jobject self, jlong shipId); - void JNICALL setShipComponentArmorHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentArmorHitpointsMaximum); - void JNICALL setShipComponentArmorHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentArmorHitpointsCurrent); - void JNICALL setShipComponentEfficiencyGeneral (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentEfficiencyGeneral); - void JNICALL setShipComponentEfficiencyEnergy (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentEfficiencyEnergy); - void JNICALL setShipComponentEnergyMaintenanceRequirement (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentEnergyMaintenanceRequirement); - void JNICALL setShipComponentMass (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentMass); - void JNICALL setShipComponentHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentHitpointsCurrent); - void JNICALL setShipComponentHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentHitpointsMaximum); - void JNICALL setShipComponentFlags (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint componentFlags); - void JNICALL setShipComponentName (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jstring componentName); - void JNICALL setShipComponentDisabled (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean componentDisabled); - void JNICALL setShipComponentLowPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean componentLowPower); - void JNICALL setShipComponentDisabledNeedsPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean componentDisabledNeedsPower); - void JNICALL setShipWeaponDamageMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponDamageMaximum); - void JNICALL setShipWeaponDamageMinimum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponDamageMinimum); - void JNICALL setShipWeaponEffectivenessShields (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEffectivenessShields); - void JNICALL setShipWeaponEffectivenessArmor (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEffectivenessArmor); - void JNICALL setShipWeaponEnergyPerShot (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEnergyPerShot); - void JNICALL setShipWeaponRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponRefireRate); - void JNICALL setShipWeaponEfficiencyRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEfficiencyRefireRate); - void JNICALL setShipWeaponAmmoCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint ammoCurrent); - void JNICALL setShipWeaponAmmoMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint ammoMaximum); - void JNICALL setShipWeaponAmmoType (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint ammoType); - void JNICALL setShipShieldHitpointsFrontCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsFrontCurrent); - void JNICALL setShipShieldHitpointsFrontMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsFrontMaximum); - void JNICALL setShipShieldHitpointsBackCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsBackCurrent); - void JNICALL setShipShieldHitpointsBackMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsBackMaximum); - void JNICALL setShipShieldRechargeRate (JNIEnv * env, jobject self, jlong shipId, jfloat shieldRechargeRate); - void JNICALL setShipCapacitorEnergyCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat capacitorEnergyCurrent); - void JNICALL setShipCapacitorEnergyMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat capacitorEnergyMaximum); - void JNICALL setShipCapacitorEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId, jfloat capacitorEnergyRechargeRate); - void JNICALL setShipEngineAccelerationRate (JNIEnv * env, jobject self, jlong shipId, jfloat engineAccelerationRate); - void JNICALL setShipEngineDecelerationRate (JNIEnv * env, jobject self, jlong shipId, jfloat engineDecelerationRate); - void JNICALL setShipEnginePitchAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat enginePitchAccelerationRateDegrees); - void JNICALL setShipEngineYawAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineYawAccelerationRateDegrees); - void JNICALL setShipEngineRollAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineRollAccelerationRateDegrees); - void JNICALL setShipEnginePitchRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat enginePitchRateMaximumDegrees); - void JNICALL setShipEngineYawRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineYawRateMaximumDegrees); - void JNICALL setShipEngineRollRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineRollRateMaximumDegrees); - void JNICALL setShipEngineSpeedMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedMaximum); - void JNICALL setShipEngineSpeedRotationFactorMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedRotationFactorMaximum); - void JNICALL setShipEngineSpeedRotationFactorMinimum (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedRotationFactorMinimum); - void JNICALL setShipEngineSpeedRotationFactorOptimal (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedRotationFactorOptimal); - void JNICALL setShipReactorEnergyGenerationRate (JNIEnv * env, jobject self, jlong shipId, jfloat reactorEnergyGenerationRate); - void JNICALL setShipBoosterEnergyCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyCurrent); - void JNICALL setShipBoosterEnergyMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyMaximum); - void JNICALL setShipBoosterEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyRechargeRate); - void JNICALL setShipBoosterEnergyConsumptionRate (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyConsumptionRate); - void JNICALL setShipBoosterAcceleration (JNIEnv * env, jobject self, jlong shipId, jfloat boosterAcceleration); - void JNICALL setShipBoosterSpeedMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat boosterSpeedMaximum); - void JNICALL setShipDroidInterfaceCommandSpeed (JNIEnv * env, jobject self, jlong shipId, jfloat droidInterfaceCommandSpeed); - void JNICALL setShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong shipId, jint contentsMaximum); - void JNICALL setShipCargoHoldContent (JNIEnv * env, jobject self, jlong shipId, jlong resourceTypeId, jint amount); - jint JNICALL getShipCargoHoldContent (JNIEnv * env, jobject self, jlong shipId, jlong resourceTypeId); - jlongArray JNICALL getShipCargoHoldContentsResourceTypes (JNIEnv * env, jobject self, jlong shipId); - jintArray JNICALL getShipCargoHoldContentsAmounts (JNIEnv * env, jobject self, jlong shipId); - jboolean JNICALL shipCanInstallComponent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jlong component); - jboolean JNICALL shipPseudoInstallComponent (JNIEnv * env, jobject self, jlong jship, jint chassisSlot, jint componentCrc); - jboolean JNICALL shipInstallComponent (JNIEnv * env, jobject self, jlong installerId, jlong shipId, jint chassisSlot, jlong component); - jlong JNICALL shipUninstallComponent (JNIEnv * env, jobject self, jlong uninstallerId, jlong shipId, jint chassisSlot, jlong containerTarget); - // allow an uninstalled component to overflow the container. - jlong JNICALL shipUninstallComponentAllowOverload (JNIEnv * env, jobject self, jlong uninstallerId, jlong shipId, jint chassisSlot, jlong containerTarget); - jlong JNICALL shipUninstallComponentBase (JNIEnv * env, jobject self, jlong uninstallerId, jlong shipId, jint chassisSlot, jlong containerTarget, bool allowOverload); - jintArray JNICALL getShipChassisSlots (JNIEnv * env, jobject self, jlong shipId); - void JNICALL setShipSlotTargetable (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean targetable); - jboolean JNICALL isShipSlotTargetable (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); - jint JNICALL getShipComponentDescriptorType (JNIEnv * env, jobject self, jlong component); - jint JNICALL getShipComponentDescriptorTypeByName (JNIEnv * env, jobject self, jstring typeName); - jstring JNICALL getShipComponentDescriptorTypeName (JNIEnv * env, jobject self, jint componentType); - jint JNICALL getShipComponentDescriptorCrc (JNIEnv * env, jobject self, jlong component); - jstring JNICALL getShipComponentDescriptorCrcName (JNIEnv * env, jobject self, jint componentCrc); - jstring JNICALL getShipComponentDescriptorCompatibility (JNIEnv * env, jobject self, jint componentCrc); - jboolean JNICALL getShipComponentDescriptorWeaponIsAmmoConsuming (JNIEnv * env, jobject self, jint componentCrc); - jboolean JNICALL getShipComponentDescriptorWeaponIsMissile (JNIEnv * env, jobject self, jint componentCrc); - jboolean JNICALL getShipComponentDescriptorWeaponIsCountermeasure (JNIEnv * env, jobject self, jint componentCrc); - jboolean JNICALL getShipComponentDescriptorWeaponIsMining (JNIEnv * env, jobject self, jint componentCrc); - jboolean JNICALL getShipComponentDescriptorWeaponIsTractor (JNIEnv * env, jobject self, jint componentCrc); - jfloat JNICALL getShipComponentDescriptorWeaponRange (JNIEnv * env, jobject self, jint componentCrc); - jfloat JNICALL getShipComponentDescriptorWeaponProjectileSpeed (JNIEnv * env, jobject self, jint componentCrc); - jlong JNICALL getDroidControlDeviceForShip (JNIEnv * env, jobject self, jlong jship); - jboolean JNICALL associateDroidControlDeviceWithShip (JNIEnv * env, jobject self, jlong jship, jlong jdroidControlDevice); - jboolean JNICALL removeDroidControlDeviceFromShip (JNIEnv * env, jobject self, jlong jship); - jlong JNICALL launchShipFromHangar (JNIEnv * env, jobject self, jlong jshipId, jstring templateToSpawn, jobject deltaFromHangarHardpoint); - void JNICALL commPlayers (JNIEnv * env, jobject self, jlong jtaunter, jstring appearanceOverloadServerTemplate, jstring soundeffect, jfloat duration, jlongArray jplayers, jstring jtauntOob, jboolean chronicles); - void JNICALL handleShipDestruction(JNIEnv * env, jobject self, jlong ship, jfloat severity); - void JNICALL handleShipComponentDestruction(JNIEnv * env, jobject self, jlong ship, jint chassisSlot, jfloat severity); - jboolean JNICALL setShipInternalDamageOverTime(JNIEnv * env, jobject self, jlong ship, jint chassisSlot, jfloat damageRate, jfloat damageThreshold); - jboolean JNICALL removeShipInternalDamageOverTime(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); - jfloat JNICALL getShipInternalDamageOverTimeDamageRate(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); - jfloat JNICALL getShipInternalDamageOverTimeDamageThreshold(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); - jboolean JNICALL hasShipInternalDamageOverTime(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); - jint JNICALL shipGetSpaceFaction(JNIEnv *env, jobject self, jlong jship); - jintArray JNICALL shipGetSpaceFactionAllies(JNIEnv *env, jobject self, jlong jship); - jintArray JNICALL shipGetSpaceFactionEnemies(JNIEnv *env, jobject self, jlong jship); - jboolean JNICALL shipGetSpaceFactionIsAggro(JNIEnv *env, jobject self, jlong jship); - void JNICALL shipSetSpaceFaction(JNIEnv *env, jobject self, jlong jship, jint spaceFaction); - void JNICALL shipSetSpaceFactionAllies(JNIEnv *env, jobject self, jlong jship, jintArray jfactionList); - void JNICALL shipSetSpaceFactionEnemies(JNIEnv *env, jobject self, jlong jship, jintArray jfactionList); - void JNICALL shipSetSpaceFactionIsAggro(JNIEnv *env, jobject self, jlong jship, jboolean isAggro); - jboolean JNICALL shipIsInNebula(JNIEnv *env, jobject self, jlong ship, jstring nebulaName); - jboolean JNICALL setShipWingName(JNIEnv *env, jobject self, jlong target, jstring str); - jstring JNICALL getShipWingName(JNIEnv *env, jobject self, jlong target); - jboolean JNICALL setShipTypeName(JNIEnv *env, jobject self, jlong target, jstring str); - jstring JNICALL getShipTypeName(JNIEnv *env, jobject self, jlong target); - jboolean JNICALL setShipDifficulty(JNIEnv *env, jobject self, jlong target, jstring str); - jstring JNICALL getShipDifficulty(JNIEnv *env, jobject self, jlong target); - jboolean JNICALL setShipFaction(JNIEnv *env, jobject self, jlong target, jstring str); - jstring JNICALL getShipFaction(JNIEnv *env, jobject self, jlong target); - jboolean JNICALL addMissionCriticalObject(JNIEnv *env, jobject self, jlong playerObjectId, jlong missionCriticalObjectId); - jboolean JNICALL removeMissionCriticalObject(JNIEnv *env, jobject self, jlong playerObjectId, jlong missionCriticalObjectId); - jboolean JNICALL clearMissionCriticalObjects(JNIEnv *env, jobject self, jlong playerObjectId); - jboolean JNICALL isMissionCriticalObject(JNIEnv *env, jobject self, jlong playerObjectId, jlong missionCriticalObjectId); - jstring JNICALL getShipComponentDebugString(JNIEnv * env, jobject self, jlong jobject_shipId, jint chassisSlot); - void JNICALL notifyShipHit(JNIEnv * env, jobject self, jlong jobject_shipId, jobject jobject_vectorUp_w, jobject jobject_vectorHitLocation_o, jint type, jfloat integrity, jfloat previousIntegrity); - void JNICALL setDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId, jobject jobject_velocity_w); - jobject JNICALL getDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId); - void JNICALL openSpaceMiningUi(JNIEnv * env, jobject self, jlong player, jlong spaceStation, jstring spaceStationName); -} - -using namespace ScriptMethodsShipNamespace; - - -//======================================================================== -// install -//======================================================================== - -bool ScriptMethodsShipNamespace::install() -{ -const JNINativeMethod NATIVES[] = { - #define JF(a,b,c) {a,b,(void*)(ScriptMethodsShipNamespace::c)} - JF("_pilotShip", "(JJ)Z", pilotShip), - JF("_unpilotShip", "(J)Z", unpilotShip), - JF("_getPilotId", "(J)J", getShipPilot), - JF("_getShipPilot", "(J)J", getShipPilot), - JF("_getPilotedShip", "(J)J", getPilotedShip), - JF("_getShipHasWings", "(J)Z", getShipHasWings), - JF("_getShipCurrentSpeed", "(J)F", getShipCurrentSpeed), - JF("_setShipSlideDampener", "(JF)Z", setShipSlideDampener), - JF("_getShipSlideDampener", "(J)F", getShipSlideDampener), - JF("_setShipCurrentYaw", "(JF)Z", setShipCurrentYaw), - JF("_getShipCurrentYaw", "(J)F", getShipCurrentYaw), - JF("_setShipCurrentPitch", "(JF)Z", setShipCurrentPitch), - JF("_getShipCurrentPitch", "(J)F", getShipCurrentPitch), - JF("_setShipCurrentRoll", "(JF)Z", setShipCurrentRoll), - JF("_getShipCurrentRoll", "(J)F", getShipCurrentRoll), - JF("_setShipCurrentChassisHitPoints", "(JF)Z", setShipCurrentChassisHitPoints), - JF("_getShipCurrentChassisHitPoints", "(J)F", getShipCurrentChassisHitPoints), - JF("_setShipMaximumChassisHitPoints", "(JF)Z", setShipMaximumChassisHitPoints), - JF("_getShipMaximumChassisHitPoints", "(J)F", getShipMaximumChassisHitPoints), - JF("_launchMissile", "(JJJII)Z", launchMissile), - JF("_launchCountermeasure", "(JIZI)Z", launchCountermeasure), - JF("_getNearestUnlockedMissileForTarget", "(J)I", getNearestUnlockedMissileForTarget), - JF("_getAllUnlockedMissilesForTarget", "(J)[I", getAllUnlockedMissilesForTarget), - JF("destroyMissile", "(I)Z", destroyMissile), - JF("getTypeByMissile","(I)I", getTypeByMissile), - JF("getWeaponIndexByMissile","(I)I",getWeaponIndexByMissile), - JF("getTimeSinceFiredByMissile","(I)I",getTimeSinceFiredByMissile), - JF("getTotalTimeByMissile","(I)I",getTotalTimeByMissile), - JF("_getWhoFiredByMissile","(I)J",getWhoFiredByMissile), - JF("_setLookAtTargetShipComponent", "(JI)Z", setLookAtTargetShipComponent), - JF("_getLookAtTargetShipComponent", "(J)I", getLookAtTargetShipComponent), - JF("_getObservedShips", "(JZ)[J", getObservedShips), - JF("_getObservedPlayerShips", "(JZ)[J", getObservedPlayerShips), - JF("_getObservedEnemyShips", "(J)[J", getObservedEnemyShips), - JF("_getObservedEnemyPlayerShips", "(J)[J", getObservedEnemyPlayerShips), - JF("_notifyShipDamage", "(JJF)V", notifyShipDamage), - JF("_getShipChassisSpeedMaximumModifier", "(J)F", getShipChassisSpeedMaximumModifier), - JF("_setShipChassisSpeedMaximumModifier", "(JF)V", setShipChassisSpeedMaximumModifier), - JF("_getShipActualAccelerationRate", "(J)F", getShipActualAccelerationRate), - JF("_getShipActualDecelerationRate", "(J)F", getShipActualDecelerationRate), - JF("_getShipActualPitchAccelerationRateDegrees", "(J)F", getShipActualPitchAccelerationRateDegrees), - JF("_getShipActualYawAccelerationRateDegrees", "(J)F", getShipActualYawAccelerationRateDegrees), - JF("_getShipActualRollAccelerationRateDegrees", "(J)F", getShipActualRollAccelerationRateDegrees), - JF("_getShipActualPitchRateMaximumDegrees", "(J)F", getShipActualPitchRateMaximumDegrees), - JF("_getShipActualYawRateMaximumDegrees", "(J)F", getShipActualYawRateMaximumDegrees), - JF("_getShipActualRollRateMaximumDegrees", "(J)F", getShipActualRollRateMaximumDegrees), - JF("_getShipActualSpeedMaximum", "(J)F", getShipActualSpeedMaximum), - JF("_handleShipDestruction", "(JF)V", handleShipDestruction), - JF("_handleShipComponentDestruction", "(JIF)V", handleShipComponentDestruction), - JF("_setShipInternalDamageOverTime", "(JIFF)Z", setShipInternalDamageOverTime), - JF("_removeShipInternalDamageOverTime", "(JI)Z", removeShipInternalDamageOverTime), - JF("_getShipInternalDamageOverTimeDamageRate", "(JI)F", getShipInternalDamageOverTimeDamageRate), - JF("_getShipInternalDamageOverTimeDamageThreshold", "(JI)F", getShipInternalDamageOverTimeDamageThreshold), - JF("_hasShipInternalDamageOverTime", "(JI)Z", hasShipInternalDamageOverTime), - JF("_shipGetSpaceFaction", "(J)I", shipGetSpaceFaction), - JF("_shipGetSpaceFactionAllies", "(J)[I", shipGetSpaceFactionAllies), - JF("_shipGetSpaceFactionEnemies", "(J)[I", shipGetSpaceFactionEnemies), - JF("_shipGetSpaceFactionIsAggro", "(J)Z", shipGetSpaceFactionIsAggro), - JF("_shipSetSpaceFaction", "(JI)V", shipSetSpaceFaction), - JF("_shipSetSpaceFactionAllies", "(J[I)V", shipSetSpaceFactionAllies), - JF("_shipSetSpaceFactionEnemies", "(J[I)V", shipSetSpaceFactionEnemies), - JF("_shipSetSpaceFactionIsAggro", "(JZ)V", shipSetSpaceFactionIsAggro), - JF("_getShipChassisType", "(J)Ljava/lang/String;", getShipChassisType), - JF("_getChassisComponentMassCurrent", "(J)F", getChassisComponentMassCurrent), - JF("_getChassisComponentMassMaximum", "(J)F", getChassisComponentMassMaximum), - JF("_setChassisComponentMassMaximum", "(JF)Z", setChassisComponentMassMaximum), - JF("_isShipSlotInstalled", "(JI)Z", isShipSlotInstalled), - JF("_isShipComponentDisabled", "(JI)Z", isShipComponentDisabled), - JF("_isShipComponentLowPower", "(JI)Z", isShipComponentLowPower), - JF("_isShipComponentDisabledNeedsPower", "(JI)Z", isShipComponentDisabledNeedsPower), - JF("_getShipComponentArmorHitpointsMaximum", "(JI)F", getShipComponentArmorHitpointsMaximum), - JF("_getShipComponentArmorHitpointsCurrent", "(JI)F", getShipComponentArmorHitpointsCurrent), - JF("_getShipComponentEfficiencyGeneral", "(JI)F", getShipComponentEfficiencyGeneral), - JF("_getShipComponentEfficiencyEnergy", "(JI)F", getShipComponentEfficiencyEnergy), - JF("_getShipComponentEnergyMaintenanceRequirement", "(JI)F", getShipComponentEnergyMaintenanceRequirement), - JF("_getShipComponentMass", "(JI)F", getShipComponentMass), - JF("_getShipComponentCrc", "(JI)I", getShipComponentCrc), - JF("_getShipComponentHitpointsCurrent", "(JI)F", getShipComponentHitpointsCurrent), - JF("_getShipComponentHitpointsMaximum", "(JI)F", getShipComponentHitpointsMaximum), - JF("_getShipComponentFlags", "(JI)I", getShipComponentFlags), - JF("_getShipComponentName", "(JI)Ljava/lang/String;", getShipComponentName), - JF("_getShipWeaponDamageMaximum", "(JI)F", getShipWeaponDamageMaximum), - JF("_getShipWeaponDamageMinimum", "(JI)F", getShipWeaponDamageMinimum), - JF("_getShipWeaponEffectivenessShields", "(JI)F", getShipWeaponEffectivenessShields), - JF("_getShipWeaponEffectivenessArmor", "(JI)F", getShipWeaponEffectivenessArmor), - JF("_getShipWeaponEnergyPerShot", "(JI)F", getShipWeaponEnergyPerShot), - JF("_getShipWeaponRefireRate", "(JI)F", getShipWeaponRefireRate), - JF("_getShipWeaponActualRefireRate", "(JI)F", getShipWeaponActualRefireRate), - JF("_getShipWeaponEfficiencyRefireRate", "(JI)F", getShipWeaponEfficiencyRefireRate), - JF("_getShipWeaponAmmoCurrent", "(JI)I", getShipWeaponAmmoCurrent), - JF("_getShipWeaponAmmoMaximum", "(JI)I", getShipWeaponAmmoMaximum), - JF("_getShipWeaponAmmoType", "(JI)I", getShipWeaponAmmoType), - JF("_getShipShieldHitpointsFrontCurrent", "(J)F", getShipShieldHitpointsFrontCurrent), - JF("_getShipShieldHitpointsFrontMaximum", "(J)F", getShipShieldHitpointsFrontMaximum), - JF("_getShipShieldHitpointsBackCurrent", "(J)F", getShipShieldHitpointsBackCurrent), - JF("_getShipShieldHitpointsBackMaximum", "(J)F", getShipShieldHitpointsBackMaximum), - JF("_getShipShieldRechargeRate", "(J)F", getShipShieldRechargeRate), - JF("_getShipCapacitorEnergyCurrent", "(J)F", getShipCapacitorEnergyCurrent), - JF("_getShipCapacitorEnergyMaximum", "(J)F", getShipCapacitorEnergyMaximum), - JF("_getShipCapacitorEnergyRechargeRate", "(J)F", getShipCapacitorEnergyRechargeRate), - JF("_getShipEngineAccelerationRate", "(J)F", getShipEngineAccelerationRate), - JF("_getShipEngineDecelerationRate", "(J)F", getShipEngineDecelerationRate), - JF("_getShipEnginePitchAccelerationRateDegrees", "(J)F", getShipEnginePitchAccelerationRateDegrees), - JF("_getShipEngineYawAccelerationRateDegrees", "(J)F", getShipEngineYawAccelerationRateDegrees), - JF("_getShipEngineRollAccelerationRateDegrees", "(J)F", getShipEngineRollAccelerationRateDegrees), - JF("_getShipEnginePitchRateMaximumDegrees", "(J)F", getShipEnginePitchRateMaximumDegrees), - JF("_getShipEngineYawRateMaximumDegrees", "(J)F", getShipEngineYawRateMaximumDegrees), - JF("_getShipEngineRollRateMaximumDegrees", "(J)F", getShipEngineRollRateMaximumDegrees), - JF("_getShipEngineSpeedMaximum", "(J)F", getShipEngineSpeedMaximum), - JF("_getShipEngineSpeedRotationFactorMaximum", "(J)F", getShipEngineSpeedRotationFactorMaximum), - JF("_getShipEngineSpeedRotationFactorMinimum", "(J)F", getShipEngineSpeedRotationFactorMinimum), - JF("_getShipEngineSpeedRotationFactorOptimal", "(J)F", getShipEngineSpeedRotationFactorOptimal), - JF("_getShipReactorEnergyGenerationRate", "(J)F", getShipReactorEnergyGenerationRate), - JF("_getShipBoosterEnergyCurrent", "(J)F", getShipBoosterEnergyCurrent), - JF("_getShipBoosterEnergyMaximum", "(J)F", getShipBoosterEnergyMaximum), - JF("_getShipBoosterEnergyRechargeRate", "(J)F", getShipBoosterEnergyRechargeRate), - JF("_getShipBoosterEnergyConsumptionRate", "(J)F", getShipBoosterEnergyConsumptionRate), - JF("_getShipBoosterAcceleration", "(J)F", getShipBoosterAcceleration), - JF("_getShipBoosterSpeedMaximum", "(J)F", getShipBoosterSpeedMaximum), - JF("_isShipBoosterActive", "(J)Z", isShipBoosterActive), - JF("_getShipDroidInterfaceCommandSpeed", "(J)F", getShipDroidInterfaceCommandSpeed), - JF("_getShipCargoHoldContentsMaximum", "(J)I", getShipCargoHoldContentsMaximum), - JF("_getShipCargoHoldContentsCurrent", "(J)I", getShipCargoHoldContentsCurrent), - JF("_setShipComponentArmorHitpointsMaximum", "(JIF)V", setShipComponentArmorHitpointsMaximum), - JF("_setShipComponentArmorHitpointsCurrent", "(JIF)V", setShipComponentArmorHitpointsCurrent), - JF("_setShipComponentEfficiencyGeneral", "(JIF)V", setShipComponentEfficiencyGeneral), - JF("_setShipComponentEfficiencyEnergy", "(JIF)V", setShipComponentEfficiencyEnergy), - JF("_setShipComponentEnergyMaintenanceRequirement", "(JIF)V", setShipComponentEnergyMaintenanceRequirement), - JF("_setShipComponentMass", "(JIF)V", setShipComponentMass), - JF("_setShipComponentHitpointsCurrent", "(JIF)V", setShipComponentHitpointsCurrent), - JF("_setShipComponentHitpointsMaximum", "(JIF)V", setShipComponentHitpointsMaximum), - JF("_setShipComponentFlags", "(JII)V", setShipComponentFlags), - JF("_setShipComponentName", "(JILjava/lang/String;)V", setShipComponentName), - JF("_setShipComponentDisabled", "(JIZ)V", setShipComponentDisabled), - JF("_setShipComponentLowPower", "(JIZ)V", setShipComponentLowPower), - JF("_setShipComponentDisabledNeedsPower", "(JIZ)V", setShipComponentDisabledNeedsPower), - JF("_setShipWeaponDamageMaximum", "(JIF)V", setShipWeaponDamageMaximum), - JF("_setShipWeaponDamageMinimum", "(JIF)V", setShipWeaponDamageMinimum), - JF("_setShipWeaponEffectivenessShields", "(JIF)V", setShipWeaponEffectivenessShields), - JF("_setShipWeaponEffectivenessArmor", "(JIF)V", setShipWeaponEffectivenessArmor), - JF("_setShipWeaponEnergyPerShot", "(JIF)V", setShipWeaponEnergyPerShot), - JF("_setShipWeaponRefireRate", "(JIF)V", setShipWeaponRefireRate), - JF("_setShipWeaponEfficiencyRefireRate", "(JIF)V", setShipWeaponEfficiencyRefireRate), - JF("_setShipWeaponAmmoCurrent", "(JII)V", setShipWeaponAmmoCurrent), - JF("_setShipWeaponAmmoMaximum", "(JII)V", setShipWeaponAmmoMaximum), - JF("_setShipWeaponAmmoType", "(JII)V", setShipWeaponAmmoType), - JF("_setShipShieldHitpointsFrontCurrent", "(JF)V", setShipShieldHitpointsFrontCurrent), - JF("_setShipShieldHitpointsFrontMaximum", "(JF)V", setShipShieldHitpointsFrontMaximum), - JF("_setShipShieldHitpointsBackCurrent", "(JF)V", setShipShieldHitpointsBackCurrent), - JF("_setShipShieldHitpointsBackMaximum", "(JF)V", setShipShieldHitpointsBackMaximum), - JF("_setShipShieldRechargeRate", "(JF)V", setShipShieldRechargeRate), - JF("_setShipCapacitorEnergyCurrent", "(JF)V", setShipCapacitorEnergyCurrent), - JF("_setShipCapacitorEnergyMaximum", "(JF)V", setShipCapacitorEnergyMaximum), - JF("_setShipCapacitorEnergyRechargeRate", "(JF)V", setShipCapacitorEnergyRechargeRate), - JF("_setShipEngineAccelerationRate", "(JF)V", setShipEngineAccelerationRate), - JF("_setShipEngineDecelerationRate", "(JF)V", setShipEngineDecelerationRate), - JF("_setShipEnginePitchAccelerationRateDegrees", "(JF)V", setShipEnginePitchAccelerationRateDegrees), - JF("_setShipEngineYawAccelerationRateDegrees", "(JF)V", setShipEngineYawAccelerationRateDegrees), - JF("_setShipEngineRollAccelerationRateDegrees", "(JF)V", setShipEngineRollAccelerationRateDegrees), - JF("_setShipEnginePitchRateMaximumDegrees", "(JF)V", setShipEnginePitchRateMaximumDegrees), - JF("_setShipEngineYawRateMaximumDegrees", "(JF)V", setShipEngineYawRateMaximumDegrees), - JF("_setShipEngineRollRateMaximumDegrees", "(JF)V", setShipEngineRollRateMaximumDegrees), - JF("_setShipEngineSpeedMaximum", "(JF)V", setShipEngineSpeedMaximum), - JF("_setShipEngineSpeedRotationFactorMaximum", "(JF)V", setShipEngineSpeedRotationFactorMaximum), - JF("_setShipEngineSpeedRotationFactorMinimum", "(JF)V", setShipEngineSpeedRotationFactorMinimum), - JF("_setShipEngineSpeedRotationFactorOptimal", "(JF)V", setShipEngineSpeedRotationFactorOptimal), - JF("_setShipReactorEnergyGenerationRate", "(JF)V", setShipReactorEnergyGenerationRate), - JF("_setShipBoosterEnergyCurrent", "(JF)V", setShipBoosterEnergyCurrent), - JF("_setShipBoosterEnergyMaximum", "(JF)V", setShipBoosterEnergyMaximum), - JF("_setShipBoosterEnergyRechargeRate", "(JF)V", setShipBoosterEnergyRechargeRate), - JF("_setShipBoosterEnergyConsumptionRate", "(JF)V", setShipBoosterEnergyConsumptionRate), - JF("_setShipBoosterAcceleration", "(JF)V", setShipBoosterAcceleration), - JF("_setShipBoosterSpeedMaximum", "(JF)V", setShipBoosterSpeedMaximum), - JF("_setShipDroidInterfaceCommandSpeed", "(JF)V", setShipDroidInterfaceCommandSpeed), - JF("_setShipCargoHoldContentsMaximum", "(JI)V", setShipCargoHoldContentsMaximum), - JF("_setShipCargoHoldContent", "(JJI)V", setShipCargoHoldContent), - JF("_getShipCargoHoldContent", "(JJ)I", getShipCargoHoldContent), - JF("_getShipCargoHoldContentsResourceTypes", "(J)[J", getShipCargoHoldContentsResourceTypes), - JF("_getShipCargoHoldContentsAmounts", "(J)[I", getShipCargoHoldContentsAmounts), - JF("_shipCanInstallComponent", "(JIJ)Z", shipCanInstallComponent), - JF("_shipPseudoInstallComponent", "(JII)Z", shipPseudoInstallComponent), - JF("_shipInstallComponent", "(JJIJ)Z", shipInstallComponent), - JF("_shipUninstallComponent", "(JJIJ)J", shipUninstallComponent), - JF("_shipUninstallComponentAllowOverload", "(JJIJ)J", shipUninstallComponentAllowOverload), - JF("_getShipChassisSlots", "(J)[I", getShipChassisSlots), - JF("_setShipSlotTargetable", "(JIZ)V", setShipSlotTargetable), - JF("_isShipSlotTargetable", "(JI)Z", isShipSlotTargetable), - JF("_getShipComponentDescriptorType", "(J)I", getShipComponentDescriptorType), - JF("getShipComponentDescriptorTypeName", "(I)Ljava/lang/String;", getShipComponentDescriptorTypeName), - JF("getShipComponentDescriptorTypeByName", "(Ljava/lang/String;)I", getShipComponentDescriptorTypeByName), - JF("_getShipComponentDescriptorCrc", "(J)I", getShipComponentDescriptorCrc), - JF("getShipComponentDescriptorCrcName", "(I)Ljava/lang/String;", getShipComponentDescriptorCrcName), - JF("getShipComponentDescriptorCompatibility", "(I)Ljava/lang/String;", getShipComponentDescriptorCompatibility), - JF("getShipComponentDescriptorWeaponIsAmmoConsuming", "(I)Z", getShipComponentDescriptorWeaponIsAmmoConsuming), - JF("getShipComponentDescriptorWeaponIsMissile", "(I)Z", getShipComponentDescriptorWeaponIsMissile), - JF("getShipComponentDescriptorWeaponIsCountermeasure","(I)Z", getShipComponentDescriptorWeaponIsCountermeasure), - JF("getShipComponentDescriptorWeaponIsMining", "(I)Z", getShipComponentDescriptorWeaponIsMining), - JF("getShipComponentDescriptorWeaponIsTractor", "(I)Z", getShipComponentDescriptorWeaponIsTractor), - JF("getShipComponentDescriptorWeaponRange", "(I)F", getShipComponentDescriptorWeaponRange), - JF("getShipComponentDescriptorWeaponProjectileSpeed", "(I)F", getShipComponentDescriptorWeaponProjectileSpeed), - JF("_getDroidControlDeviceForShip", "(J)J", getDroidControlDeviceForShip), - JF("_associateDroidControlDeviceWithShip", "(JJ)Z", associateDroidControlDeviceWithShip), - JF("_removeDroidControlDeviceFromShip", "(J)Z", removeDroidControlDeviceFromShip), - JF("_launchShipFromHangar", "(JLjava/lang/String;Lscript/transform;)J", launchShipFromHangar), - JF("__commPlayers", "(JLjava/lang/String;Ljava/lang/String;F[JLjava/lang/String;Z)V", commPlayers), - JF("_shipIsInNebula", "(JLjava/lang/String;)Z", shipIsInNebula), - JF("_setShipWingName", "(JLjava/lang/String;)Z", setShipWingName), - JF("_getShipWingName", "(J)Ljava/lang/String;", getShipWingName), - JF("_setShipTypeName", "(JLjava/lang/String;)Z", setShipTypeName), - JF("_getShipTypeName", "(J)Ljava/lang/String;", getShipTypeName), - JF("_setShipDifficulty", "(JLjava/lang/String;)Z", setShipDifficulty), - JF("_getShipDifficulty", "(J)Ljava/lang/String;", getShipDifficulty), - JF("_setShipFaction", "(JLjava/lang/String;)Z", setShipFaction), - JF("_getShipFaction", "(J)Ljava/lang/String;", getShipFaction), - JF("_addMissionCriticalObject", "(JJ)Z", addMissionCriticalObject), - JF("_removeMissionCriticalObject", "(JJ)Z", removeMissionCriticalObject), - JF("_clearMissionCriticalObjects", "(J)Z", clearMissionCriticalObjects), - JF("_isMissionCriticalObject", "(JJ)Z", isMissionCriticalObject), - JF("_getShipComponentDebugString", "(JI)Ljava/lang/String;", getShipComponentDebugString), - JF("_notifyShipHit", "(JLscript/vector;Lscript/vector;IFF)V", notifyShipHit), - JF("_setDynamicMiningAsteroidVelocity", "(JLscript/vector;)V", setDynamicMiningAsteroidVelocity), - JF("_getDynamicMiningAsteroidVelocity", "(J)Lscript/vector;", getDynamicMiningAsteroidVelocity), - JF("_openSpaceMiningUi", "(JJLjava/lang/String;)V", openSpaceMiningUi), -}; - - return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); -} - - -// ====================================================================== - -jboolean JNICALL ScriptMethodsShipNamespace::pilotShip(JNIEnv *env, jobject /*self*/, jlong pilotId, jlong pilotSlotId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - //-- Get the pilot object. - CreatureObject * const pilotObject = JavaLibrary::getCreatureThrow(env, pilotId, "pilotShip(): error in pilotId arg"); - if (!pilotObject) - return JNI_FALSE; - - //-- Ensure that the pilot is not already piloting a ship. - if (pilotObject->getPilotedShip()) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::pilotShip(): pilot id=[%s] is already riding a ship.", pilotObject->getNetworkId().getValueString().c_str())); - return JNI_FALSE; - } - - //-- Get the pilot slot object. - ServerObject * pilotSlotObject = 0; - if (!JavaLibrary::getObject(pilotSlotId, pilotSlotObject)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::pilotShip: could not resolve pilotSlotObject")); - return JNI_FALSE; - } - - //-- Make sure the ship is a player controlled ship - if (pilotObject->isPlayerControlled()) - { - //-- Get the containing ship - ShipObject * const shipObject = ShipObject::getContainingShipObject(pilotSlotObject); - if (!shipObject) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::pilotShip: pilotSlotObject [id=%s, template=%s] does not have a containing ship", pilotSlotObject->getNetworkId().getValueString().c_str(), pilotSlotObject->getObjectTemplateName())); - return JNI_FALSE; - } - - if (!shipObject->isPlayerShip()) - return JNI_FALSE; - } - - //-- Have the pilot mount the ship. - if (!pilotObject->pilotShip(*pilotSlotObject)) - return JNI_FALSE; - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::unpilotShip(JNIEnv *env, jobject /*self*/, jlong pilotId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - //-- Get the pilot. - CreatureObject * const pilotObject = JavaLibrary::getCreatureThrow(env, pilotId, "unpilotShip(): error in pilotId arg"); - if (!pilotObject) - return JNI_FALSE; - - //-- Get the ship. - ShipObject * const shipObject = pilotObject->getPilotedShip(); - if (!shipObject) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::unpilotShip(): pilot id=[%s] is not piloting a ship.", pilotObject->getNetworkId().getValueString().c_str())); - return JNI_FALSE; - } - - //-- Detach the pilot from the ship. - if (!pilotObject->unpilotShip()) - return JNI_FALSE; - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jlong JNICALL ScriptMethodsShipNamespace::getShipPilot(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0; - - //-- Get the ship object. - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipPilot(): obj_id shipId did not resolve to a ShipObject", false); - if (!shipObject) - return 0; - - //-- Get the pilot object - CreatureObject const * const pilotObject = shipObject->getPilot(); - NetworkId const pilotNetworkId = (pilotObject ? pilotObject->getNetworkId() : NetworkId::cms_invalid); - - return pilotNetworkId.getValue(); -} - -// ---------------------------------------------------------------------- - -jlong JNICALL ScriptMethodsShipNamespace::getPilotedShip(JNIEnv * env, jobject /*self*/, jlong jobject_pilotId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0; - - //-- Get the pilot object. - CreatureObject const * const creatureObject = JavaLibrary::getCreatureThrow(env, jobject_pilotId, "getPilotedShip(): obj_id pilotId did not resolve to a ShipObject", false); - if (!creatureObject) - return 0; - - ShipObject const * const shipObject = creatureObject->getPilotedShip(); - NetworkId const shipNetworkId = (shipObject ? shipObject->getNetworkId() : NetworkId::cms_invalid); - - return shipNetworkId.getValue(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::getShipHasWings(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipHasWings(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - if (!shipObject->hasWings()) - return JNI_FALSE; - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentSpeed(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentSpeed(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getCurrentSpeed(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipSlideDampener(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_slideDampener) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipSlideDampener(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - bool const result = shipObject->setSlideDampener(jfloat_slideDampener); - if (!result) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipSlideDampener(): could not set value %1.2f (possibly out of range)", jfloat_slideDampener)); - return JNI_FALSE; - } - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipSlideDampener(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipSlideDampener(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getSlideDampener(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentYaw(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentYaw) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentYaw(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - bool const result = shipObject->setCurrentYaw(jfloat_currentYaw); - if (!result) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentYaw(): could not set value %1.2f (possibly out of range)", jfloat_currentYaw)); - return JNI_FALSE; - } - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentYaw(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentYaw(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getCurrentYaw(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentPitch(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentPitch) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentPitch(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - bool const result = shipObject->setCurrentPitch(jfloat_currentPitch); - if (!result) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentPitch(): could not set value %1.2f (possibly out of range)", jfloat_currentPitch)); - return JNI_FALSE; - } - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentPitch(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentPitch(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getCurrentPitch(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentRoll(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentRoll) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentRoll(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - bool const result = shipObject->setCurrentRoll(jfloat_currentRoll); - if (!result) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentRoll(): could not set value %1.2f (possibly out of range)", jfloat_currentRoll)); - return JNI_FALSE; - } - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentRoll(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentRoll(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getCurrentRoll(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentChassisHitPoints) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - bool const result = shipObject->setCurrentChassisHitPoints(jfloat_currentChassisHitPoints); - if (!result) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentChassisHitPoints(): could not set value %1.2f (possibly out of range)", jfloat_currentChassisHitPoints)); - return JNI_FALSE; - } - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getCurrentChassisHitPoints(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipMaximumChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentChassisHitPoints) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipMaximumChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - bool const result = shipObject->setMaximumChassisHitPoints(jfloat_currentChassisHitPoints); - if (!result) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipMaximumChassisHitPoints(): could not set value %1.2f (possibly out of range)", jfloat_currentChassisHitPoints)); - return JNI_FALSE; - } - - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipMaximumChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipMaximumChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getMaximumChassisHitPoints(); -} - -//---------------------------------------------------------------------- -//---------------------------------------------------------------------- -//-- component system -//---------------------------------------------------------------------- -//---------------------------------------------------------------------- - -//-- ship component methods - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualAccelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getShipActualAccelerationRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualDecelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualDecelerationRate(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getShipActualDecelerationRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualPitchAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualPitchAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return convertRadiansToDegrees(shipObject->getShipActualPitchAccelerationRate()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualYawAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualYawAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return convertRadiansToDegrees(shipObject->getShipActualYawAccelerationRate()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualRollAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualRollAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return convertRadiansToDegrees(shipObject->getShipActualRollAccelerationRate()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualPitchRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualPitchRateMaximum(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return convertRadiansToDegrees(shipObject->getShipActualPitchRateMaximum()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualYawRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualYawRateMaximum(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return convertRadiansToDegrees(shipObject->getShipActualYawRateMaximum()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualRollRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualRollRateMaximum(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return convertRadiansToDegrees(shipObject->getShipActualRollRateMaximum()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipActualSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualSpeedMaximum(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.f; - - return shipObject->getShipActualSpeedMaximum(); -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipChassisType(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return NULL; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return NULL; - - ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (shipObject->getChassisType()); - if (shipChassis) - return JavaString(shipChassis->getName ().getString ()).getReturnValue(); - - return NULL; -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getChassisComponentMassCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.0f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.0f; - - return shipObject->getChassisComponentMassCurrent(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getChassisComponentMassMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.0f; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0.0f; - - return shipObject->getChassisComponentMassMaximum(); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setChassisComponentMassMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, float chassisComponentMassMaximum) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - shipObject->setChassisComponentMassMaximum(chassisComponentMassMaximum); - - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::isShipSlotInstalled(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "JavaLibrary::isShipSlotInstalled ship obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return false; - - return shipObject->isSlotInstalled(chassisSlot); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::isShipComponentDisabled(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipComponentDisabled() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->isComponentDisabled(chassisSlot); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::isShipComponentDisabledNeedsPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipComponentDisabledNeedsPower() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->isComponentDisabledNeedsPower(chassisSlot); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::isShipComponentLowPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipComponentLowPower() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->isComponentLowPower(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentArmorHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentArmorHitpointsMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentArmorHitpointsMaximum(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentArmorHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentArmorHitpointsCurrent() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentArmorHitpointsCurrent(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentEfficiencyGeneral(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentEfficiencyGeneral() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentEfficiencyGeneral(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentEfficiencyEnergy(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentEfficiencyEnergy() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentEfficiencyEnergy(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentEnergyMaintenanceRequirement(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentEnergyMaintenanceRequirement() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentEnergyMaintenanceRequirement(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentMass(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentMass() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentMass(chassisSlot); -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipComponentCrc(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentCrc() invalid ship", false); - if (!shipObject) - return false; - - return static_cast(shipObject->getComponentCrc(chassisSlot)); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentHitpointsCurrent() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentHitpointsCurrent(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentHitpointsMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentHitpointsMaximum(chassisSlot); -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipComponentFlags(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentFlags() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getComponentFlags(chassisSlot); -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipComponentName(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentName() invalid ship", false); - if (!shipObject) - return NULL; - - Unicode::String const & name = shipObject->getComponentName(chassisSlot); - if (!name.empty()) - return JavaString(name).getReturnValue(); - - ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc(shipObject->getComponentCrc(chassisSlot)); - if (shipComponentDescriptor) - { - ObjectTemplate const * const t = shipComponentDescriptor->getSharedObjectTemplate(); - if (t) - { - SharedObjectTemplate const * const sharedTemplate = t->asSharedObjectTemplate(); - if (sharedTemplate) - return JavaString("@"+sharedTemplate->getObjectName().getCanonicalRepresentation()).getReturnValue(); - } - } - return JavaString("").getReturnValue(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponDamageMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponDamageMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponDamageMaximum(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponDamageMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponDamageMinimum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponDamageMinimum(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEffectivenessShields(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEffectivenessShields() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponEffectivenessShields(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEffectivenessArmor(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEffectivenessArmor() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponEffectivenessArmor(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEnergyPerShot(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEnergyPerShot() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponEnergyPerShot(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponRefireRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponRefireRate(chassisSlot); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponActualRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponActualRefireRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponActualRefireRate(chassisSlot); -} -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEfficiencyRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEfficiencyRefireRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponEfficiencyRefireRate(chassisSlot); -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipWeaponAmmoCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponAmmoCurrent() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponAmmoCurrent(chassisSlot); -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipWeaponAmmoMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponAmmoMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getWeaponAmmoMaximum(chassisSlot); -} - - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipWeaponAmmoType(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponAmmoType() invalid ship", false); - if (!shipObject) - return false; - - return static_cast(shipObject->getWeaponAmmoType(chassisSlot)); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsFrontCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsFrontCurrent() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getShieldHitpointsFrontCurrent(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsFrontMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsFrontMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getShieldHitpointsFrontMaximum(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsBackCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsBackCurrent() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getShieldHitpointsBackCurrent(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsBackMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsBackMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getShieldHitpointsBackMaximum(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldRechargeRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getShieldRechargeRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCapacitorEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCapacitorEnergyCurrent() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getCapacitorEnergyCurrent(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCapacitorEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCapacitorEnergyMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getCapacitorEnergyEffectiveMaximum(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipCapacitorEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCapacitorEnergyRechargeRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getCapacitorEnergyRechargeRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineAccelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineAccelerationRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getEngineAccelerationRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineDecelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineDecelerationRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getEngineDecelerationRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEnginePitchAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEnginePitchAccelerationRateDegrees() invalid ship", false); - if (!shipObject) - return false; - - return convertRadiansToDegrees(shipObject->getEnginePitchAccelerationRate()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineYawAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineYawAccelerationRateDegrees() invalid ship", false); - if (!shipObject) - return false; - - return convertRadiansToDegrees(shipObject->getEngineYawAccelerationRate()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineRollAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineRollAccelerationRateDegrees() invalid ship", false); - if (!shipObject) - return false; - - return convertRadiansToDegrees(shipObject->getEngineRollAccelerationRate()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEnginePitchRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEnginePitchRateMaximumDegrees() invalid ship", false); - if (!shipObject) - return false; - - return convertRadiansToDegrees(shipObject->getEnginePitchRateMaximum()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineYawRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineYawRateMaximumDegrees() invalid ship", false); - if (!shipObject) - return false; - - return convertRadiansToDegrees(shipObject->getEngineYawRateMaximum()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineRollRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineRollRateMaximumDegrees() invalid ship", false); - if (!shipObject) - return false; - - return convertRadiansToDegrees(shipObject->getEngineRollRateMaximum()); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getEngineSpeedMaximum(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedRotationFactorMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedRotationFactorMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getEngineSpeedRotationFactorMaximum(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedRotationFactorMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedRotationFactorMinimum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getEngineSpeedRotationFactorMinimum(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedRotationFactorOptimal(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedRotationFactorOptimal() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getEngineSpeedRotationFactorOptimal(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipReactorEnergyGenerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipReactorEnergyGenerationRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getReactorEnergyGenerationRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyCurrent() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getBoosterEnergyCurrent(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getBoosterEnergyMaximum(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyRechargeRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getBoosterEnergyRechargeRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyConsumptionRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyConsumptionRate() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getBoosterEnergyConsumptionRate(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterAcceleration(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterAcceleration() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getBoosterAcceleration(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterSpeedMaximum() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getBoosterSpeedMaximum(); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::isShipBoosterActive(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipBoosterActive() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->isBoosterActive(); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipDroidInterfaceCommandSpeed(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipDroidInterfaceCommandSpeed() invalid ship", false); - if (!shipObject) - return false; - - return shipObject->getDroidInterfaceCommandSpeed(); -} - -//---------------------------------------------------------------------- -//---------------------------------------------------------------------- -// component setters -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentArmorHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentArmorHitpointsMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentArmorHitpointsMaximum()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentArmorHitpointsMaximum(chassisSlot, componentArmorHitpointsMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentArmorHitpointsMaximum (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentArmorHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentArmorHitpointsCurrent) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentArmorHitpointsCurrent()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentArmorHitpointsCurrent(chassisSlot, componentArmorHitpointsCurrent)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentArmorHitpointsCurrent (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentEfficiencyGeneral(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentEfficiencyGeneral) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentEfficiencyGeneral()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentEfficiencyGeneral(chassisSlot, componentEfficiencyGeneral)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentEfficiencyGeneral (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentEfficiencyEnergy(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentEfficiencyEnergy) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentEfficiencyEnergy()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentEfficiencyEnergy(chassisSlot, componentEfficiencyEnergy)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentEfficiencyEnergy (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentEnergyMaintenanceRequirement(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentEnergyMaintenanceRequirement) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentEnergyMaintenanceRequirement()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentEnergyMaintenanceRequirement(chassisSlot, componentEnergyMaintenanceRequirement)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentEnergyMaintenanceRequirement (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentMass(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentMass) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentMass()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentMass(chassisSlot, componentMass)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentMass (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentHitpointsCurrent) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentHitpointsCurrent()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentHitpointsCurrent(chassisSlot, componentHitpointsCurrent)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentHitpointsCurrent (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentHitpointsMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentHitpointsMaximum()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentHitpointsMaximum(chassisSlot, componentHitpointsMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentHitpointsMaximum (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentFlags(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint componentFlags) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentFlags()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentFlags(chassisSlot, componentFlags)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentFlags (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentName(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jstring componentName) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentName()", false, chassisSlot); - if (!shipObject) - return; - - if (componentName == NULL) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): null name")); - return; - } - - JavaStringParam const jsp(componentName); - Unicode::String nameString; - if (!JavaLibrary::convert(jsp, nameString)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): failed to convert name string")); - else - { - if (!shipObject->setComponentName(chassisSlot, nameString)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): component at slot [%d] error", chassisSlot)); - } -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentDisabled(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jboolean componentDisabled) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentDisabled()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentDisabled(chassisSlot, componentDisabled == JNI_TRUE)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentDisabled (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentDisabledNeedsPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jboolean componentDisabledNeedsPower) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentDisabledNeedsPower()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentDisabledNeedsPower(chassisSlot, componentDisabledNeedsPower == JNI_TRUE)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentDisabledNeedsPower(): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipComponentLowPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jboolean componentLowPower) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentLowPower()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setComponentLowPower(chassisSlot, componentLowPower == JNI_TRUE)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentLowPower (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponDamageMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponDamageMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponDamageMaximum()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponDamageMaximum(chassisSlot, weaponDamageMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponDamageMaximum (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponDamageMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponDamageMinimum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponDamageMinimum()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponDamageMinimum(chassisSlot, weaponDamageMinimum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponDamageMinimum (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponEffectivenessShields(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEffectivenessShields) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEffectivenessShields()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponEffectivenessShields(chassisSlot, weaponEffectivenessShields)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEffectivenessShields (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponEffectivenessArmor(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEffectivenessArmor) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEffectivenessArmor()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponEffectivenessArmor(chassisSlot, weaponEffectivenessArmor)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEffectivenessArmor (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponEnergyPerShot(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEnergyPerShot) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEnergyPerShot()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponEnergyPerShot(chassisSlot, weaponEnergyPerShot)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEnergyPerShot (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponRefireRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponRefireRate()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponRefireRate(chassisSlot, weaponRefireRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponRefireRate (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponEfficiencyRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEfficiencyRefireRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEfficiencyRefireRate()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponEfficiencyRefireRate(chassisSlot, weaponEfficiencyRefireRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEfficiencyRefireRate (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponAmmoCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint weaponAmmoCurrent) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponAmmoCurrent()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponAmmoCurrent(chassisSlot, weaponAmmoCurrent)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponAmmoCurrent (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponAmmoMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint weaponAmmoMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponAmmoMaximum()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponAmmoMaximum(chassisSlot, weaponAmmoMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponAmmoMaximum (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipWeaponAmmoType(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint weaponAmmoType) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponAmmoType()", false, chassisSlot); - if (!shipObject) - return; - - if (!shipObject->setWeaponAmmoType(chassisSlot, static_cast(weaponAmmoType))) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponAmmoType (): component at slot [%d] error", chassisSlot)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsFrontCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsFrontCurrent) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsFrontCurrent()", false, ShipChassisSlotType::SCST_shield_0); - if (!shipObject) - return; - - if (!shipObject->setShieldHitpointsFrontCurrent(shieldHitpointsFrontCurrent)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsFrontCurrent (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsFrontMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsFrontMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsFrontMaximum()", false, ShipChassisSlotType::SCST_shield_0); - if (!shipObject) - return; - - if (!shipObject->setShieldHitpointsFrontMaximum(shieldHitpointsFrontMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsFrontMaximum (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsBackCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsBackCurrent) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsBackCurrent()", false, ShipChassisSlotType::SCST_shield_0); - if (!shipObject) - return; - - if (!shipObject->setShieldHitpointsBackCurrent(shieldHitpointsBackCurrent)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsBackCurrent (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsBackMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsBackMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsBackMaximum()", false, ShipChassisSlotType::SCST_shield_0); - if (!shipObject) - return; - - if (!shipObject->setShieldHitpointsBackMaximum(shieldHitpointsBackMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsBackMaximum (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipShieldRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldRechargeRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldRechargeRate()", false, ShipChassisSlotType::SCST_shield_0); - if (!shipObject) - return; - - if (!shipObject->setShieldRechargeRate(shieldRechargeRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldRechargeRate (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipCapacitorEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat capacitorEnergyCurrent) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCapacitorEnergyCurrent()", false, ShipChassisSlotType::SCST_capacitor); - if (!shipObject) - return; - - if (!shipObject->setCapacitorEnergyCurrent(capacitorEnergyCurrent)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCapacitorEnergyCurrent (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipCapacitorEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat capacitorEnergyMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCapacitorEnergyMaximum()", false, ShipChassisSlotType::SCST_capacitor); - if (!shipObject) - return; - - if (!shipObject->setCapacitorEnergyMaximum(capacitorEnergyMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCapacitorEnergyMaximum (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipCapacitorEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat capacitorEnergyRechargeRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCapacitorEnergyRechargeRate()", false, ShipChassisSlotType::SCST_capacitor); - if (!shipObject) - return; - - if (!shipObject->setCapacitorEnergyRechargeRate(capacitorEnergyRechargeRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCapacitorEnergyRechargeRate (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineAccelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineAccelerationRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineAccelerationRate()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineAccelerationRate(engineAccelerationRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineAccelerationRate (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineDecelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineDecelerationRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineDecelerationRate()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineDecelerationRate(engineDecelerationRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineDecelerationRate (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEnginePitchAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat enginePitchAccelerationRateDegrees) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEnginePitchAccelerationRateDegrees()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEnginePitchAccelerationRate(convertDegreesToRadians(enginePitchAccelerationRateDegrees))) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEnginePitchAccelerationRateDegrees (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineYawAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineYawAccelerationRateDegrees) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineYawAccelerationRateDegrees()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineYawAccelerationRate(convertDegreesToRadians(engineYawAccelerationRateDegrees))) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineYawAccelerationRateDegrees (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineRollAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineRollAccelerationRateDegrees) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineRollAccelerationRateDegrees()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineRollAccelerationRate(convertDegreesToRadians(engineRollAccelerationRateDegrees))) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineRollAccelerationRateDegrees (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEnginePitchRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat enginePitchRateMaximumDegrees) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEnginePitchRateMaximumDegrees()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEnginePitchRateMaximum(convertDegreesToRadians(enginePitchRateMaximumDegrees))) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEnginePitchRateMaximumDegrees (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineYawRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineYawRateMaximumDegrees) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineYawRateMaximumDegrees()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineYawRateMaximum(convertDegreesToRadians(engineYawRateMaximumDegrees))) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineYawRateMaximumDegrees (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineRollRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineRollRateMaximumDegrees) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineRollRateMaximumDegrees()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineRollRateMaximum(convertDegreesToRadians(engineRollRateMaximumDegrees))) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineRollRateMaximumDegrees (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedMaximum()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineSpeedMaximum(engineSpeedMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedMaximum (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedRotationFactorMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedRotationRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedRotationFactorMaximum()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineSpeedRotationFactorMaximum(engineSpeedRotationRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedRotationFactorMaximum(): component error %s", shipObject->getDebugInformation(false).c_str())); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedRotationFactorMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedRotationRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedRotationFactorMinimum()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineSpeedRotationFactorMinimum(engineSpeedRotationRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedRotationFactorMinimum(): component error %s", shipObject->getDebugInformation(false).c_str())); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedRotationFactorOptimal(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedRotationRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedRotationFactorOptimal()", false, ShipChassisSlotType::SCST_engine); - if (!shipObject) - return; - - if (!shipObject->setEngineSpeedRotationFactorOptimal(engineSpeedRotationRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedRotationFactorOptimal(): component error %s", shipObject->getDebugInformation(false).c_str())); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipReactorEnergyGenerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat reactorEnergyGenerationRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipReactorEnergyGenerationRate()", false, ShipChassisSlotType::SCST_reactor); - if (!shipObject) - return; - - if (!shipObject->setReactorEnergyGenerationRate(reactorEnergyGenerationRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipReactorEnergyGenerationRate (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyCurrent) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyCurrent()", false, ShipChassisSlotType::SCST_booster); - if (!shipObject) - return; - - if (!shipObject->setBoosterEnergyCurrent(boosterEnergyCurrent)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyCurrent (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyMaximum()", false, ShipChassisSlotType::SCST_booster); - if (!shipObject) - return; - - if (!shipObject->setBoosterEnergyMaximum(boosterEnergyMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyMaximum (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyRechargeRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyRechargeRate()", false, ShipChassisSlotType::SCST_booster); - if (!shipObject) - return; - - if (!shipObject->setBoosterEnergyRechargeRate(boosterEnergyRechargeRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyRechargeRate (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyConsumptionRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyConsumptionRate) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyConsumptionRate()", false, ShipChassisSlotType::SCST_booster); - if (!shipObject) - return; - - if (!shipObject->setBoosterEnergyConsumptionRate(boosterEnergyConsumptionRate)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyConsumptionRate (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipBoosterAcceleration(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterAcceleration) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterAcceleration()", false, ShipChassisSlotType::SCST_booster); - if (!shipObject) - return; - - if (!shipObject->setBoosterAcceleration(boosterAcceleration)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterAcceleration (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipBoosterSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterSpeedMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "isShipSlotInstalledActual()", false, ShipChassisSlotType::SCST_booster); - if (!shipObject) - return; - - if (!shipObject->setBoosterSpeedMaximum(boosterSpeedMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterSpeedMaximum (): component error")); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipDroidInterfaceCommandSpeed(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat droidInterfaceCommandSpeed) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipDroidInterfaceCommandSpeed()", false, ShipChassisSlotType::SCST_droid_interface); - if (!shipObject) - return; - - if (!shipObject->setDroidInterfaceCommandSpeed(droidInterfaceCommandSpeed)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipDroidInterfaceCommandSpeed (): component error")); -} - -//---------------------------------------------------------------------- - -//-- component support - -jboolean JNICALL ScriptMethodsShipNamespace::shipCanInstallComponent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jlong component) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "shipCanInstallComponent(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return false; - - TangibleObject * tangibleComponent = 0; - if (JavaLibrary::getObject (component, tangibleComponent) && tangibleComponent != NULL) - return shipObject->canInstallComponent(chassisSlot, *tangibleComponent); - else - { - JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipCanInstallComponent(): invalid component")); - return false; - } -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::shipPseudoInstallComponent(JNIEnv *env, jobject, jlong jship, jint chassisSlot, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "shipInstallComponent(): ship obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return false; - - return shipObject->pseudoInstallComponent(static_cast(chassisSlot), static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::shipInstallComponent(JNIEnv * env, jobject /*self*/, jlong jobject_installerId, jlong jobject_shipId, jint chassisSlot, jlong component) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "shipInstallComponent(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return false; - - NetworkId installerId(jobject_installerId); - - TangibleObject * tangibleComponent = 0; - if (JavaLibrary::getObject (component, tangibleComponent) && tangibleComponent != NULL) - return shipObject->installComponent(installerId, chassisSlot, *tangibleComponent); - else - { - JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipInstallComponent(): invalid component")); - return false; - } -} - -//---------------------------------------------------------------------- -jlong JNICALL ScriptMethodsShipNamespace::shipUninstallComponentAllowOverload(JNIEnv * env, jobject self, jlong jobject_uninstallerId, jlong jobject_shipId, jint chassisSlot, jlong containerTarget) -{ - return shipUninstallComponentBase(env, self, jobject_uninstallerId, jobject_shipId, chassisSlot, containerTarget, true); -} - -jlong JNICALL ScriptMethodsShipNamespace::shipUninstallComponent(JNIEnv * env, jobject self, jlong jobject_uninstallerId, jlong jobject_shipId, jint chassisSlot, jlong containerTarget) -{ - return shipUninstallComponentBase(env, self, jobject_uninstallerId, jobject_shipId, chassisSlot, containerTarget, false); -} - -jlong JNICALL ScriptMethodsShipNamespace::shipUninstallComponentBase(JNIEnv * env, jobject /*self*/, jlong jobject_uninstallerId, jlong jobject_shipId, jint chassisSlot, jlong containerTarget, bool allowOverload) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "shipUninstallComponent(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return 0; - - ServerObject * containerTargetObject = 0; - - if (containerTarget) - { - if (!JavaLibrary::getObject (containerTarget, containerTargetObject)) - { - JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipUninstallComponent(): containerTarget did not resolve")); - return 0; - } - - NetworkId uninstallerId(jobject_uninstallerId); - - TangibleObject * const component = shipObject->uninstallComponent(uninstallerId, chassisSlot, *containerTargetObject, allowOverload); - if (component) - return (component->getNetworkId()).getValue(); - else - { - JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipUninstallComponent(): invalid result component")); - return 0; - } - } - else - { - shipObject->purgeComponent (chassisSlot); - return 0; - } -} - - -//---------------------------------------------------------------------- - -jintArray JNICALL ScriptMethodsShipNamespace::getShipChassisSlots(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return NULL; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisSlots(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return NULL; - - ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (shipObject->getChassisType()); - if (shipChassis) - { - ShipChassis::SlotVector const & slots = shipChassis->getSlots (); - - LocalIntArrayRefPtr jslots = createNewIntArray(static_cast(slots.size ())); - if (jslots != LocalIntArrayRef::cms_nullPtr) - { - int index = 0; - for (ShipChassis::SlotVector::const_iterator it = slots.begin (); it != slots.end (); ++it, ++index) - { - ShipChassisSlot const & slot = *it; - jint value = static_cast(slot.getSlotType ()); - setIntArrayRegion(*jslots, index, 1, &value); - } - return jslots->getReturnValue(); - } - } - - return NULL; -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorType(JNIEnv * /*env*/, jobject /*self*/, jlong jobject_component) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return static_cast(ShipComponentType::SCT_num_types); - - TangibleObject * tangibleComponent = 0; - if (JavaLibrary::getObject (jobject_component, tangibleComponent)) - { - if (tangibleComponent != NULL && tangibleComponent->getObjectTemplate () != NULL) - { - ShipComponentDescriptor const * const shipComponentDescriptor = - ShipComponentDescriptor::findShipComponentDescriptorByObjectTemplate (tangibleComponent->getObjectTemplate ()->getCrcName ().getCrc ()); - if (shipComponentDescriptor) - return static_cast(shipComponentDescriptor->getComponentType ()); - } - } - - return static_cast(ShipComponentType::SCT_num_types); -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorTypeByName(JNIEnv * /*env*/, jobject /*self*/, jstring typeName) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return static_cast(ShipComponentType::SCT_num_types); - - JavaStringParam const jsp(typeName); - std::string nameString; - if (!JavaLibrary::convert(jsp, nameString)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipComponentDescriptorTypeByName (): failed to convert typeName string")); - else - { - return ShipComponentType::getTypeFromName(nameString); - } - - return static_cast(ShipComponentType::SCT_num_types); -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorTypeName(JNIEnv * /*env*/, jobject /*self*/, jint componentType) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return NULL; - - std::string const & typeName = ShipComponentType::getNameFromType(static_cast(componentType)); - - return JavaString(typeName).getReturnValue(); -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorCrc(JNIEnv * /*env*/, jobject /*self*/, jlong jobject_component) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return static_cast(ShipComponentType::SCT_num_types); - - TangibleObject * tangibleComponent = 0; - if (JavaLibrary::getObject (jobject_component, tangibleComponent)) - { - if (tangibleComponent != NULL && tangibleComponent->getObjectTemplate () != NULL) - { - ShipComponentDescriptor const * const shipComponentDescriptor = - ShipComponentDescriptor::findShipComponentDescriptorByObjectTemplate (tangibleComponent->getObjectTemplate ()->getCrcName ().getCrc ()); - if (shipComponentDescriptor) - return static_cast(shipComponentDescriptor->getCrc ()); - } - } - - return 0; -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorCrcName(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return NULL; - - ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc(static_cast(componentCrc)); - if (shipComponentDescriptor == NULL) - return NULL; - - return JavaString(shipComponentDescriptor->getName().getString()).getReturnValue(); -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorCompatibility(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return NULL; - - ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc(static_cast(componentCrc)); - if (shipComponentDescriptor == NULL) - return NULL; - - return JavaString(shipComponentDescriptor->getCompatibility().getString()).getReturnValue(); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsAmmoConsuming(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - return ShipComponentWeaponManager::isAmmoConsuming(static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsMissile(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - return ShipComponentWeaponManager::isMissile(static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsCountermeasure(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - return ShipComponentWeaponManager::isCountermeasure(static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsMining(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - return ShipComponentWeaponManager::isMining(static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsTractor(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return false; - - return ShipComponentWeaponManager::isTractor(static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponRange(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.0f; - - return ShipComponentWeaponManager::getRange(static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponProjectileSpeed(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return 0.0f; - - return ShipComponentWeaponManager::getProjectileSpeed(static_cast(componentCrc)); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::notifyShipDamage(JNIEnv * env, jobject /*self*/, jlong jobject_victim, jlong jobject_attacker, jfloat totalDamage) -{ - //-- Make sure ships are enabled - if (!verifyShipsEnabled()) - return; - - //-- Get the victim ship object. - ShipObject * const victimShipObject = JavaLibrary::getShipThrow(env, jobject_victim, "notifyShipDamage(): jobject_victim did not resolve to a ShipObject", false); - if (victimShipObject) - { - //-- Ensure we have a player controlled ship object. - if (victimShipObject->isPlayerShip()) - { - //-- Get the attacker object. It can be any tangible object. - TangibleObject const * attackerTangibleObject = NULL; - if (jobject_attacker) - IGNORE_RETURN(JavaLibrary::getObject(jobject_attacker, attackerTangibleObject)); - - Controller * const victimShipController = victimShipObject->getController(); - if (victimShipController) - { - ShipDamageMessage shipDamage(attackerTangibleObject != NULL ? attackerTangibleObject->getNetworkId() : NetworkId::cms_invalid, - attackerTangibleObject != NULL ? attackerTangibleObject->getPosition_w() : victimShipObject->getPosition_w(), - totalDamage ); - - //lint -esym(429, damageMessage) - - MessageQueueGenericValueType * const damageMessage = new MessageQueueGenericValueType(shipDamage); - - victimShipController->appendMessage(CM_shipDamageMessage, 0.0f, damageMessage, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); - } - } - } -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::launchMissile(JNIEnv * /*env*/, jobject /*self*/, jlong jplayer, jlong jship, jlong jtarget, jint missileInfo, jint targetedComponent) -{ - if (!verifyShipsEnabled()) - return false; - - const TangibleObject * player = 0; - if (!JavaLibrary::getObject (jplayer, player)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::launchMissile: could not resolve player")); - return JNI_FALSE; - } - - const TangibleObject * ship = 0; - if (!JavaLibrary::getObject (jship, ship)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::launchMissile: could not resolve ship")); - return JNI_FALSE; - } - - const TangibleObject * target = 0; - if (!JavaLibrary::getObject (jtarget, target)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::launchMissile: could not resolve target")); - return JNI_FALSE; - } - - if (player && ship && target) - return MissileManager::getInstance().requestFireMissile(player->getNetworkId(), ship->getNetworkId(), target->getNetworkId(), -1, missileInfo, getSlotType(targetedComponent)); - else - return JNI_FALSE; -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::launchCountermeasure(JNIEnv * /*env*/, jobject /*self*/, jlong ship, jint targettedMissile, jboolean successful, jint countermeasureType) -{ - if (!verifyShipsEnabled()) - return false; - - NetworkId const shipId(ship); - - bool result= MissileManager::getInstance().fireCountermeasure(shipId, targettedMissile, (successful==static_cast(JNI_TRUE)), countermeasureType); - return result ? static_cast(JNI_TRUE) : static_cast(JNI_FALSE); -} - -// ---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getNearestUnlockedMissileForTarget(JNIEnv * /*env*/, jobject /*self*/, jlong jtarget) -{ - return MissileManager::getInstance().getNearestUnlockedMissileForTarget(NetworkId(jtarget)); -} - -// ---------------------------------------------------------------------- - -jintArray JNICALL ScriptMethodsShipNamespace::getAllUnlockedMissilesForTarget(JNIEnv * env, jobject /*self*/, jlong jtarget) -{ - std::vector missiles; - MissileManager::getInstance().getAllUnlockedMissilesForTarget(NetworkId(jtarget),missiles); - - LocalIntArrayRefPtr results = createNewIntArray(static_cast(missiles.size())); - - setIntArrayRegion(*results, 0 , static_cast(missiles.size()), reinterpret_cast(&(missiles[0]))); - return results->getReturnValue(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::destroyMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) -{ - return (MissileManager::getInstance().destroyMissile(missileId)) ? static_cast(JNI_TRUE) : static_cast(JNI_FALSE); -} - -// ---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getTypeByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) -{ - const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); - if (missile) - return missile->getType(); - else - return -1; -} - -// ---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getWeaponIndexByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) -{ - const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); - if (missile) - return missile->getWeaponIndex(); - else - return -1; -} - -// ---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getTimeSinceFiredByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) -{ - const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); - if (missile) - return missile->getTimeSinceFired(); - else - return -1; -} - -// ---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getTotalTimeByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) -{ - const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); - if (missile) - return missile->getTotalTime(); - else - return -1; -} - -// ---------------------------------------------------------------------- - -jlong JNICALL ScriptMethodsShipNamespace::getWhoFiredByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) -{ - const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); - if (missile) - return (missile->getSource()).getValue(); - else - return 0; -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setLookAtTargetShipComponent(JNIEnv * env, jobject /*self*/, jlong jship, jint targetedComponentChassisSlot) -{ - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "setLookAtTargetShipComponent(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - shipObject->setPilotLookAtTargetSlot(getSlotType(targetedComponentChassisSlot)); - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getLookAtTargetShipComponent(JNIEnv * env, jobject /*self*/, jlong jship) -{ - if (!verifyShipsEnabled()) - return static_cast(ShipChassisSlotType::SCST_num_types); - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "getLookAtTargetShipComponent(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return static_cast(ShipChassisSlotType::SCST_num_types); - - return static_cast(shipObject->getPilotLookAtTargetSlot()); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::associateDroidControlDeviceWithShip(JNIEnv * env, jobject /*self*/, jlong jship, jlong jdroidControlDevice) -{ - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "associateDroidControlDeviceWithShip(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - const ServerObject * droidControlDevice = 0; - if (!JavaLibrary::getObject (jdroidControlDevice, droidControlDevice)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::associateDroidControlDeviceWithShip: could not resolve droid control device")); - return JNI_FALSE; - } - - shipObject->setInstalledDroidControlDevice(droidControlDevice->getNetworkId()); - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::removeDroidControlDeviceFromShip(JNIEnv * env, jobject /*self*/, jlong jship) -{ - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "removeDroidControlDeviceFromShip(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - shipObject->setInstalledDroidControlDevice(NetworkId::cms_invalid); - return JNI_TRUE; -} - -// ---------------------------------------------------------------------- - -jlong JNICALL ScriptMethodsShipNamespace::getDroidControlDeviceForShip(JNIEnv * env, jobject /*self*/, jlong jship) -{ - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jship, "getDroidControlDeviceForShip(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - NetworkId const & droidControlDeviceId = shipObject->getInstalledDroidControlDevice(); - Object const * const droidControlDevice = NetworkIdManager::getObjectById(droidControlDeviceId); - ServerObject const * const serverDroidControlDevice = droidControlDevice ? droidControlDevice->asServerObject() : NULL; - if(!serverDroidControlDevice) - return 0; - else - return (serverDroidControlDevice->getNetworkId()).getValue(); -} - -// ---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::commPlayers(JNIEnv *env, jobject /*self*/, jlong jtaunter, jstring jappearanceOverloadServerTemplate, jstring jSoundEffect, jfloat jDuration, jlongArray jplayers, jstring jtauntOob, jboolean chronicles) -{ - ServerObject const *taunter = 0; - if (!JavaLibrary::getObject(jtaunter, taunter)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::commPlayers: could not resolve taunter")); - return; - } - - Unicode::String oob; - if (jtauntOob) - { - JavaStringParam localTauntOob(jtauntOob); - if (!JavaLibrary::convert(localTauntOob, oob)) - { - JAVA_THROW_SCRIPT_EXCEPTION (true, ("JavaLibrary::commPlayers unable to convert tauntOob")); - return; - } - } - - Unicode::String appearanceOverloadServerTemplateWide; - if (jappearanceOverloadServerTemplate) - { - JavaStringParam localAppearanceOverloadServerTemplate(jappearanceOverloadServerTemplate); - if (!JavaLibrary::convert(localAppearanceOverloadServerTemplate, appearanceOverloadServerTemplateWide)) - { - JAVA_THROW_SCRIPT_EXCEPTION (true, ("JavaLibrary::commPlayers unable to convert jappearanceOverloadServerTemplate to a string")); - return; - } - } - - uint32 appearanceOverloadSharedTemplateCrc = 0; - ObjectTemplate const * const ot = ObjectTemplateList::fetch(Unicode::wideToNarrow(appearanceOverloadServerTemplateWide)); - ServerObjectTemplate const * const sot = ot ? ot->asServerObjectTemplate() : NULL; - if(sot) - { - std::string const & sharedTemplateName = sot->getSharedTemplate(); - appearanceOverloadSharedTemplateCrc = Crc::calculate(sharedTemplateName.c_str()); - } - - typedef std::map > DistributionList; - DistributionList distributionList; - - jsize const count = env->GetArrayLength(jplayers); - jlong jlongTmp; - for (jsize i = 0; i < count; ++i) - { - ServerObject const *player = 0; - env->GetLongArrayRegion(jplayers, i, 1, &jlongTmp); - if (JavaLibrary::getObject(jlongTmp, player)) - { - Client * const client = player->getClient(); - if (client) - distributionList[client->getConnection()].push_back(client->getCharacterObjectId()); - } - } - - std::string soundEffect; - if (jSoundEffect) - { - JavaStringParam soundEffectParam(jSoundEffect); - if (!JavaLibrary::convert(soundEffectParam, soundEffect)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::commPlayers unable to convert jSoundEffect to a string.")); - return; - } - } - - bool chroniclesMessage = (chronicles == JNI_TRUE ? true : false); - if (!distributionList.empty()) - { - GenericValueTypeMessage > > > > > const message("CommPlayerMessage", std::make_pair(chroniclesMessage, std::make_pair(taunter->getNetworkId(), std::make_pair(oob, std::make_pair(appearanceOverloadSharedTemplateCrc, std::make_pair(soundEffect, jDuration)))))); - for (DistributionList::const_iterator iter = distributionList.begin(); iter != distributionList.end(); ++iter) - { - GameClientMessage const gcm( - (*iter).second, - true, - message); - (*iter).first->send(gcm, true); - } - } -} - -// ---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipSlotTargetable(JNIEnv * env, jobject /*self*/, jlong jshipId, jint slot, jboolean targetable) -{ - if (!verifyShipsEnabled()) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentTargetable ships not enabled")); - return; - } - - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jshipId, "setShipComponentTargetable(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return; - - if(targetable) - shipObject->setSlotTargetable(getSlotType(slot)); - else - shipObject->clearSlotTargetable(getSlotType(slot)); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::isShipSlotTargetable(JNIEnv * env, jobject /*self*/, jlong jshipId, jint slot) -{ - if (!verifyShipsEnabled()) - return JNI_FALSE; - - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jshipId, "getShipComponentTargetable(): shipId obj_id did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - bool const result = shipObject->getSlotTargetable(getSlotType(slot)); - if(result) - return JNI_TRUE; - else - return JNI_FALSE; -} - -//-------------------------------------------------------------------------------- - -jlong JNICALL ScriptMethodsShipNamespace::launchShipFromHangar(JNIEnv *env, jobject /*self*/, jlong jlaunchingShipId, jstring templateToSpawn, jobject deltaFromHangarHardpoint) -{ - if (!verifyShipsEnabled()) - return 0; - - //convert ship - ShipObject * const launchingShip = JavaLibrary::getShipThrow(env, jlaunchingShipId, "getShipComponentTargetable(): shipId obj_id did not resolve to a ShipObject", false); - if (!launchingShip) - return 0; - - //convert transform - Transform deltaFromHangarTransform; - if (!ScriptConversion::convert(deltaFromHangarHardpoint, deltaFromHangarTransform)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("[designer bug] JavaLibrary::spawnShipFromHangar called with bad transform")); - return 0; - } - - // get the template name into an std::string - JavaStringParam const localSource(templateToSpawn); - std::string templateName; - IGNORE_RETURN(JavaLibrary::convert(localSource, templateName)); - - ConstCharCrcString const crcName(ObjectTemplateList::lookUp(templateName.c_str())); - if (crcName.getCrc() == 0) - - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("[designer bug] JavaLibrary::spawnShipFromHangar called with unknown template %s", templateName.c_str())); - return 0; - } - - //put spawned ship in same cell as the launching ship - ServerObject *cell = 0; - CellProperty * const cellProperty = launchingShip->getParentCell(); - if (cellProperty && cellProperty != CellProperty::getWorldCellProperty()) - cell = safe_cast(&cellProperty->getOwner()); - - //get the hardpoint from the launching ship - Transform hangarHardpointDelta; - Appearance const * const launchingShipAppearance = launchingShip->getAppearance(); - if(launchingShipAppearance) - { - static char const * const hangarHardpointName = "hangar"; - if (!launchingShipAppearance->findHardpoint(ConstCharCrcLowerString(hangarHardpointName), hangarHardpointDelta)) - WARNING(true, ("JavaLibrary::launchShipFromHangar - could not find hangar hardpoint [%s] for %s, launching from center of ship", hangarHardpointName, launchingShip->getNetworkId().getValueString().c_str())); - } - else - { - WARNING(true, ("JavaLibrary::launchShipFromHangar - could not find hangar %s, which has no appearance.", launchingShip->getNetworkId().getValueString().c_str())); - } - - //build the final hangar offset from the hangar hardpoint transform and the delta transform from script - Transform finalHangarDelta_o(Transform::IF_none); - finalHangarDelta_o.multiply(hangarHardpointDelta, deltaFromHangarTransform); - Transform const & finalCreateTransform = launchingShip->getTransform_o2p().rotateTranslate_l2p(finalHangarDelta_o); - - ServerObject * const newShip = ServerWorld::createNewObject(crcName.getCrc(), finalCreateTransform, cell, false); - if (newShip == NULL) - return 0; - - // create an objId to return - NetworkId netId = newShip->getNetworkId(); - if (netId == NetworkId::cms_invalid) - { - delete newShip; - return 0; - } - - if (!cell) - newShip->addToWorld(); - - return netId.getValue(); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::handleShipDestruction(JNIEnv * env, jobject /*self*/, jlong jship, jfloat severity) -{ - if (!verifyShipsEnabled()) - return; - - //convert ship - ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "handleShipDestruction(): shipId obj_id did not resolve to a ShipObject", false); - if (ship == NULL) - return; - - DestroyShipMessage const msg(ship->getNetworkId(), severity); - sendGameNetworkMessageToObservers(*ship, msg, true); - - if (ship->isPlayerShip()) - Pvp::removeDuelEnemyFlags(*ship, NetworkId::cms_invalid); - else - IGNORE_RETURN(ship->permanentlyDestroy(DeleteReasons::Script)); - - //@todo: we must handle player ship destruction differently -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::handleShipComponentDestruction(JNIEnv * env, jobject /*self*/, jlong jship, jint chassisSlot, jfloat severity) -{ - ShipObject * const ship = getShipThrowTestSlot(env, jship, "handleShipComponentDestruction()", false, chassisSlot); - if (!ship) - return; - - DestroyShipComponentMessage const msg(ship->getNetworkId(), chassisSlot, severity); - sendGameNetworkMessageToObservers(*ship, msg, true); - - ship->purgeComponent(chassisSlot); -} - -// ---------------------------------------------------------------------- - -jlongArray JNICALL ScriptMethodsShipNamespace::getObservedShips(JNIEnv *, jobject, jlong jsource, jboolean excludeSource) -{ - ServerObject const *source = 0; - if (JavaLibrary::getObject(jsource, source)) - { - std::vector visibleObjects; - SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); - if (!visibleObjects.empty()) - { - std::vector results(visibleObjects.size()); - for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) - if ( (*i)->asShipObject() - && ((*i) != source || !excludeSource)) - results.push_back(*i); - if (!results.empty()) - { - LocalLongArrayRefPtr rv; - if (ScriptConversion::convert(results, rv)) - return rv->getReturnValue(); - } - } - } - return 0; -} - -// ---------------------------------------------------------------------- - -jlongArray JNICALL ScriptMethodsShipNamespace::getObservedPlayerShips(JNIEnv *, jobject, jlong jsource, jboolean excludeSource) -{ - ServerObject const *source = 0; - if (JavaLibrary::getObject(jsource, source)) - { - std::vector visibleObjects; - SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); - if (!visibleObjects.empty()) - { - std::vector results(visibleObjects.size()); - for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) - { - ShipObject * const ship = (*i)->asShipObject(); - if ( ship - && ship->isPlayerShip() - && ((*i) != source || !excludeSource)) - results.push_back(*i); - } - if (!results.empty()) - { - LocalLongArrayRefPtr rv; - if (ScriptConversion::convert(results, rv)) - return rv->getReturnValue(); - } - } - } - return 0; -} - -// ---------------------------------------------------------------------- - -jlongArray JNICALL ScriptMethodsShipNamespace::getObservedEnemyShips(JNIEnv *, jobject, jlong jsource) -{ - ShipObject const *source = 0; - if (JavaLibrary::getObject(jsource, source)) - { - std::vector visibleObjects; - SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); - if (!visibleObjects.empty()) - { - std::vector results(visibleObjects.size()); - for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) - { - ShipObject * const ship = (*i)->asShipObject(); - if ( ship - && Pvp::isEnemy(*source, *ship)) - results.push_back(*i); - } - if (!results.empty()) - { - LocalLongArrayRefPtr rv; - if (ScriptConversion::convert(results, rv)) - return rv->getReturnValue(); - } - } - } - return 0; -} - -// ---------------------------------------------------------------------- - -jlongArray JNICALL ScriptMethodsShipNamespace::getObservedEnemyPlayerShips(JNIEnv *, jobject, jlong jsource) -{ - ShipObject const *source = 0; - if (JavaLibrary::getObject(jsource, source)) - { - std::vector visibleObjects; - SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); - if (!visibleObjects.empty()) - { - std::vector results(visibleObjects.size()); - for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) - { - ShipObject * const ship = (*i)->asShipObject(); - if ( ship - && ship->isPlayerShip() - && Pvp::isEnemy(*source, *ship)) - results.push_back(*i); - } - if (!results.empty()) - { - LocalLongArrayRefPtr rv; - if (ScriptConversion::convert(results, rv)) - return rv->getReturnValue(); - } - } - } - return 0; -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipInternalDamageOverTime(JNIEnv * env, jobject, jlong jship, jint chassisSlot, jfloat damageRate, jfloat damageThreshold) -{ - ShipObject * const ship = getShipThrowTestSlot(env, jship, "setShipInternalDamageOverTime()", false, chassisSlot); - if (!ship) - return false; - - return ShipInternalDamageOverTimeManager::setEntry(*ship, chassisSlot, damageRate, damageThreshold); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::removeShipInternalDamageOverTime(JNIEnv * env, jobject, jlong jship, jint chassisSlot) -{ - ShipObject * const ship = getShipThrowTestSlot(env, jship, "removeShipInternalDamageOverTime()", false, chassisSlot); - if (!ship) - return false; - - return ShipInternalDamageOverTimeManager::removeEntry(*ship, chassisSlot); -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipInternalDamageOverTimeDamageRate(JNIEnv * env, jobject, jlong jship, jint chassisSlot) -{ - ShipObject * const ship = getShipThrowTestSlot(env, jship, "getShipInternalDamageOverTimeDamageThreshold()", false, chassisSlot); - if (!ship) - return 0.0f; - - static ShipInternalDamageOverTime const * const idot = ShipInternalDamageOverTimeManager::findEntry(*ship, chassisSlot); - if (idot == NULL) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipInternalDamageOverTimeDamageThreshold idot for [%s] slot [%d] not found", ship->getNetworkId().getValueString().c_str(), chassisSlot)); - return 0.0f; - } - - return idot->getDamageRate(); -} - -// ---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipInternalDamageOverTimeDamageThreshold(JNIEnv * env, jobject, jlong jship, jint chassisSlot) -{ - ShipObject * const ship = getShipThrowTestSlot(env, jship, "getShipInternalDamageOverTimeDamageThreshold()", false, chassisSlot); - if (!ship) - return 0.0f; - - static ShipInternalDamageOverTime const * const idot = ShipInternalDamageOverTimeManager::findEntry(*ship, chassisSlot); - if (idot == NULL) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipInternalDamageOverTimeDamageThreshold idot for [%s] slot [%d] not found", ship->getNetworkId().getValueString().c_str(), chassisSlot)); - return 0.0f; - } - - return idot->getDamageThreshold(); -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::hasShipInternalDamageOverTime(JNIEnv * env, jobject, jlong jship, jint chassisSlot) -{ - if (!verifyShipsEnabled()) - return false; - - //convert ship - ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "hasShipInternalDamageOverTime(): shipId obj_id did not resolve to a ShipObject", false); - if (ship == NULL) - return false; - - static ShipInternalDamageOverTime const * const idot = ShipInternalDamageOverTimeManager::findEntry(*ship, chassisSlot); - return idot != NULL; -} - -// ---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::shipGetSpaceFaction(JNIEnv *env, jobject, jlong jship) -{ - ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFaction(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - return static_cast(ship->getSpaceFaction()); - return 0; -} - -// ---------------------------------------------------------------------- - -jintArray JNICALL ScriptMethodsShipNamespace::shipGetSpaceFactionAllies(JNIEnv *env, jobject, jlong jship) -{ - ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFactionAllies(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - { - std::vector const &factionList = ship->getSpaceFactionAllies(); - if (!factionList.empty()) - { - LocalIntArrayRefPtr ret = createNewIntArray(static_cast(factionList.size())); - setIntArrayRegion(*ret, 0, static_cast(factionList.size()), reinterpret_cast(const_cast(&factionList[0]))); - return ret->getReturnValue(); - } - } - return 0; -} - -// ---------------------------------------------------------------------- - -jintArray JNICALL ScriptMethodsShipNamespace::shipGetSpaceFactionEnemies(JNIEnv *env, jobject, jlong jship) -{ - ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFactionEnemies(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - { - std::vector const &factionList = ship->getSpaceFactionEnemies(); - if (!factionList.empty()) - { - LocalIntArrayRefPtr ret = createNewIntArray(static_cast(factionList.size())); - setIntArrayRegion(*ret, 0, static_cast(factionList.size()), reinterpret_cast(const_cast(&factionList[0]))); - return ret->getReturnValue(); - } - } - return 0; -} - -// ---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::shipGetSpaceFactionIsAggro(JNIEnv *env, jobject, jlong jship) -{ - ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFactionIsAggro(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - return static_cast(ship->getSpaceFactionIsAggro()); - return JNI_FALSE; -} - -// ---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFaction(JNIEnv *env, jobject, jlong jship, jint spaceFaction) -{ - ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFaction(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - ship->setSpaceFaction(static_cast(spaceFaction)); -} - -// ---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFactionAllies(JNIEnv *env, jobject, jlong jship, jintArray jfactionList) -{ - ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFactionAllies(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - { - std::vector factionList; - if (jfactionList) - { - unsigned int const factionCount = static_cast(env->GetArrayLength(jfactionList)); - if (factionCount > 0) - { - factionList.reserve(factionCount); - jint * const factionArray = env->GetIntArrayElements(jfactionList, 0); - for (unsigned int i = 0; i < factionCount; ++i) - factionList.push_back(static_cast(factionArray[i])); - env->ReleaseIntArrayElements(jfactionList, factionArray, JNI_ABORT); - } - } - ship->setSpaceFactionAllies(factionList); - } -} - -// ---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFactionEnemies(JNIEnv *env, jobject, jlong jship, jintArray jfactionList) -{ - ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFactionEnemies(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - { - std::vector factionList; - if (jfactionList) - { - unsigned int const factionCount = static_cast(env->GetArrayLength(jfactionList)); - if (factionCount > 0) - { - factionList.reserve(factionCount); - jint * const factionArray = env->GetIntArrayElements(jfactionList, 0); - for (unsigned int i = 0; i < factionCount; ++i) - factionList.push_back(static_cast(factionArray[i])); - env->ReleaseIntArrayElements(jfactionList, factionArray, JNI_ABORT); - } - } - ship->setSpaceFactionEnemies(factionList); - } -} - -// ---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFactionIsAggro(JNIEnv *env, jobject, jlong jship, jboolean isAggro) -{ - ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFactionIsAggro(): shipId obj_id did not resolve to a ShipObject", false); - if (ship) - ship->setSpaceFactionIsAggro(isAggro ? true : false); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::shipIsInNebula(JNIEnv *env, jobject, jlong jship, jstring j_nebulaName) -{ - ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipIsInNebula(): shipId obj_id did not resolve to a ShipObject", false); - if (!ship) - return JNI_FALSE; - - std::string nebulaName; - - if (NULL != j_nebulaName) - { - JavaStringParam const jsp(j_nebulaName); - if (!JavaLibrary::convert(jsp, nebulaName)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::shipIsInNebula (): failed to convert nebulaName string")); - } - - ShipObject::IntVector const & nebulas = ship->getNebulas(); - - //-- empty nebula name matches any nebula - if (nebulaName.empty() && !nebulas.empty()) - return JNI_TRUE; - - for (ShipObject::IntVector::const_iterator it = nebulas.begin(); it != nebulas.end(); ++it) - { - int const id = *it; - Nebula const * const nebula = NebulaManager::getNebulaById(id); - if (NULL != nebula) - { - if (nebula->getName() == nebulaName) - return JNI_TRUE; - } - } - - return JNI_FALSE; -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipWingName(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) -{ - ServerObject * object = 0; - if(!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert target")); - return JNI_FALSE; - } - ShipObject * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): target not a ship")); - return JNI_FALSE; - } - - JavaStringParam const jsp(jstr); - std::string wingName; - if (!JavaLibrary::convert(jsp, wingName)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); - return JNI_FALSE; - } - - ship->setWingName(wingName); - - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipWingName(JNIEnv * /*env*/, jobject /*self*/, jlong target) -{ - ServerObject const * object = NULL; - if (!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipWingName (): could not convert the target")); - return 0; - } - ShipObject const * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipWingName (): target is not a ship")); - return 0; - } - - return JavaString(ship->getWingName()).getReturnValue(); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipTypeName(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) -{ - ServerObject * object = 0; - if(!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipTypeName (): failed to convert target")); - return JNI_FALSE; - } - ShipObject * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipTypeName (): target not a ship")); - return JNI_FALSE; - } - - JavaStringParam const jsp(jstr); - std::string typeName; - if (!JavaLibrary::convert(jsp, typeName)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); - return JNI_FALSE; - } - ship->setTypeName(typeName); - - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipTypeName(JNIEnv * /*env*/, jobject /*self*/, jlong target) -{ - ServerObject const * object = NULL; - if (!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipTypeName (): could not convert the target")); - return 0; - } - ShipObject const * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipTypeName (): target is not a ship")); - return 0; - } - - return JavaString(ship->getTypeName()).getReturnValue(); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipDifficulty(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) -{ - ServerObject * object = 0; - if(!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipDifficultyName (): failed to convert target")); - return JNI_FALSE; - } - ShipObject * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipDifficultyName (): target not a ship")); - return JNI_FALSE; - } - - JavaStringParam const jsp(jstr); - std::string difficulty; - if (!JavaLibrary::convert(jsp, difficulty)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); - return JNI_FALSE; - } - ship->setDifficulty(difficulty); - - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipDifficulty(JNIEnv * /*env*/, jobject /*self*/, jlong target) -{ - ServerObject const * object = NULL; - if (!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipDifficulty (): could not convert the target")); - return 0; - } - ShipObject const * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipDifficulty (): target is not a ship")); - return 0; - } - return JavaString(ship->getDifficulty()).getReturnValue(); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::setShipFaction(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) -{ - ServerObject * object = 0; - if(!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipFactionName (): failed to convert target")); - return JNI_FALSE; - } - ShipObject * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipFactionName (): target not a ship")); - return JNI_FALSE; - } - - JavaStringParam const jsp(jstr); - std::string faction; - if (!JavaLibrary::convert(jsp, faction)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); - return JNI_FALSE; - } - ship->setFaction(faction); - - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipFaction(JNIEnv * /*env*/, jobject /*self*/, jlong target) -{ - ServerObject const * object = NULL; - if (!JavaLibrary::getObject(target, object)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipFaction (): could not convert the target")); - return 0; - } - ShipObject const * const ship = object->asShipObject(); - if(!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipFaction (): target is not a ship")); - return 0; - } - return JavaString(ship->getFaction()).getReturnValue(); -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::addMissionCriticalObject(JNIEnv * env, jobject /*self*/, jlong playerId, jlong missionCriticalObject) -{ - PROFILER_AUTO_BLOCK_DEFINE("JNI::addMissionCriticalObject"); - - CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "addMissionCriticalObject(): playerId did not resolve to a CreatureObject", false); - if (!creatureObject) - return JNI_FALSE; - - NetworkId missionCriticalObjectId(missionCriticalObject); - - if (missionCriticalObject) - { - if(missionCriticalObjectId == NetworkId::cms_invalid) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("addMissionCriticalObject(): missionCriticalObject is not an obj_id")); - return JNI_FALSE; - } - - if (missionCriticalObjectId != NetworkId::cms_invalid) - creatureObject->addMissionCriticalObject(missionCriticalObjectId); - } - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::removeMissionCriticalObject(JNIEnv * env, jobject /*self*/, jlong playerId, jlong missionCriticalObject) -{ - CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "removeMissionCriticalObject(): playerId did not resolve to a CreatureObject", false); - if (!creatureObject) - return JNI_FALSE; - - NetworkId missionCriticalObjectId(missionCriticalObject); - - if (missionCriticalObject) - { - if (missionCriticalObjectId == NetworkId::cms_invalid) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("removeMissionCriticalObject(): missionCriticalObject is not an obj_id")); - return JNI_FALSE; - } - - if (missionCriticalObjectId != NetworkId::cms_invalid) - creatureObject->removeMissionCriticalObject(missionCriticalObjectId); - } - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::clearMissionCriticalObjects(JNIEnv * env, jobject /*self*/, jlong playerId) -{ - CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "clearMissionCriticalObjects(): playerId did not resolve to a CreatureObject", false); - if (!creatureObject) - return JNI_FALSE; - - creatureObject->clearMissionCriticalObjects(); - - return JNI_TRUE; -} - -//---------------------------------------------------------------------- - -jboolean JNICALL ScriptMethodsShipNamespace::isMissionCriticalObject(JNIEnv * env, jobject /*self*/, jlong playerId, jlong ship) -{ - CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "isMissionCriticalObject(): playerId did not resolve to a CreatureObject", false); - if (!creatureObject) - return JNI_FALSE; - - if (!ship) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("isMissionCriticalObject(): playerId ship is null")); - return JNI_FALSE; - } - - NetworkId shipId(ship); - if (shipId == NetworkId::cms_invalid) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("isMissionCriticalObject(): playerId is not an obj_id")); - return JNI_FALSE; - } - - return creatureObject->isMissionCriticalObject(shipId); -} - -// ---------------------------------------------------------------------- - -jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDebugString(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) -{ - ShipObject const * const ship = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentDebugString(): obj_id shipId did not resolve to a ShipObject", false); - if (ship && ship->isSlotInstalled(chassisSlot)) - { - ShipComponentData * const shipComponentData = ship->createShipComponentData(chassisSlot); - if (shipComponentData) - { - Unicode::String result; - shipComponentData->printDebugString(result, Unicode::emptyString); - delete shipComponentData; - if (!result.empty()) - return JavaString(result).getReturnValue(); - } - } - return 0; -} - -//---------------------------------------------------------------------- - -jfloat JNICALL ScriptMethodsShipNamespace::getShipChassisSpeedMaximumModifier(JNIEnv * env, jobject self, jlong shipId) -{ - ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, shipId, "getShipChassisMaximumSpeedModifier(): shipId did not resolve to a ShipObject", false); - if (!shipObject) - return JNI_FALSE; - - return shipObject->getChassisSpeedMaximumModifier(); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipChassisSpeedMaximumModifier(JNIEnv * env, jobject self, jlong shipId, jfloat value) -{ - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, shipId, "setShipChassisMaximumSpeedModifier(): shipId did not resolve to a ShipObject", false); - if (!shipObject) - return; - - shipObject->setChassisSpeedMaximumModifier(value); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::notifyShipHit(JNIEnv * env, jobject self, jlong jobject_shipId, jobject jobject_vectorUp_w, jobject jobject_vectorHitLocation_o, jint type, jfloat integrity, jfloat previousIntegrity) -{ - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "notifyShipHit(): shipId did not resolve to a ShipObject", false); - if (!shipObject) - return; - - Vector up_w; - if (!ScriptConversion::convert(jobject_vectorUp_w, up_w)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("notifyShipHit(): unable to convert up_w vector")); - return; - } - - Vector hitLocation_o; - if (!ScriptConversion::convert(jobject_vectorHitLocation_o, hitLocation_o)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("notifyShipHit(): unable to convert hitLocation_o vector")); - return; - } - - MessageQueueShipHit * const msg = new MessageQueueShipHit(up_w, hitLocation_o, type, integrity, previousIntegrity); - shipObject->getController()->appendMessage( - CM_spaceShipHit, 0.0f, msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_ALL_CLIENT); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId, jobject jobject_velocity_w) -{ - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_asteroidId, "setDynamicMiningAsteroidVelocity(): shipId did not resolve to a ShipObject", false); - if (!shipObject) - return; - - Vector velocity_w; - if (!ScriptConversion::convert(jobject_velocity_w, velocity_w)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("setDynamicMiningAsteroidVelocity(): unable to convert velocity_w vector")); - return; - } - - MiningAsteroidController * const miningAsteroidController = dynamic_cast(shipObject->getController()); - if (NULL == miningAsteroidController) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("setDynamicMiningAsteroidVelocity(): called on a ship which is not a dynamic mining asteroid")); - return; - } - - miningAsteroidController->setVelocity_w(velocity_w); -} - -//---------------------------------------------------------------------- - -jobject JNICALL ScriptMethodsShipNamespace::getDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId) -{ - ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_asteroidId, "getDynamicMiningAsteroidVelocity(): shipId did not resolve to a ShipObject", false); - if (!shipObject) - return NULL; - MiningAsteroidController * const miningAsteroidController = dynamic_cast(shipObject->getController()); - if (NULL == miningAsteroidController) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("setDynamicMiningAsteroidVelocity(): called on a ship which is not a dynamic mining asteroid")); - return NULL; - } - - Vector const & velocity_w = miningAsteroidController->getVelocity_w(); - - LocalRefPtr vec; - if (!ScriptConversion::convert(velocity_w, vec)) - return 0; - - return vec->getReturnValue(); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong jobject_shipId, jint contentsMaximum) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCargoHoldContentsMaximum()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); - if (!shipObject) - return; - - if (!shipObject->setCargoHoldContentsMaximum(contentsMaximum)) - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCargoHoldContentsMaximum (): component at slot [%d] error", static_cast(ShipChassisSlotType::SCST_cargo_hold))); -} - -//---------------------------------------------------------------------- - -int JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong jobject_shipId) -{ - ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContentsMaximum()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); - if (!shipObject) - return false; - - return shipObject->getCargoHoldContentsMaximum(); -} - -//---------------------------------------------------------------------- - -int JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsCurrent (JNIEnv * env, jobject self, jlong jobject_shipId) -{ - ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContentsCurrent()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); - if (!shipObject) - return false; - - return shipObject->getCargoHoldContentsCurrent(); -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::setShipCargoHoldContent(JNIEnv * env, jobject self, jlong jobject_shipId, jlong jobject_resourceTypeId, jint amount) -{ - ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCargoHoldContent()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); - if (!shipObject) - return; - - NetworkId const & resourceTypeId = NetworkId(jobject_resourceTypeId); - - //-- check existence if amount != 0 - - shipObject->setCargoHoldContent(resourceTypeId, amount); -} - -//---------------------------------------------------------------------- - -jint JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContent(JNIEnv * env, jobject self, jlong jobject_shipId, jlong jobject_resourceTypeId) -{ - ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContent()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); - if (!shipObject) - return false; - - NetworkId const & resourceTypeId = NetworkId(jobject_resourceTypeId); - - return shipObject->getCargoHoldContent(resourceTypeId); -} - -//---------------------------------------------------------------------- - -jlongArray JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsResourceTypes(JNIEnv * env, jobject self, jlong jobject_shipId) -{ - ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContents()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); - if (!shipObject) - return NULL; - - ShipObject::NetworkIdIntMap const & contents = shipObject->getCargoHoldContents(); - - LocalLongArrayRefPtr jids = createNewLongArray(contents.size()); - - if (jids != LocalLongArrayRef::cms_nullPtr) - { - int index = 0; - for (ShipObject::NetworkIdIntMap::const_iterator it = contents.begin(); it != contents.end(); ++it, ++index) - { - jlong jlongTmp = ((*it).first).getValue(); - setLongArrayRegion(*jids, index, 1, &jlongTmp); - } - return jids->getReturnValue(); - } - - return NULL; -} - -//---------------------------------------------------------------------- - -jintArray JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsAmounts(JNIEnv * env, jobject self, jlong jobject_shipId) -{ - ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContents()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); - if (!shipObject) - return NULL; - - ShipObject::NetworkIdIntMap const & contents = shipObject->getCargoHoldContents(); - - LocalIntArrayRefPtr jamounts = createNewIntArray(static_cast(contents.size ())); - if (jamounts != LocalIntArrayRef::cms_nullPtr) - { - int index = 0; - for (ShipObject::NetworkIdIntMap::const_iterator it = contents.begin(); it != contents.end(); ++it) - { - jint amount = (*it).second; - setIntArrayRegion(*jamounts, index, 1, &amount); - } - return jamounts->getReturnValue(); - } - - return NULL; -} - -//---------------------------------------------------------------------- - -void JNICALL ScriptMethodsShipNamespace::openSpaceMiningUi(JNIEnv * env, jobject self, jlong jobject_player, jlong jobject_spaceStation, jstring jstring_spaceStationName) -{ - NetworkId const & playerId = NetworkId(jobject_player); - NetworkId const & spaceStationId = NetworkId(jobject_spaceStation); - - if (jstring_spaceStationName == NULL) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): null name")); - return; - } - - JavaStringParam const jsp(jstring_spaceStationName); - std::string spaceStationName; - if (!JavaLibrary::convert(jsp, spaceStationName)) - { - JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): failed to convert name string")); - return; - } - - Object * const player = NetworkIdManager::getObjectById(playerId); - Controller * const controller = player ? player->getController(): NULL; - - if (!controller) - { - WARNING(true, ("JavaLibrary::openSpaceMiningUi failed, no player or controller")); - return; - } - - typedef std::pair MessageData; - typedef MessageQueueGenericValueType MessageType; - MessageType * const msg = new MessageType(MessageData(spaceStationId, spaceStationName)); - - controller->appendMessage(CM_spaceMiningSaleOpen, 0.0f, msg, - GameControllerMessageFlags::SEND | - GameControllerMessageFlags::RELIABLE | - GameControllerMessageFlags::DEST_AUTH_CLIENT); -} - -// ====================================================================== - +// ====================================================================== +// +// ScriptMethodsShip.cpp +// Copyright 2003, Sony Online Entertainment, Inc. +// All rights reserved. +// +// ====================================================================== + +#include "serverScript/FirstServerScript.h" +#include "serverScript/JavaLibrary.h" + +#include "UnicodeUtils.h" +#include "serverGame/AiShipController.h" +#include "serverGame/ConfigServerGame.h" +#include "serverGame/ConnectionServerConnection.h" +#include "serverGame/ContainerInterface.h" +#include "serverGame/CreatureObject.h" +#include "serverGame/GameServer.h" +#include "serverGame/MiningAsteroidController.h" +#include "serverGame/Missile.h" +#include "serverGame/MissileManager.h" +#include "serverGame/Pvp.h" +#include "serverGame/ServerObjectTemplate.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/ShipInternalDamageOverTime.h" +#include "serverGame/ShipInternalDamageOverTimeManager.h" +#include "serverGame/ShipObject.h" +#include "serverGame/SpaceVisibilityManager.h" +#include "serverNetworkMessages/GameConnectionServerMessages.h" +#include "sharedNetworkMessages/MessageQueueShipHit.h" +#include "sharedFoundation/ConstCharCrcLowerString.h" +#include "sharedFoundation/ConstCharCrcString.h" +#include "sharedFoundation/Crc.h" +#include "sharedFoundation/GameControllerMessage.h" +#include "sharedGame/Nebula.h" +#include "sharedGame/NebulaManager.h" +#include "sharedGame/ShipChassis.h" +#include "sharedGame/ShipChassisSlot.h" +#include "sharedGame/ShipComponentData.h" +#include "sharedGame/ShipComponentDescriptor.h" +#include "sharedGame/ShipComponentWeaponManager.h" +#include "sharedNetworkMessages/DestroyShipComponentMessage.h" +#include "sharedNetworkMessages/DestroyShipMessage.h" +#include "sharedNetworkMessages/GameNetworkMessage.h" +#include "sharedNetworkMessages/GenericValueTypeMessage.h" +#include "sharedNetworkMessages/MessageQueueGenericValueType.h" +#include "sharedNetworkMessages/ShipDamageMessage.h" +#include "sharedObject/Appearance.h" +#include "sharedObject/CellProperty.h" +#include "sharedObject/Controller.h" +#include "sharedObject/NetworkIdManager.h" +#include "sharedObject/ObjectTemplateList.h" + +using namespace JNIWrappersNamespace; + + +// ====================================================================== + +namespace ScriptMethodsShipNamespace +{ + bool verifyShipsEnabled() + { + if (!ConfigServerGame::getShipsEnabled()) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("Ship support is not enabled. Make sure [GameServer] shipsEnabled=1 is in your config file.")); + return false; + } + + return true; + } + + ShipChassisSlotType::Type getSlotType(int slotType) + { + if(slotType < ShipChassisSlotType::SCST_first || slotType > ShipChassisSlotType::SCST_num_types) + return ShipChassisSlotType::SCST_num_types; + else + return static_cast(slotType); + } + + //---------------------------------------------------------------------- + + ShipObject * const getShipThrowTestSlot(JNIEnv * env, jlong jobject_shipId, char const * const functionName, bool throwIfNotOnServer, int chassisSlot) + { + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return NULL; + + char buf[256]; + snprintf(buf, sizeof(buf), "JavaLibrary::%s: ship obj_id did not resolve to a ShipObject", functionName); + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, buf, throwIfNotOnServer); + if (!shipObject) + return NULL; + + if (chassisSlot != ShipChassisSlotType::SCST_num_types && !shipObject->isSlotInstalled(chassisSlot)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::%s chassisSlot [%d] not installed", functionName, chassisSlot)); + + return shipObject; + } + + //---------------------------------------------------------------------- + + void sendGameNetworkMessageToObservers(ServerObject const & sourceObject, GameNetworkMessage const & message, bool sendToSourceObject) + { + // send the projectile to all clients observing the owner except the owner + // time is in the context of the connection server's sync stamp, so we need a unique message per connection server + typedef std::map > DistributionList; + DistributionList distributionList; + + //-- Build distribution list of clients observing object, but don't include the client doing the firing + { + typedef std::set ObserverList; + ObserverList const & observers = sourceObject.getObservers(); + for (ObserverList::const_iterator iter = observers.begin(); iter != observers.end(); ++iter) + { + Client * const client = *iter; + if (sendToSourceObject || client != sourceObject.getClient()) + distributionList[client->getConnection()].push_back(client->getCharacterObjectId()); + } + } + + //-- Send message to distribution list + { + for (DistributionList::const_iterator iter = distributionList.begin(); iter != distributionList.end(); ++iter) + { + GameClientMessage const gameClientMessage(iter->second, true, message); + iter->first->send(gameClientMessage, true); + } + } + } + + bool install(); + + jboolean JNICALL pilotShip(JNIEnv *env, jobject self, jlong pilotId, jlong shipIdId); + jboolean JNICALL unpilotShip(JNIEnv *env, jobject self, jlong pilotId); + jlong JNICALL getShipPilot(JNIEnv * env, jobject self, jlong shipId); + jlong JNICALL getPilotedShip(JNIEnv * env, jobject self, jlong pilotId); + jboolean JNICALL getShipHasWings(JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipCurrentSpeed(JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL setShipSlideDampener(JNIEnv * env, jobject self, jlong shipId, jfloat slideDampener); + jfloat JNICALL getShipSlideDampener(JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL setShipCurrentYaw(JNIEnv * env, jobject self, jlong shipId, jfloat currentYaw); + jfloat JNICALL getShipCurrentYaw(JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL setShipCurrentPitch(JNIEnv * env, jobject self, jlong shipId, jfloat currentPitch); + jfloat JNICALL getShipCurrentPitch(JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL setShipCurrentRoll(JNIEnv * env, jobject self, jlong shipId, jfloat currentRoll); + jfloat JNICALL getShipCurrentRoll(JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL setShipCurrentChassisHitPoints(JNIEnv * env, jobject self, jlong shipId, jfloat currentChassisHitPoints); + jfloat JNICALL getShipCurrentChassisHitPoints(JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL setShipMaximumChassisHitPoints(JNIEnv * env, jobject self, jlong shipId, jfloat maximumChassisHitPoints); + jfloat JNICALL getShipMaximumChassisHitPoints(JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL launchMissile(JNIEnv * env, jobject self, jlong player, jlong ship, jlong target, jint missileInfo, jint targetedComponent); + jboolean JNICALL launchCountermeasure(JNIEnv * env, jobject self, jlong ship, jint targettedMissile, jboolean successful, jint countermeasureType); + jint JNICALL getNearestUnlockedMissileForTarget(JNIEnv * env, jobject self, jlong target); + jintArray JNICALL getAllUnlockedMissilesForTarget(JNIEnv * env, jobject self, jlong jtarget); + jboolean JNICALL destroyMissile(JNIEnv * env, jobject self, jint missileId); + jint JNICALL getTypeByMissile(JNIEnv * env, jobject self, jint missileId); + jint JNICALL getWeaponIndexByMissile(JNIEnv * env, jobject self, jint missileId); + jint JNICALL getTimeSinceFiredByMissile(JNIEnv * env, jobject self, jint missileId); + jint JNICALL getTotalTimeByMissile(JNIEnv * env, jobject self, jint missileId); + jlong JNICALL getWhoFiredByMissile(JNIEnv * env, jobject self, jint missileId); + jboolean JNICALL setLookAtTargetShipComponent(JNIEnv * env, jobject self, jlong ship, jint targetedComponent); + jint JNICALL getLookAtTargetShipComponent(JNIEnv * env, jobject self, jlong ship); + jlongArray JNICALL getObservedShips(JNIEnv *env, jobject self, jlong jsource, jboolean excludeSource); + jlongArray JNICALL getObservedPlayerShips(JNIEnv *env, jobject self, jlong jsource, jboolean excludeSource); + jlongArray JNICALL getObservedEnemyShips(JNIEnv *env, jobject self, jlong jsource); + jlongArray JNICALL getObservedEnemyPlayerShips(JNIEnv *env, jobject self, jlong jsource); + void JNICALL notifyShipDamage(JNIEnv * env, jobject self, jlong victim, jlong attacker, jfloat totalDamage); + jfloat JNICALL getShipChassisSpeedMaximumModifier (JNIEnv * env, jobject self, jlong shipId); + void JNICALL setShipChassisSpeedMaximumModifier (JNIEnv * env, jobject self, jlong shipId, jfloat value); + jfloat JNICALL getShipActualAccelerationRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualDecelerationRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualPitchAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualYawAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualRollAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualPitchRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualYawRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualRollRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipActualSpeedMaximum (JNIEnv * env, jobject self, jlong shipId); + jstring JNICALL getShipChassisType (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getChassisComponentMassCurrent (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getChassisComponentMassMaximum (JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL setChassisComponentMassMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat chassisComponentMassMaximum); + jboolean JNICALL isShipSlotInstalled (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jboolean JNICALL isShipComponentDisabled (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jboolean JNICALL isShipComponentLowPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jboolean JNICALL isShipComponentDisabledNeedsPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentArmorHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentArmorHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentEfficiencyGeneral (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentEfficiencyEnergy (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentEnergyMaintenanceRequirement (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentMass (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jint JNICALL getShipComponentCrc (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipComponentHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jint JNICALL getShipComponentFlags (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jstring JNICALL getShipComponentName (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponDamageMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponDamageMinimum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponEffectivenessShields (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponEffectivenessArmor (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponEnergyPerShot (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponActualRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipWeaponEfficiencyRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jint JNICALL getShipWeaponAmmoCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jint JNICALL getShipWeaponAmmoMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jint JNICALL getShipWeaponAmmoType (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jfloat JNICALL getShipShieldHitpointsFrontCurrent (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipShieldHitpointsFrontMaximum (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipShieldHitpointsBackCurrent (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipShieldHitpointsBackMaximum (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipShieldRechargeRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipCapacitorEnergyCurrent (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipCapacitorEnergyMaximum (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipCapacitorEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineAccelerationRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineDecelerationRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEnginePitchAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineYawAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineRollAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEnginePitchRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineYawRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineRollRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineSpeedMaximum (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineSpeedRotationFactorMaximum (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineSpeedRotationFactorMinimum (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipEngineSpeedRotationFactorOptimal (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipReactorEnergyGenerationRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipBoosterEnergyCurrent (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipBoosterEnergyMaximum (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipBoosterEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipBoosterEnergyConsumptionRate (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipBoosterAcceleration (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipBoosterSpeedMaximum (JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL isShipBoosterActive (JNIEnv * env, jobject self, jlong shipId); + jfloat JNICALL getShipDroidInterfaceCommandSpeed (JNIEnv * env, jobject self, jlong shipId); + int JNICALL getShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong shipId); + int JNICALL getShipCargoHoldContentsCurrent (JNIEnv * env, jobject self, jlong shipId); + void JNICALL setShipComponentArmorHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentArmorHitpointsMaximum); + void JNICALL setShipComponentArmorHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentArmorHitpointsCurrent); + void JNICALL setShipComponentEfficiencyGeneral (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentEfficiencyGeneral); + void JNICALL setShipComponentEfficiencyEnergy (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentEfficiencyEnergy); + void JNICALL setShipComponentEnergyMaintenanceRequirement (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentEnergyMaintenanceRequirement); + void JNICALL setShipComponentMass (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentMass); + void JNICALL setShipComponentHitpointsCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentHitpointsCurrent); + void JNICALL setShipComponentHitpointsMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat componentHitpointsMaximum); + void JNICALL setShipComponentFlags (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint componentFlags); + void JNICALL setShipComponentName (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jstring componentName); + void JNICALL setShipComponentDisabled (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean componentDisabled); + void JNICALL setShipComponentLowPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean componentLowPower); + void JNICALL setShipComponentDisabledNeedsPower (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean componentDisabledNeedsPower); + void JNICALL setShipWeaponDamageMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponDamageMaximum); + void JNICALL setShipWeaponDamageMinimum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponDamageMinimum); + void JNICALL setShipWeaponEffectivenessShields (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEffectivenessShields); + void JNICALL setShipWeaponEffectivenessArmor (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEffectivenessArmor); + void JNICALL setShipWeaponEnergyPerShot (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEnergyPerShot); + void JNICALL setShipWeaponRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponRefireRate); + void JNICALL setShipWeaponEfficiencyRefireRate (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jfloat weaponEfficiencyRefireRate); + void JNICALL setShipWeaponAmmoCurrent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint ammoCurrent); + void JNICALL setShipWeaponAmmoMaximum (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint ammoMaximum); + void JNICALL setShipWeaponAmmoType (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jint ammoType); + void JNICALL setShipShieldHitpointsFrontCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsFrontCurrent); + void JNICALL setShipShieldHitpointsFrontMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsFrontMaximum); + void JNICALL setShipShieldHitpointsBackCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsBackCurrent); + void JNICALL setShipShieldHitpointsBackMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat shieldHitpointsBackMaximum); + void JNICALL setShipShieldRechargeRate (JNIEnv * env, jobject self, jlong shipId, jfloat shieldRechargeRate); + void JNICALL setShipCapacitorEnergyCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat capacitorEnergyCurrent); + void JNICALL setShipCapacitorEnergyMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat capacitorEnergyMaximum); + void JNICALL setShipCapacitorEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId, jfloat capacitorEnergyRechargeRate); + void JNICALL setShipEngineAccelerationRate (JNIEnv * env, jobject self, jlong shipId, jfloat engineAccelerationRate); + void JNICALL setShipEngineDecelerationRate (JNIEnv * env, jobject self, jlong shipId, jfloat engineDecelerationRate); + void JNICALL setShipEnginePitchAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat enginePitchAccelerationRateDegrees); + void JNICALL setShipEngineYawAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineYawAccelerationRateDegrees); + void JNICALL setShipEngineRollAccelerationRateDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineRollAccelerationRateDegrees); + void JNICALL setShipEnginePitchRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat enginePitchRateMaximumDegrees); + void JNICALL setShipEngineYawRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineYawRateMaximumDegrees); + void JNICALL setShipEngineRollRateMaximumDegrees (JNIEnv * env, jobject self, jlong shipId, jfloat engineRollRateMaximumDegrees); + void JNICALL setShipEngineSpeedMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedMaximum); + void JNICALL setShipEngineSpeedRotationFactorMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedRotationFactorMaximum); + void JNICALL setShipEngineSpeedRotationFactorMinimum (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedRotationFactorMinimum); + void JNICALL setShipEngineSpeedRotationFactorOptimal (JNIEnv * env, jobject self, jlong shipId, jfloat engineSpeedRotationFactorOptimal); + void JNICALL setShipReactorEnergyGenerationRate (JNIEnv * env, jobject self, jlong shipId, jfloat reactorEnergyGenerationRate); + void JNICALL setShipBoosterEnergyCurrent (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyCurrent); + void JNICALL setShipBoosterEnergyMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyMaximum); + void JNICALL setShipBoosterEnergyRechargeRate (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyRechargeRate); + void JNICALL setShipBoosterEnergyConsumptionRate (JNIEnv * env, jobject self, jlong shipId, jfloat boosterEnergyConsumptionRate); + void JNICALL setShipBoosterAcceleration (JNIEnv * env, jobject self, jlong shipId, jfloat boosterAcceleration); + void JNICALL setShipBoosterSpeedMaximum (JNIEnv * env, jobject self, jlong shipId, jfloat boosterSpeedMaximum); + void JNICALL setShipDroidInterfaceCommandSpeed (JNIEnv * env, jobject self, jlong shipId, jfloat droidInterfaceCommandSpeed); + void JNICALL setShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong shipId, jint contentsMaximum); + void JNICALL setShipCargoHoldContent (JNIEnv * env, jobject self, jlong shipId, jlong resourceTypeId, jint amount); + jint JNICALL getShipCargoHoldContent (JNIEnv * env, jobject self, jlong shipId, jlong resourceTypeId); + jlongArray JNICALL getShipCargoHoldContentsResourceTypes (JNIEnv * env, jobject self, jlong shipId); + jintArray JNICALL getShipCargoHoldContentsAmounts (JNIEnv * env, jobject self, jlong shipId); + jboolean JNICALL shipCanInstallComponent (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jlong component); + jboolean JNICALL shipPseudoInstallComponent (JNIEnv * env, jobject self, jlong jship, jint chassisSlot, jint componentCrc); + jboolean JNICALL shipInstallComponent (JNIEnv * env, jobject self, jlong installerId, jlong shipId, jint chassisSlot, jlong component); + jlong JNICALL shipUninstallComponent (JNIEnv * env, jobject self, jlong uninstallerId, jlong shipId, jint chassisSlot, jlong containerTarget); + // allow an uninstalled component to overflow the container. + jlong JNICALL shipUninstallComponentAllowOverload (JNIEnv * env, jobject self, jlong uninstallerId, jlong shipId, jint chassisSlot, jlong containerTarget); + jlong JNICALL shipUninstallComponentBase (JNIEnv * env, jobject self, jlong uninstallerId, jlong shipId, jint chassisSlot, jlong containerTarget, bool allowOverload); + jintArray JNICALL getShipChassisSlots (JNIEnv * env, jobject self, jlong shipId); + void JNICALL setShipSlotTargetable (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot, jboolean targetable); + jboolean JNICALL isShipSlotTargetable (JNIEnv * env, jobject self, jlong shipId, jint chassisSlot); + jint JNICALL getShipComponentDescriptorType (JNIEnv * env, jobject self, jlong component); + jint JNICALL getShipComponentDescriptorTypeByName (JNIEnv * env, jobject self, jstring typeName); + jstring JNICALL getShipComponentDescriptorTypeName (JNIEnv * env, jobject self, jint componentType); + jint JNICALL getShipComponentDescriptorCrc (JNIEnv * env, jobject self, jlong component); + jstring JNICALL getShipComponentDescriptorCrcName (JNIEnv * env, jobject self, jint componentCrc); + jstring JNICALL getShipComponentDescriptorCompatibility (JNIEnv * env, jobject self, jint componentCrc); + jboolean JNICALL getShipComponentDescriptorWeaponIsAmmoConsuming (JNIEnv * env, jobject self, jint componentCrc); + jboolean JNICALL getShipComponentDescriptorWeaponIsMissile (JNIEnv * env, jobject self, jint componentCrc); + jboolean JNICALL getShipComponentDescriptorWeaponIsCountermeasure (JNIEnv * env, jobject self, jint componentCrc); + jboolean JNICALL getShipComponentDescriptorWeaponIsMining (JNIEnv * env, jobject self, jint componentCrc); + jboolean JNICALL getShipComponentDescriptorWeaponIsTractor (JNIEnv * env, jobject self, jint componentCrc); + jfloat JNICALL getShipComponentDescriptorWeaponRange (JNIEnv * env, jobject self, jint componentCrc); + jfloat JNICALL getShipComponentDescriptorWeaponProjectileSpeed (JNIEnv * env, jobject self, jint componentCrc); + jlong JNICALL getDroidControlDeviceForShip (JNIEnv * env, jobject self, jlong jship); + jboolean JNICALL associateDroidControlDeviceWithShip (JNIEnv * env, jobject self, jlong jship, jlong jdroidControlDevice); + jboolean JNICALL removeDroidControlDeviceFromShip (JNIEnv * env, jobject self, jlong jship); + jlong JNICALL launchShipFromHangar (JNIEnv * env, jobject self, jlong jshipId, jstring templateToSpawn, jobject deltaFromHangarHardpoint); + void JNICALL commPlayers (JNIEnv * env, jobject self, jlong jtaunter, jstring appearanceOverloadServerTemplate, jstring soundeffect, jfloat duration, jlongArray jplayers, jstring jtauntOob, jboolean chronicles); + void JNICALL handleShipDestruction(JNIEnv * env, jobject self, jlong ship, jfloat severity); + void JNICALL handleShipComponentDestruction(JNIEnv * env, jobject self, jlong ship, jint chassisSlot, jfloat severity); + jboolean JNICALL setShipInternalDamageOverTime(JNIEnv * env, jobject self, jlong ship, jint chassisSlot, jfloat damageRate, jfloat damageThreshold); + jboolean JNICALL removeShipInternalDamageOverTime(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); + jfloat JNICALL getShipInternalDamageOverTimeDamageRate(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); + jfloat JNICALL getShipInternalDamageOverTimeDamageThreshold(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); + jboolean JNICALL hasShipInternalDamageOverTime(JNIEnv * env, jobject self, jlong ship, jint chassisSlot); + jint JNICALL shipGetSpaceFaction(JNIEnv *env, jobject self, jlong jship); + jintArray JNICALL shipGetSpaceFactionAllies(JNIEnv *env, jobject self, jlong jship); + jintArray JNICALL shipGetSpaceFactionEnemies(JNIEnv *env, jobject self, jlong jship); + jboolean JNICALL shipGetSpaceFactionIsAggro(JNIEnv *env, jobject self, jlong jship); + void JNICALL shipSetSpaceFaction(JNIEnv *env, jobject self, jlong jship, jint spaceFaction); + void JNICALL shipSetSpaceFactionAllies(JNIEnv *env, jobject self, jlong jship, jintArray jfactionList); + void JNICALL shipSetSpaceFactionEnemies(JNIEnv *env, jobject self, jlong jship, jintArray jfactionList); + void JNICALL shipSetSpaceFactionIsAggro(JNIEnv *env, jobject self, jlong jship, jboolean isAggro); + jboolean JNICALL shipIsInNebula(JNIEnv *env, jobject self, jlong ship, jstring nebulaName); + jboolean JNICALL setShipWingName(JNIEnv *env, jobject self, jlong target, jstring str); + jstring JNICALL getShipWingName(JNIEnv *env, jobject self, jlong target); + jboolean JNICALL setShipTypeName(JNIEnv *env, jobject self, jlong target, jstring str); + jstring JNICALL getShipTypeName(JNIEnv *env, jobject self, jlong target); + jboolean JNICALL setShipDifficulty(JNIEnv *env, jobject self, jlong target, jstring str); + jstring JNICALL getShipDifficulty(JNIEnv *env, jobject self, jlong target); + jboolean JNICALL setShipFaction(JNIEnv *env, jobject self, jlong target, jstring str); + jstring JNICALL getShipFaction(JNIEnv *env, jobject self, jlong target); + jboolean JNICALL addMissionCriticalObject(JNIEnv *env, jobject self, jlong playerObjectId, jlong missionCriticalObjectId); + jboolean JNICALL removeMissionCriticalObject(JNIEnv *env, jobject self, jlong playerObjectId, jlong missionCriticalObjectId); + jboolean JNICALL clearMissionCriticalObjects(JNIEnv *env, jobject self, jlong playerObjectId); + jboolean JNICALL isMissionCriticalObject(JNIEnv *env, jobject self, jlong playerObjectId, jlong missionCriticalObjectId); + jstring JNICALL getShipComponentDebugString(JNIEnv * env, jobject self, jlong jobject_shipId, jint chassisSlot); + void JNICALL notifyShipHit(JNIEnv * env, jobject self, jlong jobject_shipId, jobject jobject_vectorUp_w, jobject jobject_vectorHitLocation_o, jint type, jfloat integrity, jfloat previousIntegrity); + void JNICALL setDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId, jobject jobject_velocity_w); + jobject JNICALL getDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId); + void JNICALL openSpaceMiningUi(JNIEnv * env, jobject self, jlong player, jlong spaceStation, jstring spaceStationName); +} + +using namespace ScriptMethodsShipNamespace; + + +//======================================================================== +// install +//======================================================================== + +bool ScriptMethodsShipNamespace::install() +{ +const JNINativeMethod NATIVES[] = { + #define JF(a,b,c) {a,b,(void*)(ScriptMethodsShipNamespace::c)} + JF("_pilotShip", "(JJ)Z", pilotShip), + JF("_unpilotShip", "(J)Z", unpilotShip), + JF("_getPilotId", "(J)J", getShipPilot), + JF("_getShipPilot", "(J)J", getShipPilot), + JF("_getPilotedShip", "(J)J", getPilotedShip), + JF("_getShipHasWings", "(J)Z", getShipHasWings), + JF("_getShipCurrentSpeed", "(J)F", getShipCurrentSpeed), + JF("_setShipSlideDampener", "(JF)Z", setShipSlideDampener), + JF("_getShipSlideDampener", "(J)F", getShipSlideDampener), + JF("_setShipCurrentYaw", "(JF)Z", setShipCurrentYaw), + JF("_getShipCurrentYaw", "(J)F", getShipCurrentYaw), + JF("_setShipCurrentPitch", "(JF)Z", setShipCurrentPitch), + JF("_getShipCurrentPitch", "(J)F", getShipCurrentPitch), + JF("_setShipCurrentRoll", "(JF)Z", setShipCurrentRoll), + JF("_getShipCurrentRoll", "(J)F", getShipCurrentRoll), + JF("_setShipCurrentChassisHitPoints", "(JF)Z", setShipCurrentChassisHitPoints), + JF("_getShipCurrentChassisHitPoints", "(J)F", getShipCurrentChassisHitPoints), + JF("_setShipMaximumChassisHitPoints", "(JF)Z", setShipMaximumChassisHitPoints), + JF("_getShipMaximumChassisHitPoints", "(J)F", getShipMaximumChassisHitPoints), + JF("_launchMissile", "(JJJII)Z", launchMissile), + JF("_launchCountermeasure", "(JIZI)Z", launchCountermeasure), + JF("_getNearestUnlockedMissileForTarget", "(J)I", getNearestUnlockedMissileForTarget), + JF("_getAllUnlockedMissilesForTarget", "(J)[I", getAllUnlockedMissilesForTarget), + JF("destroyMissile", "(I)Z", destroyMissile), + JF("getTypeByMissile","(I)I", getTypeByMissile), + JF("getWeaponIndexByMissile","(I)I",getWeaponIndexByMissile), + JF("getTimeSinceFiredByMissile","(I)I",getTimeSinceFiredByMissile), + JF("getTotalTimeByMissile","(I)I",getTotalTimeByMissile), + JF("_getWhoFiredByMissile","(I)J",getWhoFiredByMissile), + JF("_setLookAtTargetShipComponent", "(JI)Z", setLookAtTargetShipComponent), + JF("_getLookAtTargetShipComponent", "(J)I", getLookAtTargetShipComponent), + JF("_getObservedShips", "(JZ)[J", getObservedShips), + JF("_getObservedPlayerShips", "(JZ)[J", getObservedPlayerShips), + JF("_getObservedEnemyShips", "(J)[J", getObservedEnemyShips), + JF("_getObservedEnemyPlayerShips", "(J)[J", getObservedEnemyPlayerShips), + JF("_notifyShipDamage", "(JJF)V", notifyShipDamage), + JF("_getShipChassisSpeedMaximumModifier", "(J)F", getShipChassisSpeedMaximumModifier), + JF("_setShipChassisSpeedMaximumModifier", "(JF)V", setShipChassisSpeedMaximumModifier), + JF("_getShipActualAccelerationRate", "(J)F", getShipActualAccelerationRate), + JF("_getShipActualDecelerationRate", "(J)F", getShipActualDecelerationRate), + JF("_getShipActualPitchAccelerationRateDegrees", "(J)F", getShipActualPitchAccelerationRateDegrees), + JF("_getShipActualYawAccelerationRateDegrees", "(J)F", getShipActualYawAccelerationRateDegrees), + JF("_getShipActualRollAccelerationRateDegrees", "(J)F", getShipActualRollAccelerationRateDegrees), + JF("_getShipActualPitchRateMaximumDegrees", "(J)F", getShipActualPitchRateMaximumDegrees), + JF("_getShipActualYawRateMaximumDegrees", "(J)F", getShipActualYawRateMaximumDegrees), + JF("_getShipActualRollRateMaximumDegrees", "(J)F", getShipActualRollRateMaximumDegrees), + JF("_getShipActualSpeedMaximum", "(J)F", getShipActualSpeedMaximum), + JF("_handleShipDestruction", "(JF)V", handleShipDestruction), + JF("_handleShipComponentDestruction", "(JIF)V", handleShipComponentDestruction), + JF("_setShipInternalDamageOverTime", "(JIFF)Z", setShipInternalDamageOverTime), + JF("_removeShipInternalDamageOverTime", "(JI)Z", removeShipInternalDamageOverTime), + JF("_getShipInternalDamageOverTimeDamageRate", "(JI)F", getShipInternalDamageOverTimeDamageRate), + JF("_getShipInternalDamageOverTimeDamageThreshold", "(JI)F", getShipInternalDamageOverTimeDamageThreshold), + JF("_hasShipInternalDamageOverTime", "(JI)Z", hasShipInternalDamageOverTime), + JF("_shipGetSpaceFaction", "(J)I", shipGetSpaceFaction), + JF("_shipGetSpaceFactionAllies", "(J)[I", shipGetSpaceFactionAllies), + JF("_shipGetSpaceFactionEnemies", "(J)[I", shipGetSpaceFactionEnemies), + JF("_shipGetSpaceFactionIsAggro", "(J)Z", shipGetSpaceFactionIsAggro), + JF("_shipSetSpaceFaction", "(JI)V", shipSetSpaceFaction), + JF("_shipSetSpaceFactionAllies", "(J[I)V", shipSetSpaceFactionAllies), + JF("_shipSetSpaceFactionEnemies", "(J[I)V", shipSetSpaceFactionEnemies), + JF("_shipSetSpaceFactionIsAggro", "(JZ)V", shipSetSpaceFactionIsAggro), + JF("_getShipChassisType", "(J)Ljava/lang/String;", getShipChassisType), + JF("_getChassisComponentMassCurrent", "(J)F", getChassisComponentMassCurrent), + JF("_getChassisComponentMassMaximum", "(J)F", getChassisComponentMassMaximum), + JF("_setChassisComponentMassMaximum", "(JF)Z", setChassisComponentMassMaximum), + JF("_isShipSlotInstalled", "(JI)Z", isShipSlotInstalled), + JF("_isShipComponentDisabled", "(JI)Z", isShipComponentDisabled), + JF("_isShipComponentLowPower", "(JI)Z", isShipComponentLowPower), + JF("_isShipComponentDisabledNeedsPower", "(JI)Z", isShipComponentDisabledNeedsPower), + JF("_getShipComponentArmorHitpointsMaximum", "(JI)F", getShipComponentArmorHitpointsMaximum), + JF("_getShipComponentArmorHitpointsCurrent", "(JI)F", getShipComponentArmorHitpointsCurrent), + JF("_getShipComponentEfficiencyGeneral", "(JI)F", getShipComponentEfficiencyGeneral), + JF("_getShipComponentEfficiencyEnergy", "(JI)F", getShipComponentEfficiencyEnergy), + JF("_getShipComponentEnergyMaintenanceRequirement", "(JI)F", getShipComponentEnergyMaintenanceRequirement), + JF("_getShipComponentMass", "(JI)F", getShipComponentMass), + JF("_getShipComponentCrc", "(JI)I", getShipComponentCrc), + JF("_getShipComponentHitpointsCurrent", "(JI)F", getShipComponentHitpointsCurrent), + JF("_getShipComponentHitpointsMaximum", "(JI)F", getShipComponentHitpointsMaximum), + JF("_getShipComponentFlags", "(JI)I", getShipComponentFlags), + JF("_getShipComponentName", "(JI)Ljava/lang/String;", getShipComponentName), + JF("_getShipWeaponDamageMaximum", "(JI)F", getShipWeaponDamageMaximum), + JF("_getShipWeaponDamageMinimum", "(JI)F", getShipWeaponDamageMinimum), + JF("_getShipWeaponEffectivenessShields", "(JI)F", getShipWeaponEffectivenessShields), + JF("_getShipWeaponEffectivenessArmor", "(JI)F", getShipWeaponEffectivenessArmor), + JF("_getShipWeaponEnergyPerShot", "(JI)F", getShipWeaponEnergyPerShot), + JF("_getShipWeaponRefireRate", "(JI)F", getShipWeaponRefireRate), + JF("_getShipWeaponActualRefireRate", "(JI)F", getShipWeaponActualRefireRate), + JF("_getShipWeaponEfficiencyRefireRate", "(JI)F", getShipWeaponEfficiencyRefireRate), + JF("_getShipWeaponAmmoCurrent", "(JI)I", getShipWeaponAmmoCurrent), + JF("_getShipWeaponAmmoMaximum", "(JI)I", getShipWeaponAmmoMaximum), + JF("_getShipWeaponAmmoType", "(JI)I", getShipWeaponAmmoType), + JF("_getShipShieldHitpointsFrontCurrent", "(J)F", getShipShieldHitpointsFrontCurrent), + JF("_getShipShieldHitpointsFrontMaximum", "(J)F", getShipShieldHitpointsFrontMaximum), + JF("_getShipShieldHitpointsBackCurrent", "(J)F", getShipShieldHitpointsBackCurrent), + JF("_getShipShieldHitpointsBackMaximum", "(J)F", getShipShieldHitpointsBackMaximum), + JF("_getShipShieldRechargeRate", "(J)F", getShipShieldRechargeRate), + JF("_getShipCapacitorEnergyCurrent", "(J)F", getShipCapacitorEnergyCurrent), + JF("_getShipCapacitorEnergyMaximum", "(J)F", getShipCapacitorEnergyMaximum), + JF("_getShipCapacitorEnergyRechargeRate", "(J)F", getShipCapacitorEnergyRechargeRate), + JF("_getShipEngineAccelerationRate", "(J)F", getShipEngineAccelerationRate), + JF("_getShipEngineDecelerationRate", "(J)F", getShipEngineDecelerationRate), + JF("_getShipEnginePitchAccelerationRateDegrees", "(J)F", getShipEnginePitchAccelerationRateDegrees), + JF("_getShipEngineYawAccelerationRateDegrees", "(J)F", getShipEngineYawAccelerationRateDegrees), + JF("_getShipEngineRollAccelerationRateDegrees", "(J)F", getShipEngineRollAccelerationRateDegrees), + JF("_getShipEnginePitchRateMaximumDegrees", "(J)F", getShipEnginePitchRateMaximumDegrees), + JF("_getShipEngineYawRateMaximumDegrees", "(J)F", getShipEngineYawRateMaximumDegrees), + JF("_getShipEngineRollRateMaximumDegrees", "(J)F", getShipEngineRollRateMaximumDegrees), + JF("_getShipEngineSpeedMaximum", "(J)F", getShipEngineSpeedMaximum), + JF("_getShipEngineSpeedRotationFactorMaximum", "(J)F", getShipEngineSpeedRotationFactorMaximum), + JF("_getShipEngineSpeedRotationFactorMinimum", "(J)F", getShipEngineSpeedRotationFactorMinimum), + JF("_getShipEngineSpeedRotationFactorOptimal", "(J)F", getShipEngineSpeedRotationFactorOptimal), + JF("_getShipReactorEnergyGenerationRate", "(J)F", getShipReactorEnergyGenerationRate), + JF("_getShipBoosterEnergyCurrent", "(J)F", getShipBoosterEnergyCurrent), + JF("_getShipBoosterEnergyMaximum", "(J)F", getShipBoosterEnergyMaximum), + JF("_getShipBoosterEnergyRechargeRate", "(J)F", getShipBoosterEnergyRechargeRate), + JF("_getShipBoosterEnergyConsumptionRate", "(J)F", getShipBoosterEnergyConsumptionRate), + JF("_getShipBoosterAcceleration", "(J)F", getShipBoosterAcceleration), + JF("_getShipBoosterSpeedMaximum", "(J)F", getShipBoosterSpeedMaximum), + JF("_isShipBoosterActive", "(J)Z", isShipBoosterActive), + JF("_getShipDroidInterfaceCommandSpeed", "(J)F", getShipDroidInterfaceCommandSpeed), + JF("_getShipCargoHoldContentsMaximum", "(J)I", getShipCargoHoldContentsMaximum), + JF("_getShipCargoHoldContentsCurrent", "(J)I", getShipCargoHoldContentsCurrent), + JF("_setShipComponentArmorHitpointsMaximum", "(JIF)V", setShipComponentArmorHitpointsMaximum), + JF("_setShipComponentArmorHitpointsCurrent", "(JIF)V", setShipComponentArmorHitpointsCurrent), + JF("_setShipComponentEfficiencyGeneral", "(JIF)V", setShipComponentEfficiencyGeneral), + JF("_setShipComponentEfficiencyEnergy", "(JIF)V", setShipComponentEfficiencyEnergy), + JF("_setShipComponentEnergyMaintenanceRequirement", "(JIF)V", setShipComponentEnergyMaintenanceRequirement), + JF("_setShipComponentMass", "(JIF)V", setShipComponentMass), + JF("_setShipComponentHitpointsCurrent", "(JIF)V", setShipComponentHitpointsCurrent), + JF("_setShipComponentHitpointsMaximum", "(JIF)V", setShipComponentHitpointsMaximum), + JF("_setShipComponentFlags", "(JII)V", setShipComponentFlags), + JF("_setShipComponentName", "(JILjava/lang/String;)V", setShipComponentName), + JF("_setShipComponentDisabled", "(JIZ)V", setShipComponentDisabled), + JF("_setShipComponentLowPower", "(JIZ)V", setShipComponentLowPower), + JF("_setShipComponentDisabledNeedsPower", "(JIZ)V", setShipComponentDisabledNeedsPower), + JF("_setShipWeaponDamageMaximum", "(JIF)V", setShipWeaponDamageMaximum), + JF("_setShipWeaponDamageMinimum", "(JIF)V", setShipWeaponDamageMinimum), + JF("_setShipWeaponEffectivenessShields", "(JIF)V", setShipWeaponEffectivenessShields), + JF("_setShipWeaponEffectivenessArmor", "(JIF)V", setShipWeaponEffectivenessArmor), + JF("_setShipWeaponEnergyPerShot", "(JIF)V", setShipWeaponEnergyPerShot), + JF("_setShipWeaponRefireRate", "(JIF)V", setShipWeaponRefireRate), + JF("_setShipWeaponEfficiencyRefireRate", "(JIF)V", setShipWeaponEfficiencyRefireRate), + JF("_setShipWeaponAmmoCurrent", "(JII)V", setShipWeaponAmmoCurrent), + JF("_setShipWeaponAmmoMaximum", "(JII)V", setShipWeaponAmmoMaximum), + JF("_setShipWeaponAmmoType", "(JII)V", setShipWeaponAmmoType), + JF("_setShipShieldHitpointsFrontCurrent", "(JF)V", setShipShieldHitpointsFrontCurrent), + JF("_setShipShieldHitpointsFrontMaximum", "(JF)V", setShipShieldHitpointsFrontMaximum), + JF("_setShipShieldHitpointsBackCurrent", "(JF)V", setShipShieldHitpointsBackCurrent), + JF("_setShipShieldHitpointsBackMaximum", "(JF)V", setShipShieldHitpointsBackMaximum), + JF("_setShipShieldRechargeRate", "(JF)V", setShipShieldRechargeRate), + JF("_setShipCapacitorEnergyCurrent", "(JF)V", setShipCapacitorEnergyCurrent), + JF("_setShipCapacitorEnergyMaximum", "(JF)V", setShipCapacitorEnergyMaximum), + JF("_setShipCapacitorEnergyRechargeRate", "(JF)V", setShipCapacitorEnergyRechargeRate), + JF("_setShipEngineAccelerationRate", "(JF)V", setShipEngineAccelerationRate), + JF("_setShipEngineDecelerationRate", "(JF)V", setShipEngineDecelerationRate), + JF("_setShipEnginePitchAccelerationRateDegrees", "(JF)V", setShipEnginePitchAccelerationRateDegrees), + JF("_setShipEngineYawAccelerationRateDegrees", "(JF)V", setShipEngineYawAccelerationRateDegrees), + JF("_setShipEngineRollAccelerationRateDegrees", "(JF)V", setShipEngineRollAccelerationRateDegrees), + JF("_setShipEnginePitchRateMaximumDegrees", "(JF)V", setShipEnginePitchRateMaximumDegrees), + JF("_setShipEngineYawRateMaximumDegrees", "(JF)V", setShipEngineYawRateMaximumDegrees), + JF("_setShipEngineRollRateMaximumDegrees", "(JF)V", setShipEngineRollRateMaximumDegrees), + JF("_setShipEngineSpeedMaximum", "(JF)V", setShipEngineSpeedMaximum), + JF("_setShipEngineSpeedRotationFactorMaximum", "(JF)V", setShipEngineSpeedRotationFactorMaximum), + JF("_setShipEngineSpeedRotationFactorMinimum", "(JF)V", setShipEngineSpeedRotationFactorMinimum), + JF("_setShipEngineSpeedRotationFactorOptimal", "(JF)V", setShipEngineSpeedRotationFactorOptimal), + JF("_setShipReactorEnergyGenerationRate", "(JF)V", setShipReactorEnergyGenerationRate), + JF("_setShipBoosterEnergyCurrent", "(JF)V", setShipBoosterEnergyCurrent), + JF("_setShipBoosterEnergyMaximum", "(JF)V", setShipBoosterEnergyMaximum), + JF("_setShipBoosterEnergyRechargeRate", "(JF)V", setShipBoosterEnergyRechargeRate), + JF("_setShipBoosterEnergyConsumptionRate", "(JF)V", setShipBoosterEnergyConsumptionRate), + JF("_setShipBoosterAcceleration", "(JF)V", setShipBoosterAcceleration), + JF("_setShipBoosterSpeedMaximum", "(JF)V", setShipBoosterSpeedMaximum), + JF("_setShipDroidInterfaceCommandSpeed", "(JF)V", setShipDroidInterfaceCommandSpeed), + JF("_setShipCargoHoldContentsMaximum", "(JI)V", setShipCargoHoldContentsMaximum), + JF("_setShipCargoHoldContent", "(JJI)V", setShipCargoHoldContent), + JF("_getShipCargoHoldContent", "(JJ)I", getShipCargoHoldContent), + JF("_getShipCargoHoldContentsResourceTypes", "(J)[J", getShipCargoHoldContentsResourceTypes), + JF("_getShipCargoHoldContentsAmounts", "(J)[I", getShipCargoHoldContentsAmounts), + JF("_shipCanInstallComponent", "(JIJ)Z", shipCanInstallComponent), + JF("_shipPseudoInstallComponent", "(JII)Z", shipPseudoInstallComponent), + JF("_shipInstallComponent", "(JJIJ)Z", shipInstallComponent), + JF("_shipUninstallComponent", "(JJIJ)J", shipUninstallComponent), + JF("_shipUninstallComponentAllowOverload", "(JJIJ)J", shipUninstallComponentAllowOverload), + JF("_getShipChassisSlots", "(J)[I", getShipChassisSlots), + JF("_setShipSlotTargetable", "(JIZ)V", setShipSlotTargetable), + JF("_isShipSlotTargetable", "(JI)Z", isShipSlotTargetable), + JF("_getShipComponentDescriptorType", "(J)I", getShipComponentDescriptorType), + JF("getShipComponentDescriptorTypeName", "(I)Ljava/lang/String;", getShipComponentDescriptorTypeName), + JF("getShipComponentDescriptorTypeByName", "(Ljava/lang/String;)I", getShipComponentDescriptorTypeByName), + JF("_getShipComponentDescriptorCrc", "(J)I", getShipComponentDescriptorCrc), + JF("getShipComponentDescriptorCrcName", "(I)Ljava/lang/String;", getShipComponentDescriptorCrcName), + JF("getShipComponentDescriptorCompatibility", "(I)Ljava/lang/String;", getShipComponentDescriptorCompatibility), + JF("getShipComponentDescriptorWeaponIsAmmoConsuming", "(I)Z", getShipComponentDescriptorWeaponIsAmmoConsuming), + JF("getShipComponentDescriptorWeaponIsMissile", "(I)Z", getShipComponentDescriptorWeaponIsMissile), + JF("getShipComponentDescriptorWeaponIsCountermeasure","(I)Z", getShipComponentDescriptorWeaponIsCountermeasure), + JF("getShipComponentDescriptorWeaponIsMining", "(I)Z", getShipComponentDescriptorWeaponIsMining), + JF("getShipComponentDescriptorWeaponIsTractor", "(I)Z", getShipComponentDescriptorWeaponIsTractor), + JF("getShipComponentDescriptorWeaponRange", "(I)F", getShipComponentDescriptorWeaponRange), + JF("getShipComponentDescriptorWeaponProjectileSpeed", "(I)F", getShipComponentDescriptorWeaponProjectileSpeed), + JF("_getDroidControlDeviceForShip", "(J)J", getDroidControlDeviceForShip), + JF("_associateDroidControlDeviceWithShip", "(JJ)Z", associateDroidControlDeviceWithShip), + JF("_removeDroidControlDeviceFromShip", "(J)Z", removeDroidControlDeviceFromShip), + JF("_launchShipFromHangar", "(JLjava/lang/String;Lscript/transform;)J", launchShipFromHangar), + JF("__commPlayers", "(JLjava/lang/String;Ljava/lang/String;F[JLjava/lang/String;Z)V", commPlayers), + JF("_shipIsInNebula", "(JLjava/lang/String;)Z", shipIsInNebula), + JF("_setShipWingName", "(JLjava/lang/String;)Z", setShipWingName), + JF("_getShipWingName", "(J)Ljava/lang/String;", getShipWingName), + JF("_setShipTypeName", "(JLjava/lang/String;)Z", setShipTypeName), + JF("_getShipTypeName", "(J)Ljava/lang/String;", getShipTypeName), + JF("_setShipDifficulty", "(JLjava/lang/String;)Z", setShipDifficulty), + JF("_getShipDifficulty", "(J)Ljava/lang/String;", getShipDifficulty), + JF("_setShipFaction", "(JLjava/lang/String;)Z", setShipFaction), + JF("_getShipFaction", "(J)Ljava/lang/String;", getShipFaction), + JF("_addMissionCriticalObject", "(JJ)Z", addMissionCriticalObject), + JF("_removeMissionCriticalObject", "(JJ)Z", removeMissionCriticalObject), + JF("_clearMissionCriticalObjects", "(J)Z", clearMissionCriticalObjects), + JF("_isMissionCriticalObject", "(JJ)Z", isMissionCriticalObject), + JF("_getShipComponentDebugString", "(JI)Ljava/lang/String;", getShipComponentDebugString), + JF("_notifyShipHit", "(JLscript/vector;Lscript/vector;IFF)V", notifyShipHit), + JF("_setDynamicMiningAsteroidVelocity", "(JLscript/vector;)V", setDynamicMiningAsteroidVelocity), + JF("_getDynamicMiningAsteroidVelocity", "(J)Lscript/vector;", getDynamicMiningAsteroidVelocity), + JF("_openSpaceMiningUi", "(JJLjava/lang/String;)V", openSpaceMiningUi), +}; + + return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); +} + + +// ====================================================================== + +jboolean JNICALL ScriptMethodsShipNamespace::pilotShip(JNIEnv *env, jobject /*self*/, jlong pilotId, jlong pilotSlotId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + //-- Get the pilot object. + CreatureObject * const pilotObject = JavaLibrary::getCreatureThrow(env, pilotId, "pilotShip(): error in pilotId arg"); + if (!pilotObject) + return JNI_FALSE; + + //-- Ensure that the pilot is not already piloting a ship. + if (pilotObject->getPilotedShip()) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::pilotShip(): pilot id=[%s] is already riding a ship.", pilotObject->getNetworkId().getValueString().c_str())); + return JNI_FALSE; + } + + //-- Get the pilot slot object. + ServerObject * pilotSlotObject = 0; + if (!JavaLibrary::getObject(pilotSlotId, pilotSlotObject)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::pilotShip: could not resolve pilotSlotObject")); + return JNI_FALSE; + } + + //-- Make sure the ship is a player controlled ship + if (pilotObject->isPlayerControlled()) + { + //-- Get the containing ship + ShipObject * const shipObject = ShipObject::getContainingShipObject(pilotSlotObject); + if (!shipObject) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::pilotShip: pilotSlotObject [id=%s, template=%s] does not have a containing ship", pilotSlotObject->getNetworkId().getValueString().c_str(), pilotSlotObject->getObjectTemplateName())); + return JNI_FALSE; + } + + if (!shipObject->isPlayerShip()) + return JNI_FALSE; + } + + //-- Have the pilot mount the ship. + if (!pilotObject->pilotShip(*pilotSlotObject)) + return JNI_FALSE; + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::unpilotShip(JNIEnv *env, jobject /*self*/, jlong pilotId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + //-- Get the pilot. + CreatureObject * const pilotObject = JavaLibrary::getCreatureThrow(env, pilotId, "unpilotShip(): error in pilotId arg"); + if (!pilotObject) + return JNI_FALSE; + + //-- Get the ship. + ShipObject * const shipObject = pilotObject->getPilotedShip(); + if (!shipObject) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::unpilotShip(): pilot id=[%s] is not piloting a ship.", pilotObject->getNetworkId().getValueString().c_str())); + return JNI_FALSE; + } + + //-- Detach the pilot from the ship. + if (!pilotObject->unpilotShip()) + return JNI_FALSE; + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jlong JNICALL ScriptMethodsShipNamespace::getShipPilot(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0; + + //-- Get the ship object. + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipPilot(): obj_id shipId did not resolve to a ShipObject", false); + if (!shipObject) + return 0; + + //-- Get the pilot object + CreatureObject const * const pilotObject = shipObject->getPilot(); + NetworkId const pilotNetworkId = (pilotObject ? pilotObject->getNetworkId() : NetworkId::cms_invalid); + + return pilotNetworkId.getValue(); +} + +// ---------------------------------------------------------------------- + +jlong JNICALL ScriptMethodsShipNamespace::getPilotedShip(JNIEnv * env, jobject /*self*/, jlong jobject_pilotId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0; + + //-- Get the pilot object. + CreatureObject const * const creatureObject = JavaLibrary::getCreatureThrow(env, jobject_pilotId, "getPilotedShip(): obj_id pilotId did not resolve to a ShipObject", false); + if (!creatureObject) + return 0; + + ShipObject const * const shipObject = creatureObject->getPilotedShip(); + NetworkId const shipNetworkId = (shipObject ? shipObject->getNetworkId() : NetworkId::cms_invalid); + + return shipNetworkId.getValue(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::getShipHasWings(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipHasWings(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + if (!shipObject->hasWings()) + return JNI_FALSE; + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentSpeed(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentSpeed(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getCurrentSpeed(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipSlideDampener(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_slideDampener) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipSlideDampener(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + bool const result = shipObject->setSlideDampener(jfloat_slideDampener); + if (!result) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipSlideDampener(): could not set value %1.2f (possibly out of range)", jfloat_slideDampener)); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipSlideDampener(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipSlideDampener(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getSlideDampener(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentYaw(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentYaw) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentYaw(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + bool const result = shipObject->setCurrentYaw(jfloat_currentYaw); + if (!result) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentYaw(): could not set value %1.2f (possibly out of range)", jfloat_currentYaw)); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentYaw(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentYaw(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getCurrentYaw(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentPitch(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentPitch) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentPitch(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + bool const result = shipObject->setCurrentPitch(jfloat_currentPitch); + if (!result) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentPitch(): could not set value %1.2f (possibly out of range)", jfloat_currentPitch)); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentPitch(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentPitch(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getCurrentPitch(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentRoll(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentRoll) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentRoll(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + bool const result = shipObject->setCurrentRoll(jfloat_currentRoll); + if (!result) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentRoll(): could not set value %1.2f (possibly out of range)", jfloat_currentRoll)); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentRoll(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentRoll(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getCurrentRoll(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipCurrentChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentChassisHitPoints) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipCurrentChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + bool const result = shipObject->setCurrentChassisHitPoints(jfloat_currentChassisHitPoints); + if (!result) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCurrentChassisHitPoints(): could not set value %1.2f (possibly out of range)", jfloat_currentChassisHitPoints)); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCurrentChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCurrentChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getCurrentChassisHitPoints(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipMaximumChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat jfloat_currentChassisHitPoints) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "setShipMaximumChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + bool const result = shipObject->setMaximumChassisHitPoints(jfloat_currentChassisHitPoints); + if (!result) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipMaximumChassisHitPoints(): could not set value %1.2f (possibly out of range)", jfloat_currentChassisHitPoints)); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipMaximumChassisHitPoints(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipMaximumChassisHitPoints(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getMaximumChassisHitPoints(); +} + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +//-- component system +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- + +//-- ship component methods + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualAccelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getShipActualAccelerationRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualDecelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualDecelerationRate(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getShipActualDecelerationRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualPitchAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualPitchAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return convertRadiansToDegrees(shipObject->getShipActualPitchAccelerationRate()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualYawAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualYawAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return convertRadiansToDegrees(shipObject->getShipActualYawAccelerationRate()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualRollAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualRollAccelerationRate(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return convertRadiansToDegrees(shipObject->getShipActualRollAccelerationRate()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualPitchRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualPitchRateMaximum(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return convertRadiansToDegrees(shipObject->getShipActualPitchRateMaximum()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualYawRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualYawRateMaximum(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return convertRadiansToDegrees(shipObject->getShipActualYawRateMaximum()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualRollRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualRollRateMaximum(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return convertRadiansToDegrees(shipObject->getShipActualRollRateMaximum()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipActualSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipActualSpeedMaximum(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.f; + + return shipObject->getShipActualSpeedMaximum(); +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipChassisType(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return NULL; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return NULL; + + ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (shipObject->getChassisType()); + if (shipChassis) + return JavaString(shipChassis->getName ().getString ()).getReturnValue(); + + return NULL; +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getChassisComponentMassCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.0f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.0f; + + return shipObject->getChassisComponentMassCurrent(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getChassisComponentMassMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.0f; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0.0f; + + return shipObject->getChassisComponentMassMaximum(); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setChassisComponentMassMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, float chassisComponentMassMaximum) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisType(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + shipObject->setChassisComponentMassMaximum(chassisComponentMassMaximum); + + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::isShipSlotInstalled(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "JavaLibrary::isShipSlotInstalled ship obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return false; + + return shipObject->isSlotInstalled(chassisSlot); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::isShipComponentDisabled(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipComponentDisabled() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->isComponentDisabled(chassisSlot); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::isShipComponentDisabledNeedsPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipComponentDisabledNeedsPower() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->isComponentDisabledNeedsPower(chassisSlot); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::isShipComponentLowPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipComponentLowPower() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->isComponentLowPower(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentArmorHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentArmorHitpointsMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentArmorHitpointsMaximum(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentArmorHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentArmorHitpointsCurrent() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentArmorHitpointsCurrent(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentEfficiencyGeneral(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentEfficiencyGeneral() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentEfficiencyGeneral(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentEfficiencyEnergy(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentEfficiencyEnergy() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentEfficiencyEnergy(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentEnergyMaintenanceRequirement(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentEnergyMaintenanceRequirement() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentEnergyMaintenanceRequirement(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentMass(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentMass() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentMass(chassisSlot); +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipComponentCrc(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentCrc() invalid ship", false); + if (!shipObject) + return false; + + return static_cast(shipObject->getComponentCrc(chassisSlot)); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentHitpointsCurrent() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentHitpointsCurrent(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentHitpointsMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentHitpointsMaximum(chassisSlot); +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipComponentFlags(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentFlags() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getComponentFlags(chassisSlot); +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipComponentName(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentName() invalid ship", false); + if (!shipObject) + return NULL; + + Unicode::String const & name = shipObject->getComponentName(chassisSlot); + if (!name.empty()) + return JavaString(name).getReturnValue(); + + ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc(shipObject->getComponentCrc(chassisSlot)); + if (shipComponentDescriptor) + { + ObjectTemplate const * const t = shipComponentDescriptor->getSharedObjectTemplate(); + if (t) + { + SharedObjectTemplate const * const sharedTemplate = t->asSharedObjectTemplate(); + if (sharedTemplate) + return JavaString("@"+sharedTemplate->getObjectName().getCanonicalRepresentation()).getReturnValue(); + } + } + return JavaString("").getReturnValue(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponDamageMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponDamageMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponDamageMaximum(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponDamageMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponDamageMinimum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponDamageMinimum(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEffectivenessShields(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEffectivenessShields() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponEffectivenessShields(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEffectivenessArmor(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEffectivenessArmor() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponEffectivenessArmor(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEnergyPerShot(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEnergyPerShot() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponEnergyPerShot(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponRefireRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponRefireRate(chassisSlot); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponActualRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponActualRefireRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponActualRefireRate(chassisSlot); +} +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipWeaponEfficiencyRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponEfficiencyRefireRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponEfficiencyRefireRate(chassisSlot); +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipWeaponAmmoCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponAmmoCurrent() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponAmmoCurrent(chassisSlot); +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipWeaponAmmoMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponAmmoMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getWeaponAmmoMaximum(chassisSlot); +} + + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipWeaponAmmoType(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipWeaponAmmoType() invalid ship", false); + if (!shipObject) + return false; + + return static_cast(shipObject->getWeaponAmmoType(chassisSlot)); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsFrontCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsFrontCurrent() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getShieldHitpointsFrontCurrent(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsFrontMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsFrontMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getShieldHitpointsFrontMaximum(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsBackCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsBackCurrent() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getShieldHitpointsBackCurrent(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldHitpointsBackMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldHitpointsBackMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getShieldHitpointsBackMaximum(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipShieldRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipShieldRechargeRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getShieldRechargeRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCapacitorEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCapacitorEnergyCurrent() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getCapacitorEnergyCurrent(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCapacitorEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCapacitorEnergyMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getCapacitorEnergyEffectiveMaximum(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipCapacitorEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipCapacitorEnergyRechargeRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getCapacitorEnergyRechargeRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineAccelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineAccelerationRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getEngineAccelerationRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineDecelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineDecelerationRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getEngineDecelerationRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEnginePitchAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEnginePitchAccelerationRateDegrees() invalid ship", false); + if (!shipObject) + return false; + + return convertRadiansToDegrees(shipObject->getEnginePitchAccelerationRate()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineYawAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineYawAccelerationRateDegrees() invalid ship", false); + if (!shipObject) + return false; + + return convertRadiansToDegrees(shipObject->getEngineYawAccelerationRate()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineRollAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineRollAccelerationRateDegrees() invalid ship", false); + if (!shipObject) + return false; + + return convertRadiansToDegrees(shipObject->getEngineRollAccelerationRate()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEnginePitchRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEnginePitchRateMaximumDegrees() invalid ship", false); + if (!shipObject) + return false; + + return convertRadiansToDegrees(shipObject->getEnginePitchRateMaximum()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineYawRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineYawRateMaximumDegrees() invalid ship", false); + if (!shipObject) + return false; + + return convertRadiansToDegrees(shipObject->getEngineYawRateMaximum()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineRollRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineRollRateMaximumDegrees() invalid ship", false); + if (!shipObject) + return false; + + return convertRadiansToDegrees(shipObject->getEngineRollRateMaximum()); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getEngineSpeedMaximum(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedRotationFactorMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedRotationFactorMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getEngineSpeedRotationFactorMaximum(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedRotationFactorMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedRotationFactorMinimum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getEngineSpeedRotationFactorMinimum(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipEngineSpeedRotationFactorOptimal(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipEngineSpeedRotationFactorOptimal() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getEngineSpeedRotationFactorOptimal(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipReactorEnergyGenerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipReactorEnergyGenerationRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getReactorEnergyGenerationRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyCurrent() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getBoosterEnergyCurrent(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getBoosterEnergyMaximum(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyRechargeRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getBoosterEnergyRechargeRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterEnergyConsumptionRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterEnergyConsumptionRate() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getBoosterEnergyConsumptionRate(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterAcceleration(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterAcceleration() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getBoosterAcceleration(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipBoosterSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipBoosterSpeedMaximum() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getBoosterSpeedMaximum(); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::isShipBoosterActive(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "isShipBoosterActive() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->isBoosterActive(); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipDroidInterfaceCommandSpeed(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipDroidInterfaceCommandSpeed() invalid ship", false); + if (!shipObject) + return false; + + return shipObject->getDroidInterfaceCommandSpeed(); +} + +//---------------------------------------------------------------------- +//---------------------------------------------------------------------- +// component setters +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentArmorHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentArmorHitpointsMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentArmorHitpointsMaximum()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentArmorHitpointsMaximum(chassisSlot, componentArmorHitpointsMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentArmorHitpointsMaximum (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentArmorHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentArmorHitpointsCurrent) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentArmorHitpointsCurrent()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentArmorHitpointsCurrent(chassisSlot, componentArmorHitpointsCurrent)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentArmorHitpointsCurrent (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentEfficiencyGeneral(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentEfficiencyGeneral) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentEfficiencyGeneral()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentEfficiencyGeneral(chassisSlot, componentEfficiencyGeneral)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentEfficiencyGeneral (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentEfficiencyEnergy(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentEfficiencyEnergy) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentEfficiencyEnergy()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentEfficiencyEnergy(chassisSlot, componentEfficiencyEnergy)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentEfficiencyEnergy (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentEnergyMaintenanceRequirement(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentEnergyMaintenanceRequirement) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentEnergyMaintenanceRequirement()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentEnergyMaintenanceRequirement(chassisSlot, componentEnergyMaintenanceRequirement)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentEnergyMaintenanceRequirement (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentMass(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentMass) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentMass()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentMass(chassisSlot, componentMass)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentMass (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentHitpointsCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentHitpointsCurrent) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentHitpointsCurrent()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentHitpointsCurrent(chassisSlot, componentHitpointsCurrent)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentHitpointsCurrent (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentHitpointsMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat componentHitpointsMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentHitpointsMaximum()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentHitpointsMaximum(chassisSlot, componentHitpointsMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentHitpointsMaximum (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentFlags(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint componentFlags) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentFlags()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentFlags(chassisSlot, componentFlags)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentFlags (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentName(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jstring componentName) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentName()", false, chassisSlot); + if (!shipObject) + return; + + if (componentName == NULL) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): null name")); + return; + } + + JavaStringParam const jsp(componentName); + Unicode::String nameString; + if (!JavaLibrary::convert(jsp, nameString)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): failed to convert name string")); + else + { + if (!shipObject->setComponentName(chassisSlot, nameString)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): component at slot [%d] error", chassisSlot)); + } +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentDisabled(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jboolean componentDisabled) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentDisabled()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentDisabled(chassisSlot, componentDisabled == JNI_TRUE)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentDisabled (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentDisabledNeedsPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jboolean componentDisabledNeedsPower) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentDisabledNeedsPower()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentDisabledNeedsPower(chassisSlot, componentDisabledNeedsPower == JNI_TRUE)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentDisabledNeedsPower(): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipComponentLowPower(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jboolean componentLowPower) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipComponentLowPower()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setComponentLowPower(chassisSlot, componentLowPower == JNI_TRUE)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentLowPower (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponDamageMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponDamageMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponDamageMaximum()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponDamageMaximum(chassisSlot, weaponDamageMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponDamageMaximum (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponDamageMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponDamageMinimum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponDamageMinimum()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponDamageMinimum(chassisSlot, weaponDamageMinimum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponDamageMinimum (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponEffectivenessShields(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEffectivenessShields) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEffectivenessShields()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponEffectivenessShields(chassisSlot, weaponEffectivenessShields)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEffectivenessShields (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponEffectivenessArmor(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEffectivenessArmor) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEffectivenessArmor()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponEffectivenessArmor(chassisSlot, weaponEffectivenessArmor)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEffectivenessArmor (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponEnergyPerShot(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEnergyPerShot) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEnergyPerShot()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponEnergyPerShot(chassisSlot, weaponEnergyPerShot)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEnergyPerShot (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponRefireRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponRefireRate()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponRefireRate(chassisSlot, weaponRefireRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponRefireRate (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponEfficiencyRefireRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jfloat weaponEfficiencyRefireRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponEfficiencyRefireRate()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponEfficiencyRefireRate(chassisSlot, weaponEfficiencyRefireRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponEfficiencyRefireRate (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponAmmoCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint weaponAmmoCurrent) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponAmmoCurrent()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponAmmoCurrent(chassisSlot, weaponAmmoCurrent)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponAmmoCurrent (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponAmmoMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint weaponAmmoMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponAmmoMaximum()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponAmmoMaximum(chassisSlot, weaponAmmoMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponAmmoMaximum (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipWeaponAmmoType(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jint weaponAmmoType) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipWeaponAmmoType()", false, chassisSlot); + if (!shipObject) + return; + + if (!shipObject->setWeaponAmmoType(chassisSlot, static_cast(weaponAmmoType))) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWeaponAmmoType (): component at slot [%d] error", chassisSlot)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsFrontCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsFrontCurrent) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsFrontCurrent()", false, ShipChassisSlotType::SCST_shield_0); + if (!shipObject) + return; + + if (!shipObject->setShieldHitpointsFrontCurrent(shieldHitpointsFrontCurrent)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsFrontCurrent (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsFrontMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsFrontMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsFrontMaximum()", false, ShipChassisSlotType::SCST_shield_0); + if (!shipObject) + return; + + if (!shipObject->setShieldHitpointsFrontMaximum(shieldHitpointsFrontMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsFrontMaximum (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsBackCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsBackCurrent) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsBackCurrent()", false, ShipChassisSlotType::SCST_shield_0); + if (!shipObject) + return; + + if (!shipObject->setShieldHitpointsBackCurrent(shieldHitpointsBackCurrent)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsBackCurrent (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipShieldHitpointsBackMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldHitpointsBackMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldHitpointsBackMaximum()", false, ShipChassisSlotType::SCST_shield_0); + if (!shipObject) + return; + + if (!shipObject->setShieldHitpointsBackMaximum(shieldHitpointsBackMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldHitpointsBackMaximum (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipShieldRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat shieldRechargeRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipShieldRechargeRate()", false, ShipChassisSlotType::SCST_shield_0); + if (!shipObject) + return; + + if (!shipObject->setShieldRechargeRate(shieldRechargeRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipShieldRechargeRate (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipCapacitorEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat capacitorEnergyCurrent) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCapacitorEnergyCurrent()", false, ShipChassisSlotType::SCST_capacitor); + if (!shipObject) + return; + + if (!shipObject->setCapacitorEnergyCurrent(capacitorEnergyCurrent)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCapacitorEnergyCurrent (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipCapacitorEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat capacitorEnergyMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCapacitorEnergyMaximum()", false, ShipChassisSlotType::SCST_capacitor); + if (!shipObject) + return; + + if (!shipObject->setCapacitorEnergyMaximum(capacitorEnergyMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCapacitorEnergyMaximum (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipCapacitorEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat capacitorEnergyRechargeRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCapacitorEnergyRechargeRate()", false, ShipChassisSlotType::SCST_capacitor); + if (!shipObject) + return; + + if (!shipObject->setCapacitorEnergyRechargeRate(capacitorEnergyRechargeRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCapacitorEnergyRechargeRate (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineAccelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineAccelerationRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineAccelerationRate()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineAccelerationRate(engineAccelerationRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineAccelerationRate (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineDecelerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineDecelerationRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineDecelerationRate()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineDecelerationRate(engineDecelerationRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineDecelerationRate (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEnginePitchAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat enginePitchAccelerationRateDegrees) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEnginePitchAccelerationRateDegrees()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEnginePitchAccelerationRate(convertDegreesToRadians(enginePitchAccelerationRateDegrees))) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEnginePitchAccelerationRateDegrees (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineYawAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineYawAccelerationRateDegrees) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineYawAccelerationRateDegrees()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineYawAccelerationRate(convertDegreesToRadians(engineYawAccelerationRateDegrees))) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineYawAccelerationRateDegrees (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineRollAccelerationRateDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineRollAccelerationRateDegrees) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineRollAccelerationRateDegrees()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineRollAccelerationRate(convertDegreesToRadians(engineRollAccelerationRateDegrees))) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineRollAccelerationRateDegrees (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEnginePitchRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat enginePitchRateMaximumDegrees) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEnginePitchRateMaximumDegrees()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEnginePitchRateMaximum(convertDegreesToRadians(enginePitchRateMaximumDegrees))) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEnginePitchRateMaximumDegrees (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineYawRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineYawRateMaximumDegrees) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineYawRateMaximumDegrees()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineYawRateMaximum(convertDegreesToRadians(engineYawRateMaximumDegrees))) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineYawRateMaximumDegrees (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineRollRateMaximumDegrees(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineRollRateMaximumDegrees) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineRollRateMaximumDegrees()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineRollRateMaximum(convertDegreesToRadians(engineRollRateMaximumDegrees))) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineRollRateMaximumDegrees (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedMaximum()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineSpeedMaximum(engineSpeedMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedMaximum (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedRotationFactorMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedRotationRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedRotationFactorMaximum()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineSpeedRotationFactorMaximum(engineSpeedRotationRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedRotationFactorMaximum(): component error %s", shipObject->getDebugInformation(false).c_str())); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedRotationFactorMinimum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedRotationRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedRotationFactorMinimum()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineSpeedRotationFactorMinimum(engineSpeedRotationRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedRotationFactorMinimum(): component error %s", shipObject->getDebugInformation(false).c_str())); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipEngineSpeedRotationFactorOptimal(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat engineSpeedRotationRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipEngineSpeedRotationFactorOptimal()", false, ShipChassisSlotType::SCST_engine); + if (!shipObject) + return; + + if (!shipObject->setEngineSpeedRotationFactorOptimal(engineSpeedRotationRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipEngineSpeedRotationFactorOptimal(): component error %s", shipObject->getDebugInformation(false).c_str())); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipReactorEnergyGenerationRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat reactorEnergyGenerationRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipReactorEnergyGenerationRate()", false, ShipChassisSlotType::SCST_reactor); + if (!shipObject) + return; + + if (!shipObject->setReactorEnergyGenerationRate(reactorEnergyGenerationRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipReactorEnergyGenerationRate (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyCurrent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyCurrent) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyCurrent()", false, ShipChassisSlotType::SCST_booster); + if (!shipObject) + return; + + if (!shipObject->setBoosterEnergyCurrent(boosterEnergyCurrent)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyCurrent (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyMaximum()", false, ShipChassisSlotType::SCST_booster); + if (!shipObject) + return; + + if (!shipObject->setBoosterEnergyMaximum(boosterEnergyMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyMaximum (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyRechargeRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyRechargeRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyRechargeRate()", false, ShipChassisSlotType::SCST_booster); + if (!shipObject) + return; + + if (!shipObject->setBoosterEnergyRechargeRate(boosterEnergyRechargeRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyRechargeRate (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipBoosterEnergyConsumptionRate(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterEnergyConsumptionRate) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterEnergyConsumptionRate()", false, ShipChassisSlotType::SCST_booster); + if (!shipObject) + return; + + if (!shipObject->setBoosterEnergyConsumptionRate(boosterEnergyConsumptionRate)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterEnergyConsumptionRate (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipBoosterAcceleration(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterAcceleration) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipBoosterAcceleration()", false, ShipChassisSlotType::SCST_booster); + if (!shipObject) + return; + + if (!shipObject->setBoosterAcceleration(boosterAcceleration)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterAcceleration (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipBoosterSpeedMaximum(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat boosterSpeedMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "isShipSlotInstalledActual()", false, ShipChassisSlotType::SCST_booster); + if (!shipObject) + return; + + if (!shipObject->setBoosterSpeedMaximum(boosterSpeedMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipBoosterSpeedMaximum (): component error")); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipDroidInterfaceCommandSpeed(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jfloat droidInterfaceCommandSpeed) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipDroidInterfaceCommandSpeed()", false, ShipChassisSlotType::SCST_droid_interface); + if (!shipObject) + return; + + if (!shipObject->setDroidInterfaceCommandSpeed(droidInterfaceCommandSpeed)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipDroidInterfaceCommandSpeed (): component error")); +} + +//---------------------------------------------------------------------- + +//-- component support + +jboolean JNICALL ScriptMethodsShipNamespace::shipCanInstallComponent(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot, jlong component) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "shipCanInstallComponent(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return false; + + TangibleObject * tangibleComponent = 0; + if (JavaLibrary::getObject (component, tangibleComponent) && tangibleComponent != NULL) + return shipObject->canInstallComponent(chassisSlot, *tangibleComponent); + else + { + JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipCanInstallComponent(): invalid component")); + return false; + } +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::shipPseudoInstallComponent(JNIEnv *env, jobject, jlong jship, jint chassisSlot, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "shipInstallComponent(): ship obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return false; + + return shipObject->pseudoInstallComponent(static_cast(chassisSlot), static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::shipInstallComponent(JNIEnv * env, jobject /*self*/, jlong jobject_installerId, jlong jobject_shipId, jint chassisSlot, jlong component) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "shipInstallComponent(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return false; + + NetworkId installerId(jobject_installerId); + + TangibleObject * tangibleComponent = 0; + if (JavaLibrary::getObject (component, tangibleComponent) && tangibleComponent != NULL) + return shipObject->installComponent(installerId, chassisSlot, *tangibleComponent); + else + { + JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipInstallComponent(): invalid component")); + return false; + } +} + +//---------------------------------------------------------------------- +jlong JNICALL ScriptMethodsShipNamespace::shipUninstallComponentAllowOverload(JNIEnv * env, jobject self, jlong jobject_uninstallerId, jlong jobject_shipId, jint chassisSlot, jlong containerTarget) +{ + return shipUninstallComponentBase(env, self, jobject_uninstallerId, jobject_shipId, chassisSlot, containerTarget, true); +} + +jlong JNICALL ScriptMethodsShipNamespace::shipUninstallComponent(JNIEnv * env, jobject self, jlong jobject_uninstallerId, jlong jobject_shipId, jint chassisSlot, jlong containerTarget) +{ + return shipUninstallComponentBase(env, self, jobject_uninstallerId, jobject_shipId, chassisSlot, containerTarget, false); +} + +jlong JNICALL ScriptMethodsShipNamespace::shipUninstallComponentBase(JNIEnv * env, jobject /*self*/, jlong jobject_uninstallerId, jlong jobject_shipId, jint chassisSlot, jlong containerTarget, bool allowOverload) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "shipUninstallComponent(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return 0; + + ServerObject * containerTargetObject = 0; + + if (containerTarget) + { + if (!JavaLibrary::getObject (containerTarget, containerTargetObject)) + { + JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipUninstallComponent(): containerTarget did not resolve")); + return 0; + } + + NetworkId uninstallerId(jobject_uninstallerId); + + TangibleObject * const component = shipObject->uninstallComponent(uninstallerId, chassisSlot, *containerTargetObject, allowOverload); + if (component) + return (component->getNetworkId()).getValue(); + else + { + JAVA_THROW_SCRIPT_EXCEPTION (true, ("shipUninstallComponent(): invalid result component")); + return 0; + } + } + else + { + shipObject->purgeComponent (chassisSlot); + return 0; + } +} + + +//---------------------------------------------------------------------- + +jintArray JNICALL ScriptMethodsShipNamespace::getShipChassisSlots(JNIEnv * env, jobject /*self*/, jlong jobject_shipId) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return NULL; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipChassisSlots(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return NULL; + + ShipChassis const * const shipChassis = ShipChassis::findShipChassisByCrc (shipObject->getChassisType()); + if (shipChassis) + { + ShipChassis::SlotVector const & slots = shipChassis->getSlots (); + + LocalIntArrayRefPtr jslots = createNewIntArray(static_cast(slots.size ())); + if (jslots != LocalIntArrayRef::cms_nullPtr) + { + int index = 0; + for (ShipChassis::SlotVector::const_iterator it = slots.begin (); it != slots.end (); ++it, ++index) + { + ShipChassisSlot const & slot = *it; + jint value = static_cast(slot.getSlotType ()); + setIntArrayRegion(*jslots, index, 1, &value); + } + return jslots->getReturnValue(); + } + } + + return NULL; +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorType(JNIEnv * /*env*/, jobject /*self*/, jlong jobject_component) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return static_cast(ShipComponentType::SCT_num_types); + + TangibleObject * tangibleComponent = 0; + if (JavaLibrary::getObject (jobject_component, tangibleComponent)) + { + if (tangibleComponent != NULL && tangibleComponent->getObjectTemplate () != NULL) + { + ShipComponentDescriptor const * const shipComponentDescriptor = + ShipComponentDescriptor::findShipComponentDescriptorByObjectTemplate (tangibleComponent->getObjectTemplate ()->getCrcName ().getCrc ()); + if (shipComponentDescriptor) + return static_cast(shipComponentDescriptor->getComponentType ()); + } + } + + return static_cast(ShipComponentType::SCT_num_types); +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorTypeByName(JNIEnv * /*env*/, jobject /*self*/, jstring typeName) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return static_cast(ShipComponentType::SCT_num_types); + + JavaStringParam const jsp(typeName); + std::string nameString; + if (!JavaLibrary::convert(jsp, nameString)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipComponentDescriptorTypeByName (): failed to convert typeName string")); + else + { + return ShipComponentType::getTypeFromName(nameString); + } + + return static_cast(ShipComponentType::SCT_num_types); +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorTypeName(JNIEnv * /*env*/, jobject /*self*/, jint componentType) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return NULL; + + std::string const & typeName = ShipComponentType::getNameFromType(static_cast(componentType)); + + return JavaString(typeName).getReturnValue(); +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorCrc(JNIEnv * /*env*/, jobject /*self*/, jlong jobject_component) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return static_cast(ShipComponentType::SCT_num_types); + + TangibleObject * tangibleComponent = 0; + if (JavaLibrary::getObject (jobject_component, tangibleComponent)) + { + if (tangibleComponent != NULL && tangibleComponent->getObjectTemplate () != NULL) + { + ShipComponentDescriptor const * const shipComponentDescriptor = + ShipComponentDescriptor::findShipComponentDescriptorByObjectTemplate (tangibleComponent->getObjectTemplate ()->getCrcName ().getCrc ()); + if (shipComponentDescriptor) + return static_cast(shipComponentDescriptor->getCrc ()); + } + } + + return 0; +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorCrcName(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return NULL; + + ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc(static_cast(componentCrc)); + if (shipComponentDescriptor == NULL) + return NULL; + + return JavaString(shipComponentDescriptor->getName().getString()).getReturnValue(); +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorCompatibility(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return NULL; + + ShipComponentDescriptor const * const shipComponentDescriptor = ShipComponentDescriptor::findShipComponentDescriptorByCrc(static_cast(componentCrc)); + if (shipComponentDescriptor == NULL) + return NULL; + + return JavaString(shipComponentDescriptor->getCompatibility().getString()).getReturnValue(); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsAmmoConsuming(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + return ShipComponentWeaponManager::isAmmoConsuming(static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsMissile(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + return ShipComponentWeaponManager::isMissile(static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsCountermeasure(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + return ShipComponentWeaponManager::isCountermeasure(static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsMining(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + return ShipComponentWeaponManager::isMining(static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponIsTractor(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return false; + + return ShipComponentWeaponManager::isTractor(static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponRange(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.0f; + + return ShipComponentWeaponManager::getRange(static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipComponentDescriptorWeaponProjectileSpeed(JNIEnv * /*env*/, jobject /*self*/, jint componentCrc) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return 0.0f; + + return ShipComponentWeaponManager::getProjectileSpeed(static_cast(componentCrc)); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::notifyShipDamage(JNIEnv * env, jobject /*self*/, jlong jobject_victim, jlong jobject_attacker, jfloat totalDamage) +{ + //-- Make sure ships are enabled + if (!verifyShipsEnabled()) + return; + + //-- Get the victim ship object. + ShipObject * const victimShipObject = JavaLibrary::getShipThrow(env, jobject_victim, "notifyShipDamage(): jobject_victim did not resolve to a ShipObject", false); + if (victimShipObject) + { + //-- Ensure we have a player controlled ship object. + if (victimShipObject->isPlayerShip()) + { + //-- Get the attacker object. It can be any tangible object. + TangibleObject const * attackerTangibleObject = NULL; + if (jobject_attacker) + IGNORE_RETURN(JavaLibrary::getObject(jobject_attacker, attackerTangibleObject)); + + Controller * const victimShipController = victimShipObject->getController(); + if (victimShipController) + { + ShipDamageMessage shipDamage(attackerTangibleObject != NULL ? attackerTangibleObject->getNetworkId() : NetworkId::cms_invalid, + attackerTangibleObject != NULL ? attackerTangibleObject->getPosition_w() : victimShipObject->getPosition_w(), + totalDamage ); + + //lint -esym(429, damageMessage) + + MessageQueueGenericValueType * const damageMessage = new MessageQueueGenericValueType(shipDamage); + + victimShipController->appendMessage(CM_shipDamageMessage, 0.0f, damageMessage, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); + } + } + } +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::launchMissile(JNIEnv * /*env*/, jobject /*self*/, jlong jplayer, jlong jship, jlong jtarget, jint missileInfo, jint targetedComponent) +{ + if (!verifyShipsEnabled()) + return false; + + const TangibleObject * player = 0; + if (!JavaLibrary::getObject (jplayer, player)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::launchMissile: could not resolve player")); + return JNI_FALSE; + } + + const TangibleObject * ship = 0; + if (!JavaLibrary::getObject (jship, ship)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::launchMissile: could not resolve ship")); + return JNI_FALSE; + } + + const TangibleObject * target = 0; + if (!JavaLibrary::getObject (jtarget, target)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::launchMissile: could not resolve target")); + return JNI_FALSE; + } + + if (player && ship && target) + return MissileManager::getInstance().requestFireMissile(player->getNetworkId(), ship->getNetworkId(), target->getNetworkId(), -1, missileInfo, getSlotType(targetedComponent)); + else + return JNI_FALSE; +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::launchCountermeasure(JNIEnv * /*env*/, jobject /*self*/, jlong ship, jint targettedMissile, jboolean successful, jint countermeasureType) +{ + if (!verifyShipsEnabled()) + return false; + + NetworkId const shipId(ship); + + bool result= MissileManager::getInstance().fireCountermeasure(shipId, targettedMissile, (successful==static_cast(JNI_TRUE)), countermeasureType); + return result ? static_cast(JNI_TRUE) : static_cast(JNI_FALSE); +} + +// ---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getNearestUnlockedMissileForTarget(JNIEnv * /*env*/, jobject /*self*/, jlong jtarget) +{ + return MissileManager::getInstance().getNearestUnlockedMissileForTarget(NetworkId(jtarget)); +} + +// ---------------------------------------------------------------------- + +jintArray JNICALL ScriptMethodsShipNamespace::getAllUnlockedMissilesForTarget(JNIEnv * env, jobject /*self*/, jlong jtarget) +{ + std::vector missiles; + MissileManager::getInstance().getAllUnlockedMissilesForTarget(NetworkId(jtarget),missiles); + + LocalIntArrayRefPtr results = createNewIntArray(static_cast(missiles.size())); + + setIntArrayRegion(*results, 0 , static_cast(missiles.size()), reinterpret_cast(&(missiles[0]))); + return results->getReturnValue(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::destroyMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) +{ + return (MissileManager::getInstance().destroyMissile(missileId)) ? static_cast(JNI_TRUE) : static_cast(JNI_FALSE); +} + +// ---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getTypeByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) +{ + const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); + if (missile) + return missile->getType(); + else + return -1; +} + +// ---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getWeaponIndexByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) +{ + const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); + if (missile) + return missile->getWeaponIndex(); + else + return -1; +} + +// ---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getTimeSinceFiredByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) +{ + const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); + if (missile) + return missile->getTimeSinceFired(); + else + return -1; +} + +// ---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getTotalTimeByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) +{ + const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); + if (missile) + return missile->getTotalTime(); + else + return -1; +} + +// ---------------------------------------------------------------------- + +jlong JNICALL ScriptMethodsShipNamespace::getWhoFiredByMissile(JNIEnv * /*env*/, jobject /*self*/, jint missileId) +{ + const Missile* missile = MissileManager::getInstance().getConstMissile(missileId); + if (missile) + return (missile->getSource()).getValue(); + else + return 0; +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setLookAtTargetShipComponent(JNIEnv * env, jobject /*self*/, jlong jship, jint targetedComponentChassisSlot) +{ + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "setLookAtTargetShipComponent(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + shipObject->setPilotLookAtTargetSlot(getSlotType(targetedComponentChassisSlot)); + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getLookAtTargetShipComponent(JNIEnv * env, jobject /*self*/, jlong jship) +{ + if (!verifyShipsEnabled()) + return static_cast(ShipChassisSlotType::SCST_num_types); + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "getLookAtTargetShipComponent(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return static_cast(ShipChassisSlotType::SCST_num_types); + + return static_cast(shipObject->getPilotLookAtTargetSlot()); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::associateDroidControlDeviceWithShip(JNIEnv * env, jobject /*self*/, jlong jship, jlong jdroidControlDevice) +{ + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "associateDroidControlDeviceWithShip(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + const ServerObject * droidControlDevice = 0; + if (!JavaLibrary::getObject (jdroidControlDevice, droidControlDevice)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::associateDroidControlDeviceWithShip: could not resolve droid control device")); + return JNI_FALSE; + } + + shipObject->setInstalledDroidControlDevice(droidControlDevice->getNetworkId()); + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::removeDroidControlDeviceFromShip(JNIEnv * env, jobject /*self*/, jlong jship) +{ + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jship, "removeDroidControlDeviceFromShip(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + shipObject->setInstalledDroidControlDevice(NetworkId::cms_invalid); + return JNI_TRUE; +} + +// ---------------------------------------------------------------------- + +jlong JNICALL ScriptMethodsShipNamespace::getDroidControlDeviceForShip(JNIEnv * env, jobject /*self*/, jlong jship) +{ + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jship, "getDroidControlDeviceForShip(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + NetworkId const & droidControlDeviceId = shipObject->getInstalledDroidControlDevice(); + Object const * const droidControlDevice = NetworkIdManager::getObjectById(droidControlDeviceId); + ServerObject const * const serverDroidControlDevice = droidControlDevice ? droidControlDevice->asServerObject() : NULL; + if(!serverDroidControlDevice) + return 0; + else + return (serverDroidControlDevice->getNetworkId()).getValue(); +} + +// ---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::commPlayers(JNIEnv *env, jobject /*self*/, jlong jtaunter, jstring jappearanceOverloadServerTemplate, jstring jSoundEffect, jfloat jDuration, jlongArray jplayers, jstring jtauntOob, jboolean chronicles) +{ + ServerObject const *taunter = 0; + if (!JavaLibrary::getObject(jtaunter, taunter)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::commPlayers: could not resolve taunter")); + return; + } + + Unicode::String oob; + if (jtauntOob) + { + JavaStringParam localTauntOob(jtauntOob); + if (!JavaLibrary::convert(localTauntOob, oob)) + { + JAVA_THROW_SCRIPT_EXCEPTION (true, ("JavaLibrary::commPlayers unable to convert tauntOob")); + return; + } + } + + Unicode::String appearanceOverloadServerTemplateWide; + if (jappearanceOverloadServerTemplate) + { + JavaStringParam localAppearanceOverloadServerTemplate(jappearanceOverloadServerTemplate); + if (!JavaLibrary::convert(localAppearanceOverloadServerTemplate, appearanceOverloadServerTemplateWide)) + { + JAVA_THROW_SCRIPT_EXCEPTION (true, ("JavaLibrary::commPlayers unable to convert jappearanceOverloadServerTemplate to a string")); + return; + } + } + + uint32 appearanceOverloadSharedTemplateCrc = 0; + ObjectTemplate const * const ot = ObjectTemplateList::fetch(Unicode::wideToNarrow(appearanceOverloadServerTemplateWide)); + ServerObjectTemplate const * const sot = ot ? ot->asServerObjectTemplate() : NULL; + if(sot) + { + std::string const & sharedTemplateName = sot->getSharedTemplate(); + appearanceOverloadSharedTemplateCrc = Crc::calculate(sharedTemplateName.c_str()); + } + + typedef std::map > DistributionList; + DistributionList distributionList; + + jsize const count = env->GetArrayLength(jplayers); + jlong jlongTmp; + for (jsize i = 0; i < count; ++i) + { + ServerObject const *player = 0; + env->GetLongArrayRegion(jplayers, i, 1, &jlongTmp); + if (JavaLibrary::getObject(jlongTmp, player)) + { + Client * const client = player->getClient(); + if (client) + distributionList[client->getConnection()].push_back(client->getCharacterObjectId()); + } + } + + std::string soundEffect; + if (jSoundEffect) + { + JavaStringParam soundEffectParam(jSoundEffect); + if (!JavaLibrary::convert(soundEffectParam, soundEffect)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::commPlayers unable to convert jSoundEffect to a string.")); + return; + } + } + + bool chroniclesMessage = (chronicles == JNI_TRUE ? true : false); + if (!distributionList.empty()) + { + GenericValueTypeMessage > > > > > const message("CommPlayerMessage", std::make_pair(chroniclesMessage, std::make_pair(taunter->getNetworkId(), std::make_pair(oob, std::make_pair(appearanceOverloadSharedTemplateCrc, std::make_pair(soundEffect, jDuration)))))); + for (DistributionList::const_iterator iter = distributionList.begin(); iter != distributionList.end(); ++iter) + { + GameClientMessage const gcm( + (*iter).second, + true, + message); + (*iter).first->send(gcm, true); + } + } +} + +// ---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipSlotTargetable(JNIEnv * env, jobject /*self*/, jlong jshipId, jint slot, jboolean targetable) +{ + if (!verifyShipsEnabled()) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentTargetable ships not enabled")); + return; + } + + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jshipId, "setShipComponentTargetable(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return; + + if(targetable) + shipObject->setSlotTargetable(getSlotType(slot)); + else + shipObject->clearSlotTargetable(getSlotType(slot)); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::isShipSlotTargetable(JNIEnv * env, jobject /*self*/, jlong jshipId, jint slot) +{ + if (!verifyShipsEnabled()) + return JNI_FALSE; + + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, jshipId, "getShipComponentTargetable(): shipId obj_id did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + bool const result = shipObject->getSlotTargetable(getSlotType(slot)); + if(result) + return JNI_TRUE; + else + return JNI_FALSE; +} + +//-------------------------------------------------------------------------------- + +jlong JNICALL ScriptMethodsShipNamespace::launchShipFromHangar(JNIEnv *env, jobject /*self*/, jlong jlaunchingShipId, jstring templateToSpawn, jobject deltaFromHangarHardpoint) +{ + if (!verifyShipsEnabled()) + return 0; + + //convert ship + ShipObject * const launchingShip = JavaLibrary::getShipThrow(env, jlaunchingShipId, "getShipComponentTargetable(): shipId obj_id did not resolve to a ShipObject", false); + if (!launchingShip) + return 0; + + //convert transform + Transform deltaFromHangarTransform; + if (!ScriptConversion::convert(deltaFromHangarHardpoint, deltaFromHangarTransform)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("[designer bug] JavaLibrary::spawnShipFromHangar called with bad transform")); + return 0; + } + + // get the template name into an std::string + JavaStringParam const localSource(templateToSpawn); + std::string templateName; + IGNORE_RETURN(JavaLibrary::convert(localSource, templateName)); + + ConstCharCrcString const crcName(ObjectTemplateList::lookUp(templateName.c_str())); + if (crcName.getCrc() == 0) + + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("[designer bug] JavaLibrary::spawnShipFromHangar called with unknown template %s", templateName.c_str())); + return 0; + } + + //put spawned ship in same cell as the launching ship + ServerObject *cell = 0; + CellProperty * const cellProperty = launchingShip->getParentCell(); + if (cellProperty && cellProperty != CellProperty::getWorldCellProperty()) + cell = safe_cast(&cellProperty->getOwner()); + + //get the hardpoint from the launching ship + Transform hangarHardpointDelta; + Appearance const * const launchingShipAppearance = launchingShip->getAppearance(); + if(launchingShipAppearance) + { + static char const * const hangarHardpointName = "hangar"; + if (!launchingShipAppearance->findHardpoint(ConstCharCrcLowerString(hangarHardpointName), hangarHardpointDelta)) + WARNING(true, ("JavaLibrary::launchShipFromHangar - could not find hangar hardpoint [%s] for %s, launching from center of ship", hangarHardpointName, launchingShip->getNetworkId().getValueString().c_str())); + } + else + { + WARNING(true, ("JavaLibrary::launchShipFromHangar - could not find hangar %s, which has no appearance.", launchingShip->getNetworkId().getValueString().c_str())); + } + + //build the final hangar offset from the hangar hardpoint transform and the delta transform from script + Transform finalHangarDelta_o(Transform::IF_none); + finalHangarDelta_o.multiply(hangarHardpointDelta, deltaFromHangarTransform); + Transform const & finalCreateTransform = launchingShip->getTransform_o2p().rotateTranslate_l2p(finalHangarDelta_o); + + ServerObject * const newShip = ServerWorld::createNewObject(crcName.getCrc(), finalCreateTransform, cell, false); + if (newShip == NULL) + return 0; + + // create an objId to return + NetworkId netId = newShip->getNetworkId(); + if (netId == NetworkId::cms_invalid) + { + delete newShip; + return 0; + } + + if (!cell) + newShip->addToWorld(); + + return netId.getValue(); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::handleShipDestruction(JNIEnv * env, jobject /*self*/, jlong jship, jfloat severity) +{ + if (!verifyShipsEnabled()) + return; + + //convert ship + ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "handleShipDestruction(): shipId obj_id did not resolve to a ShipObject", false); + if (ship == NULL) + return; + + DestroyShipMessage const msg(ship->getNetworkId(), severity); + sendGameNetworkMessageToObservers(*ship, msg, true); + + if (ship->isPlayerShip()) + Pvp::removeDuelEnemyFlags(*ship, NetworkId::cms_invalid); + else + IGNORE_RETURN(ship->permanentlyDestroy(DeleteReasons::Script)); + + //@todo: we must handle player ship destruction differently +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::handleShipComponentDestruction(JNIEnv * env, jobject /*self*/, jlong jship, jint chassisSlot, jfloat severity) +{ + ShipObject * const ship = getShipThrowTestSlot(env, jship, "handleShipComponentDestruction()", false, chassisSlot); + if (!ship) + return; + + DestroyShipComponentMessage const msg(ship->getNetworkId(), chassisSlot, severity); + sendGameNetworkMessageToObservers(*ship, msg, true); + + ship->purgeComponent(chassisSlot); +} + +// ---------------------------------------------------------------------- + +jlongArray JNICALL ScriptMethodsShipNamespace::getObservedShips(JNIEnv *, jobject, jlong jsource, jboolean excludeSource) +{ + ServerObject const *source = 0; + if (JavaLibrary::getObject(jsource, source)) + { + std::vector visibleObjects; + SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); + if (!visibleObjects.empty()) + { + std::vector results(visibleObjects.size()); + for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) + if ( (*i)->asShipObject() + && ((*i) != source || !excludeSource)) + results.push_back(*i); + if (!results.empty()) + { + LocalLongArrayRefPtr rv; + if (ScriptConversion::convert(results, rv)) + return rv->getReturnValue(); + } + } + } + return 0; +} + +// ---------------------------------------------------------------------- + +jlongArray JNICALL ScriptMethodsShipNamespace::getObservedPlayerShips(JNIEnv *, jobject, jlong jsource, jboolean excludeSource) +{ + ServerObject const *source = 0; + if (JavaLibrary::getObject(jsource, source)) + { + std::vector visibleObjects; + SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); + if (!visibleObjects.empty()) + { + std::vector results(visibleObjects.size()); + for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) + { + ShipObject * const ship = (*i)->asShipObject(); + if ( ship + && ship->isPlayerShip() + && ((*i) != source || !excludeSource)) + results.push_back(*i); + } + if (!results.empty()) + { + LocalLongArrayRefPtr rv; + if (ScriptConversion::convert(results, rv)) + return rv->getReturnValue(); + } + } + } + return 0; +} + +// ---------------------------------------------------------------------- + +jlongArray JNICALL ScriptMethodsShipNamespace::getObservedEnemyShips(JNIEnv *, jobject, jlong jsource) +{ + ShipObject const *source = 0; + if (JavaLibrary::getObject(jsource, source)) + { + std::vector visibleObjects; + SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); + if (!visibleObjects.empty()) + { + std::vector results(visibleObjects.size()); + for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) + { + ShipObject * const ship = (*i)->asShipObject(); + if ( ship + && Pvp::isEnemy(*source, *ship)) + results.push_back(*i); + } + if (!results.empty()) + { + LocalLongArrayRefPtr rv; + if (ScriptConversion::convert(results, rv)) + return rv->getReturnValue(); + } + } + } + return 0; +} + +// ---------------------------------------------------------------------- + +jlongArray JNICALL ScriptMethodsShipNamespace::getObservedEnemyPlayerShips(JNIEnv *, jobject, jlong jsource) +{ + ShipObject const *source = 0; + if (JavaLibrary::getObject(jsource, source)) + { + std::vector visibleObjects; + SpaceVisibilityManager::getObjectsVisibleFromLocation(source->getPosition_w(), visibleObjects); + if (!visibleObjects.empty()) + { + std::vector results(visibleObjects.size()); + for (std::vector::const_iterator i = visibleObjects.begin(); i != visibleObjects.end(); ++i) + { + ShipObject * const ship = (*i)->asShipObject(); + if ( ship + && ship->isPlayerShip() + && Pvp::isEnemy(*source, *ship)) + results.push_back(*i); + } + if (!results.empty()) + { + LocalLongArrayRefPtr rv; + if (ScriptConversion::convert(results, rv)) + return rv->getReturnValue(); + } + } + } + return 0; +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipInternalDamageOverTime(JNIEnv * env, jobject, jlong jship, jint chassisSlot, jfloat damageRate, jfloat damageThreshold) +{ + ShipObject * const ship = getShipThrowTestSlot(env, jship, "setShipInternalDamageOverTime()", false, chassisSlot); + if (!ship) + return false; + + return ShipInternalDamageOverTimeManager::setEntry(*ship, chassisSlot, damageRate, damageThreshold); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::removeShipInternalDamageOverTime(JNIEnv * env, jobject, jlong jship, jint chassisSlot) +{ + ShipObject * const ship = getShipThrowTestSlot(env, jship, "removeShipInternalDamageOverTime()", false, chassisSlot); + if (!ship) + return false; + + return ShipInternalDamageOverTimeManager::removeEntry(*ship, chassisSlot); +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipInternalDamageOverTimeDamageRate(JNIEnv * env, jobject, jlong jship, jint chassisSlot) +{ + ShipObject * const ship = getShipThrowTestSlot(env, jship, "getShipInternalDamageOverTimeDamageThreshold()", false, chassisSlot); + if (!ship) + return 0.0f; + + static ShipInternalDamageOverTime const * const idot = ShipInternalDamageOverTimeManager::findEntry(*ship, chassisSlot); + if (idot == NULL) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipInternalDamageOverTimeDamageThreshold idot for [%s] slot [%d] not found", ship->getNetworkId().getValueString().c_str(), chassisSlot)); + return 0.0f; + } + + return idot->getDamageRate(); +} + +// ---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipInternalDamageOverTimeDamageThreshold(JNIEnv * env, jobject, jlong jship, jint chassisSlot) +{ + ShipObject * const ship = getShipThrowTestSlot(env, jship, "getShipInternalDamageOverTimeDamageThreshold()", false, chassisSlot); + if (!ship) + return 0.0f; + + static ShipInternalDamageOverTime const * const idot = ShipInternalDamageOverTimeManager::findEntry(*ship, chassisSlot); + if (idot == NULL) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipInternalDamageOverTimeDamageThreshold idot for [%s] slot [%d] not found", ship->getNetworkId().getValueString().c_str(), chassisSlot)); + return 0.0f; + } + + return idot->getDamageThreshold(); +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::hasShipInternalDamageOverTime(JNIEnv * env, jobject, jlong jship, jint chassisSlot) +{ + if (!verifyShipsEnabled()) + return false; + + //convert ship + ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "hasShipInternalDamageOverTime(): shipId obj_id did not resolve to a ShipObject", false); + if (ship == NULL) + return false; + + static ShipInternalDamageOverTime const * const idot = ShipInternalDamageOverTimeManager::findEntry(*ship, chassisSlot); + return idot != NULL; +} + +// ---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::shipGetSpaceFaction(JNIEnv *env, jobject, jlong jship) +{ + ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFaction(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + return static_cast(ship->getSpaceFaction()); + return 0; +} + +// ---------------------------------------------------------------------- + +jintArray JNICALL ScriptMethodsShipNamespace::shipGetSpaceFactionAllies(JNIEnv *env, jobject, jlong jship) +{ + ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFactionAllies(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + { + std::vector const &factionList = ship->getSpaceFactionAllies(); + if (!factionList.empty()) + { + LocalIntArrayRefPtr ret = createNewIntArray(static_cast(factionList.size())); + setIntArrayRegion(*ret, 0, static_cast(factionList.size()), reinterpret_cast(const_cast(&factionList[0]))); + return ret->getReturnValue(); + } + } + return 0; +} + +// ---------------------------------------------------------------------- + +jintArray JNICALL ScriptMethodsShipNamespace::shipGetSpaceFactionEnemies(JNIEnv *env, jobject, jlong jship) +{ + ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFactionEnemies(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + { + std::vector const &factionList = ship->getSpaceFactionEnemies(); + if (!factionList.empty()) + { + LocalIntArrayRefPtr ret = createNewIntArray(static_cast(factionList.size())); + setIntArrayRegion(*ret, 0, static_cast(factionList.size()), reinterpret_cast(const_cast(&factionList[0]))); + return ret->getReturnValue(); + } + } + return 0; +} + +// ---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::shipGetSpaceFactionIsAggro(JNIEnv *env, jobject, jlong jship) +{ + ShipObject const * const ship = JavaLibrary::getShipThrow(env, jship, "shipGetSpaceFactionIsAggro(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + return static_cast(ship->getSpaceFactionIsAggro()); + return JNI_FALSE; +} + +// ---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFaction(JNIEnv *env, jobject, jlong jship, jint spaceFaction) +{ + ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFaction(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + ship->setSpaceFaction(static_cast(spaceFaction)); +} + +// ---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFactionAllies(JNIEnv *env, jobject, jlong jship, jintArray jfactionList) +{ + ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFactionAllies(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + { + std::vector factionList; + if (jfactionList) + { + unsigned int const factionCount = static_cast(env->GetArrayLength(jfactionList)); + if (factionCount > 0) + { + factionList.reserve(factionCount); + jint * const factionArray = env->GetIntArrayElements(jfactionList, 0); + for (unsigned int i = 0; i < factionCount; ++i) + factionList.push_back(static_cast(factionArray[i])); + env->ReleaseIntArrayElements(jfactionList, factionArray, JNI_ABORT); + } + } + ship->setSpaceFactionAllies(factionList); + } +} + +// ---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFactionEnemies(JNIEnv *env, jobject, jlong jship, jintArray jfactionList) +{ + ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFactionEnemies(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + { + std::vector factionList; + if (jfactionList) + { + unsigned int const factionCount = static_cast(env->GetArrayLength(jfactionList)); + if (factionCount > 0) + { + factionList.reserve(factionCount); + jint * const factionArray = env->GetIntArrayElements(jfactionList, 0); + for (unsigned int i = 0; i < factionCount; ++i) + factionList.push_back(static_cast(factionArray[i])); + env->ReleaseIntArrayElements(jfactionList, factionArray, JNI_ABORT); + } + } + ship->setSpaceFactionEnemies(factionList); + } +} + +// ---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::shipSetSpaceFactionIsAggro(JNIEnv *env, jobject, jlong jship, jboolean isAggro) +{ + ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipSetSpaceFactionIsAggro(): shipId obj_id did not resolve to a ShipObject", false); + if (ship) + ship->setSpaceFactionIsAggro(isAggro ? true : false); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::shipIsInNebula(JNIEnv *env, jobject, jlong jship, jstring j_nebulaName) +{ + ShipObject * const ship = JavaLibrary::getShipThrow(env, jship, "shipIsInNebula(): shipId obj_id did not resolve to a ShipObject", false); + if (!ship) + return JNI_FALSE; + + std::string nebulaName; + + if (NULL != j_nebulaName) + { + JavaStringParam const jsp(j_nebulaName); + if (!JavaLibrary::convert(jsp, nebulaName)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::shipIsInNebula (): failed to convert nebulaName string")); + } + + ShipObject::IntVector const & nebulas = ship->getNebulas(); + + //-- empty nebula name matches any nebula + if (nebulaName.empty() && !nebulas.empty()) + return JNI_TRUE; + + for (ShipObject::IntVector::const_iterator it = nebulas.begin(); it != nebulas.end(); ++it) + { + int const id = *it; + Nebula const * const nebula = NebulaManager::getNebulaById(id); + if (NULL != nebula) + { + if (nebula->getName() == nebulaName) + return JNI_TRUE; + } + } + + return JNI_FALSE; +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipWingName(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) +{ + ServerObject * object = 0; + if(!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert target")); + return JNI_FALSE; + } + ShipObject * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): target not a ship")); + return JNI_FALSE; + } + + JavaStringParam const jsp(jstr); + std::string wingName; + if (!JavaLibrary::convert(jsp, wingName)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); + return JNI_FALSE; + } + + ship->setWingName(wingName); + + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipWingName(JNIEnv * /*env*/, jobject /*self*/, jlong target) +{ + ServerObject const * object = NULL; + if (!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipWingName (): could not convert the target")); + return 0; + } + ShipObject const * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipWingName (): target is not a ship")); + return 0; + } + + return JavaString(ship->getWingName()).getReturnValue(); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipTypeName(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) +{ + ServerObject * object = 0; + if(!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipTypeName (): failed to convert target")); + return JNI_FALSE; + } + ShipObject * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipTypeName (): target not a ship")); + return JNI_FALSE; + } + + JavaStringParam const jsp(jstr); + std::string typeName; + if (!JavaLibrary::convert(jsp, typeName)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); + return JNI_FALSE; + } + ship->setTypeName(typeName); + + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipTypeName(JNIEnv * /*env*/, jobject /*self*/, jlong target) +{ + ServerObject const * object = NULL; + if (!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipTypeName (): could not convert the target")); + return 0; + } + ShipObject const * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipTypeName (): target is not a ship")); + return 0; + } + + return JavaString(ship->getTypeName()).getReturnValue(); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipDifficulty(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) +{ + ServerObject * object = 0; + if(!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipDifficultyName (): failed to convert target")); + return JNI_FALSE; + } + ShipObject * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipDifficultyName (): target not a ship")); + return JNI_FALSE; + } + + JavaStringParam const jsp(jstr); + std::string difficulty; + if (!JavaLibrary::convert(jsp, difficulty)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); + return JNI_FALSE; + } + ship->setDifficulty(difficulty); + + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipDifficulty(JNIEnv * /*env*/, jobject /*self*/, jlong target) +{ + ServerObject const * object = NULL; + if (!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipDifficulty (): could not convert the target")); + return 0; + } + ShipObject const * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipDifficulty (): target is not a ship")); + return 0; + } + return JavaString(ship->getDifficulty()).getReturnValue(); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::setShipFaction(JNIEnv * /*env*/, jobject /*self*/, jlong target, jstring jstr) +{ + ServerObject * object = 0; + if(!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipFactionName (): failed to convert target")); + return JNI_FALSE; + } + ShipObject * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipFactionName (): target not a ship")); + return JNI_FALSE; + } + + JavaStringParam const jsp(jstr); + std::string faction; + if (!JavaLibrary::convert(jsp, faction)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipWingName (): failed to convert mobileName string")); + return JNI_FALSE; + } + ship->setFaction(faction); + + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipFaction(JNIEnv * /*env*/, jobject /*self*/, jlong target) +{ + ServerObject const * object = NULL; + if (!JavaLibrary::getObject(target, object)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipFaction (): could not convert the target")); + return 0; + } + ShipObject const * const ship = object->asShipObject(); + if(!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::getShipFaction (): target is not a ship")); + return 0; + } + return JavaString(ship->getFaction()).getReturnValue(); +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::addMissionCriticalObject(JNIEnv * env, jobject /*self*/, jlong playerId, jlong missionCriticalObject) +{ + PROFILER_AUTO_BLOCK_DEFINE("JNI::addMissionCriticalObject"); + + CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "addMissionCriticalObject(): playerId did not resolve to a CreatureObject", false); + if (!creatureObject) + return JNI_FALSE; + + NetworkId missionCriticalObjectId(missionCriticalObject); + + if (missionCriticalObject) + { + if(missionCriticalObjectId == NetworkId::cms_invalid) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("addMissionCriticalObject(): missionCriticalObject is not an obj_id")); + return JNI_FALSE; + } + + if (missionCriticalObjectId != NetworkId::cms_invalid) + creatureObject->addMissionCriticalObject(missionCriticalObjectId); + } + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::removeMissionCriticalObject(JNIEnv * env, jobject /*self*/, jlong playerId, jlong missionCriticalObject) +{ + CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "removeMissionCriticalObject(): playerId did not resolve to a CreatureObject", false); + if (!creatureObject) + return JNI_FALSE; + + NetworkId missionCriticalObjectId(missionCriticalObject); + + if (missionCriticalObject) + { + if (missionCriticalObjectId == NetworkId::cms_invalid) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("removeMissionCriticalObject(): missionCriticalObject is not an obj_id")); + return JNI_FALSE; + } + + if (missionCriticalObjectId != NetworkId::cms_invalid) + creatureObject->removeMissionCriticalObject(missionCriticalObjectId); + } + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::clearMissionCriticalObjects(JNIEnv * env, jobject /*self*/, jlong playerId) +{ + CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "clearMissionCriticalObjects(): playerId did not resolve to a CreatureObject", false); + if (!creatureObject) + return JNI_FALSE; + + creatureObject->clearMissionCriticalObjects(); + + return JNI_TRUE; +} + +//---------------------------------------------------------------------- + +jboolean JNICALL ScriptMethodsShipNamespace::isMissionCriticalObject(JNIEnv * env, jobject /*self*/, jlong playerId, jlong ship) +{ + CreatureObject * const creatureObject = JavaLibrary::getCreatureThrow(env, playerId, "isMissionCriticalObject(): playerId did not resolve to a CreatureObject", false); + if (!creatureObject) + return JNI_FALSE; + + if (!ship) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("isMissionCriticalObject(): playerId ship is null")); + return JNI_FALSE; + } + + NetworkId shipId(ship); + if (shipId == NetworkId::cms_invalid) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("isMissionCriticalObject(): playerId is not an obj_id")); + return JNI_FALSE; + } + + return creatureObject->isMissionCriticalObject(shipId); +} + +// ---------------------------------------------------------------------- + +jstring JNICALL ScriptMethodsShipNamespace::getShipComponentDebugString(JNIEnv * env, jobject /*self*/, jlong jobject_shipId, jint chassisSlot) +{ + ShipObject const * const ship = JavaLibrary::getShipThrow(env, jobject_shipId, "getShipComponentDebugString(): obj_id shipId did not resolve to a ShipObject", false); + if (ship && ship->isSlotInstalled(chassisSlot)) + { + ShipComponentData * const shipComponentData = ship->createShipComponentData(chassisSlot); + if (shipComponentData) + { + Unicode::String result; + shipComponentData->printDebugString(result, Unicode::emptyString); + delete shipComponentData; + if (!result.empty()) + return JavaString(result).getReturnValue(); + } + } + return 0; +} + +//---------------------------------------------------------------------- + +jfloat JNICALL ScriptMethodsShipNamespace::getShipChassisSpeedMaximumModifier(JNIEnv * env, jobject self, jlong shipId) +{ + ShipObject const * const shipObject = JavaLibrary::getShipThrow(env, shipId, "getShipChassisMaximumSpeedModifier(): shipId did not resolve to a ShipObject", false); + if (!shipObject) + return JNI_FALSE; + + return shipObject->getChassisSpeedMaximumModifier(); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipChassisSpeedMaximumModifier(JNIEnv * env, jobject self, jlong shipId, jfloat value) +{ + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, shipId, "setShipChassisMaximumSpeedModifier(): shipId did not resolve to a ShipObject", false); + if (!shipObject) + return; + + shipObject->setChassisSpeedMaximumModifier(value); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::notifyShipHit(JNIEnv * env, jobject self, jlong jobject_shipId, jobject jobject_vectorUp_w, jobject jobject_vectorHitLocation_o, jint type, jfloat integrity, jfloat previousIntegrity) +{ + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_shipId, "notifyShipHit(): shipId did not resolve to a ShipObject", false); + if (!shipObject) + return; + + Vector up_w; + if (!ScriptConversion::convert(jobject_vectorUp_w, up_w)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("notifyShipHit(): unable to convert up_w vector")); + return; + } + + Vector hitLocation_o; + if (!ScriptConversion::convert(jobject_vectorHitLocation_o, hitLocation_o)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("notifyShipHit(): unable to convert hitLocation_o vector")); + return; + } + + MessageQueueShipHit * const msg = new MessageQueueShipHit(up_w, hitLocation_o, type, integrity, previousIntegrity); + shipObject->getController()->appendMessage( + CM_spaceShipHit, 0.0f, msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_ALL_CLIENT); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId, jobject jobject_velocity_w) +{ + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_asteroidId, "setDynamicMiningAsteroidVelocity(): shipId did not resolve to a ShipObject", false); + if (!shipObject) + return; + + Vector velocity_w; + if (!ScriptConversion::convert(jobject_velocity_w, velocity_w)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("setDynamicMiningAsteroidVelocity(): unable to convert velocity_w vector")); + return; + } + + MiningAsteroidController * const miningAsteroidController = dynamic_cast(shipObject->getController()); + if (NULL == miningAsteroidController) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("setDynamicMiningAsteroidVelocity(): called on a ship which is not a dynamic mining asteroid")); + return; + } + + miningAsteroidController->setVelocity_w(velocity_w); +} + +//---------------------------------------------------------------------- + +jobject JNICALL ScriptMethodsShipNamespace::getDynamicMiningAsteroidVelocity(JNIEnv * env, jobject self, jlong jobject_asteroidId) +{ + ShipObject * const shipObject = JavaLibrary::getShipThrow(env, jobject_asteroidId, "getDynamicMiningAsteroidVelocity(): shipId did not resolve to a ShipObject", false); + if (!shipObject) + return NULL; + MiningAsteroidController * const miningAsteroidController = dynamic_cast(shipObject->getController()); + if (NULL == miningAsteroidController) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("setDynamicMiningAsteroidVelocity(): called on a ship which is not a dynamic mining asteroid")); + return NULL; + } + + Vector const & velocity_w = miningAsteroidController->getVelocity_w(); + + LocalRefPtr vec; + if (!ScriptConversion::convert(velocity_w, vec)) + return 0; + + return vec->getReturnValue(); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong jobject_shipId, jint contentsMaximum) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCargoHoldContentsMaximum()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); + if (!shipObject) + return; + + if (!shipObject->setCargoHoldContentsMaximum(contentsMaximum)) + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipCargoHoldContentsMaximum (): component at slot [%d] error", static_cast(ShipChassisSlotType::SCST_cargo_hold))); +} + +//---------------------------------------------------------------------- + +int JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsMaximum (JNIEnv * env, jobject self, jlong jobject_shipId) +{ + ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContentsMaximum()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); + if (!shipObject) + return false; + + return shipObject->getCargoHoldContentsMaximum(); +} + +//---------------------------------------------------------------------- + +int JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsCurrent (JNIEnv * env, jobject self, jlong jobject_shipId) +{ + ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContentsCurrent()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); + if (!shipObject) + return false; + + return shipObject->getCargoHoldContentsCurrent(); +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::setShipCargoHoldContent(JNIEnv * env, jobject self, jlong jobject_shipId, jlong jobject_resourceTypeId, jint amount) +{ + ShipObject * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "setShipCargoHoldContent()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); + if (!shipObject) + return; + + NetworkId const & resourceTypeId = NetworkId(jobject_resourceTypeId); + + //-- check existence if amount != 0 + + shipObject->setCargoHoldContent(resourceTypeId, amount); +} + +//---------------------------------------------------------------------- + +jint JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContent(JNIEnv * env, jobject self, jlong jobject_shipId, jlong jobject_resourceTypeId) +{ + ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContent()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); + if (!shipObject) + return false; + + NetworkId const & resourceTypeId = NetworkId(jobject_resourceTypeId); + + return shipObject->getCargoHoldContent(resourceTypeId); +} + +//---------------------------------------------------------------------- + +jlongArray JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsResourceTypes(JNIEnv * env, jobject self, jlong jobject_shipId) +{ + ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContents()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); + if (!shipObject) + return NULL; + + ShipObject::NetworkIdIntMap const & contents = shipObject->getCargoHoldContents(); + + LocalLongArrayRefPtr jids = createNewLongArray(contents.size()); + + if (jids != LocalLongArrayRef::cms_nullPtr) + { + int index = 0; + for (ShipObject::NetworkIdIntMap::const_iterator it = contents.begin(); it != contents.end(); ++it, ++index) + { + jlong jlongTmp = ((*it).first).getValue(); + setLongArrayRegion(*jids, index, 1, &jlongTmp); + } + return jids->getReturnValue(); + } + + return NULL; +} + +//---------------------------------------------------------------------- + +jintArray JNICALL ScriptMethodsShipNamespace::getShipCargoHoldContentsAmounts(JNIEnv * env, jobject self, jlong jobject_shipId) +{ + ShipObject const * const shipObject = getShipThrowTestSlot(env, jobject_shipId, "getShipCargoHoldContents()", false, static_cast(ShipChassisSlotType::SCST_cargo_hold)); + if (!shipObject) + return NULL; + + ShipObject::NetworkIdIntMap const & contents = shipObject->getCargoHoldContents(); + + LocalIntArrayRefPtr jamounts = createNewIntArray(static_cast(contents.size ())); + if (jamounts != LocalIntArrayRef::cms_nullPtr) + { + int index = 0; + for (ShipObject::NetworkIdIntMap::const_iterator it = contents.begin(); it != contents.end(); ++it) + { + jint amount = (*it).second; + setIntArrayRegion(*jamounts, index, 1, &amount); + } + return jamounts->getReturnValue(); + } + + return NULL; +} + +//---------------------------------------------------------------------- + +void JNICALL ScriptMethodsShipNamespace::openSpaceMiningUi(JNIEnv * env, jobject self, jlong jobject_player, jlong jobject_spaceStation, jstring jstring_spaceStationName) +{ + NetworkId const & playerId = NetworkId(jobject_player); + NetworkId const & spaceStationId = NetworkId(jobject_spaceStation); + + if (jstring_spaceStationName == NULL) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): null name")); + return; + } + + JavaStringParam const jsp(jstring_spaceStationName); + std::string spaceStationName; + if (!JavaLibrary::convert(jsp, spaceStationName)) + { + JAVA_THROW_SCRIPT_EXCEPTION(true, ("JavaLibrary::setShipComponentName (): failed to convert name string")); + return; + } + + Object * const player = NetworkIdManager::getObjectById(playerId); + Controller * const controller = player ? player->getController(): NULL; + + if (!controller) + { + WARNING(true, ("JavaLibrary::openSpaceMiningUi failed, no player or controller")); + return; + } + + typedef std::pair MessageData; + typedef MessageQueueGenericValueType MessageType; + MessageType * const msg = new MessageType(MessageData(spaceStationId, spaceStationName)); + + controller->appendMessage(CM_spaceMiningSaleOpen, 0.0f, msg, + GameControllerMessageFlags::SEND | + GameControllerMessageFlags::RELIABLE | + GameControllerMessageFlags::DEST_AUTH_CLIENT); +} + +// ====================================================================== + diff --git a/src/engine/server/library/serverScript/src/shared/ScriptMethodsString.cpp b/src/engine/server/library/serverScript/src/shared/ScriptMethodsString.cpp index 49051c36a..e80282334 100644 --- a/src/engine/server/library/serverScript/src/shared/ScriptMethodsString.cpp +++ b/src/engine/server/library/serverScript/src/shared/ScriptMethodsString.cpp @@ -1,203 +1,203 @@ -//======================================================================= -// -// ScriptMethodsString.cpp -// Copyright 2000-05, Sony Online Entertainment Inc., all rights reserved. -// -//======================================================================= - -#include "serverScript/FirstServerScript.h" -#include "serverScript/JavaLibrary.h" - -#include "serverGame/NameManager.h" -#include "sharedGame/TextManager.h" - -using namespace JNIWrappersNamespace; - - -// ====================================================================== -// ScriptMethodsStringNamespace -// ====================================================================== - -namespace ScriptMethodsStringNamespace -{ - bool install(); - - jstring JNICALL getString(JNIEnv *env, jobject self, jobject id); - jobjectArray JNICALL getStrings(JNIEnv *env, jobject self, jobjectArray ids); - jboolean JNICALL isObscene(JNIEnv *env, jobject self, jstring data); - jboolean JNICALL isAppropriateText(JNIEnv *env, jobject self, jstring data); -} - - -//======================================================================== -// install -//======================================================================== - -bool ScriptMethodsStringNamespace::install() -{ -const JNINativeMethod NATIVES[] = { - #define JF(a,b,c) {a,b,(void*)(ScriptMethodsStringNamespace::c)} - JF("getString", "(Lscript/string_id;)Ljava/lang/String;", getString), - JF("getStrings", "([Lscript/string_id;)[Ljava/lang/String;", getStrings), - JF("isObscene", "(Ljava/lang/String;)Z", isObscene), - JF("isAppropriateText", "(Ljava/lang/String;)Z", isAppropriateText), -}; - - return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); -} - - -//---------------------------------------------------------------------- - -/** - * Returns the string associated with a stringId. - * - * @param env Java environment - * @param self class calling this function - * @param id the stringId to find - * - * @return the string, or null on error - */ -jstring JNICALL ScriptMethodsStringNamespace::getString(JNIEnv *env, jobject self, jobject id) -{ - UNREF(self); - - if (id == 0) - { - WARNING(true, ("JavaLibrary::log getString is NULL.")); - return 0; - } - - // convert the string id to a char string - if (!env->IsInstanceOf(id, JavaLibrary::getClsStringId())) - { - WARNING(true, ("JavaLibrary::log IsInstanceOf failed.")); - return 0; - } - - // get the table - JavaStringPtr tempString = getStringField(LocalRefParam(id), JavaLibrary::getFidStringIdTable()); - std::string table; - if(! JavaLibrary::convert(*tempString, table)) - { - WARNING(true, ("JavaLibrary::log failed to get the string table.")); - return 0; - } - - std::string asciiId; - JavaStringPtr tempAsciiIdString = getStringField(LocalRefParam(id), JavaLibrary::getFidStringIdAsciiId()); - if(! JavaLibrary::convert(*tempAsciiIdString, asciiId)) - { - WARNING(true, ("JavaLibrary::log failed to get the string asciiId.")); - return 0; - } - - const StringId stringId(table, asciiId); - Unicode::String localized; - - if (stringId.localize(localized)) - { - JavaString result(localized); - return result.getReturnValue(); - } -#ifdef DEBUG - else - { - WARNING(true, ("JavaLibrary::log failed to localize the stringId(%s, %s)", table.c_str(), asciiId.c_str())); - } -#endif - return 0; - -} // JavaLibrary::getString - -//---------------------------------------------------------------------- - -/** - * Returns the strings associated with an array of stringIds. - * - * @param env Java environment - * @param self class calling this function - * @param ids array of stringIds to find - * - * @return an array of strings, or null on error - */ -jobjectArray JNICALL ScriptMethodsStringNamespace::getStrings(JNIEnv *env, jobject self, jobjectArray ids) -{ - UNREF(self); - - if (ids == 0) - return 0; - - if (!env->IsInstanceOf(ids, JavaLibrary::getClsStringIdArray())) - return 0; - - jsize count = env->GetArrayLength(ids); - - // create the string array to return - LocalObjectArrayRefPtr strings = createNewObjectArray(count, JavaLibrary::getClsString()); - if (strings == LocalObjectArrayRef::cms_nullPtr) - return 0; - - // fill the array - for (jsize i = 0; i < count; ++i) - { - LocalRefPtr id = getObjectArrayElement(LocalObjectArrayRefParam(ids), i); - setObjectArrayElement(*strings, i, LocalRef(getString(env, self, id->getValue()))); - } - - return strings->getReturnValue(); -} // JavaLibrary::getStrings - -//---------------------------------------------------------------------- - -/** - * Finds if a string is obscene. - * - * @param env Java environment - * @param self class calling this function - * @param data string to test - * - * @return true if the string is obscene, false if not - */ -jboolean JNICALL ScriptMethodsStringNamespace::isObscene(JNIEnv *env, jobject self, jstring data) -{ - if (data == 0) - return JNI_FALSE; - - JavaStringParam jtext(data); - Unicode::String text; - if (JavaLibrary::convert(jtext, text)) - { - return NameManager::getInstance().isNameReserved(text); - } - - return JNI_FALSE; -} // JavaLibrary::isObscene - -//---------------------------------------------------------------------- - -/** - * Tests is a string is appropriate, whatever that means. - * - * @param env Java environment - * @param self class calling this function - * @param data string to test - * - * @return true if the string is appropriate, false if not - */ -jboolean JNICALL ScriptMethodsStringNamespace::isAppropriateText(JNIEnv *env, jobject self, jstring data) -{ - if (data == 0) - return JNI_FALSE; - - JavaStringParam jtext(data); - Unicode::String text; - if (JavaLibrary::convert(jtext, text)) - { - return TextManager::isAppropriateText(text); - } - - return JNI_FALSE; -} // JavaLibrary::isAppropriateText - -//---------------------------------------------------------------------- +//======================================================================= +// +// ScriptMethodsString.cpp +// Copyright 2000-05, Sony Online Entertainment Inc., all rights reserved. +// +//======================================================================= + +#include "serverScript/FirstServerScript.h" +#include "serverScript/JavaLibrary.h" + +#include "serverGame/NameManager.h" +#include "sharedGame/TextManager.h" + +using namespace JNIWrappersNamespace; + + +// ====================================================================== +// ScriptMethodsStringNamespace +// ====================================================================== + +namespace ScriptMethodsStringNamespace +{ + bool install(); + + jstring JNICALL getString(JNIEnv *env, jobject self, jobject id); + jobjectArray JNICALL getStrings(JNIEnv *env, jobject self, jobjectArray ids); + jboolean JNICALL isObscene(JNIEnv *env, jobject self, jstring data); + jboolean JNICALL isAppropriateText(JNIEnv *env, jobject self, jstring data); +} + + +//======================================================================== +// install +//======================================================================== + +bool ScriptMethodsStringNamespace::install() +{ +const JNINativeMethod NATIVES[] = { + #define JF(a,b,c) {a,b,(void*)(ScriptMethodsStringNamespace::c)} + JF("getString", "(Lscript/string_id;)Ljava/lang/String;", getString), + JF("getStrings", "([Lscript/string_id;)[Ljava/lang/String;", getStrings), + JF("isObscene", "(Ljava/lang/String;)Z", isObscene), + JF("isAppropriateText", "(Ljava/lang/String;)Z", isAppropriateText), +}; + + return JavaLibrary::registerNatives(NATIVES, sizeof(NATIVES)/sizeof(NATIVES[0])); +} + + +//---------------------------------------------------------------------- + +/** + * Returns the string associated with a stringId. + * + * @param env Java environment + * @param self class calling this function + * @param id the stringId to find + * + * @return the string, or null on error + */ +jstring JNICALL ScriptMethodsStringNamespace::getString(JNIEnv *env, jobject self, jobject id) +{ + UNREF(self); + + if (id == 0) + { + WARNING(true, ("JavaLibrary::log getString is NULL.")); + return 0; + } + + // convert the string id to a char string + if (!env->IsInstanceOf(id, JavaLibrary::getClsStringId())) + { + WARNING(true, ("JavaLibrary::log IsInstanceOf failed.")); + return 0; + } + + // get the table + JavaStringPtr tempString = getStringField(LocalRefParam(id), JavaLibrary::getFidStringIdTable()); + std::string table; + if(! JavaLibrary::convert(*tempString, table)) + { + WARNING(true, ("JavaLibrary::log failed to get the string table.")); + return 0; + } + + std::string asciiId; + JavaStringPtr tempAsciiIdString = getStringField(LocalRefParam(id), JavaLibrary::getFidStringIdAsciiId()); + if(! JavaLibrary::convert(*tempAsciiIdString, asciiId)) + { + WARNING(true, ("JavaLibrary::log failed to get the string asciiId.")); + return 0; + } + + const StringId stringId(table, asciiId); + Unicode::String localized; + + if (stringId.localize(localized)) + { + JavaString result(localized); + return result.getReturnValue(); + } +#ifdef DEBUG + else + { + WARNING(true, ("JavaLibrary::log failed to localize the stringId(%s, %s)", table.c_str(), asciiId.c_str())); + } +#endif + return 0; + +} // JavaLibrary::getString + +//---------------------------------------------------------------------- + +/** + * Returns the strings associated with an array of stringIds. + * + * @param env Java environment + * @param self class calling this function + * @param ids array of stringIds to find + * + * @return an array of strings, or null on error + */ +jobjectArray JNICALL ScriptMethodsStringNamespace::getStrings(JNIEnv *env, jobject self, jobjectArray ids) +{ + UNREF(self); + + if (ids == 0) + return 0; + + if (!env->IsInstanceOf(ids, JavaLibrary::getClsStringIdArray())) + return 0; + + jsize count = env->GetArrayLength(ids); + + // create the string array to return + LocalObjectArrayRefPtr strings = createNewObjectArray(count, JavaLibrary::getClsString()); + if (strings == LocalObjectArrayRef::cms_nullPtr) + return 0; + + // fill the array + for (jsize i = 0; i < count; ++i) + { + LocalRefPtr id = getObjectArrayElement(LocalObjectArrayRefParam(ids), i); + setObjectArrayElement(*strings, i, LocalRef(getString(env, self, id->getValue()))); + } + + return strings->getReturnValue(); +} // JavaLibrary::getStrings + +//---------------------------------------------------------------------- + +/** + * Finds if a string is obscene. + * + * @param env Java environment + * @param self class calling this function + * @param data string to test + * + * @return true if the string is obscene, false if not + */ +jboolean JNICALL ScriptMethodsStringNamespace::isObscene(JNIEnv *env, jobject self, jstring data) +{ + if (data == 0) + return JNI_FALSE; + + JavaStringParam jtext(data); + Unicode::String text; + if (JavaLibrary::convert(jtext, text)) + { + return NameManager::getInstance().isNameReserved(text); + } + + return JNI_FALSE; +} // JavaLibrary::isObscene + +//---------------------------------------------------------------------- + +/** + * Tests is a string is appropriate, whatever that means. + * + * @param env Java environment + * @param self class calling this function + * @param data string to test + * + * @return true if the string is appropriate, false if not + */ +jboolean JNICALL ScriptMethodsStringNamespace::isAppropriateText(JNIEnv *env, jobject self, jstring data) +{ + if (data == 0) + return JNI_FALSE; + + JavaStringParam jtext(data); + Unicode::String text; + if (JavaLibrary::convert(jtext, text)) + { + return TextManager::isAppropriateText(text); + } + + return JNI_FALSE; +} // JavaLibrary::isAppropriateText + +//---------------------------------------------------------------------- diff --git a/src/engine/server/library/serverScript/src/shared/ScriptParameters.h b/src/engine/server/library/serverScript/src/shared/ScriptParameters.h index dabb32695..98aa0870e 100644 --- a/src/engine/server/library/serverScript/src/shared/ScriptParameters.h +++ b/src/engine/server/library/serverScript/src/shared/ScriptParameters.h @@ -210,7 +210,7 @@ public: const stdvector::fwd & getValueDictionaryArrayParam(int index) const; protected: - friend void Archive::get(ReadIterator & source, ScriptParams & target); + friend void Archive::get(Archive::ReadIterator & source, ScriptParams & target); private: diff --git a/src/engine/server/library/serverUtility/src/CMakeLists.txt b/src/engine/server/library/serverUtility/src/CMakeLists.txt index 1b9793198..b522f2c18 100644 --- a/src/engine/server/library/serverUtility/src/CMakeLists.txt +++ b/src/engine/server/library/serverUtility/src/CMakeLists.txt @@ -39,10 +39,6 @@ if(WIN32) set(PLATFORM_SOURCES win32/FirstServerUtility.cpp ) -else() - set(PLATFORM_SOURCES - linux/stlhack.cpp - ) endif() include_directories( diff --git a/src/engine/server/library/serverUtility/src/shared/PopulationList.h b/src/engine/server/library/serverUtility/src/shared/PopulationList.h index 9f4a2115c..7a6bccd6d 100644 --- a/src/engine/server/library/serverUtility/src/shared/PopulationList.h +++ b/src/engine/server/library/serverUtility/src/shared/PopulationList.h @@ -70,8 +70,8 @@ class PopulationList PopulationMapType m_populationMap; mutable PopulationMapType m_populationCache; - friend void Archive::get(ReadIterator & source, PopulationList & target); - friend void Archive::put(ByteStream & target, const PopulationList & source); + friend void Archive::get(Archive::ReadIterator & source, PopulationList & target); + friend void Archive::put(Archive::ByteStream & target, const PopulationList & source); }; // ====================================================================== diff --git a/src/engine/shared/application/TemplateDefinitionCompiler/src/shared/core/TemplateDefinitionCompiler.cpp b/src/engine/shared/application/TemplateDefinitionCompiler/src/shared/core/TemplateDefinitionCompiler.cpp index 61e85ce83..f95e5c6c9 100644 --- a/src/engine/shared/application/TemplateDefinitionCompiler/src/shared/core/TemplateDefinitionCompiler.cpp +++ b/src/engine/shared/application/TemplateDefinitionCompiler/src/shared/core/TemplateDefinitionCompiler.cpp @@ -27,84 +27,6 @@ #include -#ifdef _DEBUG -//#define ALWAYS_OVERWRITE // flag to always overwrite previous code -#endif - - -//============================================================================== -// subclass Perforce API class ClientUser in order to trap errors - -//static const int SUBMIT_NO_FILE_ERR = 17; // need to add file before submitting -// -//class MyPerforceUser : public ClientUser -//{ -//public: -// MyPerforceUser(void) : ClientUser(), m_errorOccurred(false) {} -// virtual ~MyPerforceUser() {} -// virtual void HandleError( Error *err ) -// { -// if (err != NULL && err->Test()) -// { -// m_errorOccurred = true; -// m_lastError = err->GetGeneric(); -// // test for filtered errors -// for (size_t i = 0; i < m_filteredErrors.size(); ++i) -// { -// if (m_lastError == m_filteredErrors[i]) -// return; -// } -// } -// ClientUser::HandleError(err); -// } -// -// bool errorOccurred(void) const -// { -// return m_errorOccurred; -// } -// -// int getLastError(void) const -// { -// return m_lastError; -// } -// -// void clearLastError(void) -// { -// m_errorOccurred = false; -// m_lastError = 0; -// } -// -// void addFilteredError(int error) -// { -// m_filteredErrors.push_back(error); -// } -// -// void clearFilteredErrors(void) -// { -// m_filteredErrors.clear(); -// } -// -//private: -// bool m_errorOccurred; -// int m_lastError; -// std::vector m_filteredErrors; -//}; -// -// -////============================================================================== -//// subclass of the PerforceAPI StrBuf class, to workaround a bug -//// in the destructor. We can't fix the bug because it's an external library -//class StrBufFixed : public StrBuf -//{ -//public: -// ~StrBufFixed() -// { -// delete buffer; -// StringInit(); -// } -//}; - - //============================================================================== // file variables diff --git a/src/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp b/src/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp index c02aa59f6..8e3ba4bc7 100644 --- a/src/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp +++ b/src/engine/shared/library/sharedDebug/src/linux/DebugHelp.cpp @@ -404,8 +404,9 @@ static bool dwarfSearch(char const *dwarfLines, unsigned int linesLength, void c char const *srcFile = bestUnderSrcFileTable+1; for (int i = 0; i < bestUnderSrcFileNum; ++i) { - while (*srcFile++); + while (*srcFile++) { srcFile += 3; + } } retSrcFile = SymbolCache::uniqueString(srcFile); retSrcLine = bestUnderSrcLine; diff --git a/src/engine/shared/library/sharedDebug/src/shared/DataLint.cpp b/src/engine/shared/library/sharedDebug/src/shared/DataLint.cpp index 4cc080a62..5190728fe 100644 --- a/src/engine/shared/library/sharedDebug/src/shared/DataLint.cpp +++ b/src/engine/shared/library/sharedDebug/src/shared/DataLint.cpp @@ -1,907 +1,907 @@ -// ============================================================================ -// -// DataLint.cpp -// Copyright Sony Online Entertainment -// -// ============================================================================ - -#include "sharedDebug/FirstSharedDebug.h" -#include "sharedDebug/DataLint.h" - -#include "sharedFoundation/ConfigSharedFoundation.h" -#include "sharedFoundation/ExitChain.h" - -#include -#include -#include -#include -#include - -// ============================================================================ - -namespace DataLintNamespace -{ - enum Mode - { - M_client, - M_server - }; - - typedef stdvector::fwd StringList; - typedef std::pair > WarningPair; - typedef stdvector::fwd WarningList; - typedef bool (*AssetFunction)(char const *); - - bool ms_installed = false; - DataLint::AssetType m_currentAssetType = DataLint::AT_invalid; - bool m_enabled = false; - WarningList * m_warningList = NULL; - StringList * m_assetStack = NULL; - DataLint::StringPairList * m_assetList = NULL; - std::string m_dataLintCategorizedAssetsFile("DataLint_CategorizedAssets.txt"); - std::string m_dataLintUnSupportedAssetsFile("DataLint_UnSupportedAssets.txt"); - Mode m_mode = M_client; - - bool isAnAppearanceAsset(char const *text); - bool isAnArrangementDescriptorAsset(char const *text); - bool isALocalizedStringAsset(char const *text); - bool isAnObjectTemplateAsset(char const *text); - bool isAPortalProprtyAsset(char const *text); - bool isAShaderTemplateAsset(char const *text); - bool isASkyBoxAsset(char const *text); - bool isASlotDescriptorAsset(char const *text); - bool isASoundAsset(char const *text); - bool isATerrainAsset(char const *text); - bool isATextureAsset(char const *text); - bool isATextureRendererTemplateAsset(char const *text); - bool isAnUnSupportedAsset(char const *text); - - void fixUpSlashes(char *text); - DataLint::StringPairList getList(int const reserveCount, AssetFunction listTypeFunction); - void writeToCategorizedFile(FILE *fp, char const *title, DataLint::AssetType const listType); - std::string formatErrorMessage(WarningPair &warningPair, int ¤tErrorCount); - void writeError(FILE *fp, WarningPair &warningPair, int ¤tErrorCount); -} - -using namespace DataLintNamespace; - -// ============================================================================ -// -// DataLint -// -// ============================================================================ - -void DataLint::install() -{ - DEBUG_FATAL(ms_installed, ("DataLint::install: already installed")); - ms_installed = true; - m_enabled = true; - - m_warningList = new WarningList(); - m_warningList->reserve(4096); - - m_assetStack = new StringList (); - - m_assetList = new StringPairList(); - m_assetList->reserve(4096); - - FatalSetThrowExceptions(true); - - ExitChain::add(&remove, "DataLint::remove"); -} - -//----------------------------------------------------------------------------- - -bool DataLint::isInstalled() -{ - return ms_installed; -} - -//----------------------------------------------------------------------------- - -void DataLint::report() -{ - if (m_enabled) - { - // Error Assets - - DEBUG_REPORT_LOG_PRINT(true, ("Writing error files\n")); - - // Setup filenames for client versus server mode - - std::string dataLintErrorsAll((m_mode == M_client) ? "DataLint_Errors_All.txt" : "DataLintServer_Errors_All.txt"); - std::string dataLintErrorsAllFatal((m_mode == M_client) ? "DataLint_Errors_All_Fatal.txt" : "DataLintServer_Errors_All_Fatal.txt"); - std::string dataLintErrorsAllWarning((m_mode == M_client) ? "DataLint_Errors_All_Warning.txt" : "DataLintServer_Errors_All_Warning.txt"); - std::string dataLintErrorsAllObjectTemplate((m_mode == M_client) ? "DataLint_Errors_ObjectTemplate.txt" : "DataLintServer_Errors_ObjectTemplate.txt"); - - // Server/client - - FILE *assetErrorFileAll = fopen(dataLintErrorsAll.c_str(), "wt"); - FILE *assetErrorFileAllFatal = fopen(dataLintErrorsAllFatal.c_str(), "wt"); - FILE *assetErrorFileAllWarning = fopen(dataLintErrorsAllWarning.c_str(), "wt"); - FILE *assetErrorFileObjectTemplate = fopen(dataLintErrorsAllObjectTemplate.c_str(), "wt"); - - // Client only - - FILE *assetErrorFileAppearance = NULL; - FILE *assetErrorFileArrangementDescriptor = NULL; - FILE *assetErrorFileLocalizedStringTable = NULL; - FILE *assetErrorFilePortalProperty = NULL; - FILE *assetErrorFileShaderTemplate = NULL; - FILE *assetErrorFileSkyBox = NULL; - FILE *assetErrorFileSlotDescriptor = NULL; - FILE *assetErrorFileSoundTemplate = NULL; - FILE *assetErrorFileTerrain = NULL; - FILE *assetErrorFileTexture = NULL; - FILE *assetErrorFileTextureRenderer = NULL; - - if (m_mode == M_client) - { - assetErrorFileAppearance = fopen("DataLint_Errors_Appearance.txt", "wt"); - assetErrorFileArrangementDescriptor = fopen("DataLint_Errors_ArrangementDescriptor.txt", "wt"); - assetErrorFileLocalizedStringTable = fopen("DataLint_Errors_LocalizedStringTable.txt", "wt"); - assetErrorFilePortalProperty = fopen("DataLint_Errors_PortalProperty.txt", "wt"); - assetErrorFileShaderTemplate = fopen("DataLint_Errors_ShaderTemplate.txt", "wt"); - assetErrorFileSkyBox = fopen("DataLint_Errors_SkyBox.txt", "wt"); - assetErrorFileSlotDescriptor = fopen("DataLint_Errors_SlotDescriptor.txt", "wt"); - assetErrorFileSoundTemplate = fopen("DataLint_Errors_SoundTemplate.txt", "wt"); - assetErrorFileTerrain = fopen("DataLint_Errors_Terrain.txt", "wt"); - assetErrorFileTexture = fopen("DataLint_Errors_Texture.txt", "wt"); - assetErrorFileTextureRenderer = fopen("DataLint_Errors_TextureRenderer.txt", "wt"); - } - - // Might want to think of a better way to keep track of the number of errors for each specific asset type. - - int totalErrorCountAll = 1; - int totalErrorCountAllFatal = 1; - int totalErrorCountAllWarning = 1; - int totalErrorCountAppearance = 1; - int totalErrorCountArrangementDescriptor = 1; - int totalErrorCountLocalizedStringTable = 1; - int totalErrorCountObjectTemplate = 1; - int totalErrorCountPortalProperty = 1; - int totalErrorCountShaderTemplate = 1; - int totalErrorCountSkyBox = 1; - int totalErrorCountSlotDescriptor = 1; - int totalErrorCountSoundTemplate = 1; - int totalErrorCountTerrain = 1; - int totalErrorCountTexture = 1; - int totalErrorCountTextureRenderer = 1; - - typedef std::set StringSet; - StringSet duplicateStringSet; - - if (assetErrorFileAll) - { - WarningList::iterator warningListIter = m_warningList->begin(); - - for (; warningListIter != m_warningList->end(); ++warningListIter) - { - // Build a duplicate string - - std::string duplicateString(warningListIter->first); - - StringList::const_iterator stringStackIter = warningListIter->second.second.begin(); - - for (; stringStackIter != warningListIter->second.second.end(); ++stringStackIter) - { - duplicateString += *stringStackIter; - } - - if (duplicateStringSet.find(duplicateString) == duplicateStringSet.end()) - { - // This is the first instance of this error, so log it - - duplicateStringSet.insert(duplicateString); - } - else - { - // We found a duplicate warning, so don't show it twice - - continue; - } - - // Write the error to the appropriate error file - - switch (warningListIter->second.first) - { - case AT_appearance: - { - if (m_mode == M_client) - { - writeError(assetErrorFileAppearance, *warningListIter, totalErrorCountAppearance); - } - } - break; - case AT_arrangementDescriptor: - { - if (m_mode == M_client) - { - writeError(assetErrorFileArrangementDescriptor, *warningListIter, totalErrorCountArrangementDescriptor); - } - } - break; - case AT_localizedStringTable: - { - if (m_mode == M_client) - { - writeError(assetErrorFileLocalizedStringTable, *warningListIter, totalErrorCountLocalizedStringTable); - } - } - break; - case AT_objectTemplate: - { - writeError(assetErrorFileObjectTemplate, *warningListIter, totalErrorCountObjectTemplate); - } - break; - case AT_portalProperty: - { - if (m_mode == M_client) - { - writeError(assetErrorFilePortalProperty, *warningListIter, totalErrorCountPortalProperty); - } - } - break; - case AT_shaderTemplate: - { - if (m_mode == M_client) - { - writeError(assetErrorFileShaderTemplate, *warningListIter, totalErrorCountShaderTemplate); - } - } - break; - case AT_skyBox: - { - if (m_mode == M_client) - { - writeError(assetErrorFileSkyBox, *warningListIter, totalErrorCountSkyBox); - } - } - break; - case AT_slotDescriptor: - { - if (m_mode == M_client) - { - writeError(assetErrorFileSlotDescriptor, *warningListIter, totalErrorCountSlotDescriptor); - } - } - break; - case AT_soundTemplate: - { - if (m_mode == M_client) - { - writeError(assetErrorFileSoundTemplate, *warningListIter, totalErrorCountSoundTemplate); - } - } - break; - case AT_terrain: - { - if (m_mode == M_client) - { - writeError(assetErrorFileTerrain, *warningListIter, totalErrorCountTerrain); - } - } - break; - case AT_texture: - { - if (m_mode == M_client) - { - writeError(assetErrorFileTexture, *warningListIter, totalErrorCountTexture); - } - } - break; - case AT_textureRendererTemplate: - { - if (m_mode == M_client) - { - writeError(assetErrorFileTextureRenderer, *warningListIter, totalErrorCountTextureRenderer); - } - } - break; - default: - { - DEBUG_REPORT_LOG_PRINT(true, ("DataLint::remove() - Unsupported asset type: %s", warningListIter->first.c_str())); - } - break; - } - - // Write the error to the master error file - - writeError(assetErrorFileAll, *warningListIter, totalErrorCountAll); - - // If this is a fatal, write to the fatal list - - if (strstr(warningListIter->first.c_str(), "FATAL:")) - { - writeError(assetErrorFileAllFatal, *warningListIter, totalErrorCountAllFatal); - } - - // If a warning, write to the warning list - - if (strstr(warningListIter->first.c_str(), "WARNING:")) - { - writeError(assetErrorFileAllWarning, *warningListIter, totalErrorCountAllWarning); - } - } - } - - // UnSupported Assets - - DEBUG_REPORT_LOG_PRINT(true, ("Writing unsupported assets list: %s\n", m_dataLintUnSupportedAssetsFile.c_str())); - - FILE *fp = fopen(m_dataLintUnSupportedAssetsFile.c_str(), "wt"); - - if (fp) - { - StringPairList unSupportedStringPairList(getList(AT_unSupported)); - StringPairList::iterator stringPairListIter = unSupportedStringPairList.begin(); - int count = 1; - - for (; stringPairListIter != unSupportedStringPairList.end(); ++stringPairListIter) - { - fprintf(fp, "%3d %s @ %s\n", count, stringPairListIter->first.c_str(), stringPairListIter->second.c_str()); - ++count; - } - - fclose(fp); - } - else - { - DEBUG_REPORT_LOG_PRINT(true, ("Error writing unsupported assets list: %s\n", m_dataLintUnSupportedAssetsFile.c_str())); - } - - // Categorized Assets - - DEBUG_REPORT_LOG_PRINT(true, ("Writing categorized files list: %s\n", m_dataLintCategorizedAssetsFile.c_str())); - - fp = fopen(m_dataLintCategorizedAssetsFile.c_str(), "wt"); - - if (fp) - { - fprintf(fp, "This file contains a categorized listing of the linted assets in the game. The categories are as follows:\n"); - fprintf(fp, "\n"); - fprintf(fp, "1. Appearances (%5d)\n", getList(AT_appearance).size()); - fprintf(fp, "2. Arrangement Descriptors (%5d)\n", getList(AT_arrangementDescriptor).size()); - fprintf(fp, "3. Localized String Tables (%5d)\n", getList(AT_localizedStringTable).size()); - fprintf(fp, "4. Object Templates (%5d)\n", getList(AT_objectTemplate).size()); - fprintf(fp, "5. Portal Properties (%5d)\n", getList(AT_portalProperty).size()); - fprintf(fp, "6. Shader Templates (%5d)\n", getList(AT_shaderTemplate).size()); - fprintf(fp, "7. SkyBoxes (%5d)\n", getList(AT_skyBox).size()); - fprintf(fp, "8. Slot Descriptors (%5d)\n", getList(AT_slotDescriptor).size()); - fprintf(fp, "9. Sound Templates (%5d)\n", getList(AT_soundTemplate).size()); - fprintf(fp, "10. Terrain (%5d)\n", getList(AT_terrain).size()); - fprintf(fp, "11. Textures (%5d)\n", getList(AT_texture).size()); - fprintf(fp, "12. Texture Renderer Templates (%5d)\n", getList(AT_textureRendererTemplate).size()); - fprintf(fp, "--------------------------------------\n"); - fprintf(fp, "13. Total Linted Assets (%5d)\n", m_assetList->size() - getList(AT_unSupported).size()); - fprintf(fp, "\n"); - - writeToCategorizedFile(fp, "Appearances", AT_appearance); - writeToCategorizedFile(fp, "Arrangement Descriptors", AT_arrangementDescriptor); - writeToCategorizedFile(fp, "Localized String Tables", AT_localizedStringTable); - writeToCategorizedFile(fp, "Object Templates", AT_objectTemplate); - writeToCategorizedFile(fp, "Portal Properties", AT_portalProperty); - writeToCategorizedFile(fp, "Shader Templates", AT_shaderTemplate); - writeToCategorizedFile(fp, "SkyBoxes", AT_skyBox); - writeToCategorizedFile(fp, "Slot Descriptors", AT_slotDescriptor); - writeToCategorizedFile(fp, "Sound Templates", AT_soundTemplate); - writeToCategorizedFile(fp, "Terrain", AT_terrain); - writeToCategorizedFile(fp, "Textures", AT_texture); - writeToCategorizedFile(fp, "Texture Renderer Templates", AT_textureRendererTemplate); - - fclose(fp); - } - - if (assetErrorFileAll) { fclose(assetErrorFileAll); } - if (assetErrorFileAllFatal) { fclose(assetErrorFileAllFatal); } - if (assetErrorFileAllWarning) { fclose(assetErrorFileAllWarning); } - if (assetErrorFileObjectTemplate) { fclose(assetErrorFileObjectTemplate); } - - if (m_mode == M_client) - { - if (assetErrorFileAppearance) { fclose(assetErrorFileAppearance); } - if (assetErrorFileArrangementDescriptor) { fclose(assetErrorFileArrangementDescriptor); } - if (assetErrorFileLocalizedStringTable) { fclose(assetErrorFileLocalizedStringTable); } - if (assetErrorFilePortalProperty) { fclose(assetErrorFilePortalProperty); } - if (assetErrorFileShaderTemplate) { fclose(assetErrorFileShaderTemplate); } - if (assetErrorFileSkyBox) { fclose(assetErrorFileSkyBox); } - if (assetErrorFileSlotDescriptor) { fclose(assetErrorFileSlotDescriptor); } - if (assetErrorFileSoundTemplate) { fclose(assetErrorFileSoundTemplate); } - if (assetErrorFileTerrain) { fclose(assetErrorFileTerrain); } - if (assetErrorFileTexture) { fclose(assetErrorFileTexture); } - if (assetErrorFileTextureRenderer) { fclose(assetErrorFileTextureRenderer); } - } - } -} - -//----------------------------------------------------------------------------- -void DataLint::remove() -{ - DEBUG_FATAL(!ms_installed, ("DataLint::remove: not installed")); - ms_installed = false; - m_enabled = false; - - delete m_warningList; - delete m_assetStack; - delete m_assetList; - - FatalSetThrowExceptions(false); -} - -//----------------------------------------------------------------------------- -void DataLintNamespace::writeError(FILE *fp, WarningPair &warningPair, int ¤tErrorCount) -{ - std::string formatedErrorMessage(formatErrorMessage(warningPair, currentErrorCount)); - - if (fp) - { - fprintf(fp, "%s", formatedErrorMessage.c_str()); - } -} - -//----------------------------------------------------------------------------- -std::string DataLintNamespace::formatErrorMessage(WarningPair &warningPair, int ¤tErrorCount) -{ - std::string result; - char formatedError[4096]; - char text[4096]; - sprintf(text, "%s", warningPair.first.c_str()); - fixUpSlashes(text); - - char *assetError = strstr(text, " : "); - - if (assetError != NULL) - { - ++assetError; - ++assetError; - ++assetError; - } - - char *lineOfCode = &text[0]; - char *seperator = strstr(text, " : "); - - if (seperator) - { - *seperator = '\0'; - } - - if (assetError) - { - // Remove any trailing carriage returns - - int assetErrorLength = strlen(assetError); - - if (assetErrorLength > 0) - { - char *walkPtr = &assetError[0] + (assetErrorLength - 1); - - while ((assetErrorLength > 0) && (*walkPtr == '\n')) - { - --assetErrorLength; - *walkPtr = '\0'; - --walkPtr; - } - } - - sprintf(formatedError, "%3d Error: %s\n", currentErrorCount, assetError); - result += formatedError; - } - - if (lineOfCode) - { - sprintf(formatedError, " Line of Code: %s\n", lineOfCode); - result += formatedError; - } - - StringList::reverse_iterator stringListIter = warningPair.second.second.rbegin(); - - for (; stringListIter != warningPair.second.second.rend(); ++stringListIter) - { - std::string stackString(*stringListIter); - - sprintf(text, " Loaded From: %s\n", stackString.c_str()); - fixUpSlashes(text); - - sprintf(formatedError, "%s", text); - result += formatedError; - } - - result += "\n"; - ++currentErrorCount; - - return result; -} - -//----------------------------------------------------------------------------- -void DataLint::setEnabled(bool const enabled) -{ - m_enabled = enabled; -} - -//----------------------------------------------------------------------------- -bool DataLint::isEnabled() -{ - return m_enabled || ConfigSharedFoundation::getVerboseWarnings(); -} - -//----------------------------------------------------------------------------- -void DataLint::pushAsset(char const *assetPath) -{ - if (m_assetStack) - { - int const size = m_assetStack->size(); - UNREF(size); - m_assetStack->push_back(assetPath); - } -} - -//----------------------------------------------------------------------------- -void DataLint::popAsset() -{ - if (m_assetStack) - { - int const size = m_assetStack->size(); - UNREF(size); - DEBUG_FATAL(m_assetStack->empty(), ("DataLint::popAsset() - Trying to pop the asset stack when it is empty.")); - m_assetStack->pop_back(); - } -} - -//----------------------------------------------------------------------------- - -void DataLint::logWarning(std::string const &warning) -{ - if (m_enabled) - { - m_warningList->push_back(std::make_pair(warning, std::make_pair(m_currentAssetType, *m_assetStack))); - } -} - -//----------------------------------------------------------------------------- -void DataLint::clearAssetStack() -{ - if (m_assetStack) - m_assetStack->clear(); -} - -//----------------------------------------------------------------------------- -void DataLint::addFilePath(char const *filePath) -{ - if (filePath == NULL || (strlen(filePath) <= 0)) - { - return; - } - - if (m_assetList != NULL) - { - char text[4096]; - sprintf(text, "%s", filePath); - - char *seperator = strstr(text, " @ "); - char *longPath = seperator; - ++longPath; - ++longPath; - ++longPath; - char *shortPath = &text[0]; - *seperator = '\0'; - - m_assetList->push_back(std::make_pair(shortPath, longPath)); - } -} - -//----------------------------------------------------------------------------- -void DataLint::removeFilePath(char const *filePath) -{ - if (m_assetList != NULL) - { - StringPairList::iterator stringPairListIter = m_assetList->begin(); - - for (; stringPairListIter != m_assetList->end(); ++stringPairListIter) - { - char const *first = stringPairListIter->first.c_str(); - - if (strcmp(first, filePath) == 0) - { - m_assetList->erase(stringPairListIter); - } - } - } -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isAnAppearanceAsset(char const *text) -{ - bool const appearanceAsset = (strstr(text, "appearance/") != NULL); - bool const portalPropertyAsset = (strstr(text, ".pob") != NULL); - - return (appearanceAsset && !portalPropertyAsset); -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isAnArrangementDescriptorAsset(char const *text) -{ - bool const arrangementDescriptorAsset = (strstr(text, "slot/arrangement/") != NULL); - - return arrangementDescriptorAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isALocalizedStringAsset(char const *text) -{ - bool const localizedStringAsset = (strstr(text, ".stf") != NULL); - - return localizedStringAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isAnObjectTemplateAsset(char const *text) -{ - bool result = false; - UNREF(text); - bool const isInTheObjectDirectory = (strstr(text, "object/") != NULL); - bool const isInTheAbstractDirectory = (strstr(text, "abstract/") != NULL); - - if (isInTheObjectDirectory || isInTheAbstractDirectory) - { - bool const arrangementDescriptorAsset = isAnArrangementDescriptorAsset(text); - bool const slotDescriptorAsset = isASlotDescriptorAsset(text); - - result = (!arrangementDescriptorAsset) && (!slotDescriptorAsset); - } - - return result; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isAPortalProprtyAsset(char const *text) -{ - bool const portalPropertyAsset = (strstr(text, ".pob") != NULL); - - return portalPropertyAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isAShaderTemplateAsset(char const *text) -{ - bool const shaderTemplateAsset = (strstr(text, "shader/") != NULL); - - return shaderTemplateAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isASkyBoxAsset(char const *text) -{ - bool const skyBoxAsset = (strstr(text, "skybox/") != NULL); - - return skyBoxAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isASlotDescriptorAsset(char const *text) -{ - bool const slotDescriptorAsset = (strstr(text, "slot/descriptor/") != NULL); - - return slotDescriptorAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isASoundAsset(char const *text) -{ - bool const soundAsset = (strstr(text, "sound/") != NULL); - - return soundAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isATerrainAsset(char const *text) -{ - return strstr(text, ".trn") != 0; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isATextureAsset(char const *text) -{ - bool const textureAsset = (strstr(text, ".dds") != NULL); - - return textureAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isATextureRendererTemplateAsset(char const *text) -{ - bool const textureRendererAsset = (strstr(text, ".trt") != NULL); - - return textureRendererAsset; -} - -//----------------------------------------------------------------------------- -bool DataLintNamespace::isAnUnSupportedAsset(char const *text) -{ - bool const appearanceAsset = isAnAppearanceAsset(text); - bool const arrangementDescriptorAsset = isAnArrangementDescriptorAsset(text); - bool const localizedStringAsset = isALocalizedStringAsset(text); - bool const objectTemplateAsset = isAnObjectTemplateAsset(text); - bool const portalPropertyAsset = isAPortalProprtyAsset(text); - bool const shaderTemplateAsset = isAShaderTemplateAsset(text); - bool const skyBoxAsset = isASkyBoxAsset(text); - bool const slotDescriptorAsset = isASlotDescriptorAsset(text); - bool const soundAsset = isASoundAsset(text); - bool const terrainAsset = isATerrainAsset(text); - bool const textureAsset = isATextureAsset(text); - bool const textureRendererTemplateAsset = isATextureRendererTemplateAsset(text); - - bool const result = !(appearanceAsset || - arrangementDescriptorAsset || - localizedStringAsset || - objectTemplateAsset || - portalPropertyAsset || - shaderTemplateAsset || - skyBoxAsset || - slotDescriptorAsset || - soundAsset || - terrainAsset || - textureAsset || - textureRendererTemplateAsset); - - return result; -} - -//----------------------------------------------------------------------------- -DataLint::StringPairList DataLintNamespace::getList(int const reserveCount, AssetFunction assetTypeFunction) -{ - DEBUG_FATAL(!m_assetList, ("DataLint::getList() - m_assetList is NULL")); - - // Create the list of terrains - - DataLint::StringPairList stringPairList; - stringPairList.reserve(reserveCount); - - DataLint::StringPairList::iterator stringPairListIter = m_assetList->begin(); - - for (; stringPairListIter != m_assetList->end(); ++stringPairListIter) - { - char const *first = stringPairListIter->first.c_str(); - char const *second = stringPairListIter->second.c_str(); - - if (assetTypeFunction(first)) - { - stringPairList.push_back(std::make_pair(first, second)); - } - } - - return stringPairList; -} - -//----------------------------------------------------------------------------- -DataLint::StringPairList DataLint::getList(AssetType const assetType) -{ - switch (assetType) - { - case AT_appearance: - { - return DataLintNamespace::getList(8192, isAnAppearanceAsset); - } - break; - case AT_arrangementDescriptor: - { - return DataLintNamespace::getList(1024, isAnArrangementDescriptorAsset); - } - break; - case AT_localizedStringTable: - { - return DataLintNamespace::getList(1024, isALocalizedStringAsset); - } - break; - case AT_objectTemplate: - { - return DataLintNamespace::getList(8192, isAnObjectTemplateAsset); - } - break; - case AT_portalProperty: - { - return DataLintNamespace::getList(512, isAPortalProprtyAsset); - } - break; - case AT_shaderTemplate: - { - return DataLintNamespace::getList(4096, isAShaderTemplateAsset); - } - break; - case AT_skyBox: - { - return DataLintNamespace::getList(256, isASkyBoxAsset); - } - break; - case AT_slotDescriptor: - { - return DataLintNamespace::getList(1024, isASlotDescriptorAsset); - } - break; - case AT_soundTemplate: - { - return DataLintNamespace::getList(4096, isASoundAsset); - } - break; - case AT_terrain: - { - return DataLintNamespace::getList(32, isATerrainAsset); - } - break; - case AT_texture: - { - return DataLintNamespace::getList(8192, isATextureAsset); - } - break; - case AT_textureRendererTemplate: - { - return DataLintNamespace::getList(512, isATextureRendererTemplateAsset); - } - break; - case AT_unSupported: - { - return DataLintNamespace::getList(4096, isAnUnSupportedAsset); - } - break; - default: - { - DEBUG_FATAL(true, ("DataLint::getList() - Unknown list type.")); - } - } - - return StringPairList(); -} - -//----------------------------------------------------------------------------- -void DataLintNamespace::fixUpSlashes(char *text) -{ - char *slashEater = &text[0]; - - while (*slashEater != '\0') - { - if (*slashEater == '\\') - { - *slashEater = '/'; - } - - ++slashEater; - } -} - -//----------------------------------------------------------------------------- -void DataLintNamespace::writeToCategorizedFile(FILE *fp, char const *title, DataLint::AssetType const assetType) -{ - DataLint::StringPairList stringPairlist(DataLint::getList(assetType)); - - fprintf(fp, "-----------------%s (%d assets)-----------------\n", title, static_cast(stringPairlist.size())); - fprintf(fp, "\n"); - DataLint::StringPairList::const_iterator stringPairListIter = stringPairlist.begin(); - int count = 1; - - for (; stringPairListIter != stringPairlist.end(); ++stringPairListIter) - { - fprintf(fp, "%4d %s @ %s\n", count, stringPairListIter->first.c_str(), stringPairListIter->second.c_str()); - ++count; - } - - fprintf(fp, "\n"); -} - -//----------------------------------------------------------------------------- -void DataLint::setCurrentAssetType(AssetType const assetType) -{ - m_currentAssetType = assetType; -} - -//----------------------------------------------------------------------------- -void DataLint::setClientMode() -{ - m_mode = M_client; -} - -//----------------------------------------------------------------------------- -void DataLint::setServerMode() -{ - m_mode = M_server; -} - -// ============================================================================ +// ============================================================================ +// +// DataLint.cpp +// Copyright Sony Online Entertainment +// +// ============================================================================ + +#include "sharedDebug/FirstSharedDebug.h" +#include "sharedDebug/DataLint.h" + +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/ExitChain.h" + +#include +#include +#include +#include +#include + +// ============================================================================ + +namespace DataLintNamespace +{ + enum Mode + { + M_client, + M_server + }; + + typedef stdvector::fwd StringList; + typedef std::pair > WarningPair; + typedef stdvector::fwd WarningList; + typedef bool (*AssetFunction)(char const *); + + bool ms_installed = false; + DataLint::AssetType m_currentAssetType = DataLint::AT_invalid; + bool m_enabled = false; + WarningList * m_warningList = NULL; + StringList * m_assetStack = NULL; + DataLint::StringPairList * m_assetList = NULL; + std::string m_dataLintCategorizedAssetsFile("DataLint_CategorizedAssets.txt"); + std::string m_dataLintUnSupportedAssetsFile("DataLint_UnSupportedAssets.txt"); + Mode m_mode = M_client; + + bool isAnAppearanceAsset(char const *text); + bool isAnArrangementDescriptorAsset(char const *text); + bool isALocalizedStringAsset(char const *text); + bool isAnObjectTemplateAsset(char const *text); + bool isAPortalProprtyAsset(char const *text); + bool isAShaderTemplateAsset(char const *text); + bool isASkyBoxAsset(char const *text); + bool isASlotDescriptorAsset(char const *text); + bool isASoundAsset(char const *text); + bool isATerrainAsset(char const *text); + bool isATextureAsset(char const *text); + bool isATextureRendererTemplateAsset(char const *text); + bool isAnUnSupportedAsset(char const *text); + + void fixUpSlashes(char *text); + DataLint::StringPairList getList(int const reserveCount, AssetFunction listTypeFunction); + void writeToCategorizedFile(FILE *fp, char const *title, DataLint::AssetType const listType); + std::string formatErrorMessage(WarningPair &warningPair, int ¤tErrorCount); + void writeError(FILE *fp, WarningPair &warningPair, int ¤tErrorCount); +} + +using namespace DataLintNamespace; + +// ============================================================================ +// +// DataLint +// +// ============================================================================ + +void DataLint::install() +{ + DEBUG_FATAL(ms_installed, ("DataLint::install: already installed")); + ms_installed = true; + m_enabled = true; + + m_warningList = new WarningList(); + m_warningList->reserve(4096); + + m_assetStack = new StringList (); + + m_assetList = new StringPairList(); + m_assetList->reserve(4096); + + FatalSetThrowExceptions(true); + + ExitChain::add(&remove, "DataLint::remove"); +} + +//----------------------------------------------------------------------------- + +bool DataLint::isInstalled() +{ + return ms_installed; +} + +//----------------------------------------------------------------------------- + +void DataLint::report() +{ + if (m_enabled) + { + // Error Assets + + DEBUG_REPORT_LOG_PRINT(true, ("Writing error files\n")); + + // Setup filenames for client versus server mode + + std::string dataLintErrorsAll((m_mode == M_client) ? "DataLint_Errors_All.txt" : "DataLintServer_Errors_All.txt"); + std::string dataLintErrorsAllFatal((m_mode == M_client) ? "DataLint_Errors_All_Fatal.txt" : "DataLintServer_Errors_All_Fatal.txt"); + std::string dataLintErrorsAllWarning((m_mode == M_client) ? "DataLint_Errors_All_Warning.txt" : "DataLintServer_Errors_All_Warning.txt"); + std::string dataLintErrorsAllObjectTemplate((m_mode == M_client) ? "DataLint_Errors_ObjectTemplate.txt" : "DataLintServer_Errors_ObjectTemplate.txt"); + + // Server/client + + FILE *assetErrorFileAll = fopen(dataLintErrorsAll.c_str(), "wt"); + FILE *assetErrorFileAllFatal = fopen(dataLintErrorsAllFatal.c_str(), "wt"); + FILE *assetErrorFileAllWarning = fopen(dataLintErrorsAllWarning.c_str(), "wt"); + FILE *assetErrorFileObjectTemplate = fopen(dataLintErrorsAllObjectTemplate.c_str(), "wt"); + + // Client only + + FILE *assetErrorFileAppearance = NULL; + FILE *assetErrorFileArrangementDescriptor = NULL; + FILE *assetErrorFileLocalizedStringTable = NULL; + FILE *assetErrorFilePortalProperty = NULL; + FILE *assetErrorFileShaderTemplate = NULL; + FILE *assetErrorFileSkyBox = NULL; + FILE *assetErrorFileSlotDescriptor = NULL; + FILE *assetErrorFileSoundTemplate = NULL; + FILE *assetErrorFileTerrain = NULL; + FILE *assetErrorFileTexture = NULL; + FILE *assetErrorFileTextureRenderer = NULL; + + if (m_mode == M_client) + { + assetErrorFileAppearance = fopen("DataLint_Errors_Appearance.txt", "wt"); + assetErrorFileArrangementDescriptor = fopen("DataLint_Errors_ArrangementDescriptor.txt", "wt"); + assetErrorFileLocalizedStringTable = fopen("DataLint_Errors_LocalizedStringTable.txt", "wt"); + assetErrorFilePortalProperty = fopen("DataLint_Errors_PortalProperty.txt", "wt"); + assetErrorFileShaderTemplate = fopen("DataLint_Errors_ShaderTemplate.txt", "wt"); + assetErrorFileSkyBox = fopen("DataLint_Errors_SkyBox.txt", "wt"); + assetErrorFileSlotDescriptor = fopen("DataLint_Errors_SlotDescriptor.txt", "wt"); + assetErrorFileSoundTemplate = fopen("DataLint_Errors_SoundTemplate.txt", "wt"); + assetErrorFileTerrain = fopen("DataLint_Errors_Terrain.txt", "wt"); + assetErrorFileTexture = fopen("DataLint_Errors_Texture.txt", "wt"); + assetErrorFileTextureRenderer = fopen("DataLint_Errors_TextureRenderer.txt", "wt"); + } + + // Might want to think of a better way to keep track of the number of errors for each specific asset type. + + int totalErrorCountAll = 1; + int totalErrorCountAllFatal = 1; + int totalErrorCountAllWarning = 1; + int totalErrorCountAppearance = 1; + int totalErrorCountArrangementDescriptor = 1; + int totalErrorCountLocalizedStringTable = 1; + int totalErrorCountObjectTemplate = 1; + int totalErrorCountPortalProperty = 1; + int totalErrorCountShaderTemplate = 1; + int totalErrorCountSkyBox = 1; + int totalErrorCountSlotDescriptor = 1; + int totalErrorCountSoundTemplate = 1; + int totalErrorCountTerrain = 1; + int totalErrorCountTexture = 1; + int totalErrorCountTextureRenderer = 1; + + typedef std::set StringSet; + StringSet duplicateStringSet; + + if (assetErrorFileAll) + { + WarningList::iterator warningListIter = m_warningList->begin(); + + for (; warningListIter != m_warningList->end(); ++warningListIter) + { + // Build a duplicate string + + std::string duplicateString(warningListIter->first); + + StringList::const_iterator stringStackIter = warningListIter->second.second.begin(); + + for (; stringStackIter != warningListIter->second.second.end(); ++stringStackIter) + { + duplicateString += *stringStackIter; + } + + if (duplicateStringSet.find(duplicateString) == duplicateStringSet.end()) + { + // This is the first instance of this error, so log it + + duplicateStringSet.insert(duplicateString); + } + else + { + // We found a duplicate warning, so don't show it twice + + continue; + } + + // Write the error to the appropriate error file + + switch (warningListIter->second.first) + { + case AT_appearance: + { + if (m_mode == M_client) + { + writeError(assetErrorFileAppearance, *warningListIter, totalErrorCountAppearance); + } + } + break; + case AT_arrangementDescriptor: + { + if (m_mode == M_client) + { + writeError(assetErrorFileArrangementDescriptor, *warningListIter, totalErrorCountArrangementDescriptor); + } + } + break; + case AT_localizedStringTable: + { + if (m_mode == M_client) + { + writeError(assetErrorFileLocalizedStringTable, *warningListIter, totalErrorCountLocalizedStringTable); + } + } + break; + case AT_objectTemplate: + { + writeError(assetErrorFileObjectTemplate, *warningListIter, totalErrorCountObjectTemplate); + } + break; + case AT_portalProperty: + { + if (m_mode == M_client) + { + writeError(assetErrorFilePortalProperty, *warningListIter, totalErrorCountPortalProperty); + } + } + break; + case AT_shaderTemplate: + { + if (m_mode == M_client) + { + writeError(assetErrorFileShaderTemplate, *warningListIter, totalErrorCountShaderTemplate); + } + } + break; + case AT_skyBox: + { + if (m_mode == M_client) + { + writeError(assetErrorFileSkyBox, *warningListIter, totalErrorCountSkyBox); + } + } + break; + case AT_slotDescriptor: + { + if (m_mode == M_client) + { + writeError(assetErrorFileSlotDescriptor, *warningListIter, totalErrorCountSlotDescriptor); + } + } + break; + case AT_soundTemplate: + { + if (m_mode == M_client) + { + writeError(assetErrorFileSoundTemplate, *warningListIter, totalErrorCountSoundTemplate); + } + } + break; + case AT_terrain: + { + if (m_mode == M_client) + { + writeError(assetErrorFileTerrain, *warningListIter, totalErrorCountTerrain); + } + } + break; + case AT_texture: + { + if (m_mode == M_client) + { + writeError(assetErrorFileTexture, *warningListIter, totalErrorCountTexture); + } + } + break; + case AT_textureRendererTemplate: + { + if (m_mode == M_client) + { + writeError(assetErrorFileTextureRenderer, *warningListIter, totalErrorCountTextureRenderer); + } + } + break; + default: + { + DEBUG_REPORT_LOG_PRINT(true, ("DataLint::remove() - Unsupported asset type: %s", warningListIter->first.c_str())); + } + break; + } + + // Write the error to the master error file + + writeError(assetErrorFileAll, *warningListIter, totalErrorCountAll); + + // If this is a fatal, write to the fatal list + + if (strstr(warningListIter->first.c_str(), "FATAL:")) + { + writeError(assetErrorFileAllFatal, *warningListIter, totalErrorCountAllFatal); + } + + // If a warning, write to the warning list + + if (strstr(warningListIter->first.c_str(), "WARNING:")) + { + writeError(assetErrorFileAllWarning, *warningListIter, totalErrorCountAllWarning); + } + } + } + + // UnSupported Assets + + DEBUG_REPORT_LOG_PRINT(true, ("Writing unsupported assets list: %s\n", m_dataLintUnSupportedAssetsFile.c_str())); + + FILE *fp = fopen(m_dataLintUnSupportedAssetsFile.c_str(), "wt"); + + if (fp) + { + StringPairList unSupportedStringPairList(getList(AT_unSupported)); + StringPairList::iterator stringPairListIter = unSupportedStringPairList.begin(); + int count = 1; + + for (; stringPairListIter != unSupportedStringPairList.end(); ++stringPairListIter) + { + fprintf(fp, "%3d %s @ %s\n", count, stringPairListIter->first.c_str(), stringPairListIter->second.c_str()); + ++count; + } + + fclose(fp); + } + else + { + DEBUG_REPORT_LOG_PRINT(true, ("Error writing unsupported assets list: %s\n", m_dataLintUnSupportedAssetsFile.c_str())); + } + + // Categorized Assets + + DEBUG_REPORT_LOG_PRINT(true, ("Writing categorized files list: %s\n", m_dataLintCategorizedAssetsFile.c_str())); + + fp = fopen(m_dataLintCategorizedAssetsFile.c_str(), "wt"); + + if (fp) + { + fprintf(fp, "This file contains a categorized listing of the linted assets in the game. The categories are as follows:\n"); + fprintf(fp, "\n"); + fprintf(fp, "1. Appearances (%5d)\n", getList(AT_appearance).size()); + fprintf(fp, "2. Arrangement Descriptors (%5d)\n", getList(AT_arrangementDescriptor).size()); + fprintf(fp, "3. Localized String Tables (%5d)\n", getList(AT_localizedStringTable).size()); + fprintf(fp, "4. Object Templates (%5d)\n", getList(AT_objectTemplate).size()); + fprintf(fp, "5. Portal Properties (%5d)\n", getList(AT_portalProperty).size()); + fprintf(fp, "6. Shader Templates (%5d)\n", getList(AT_shaderTemplate).size()); + fprintf(fp, "7. SkyBoxes (%5d)\n", getList(AT_skyBox).size()); + fprintf(fp, "8. Slot Descriptors (%5d)\n", getList(AT_slotDescriptor).size()); + fprintf(fp, "9. Sound Templates (%5d)\n", getList(AT_soundTemplate).size()); + fprintf(fp, "10. Terrain (%5d)\n", getList(AT_terrain).size()); + fprintf(fp, "11. Textures (%5d)\n", getList(AT_texture).size()); + fprintf(fp, "12. Texture Renderer Templates (%5d)\n", getList(AT_textureRendererTemplate).size()); + fprintf(fp, "--------------------------------------\n"); + fprintf(fp, "13. Total Linted Assets (%5d)\n", m_assetList->size() - getList(AT_unSupported).size()); + fprintf(fp, "\n"); + + writeToCategorizedFile(fp, "Appearances", AT_appearance); + writeToCategorizedFile(fp, "Arrangement Descriptors", AT_arrangementDescriptor); + writeToCategorizedFile(fp, "Localized String Tables", AT_localizedStringTable); + writeToCategorizedFile(fp, "Object Templates", AT_objectTemplate); + writeToCategorizedFile(fp, "Portal Properties", AT_portalProperty); + writeToCategorizedFile(fp, "Shader Templates", AT_shaderTemplate); + writeToCategorizedFile(fp, "SkyBoxes", AT_skyBox); + writeToCategorizedFile(fp, "Slot Descriptors", AT_slotDescriptor); + writeToCategorizedFile(fp, "Sound Templates", AT_soundTemplate); + writeToCategorizedFile(fp, "Terrain", AT_terrain); + writeToCategorizedFile(fp, "Textures", AT_texture); + writeToCategorizedFile(fp, "Texture Renderer Templates", AT_textureRendererTemplate); + + fclose(fp); + } + + if (assetErrorFileAll) { fclose(assetErrorFileAll); } + if (assetErrorFileAllFatal) { fclose(assetErrorFileAllFatal); } + if (assetErrorFileAllWarning) { fclose(assetErrorFileAllWarning); } + if (assetErrorFileObjectTemplate) { fclose(assetErrorFileObjectTemplate); } + + if (m_mode == M_client) + { + if (assetErrorFileAppearance) { fclose(assetErrorFileAppearance); } + if (assetErrorFileArrangementDescriptor) { fclose(assetErrorFileArrangementDescriptor); } + if (assetErrorFileLocalizedStringTable) { fclose(assetErrorFileLocalizedStringTable); } + if (assetErrorFilePortalProperty) { fclose(assetErrorFilePortalProperty); } + if (assetErrorFileShaderTemplate) { fclose(assetErrorFileShaderTemplate); } + if (assetErrorFileSkyBox) { fclose(assetErrorFileSkyBox); } + if (assetErrorFileSlotDescriptor) { fclose(assetErrorFileSlotDescriptor); } + if (assetErrorFileSoundTemplate) { fclose(assetErrorFileSoundTemplate); } + if (assetErrorFileTerrain) { fclose(assetErrorFileTerrain); } + if (assetErrorFileTexture) { fclose(assetErrorFileTexture); } + if (assetErrorFileTextureRenderer) { fclose(assetErrorFileTextureRenderer); } + } + } +} + +//----------------------------------------------------------------------------- +void DataLint::remove() +{ + DEBUG_FATAL(!ms_installed, ("DataLint::remove: not installed")); + ms_installed = false; + m_enabled = false; + + delete m_warningList; + delete m_assetStack; + delete m_assetList; + + FatalSetThrowExceptions(false); +} + +//----------------------------------------------------------------------------- +void DataLintNamespace::writeError(FILE *fp, WarningPair &warningPair, int ¤tErrorCount) +{ + std::string formatedErrorMessage(formatErrorMessage(warningPair, currentErrorCount)); + + if (fp) + { + fprintf(fp, "%s", formatedErrorMessage.c_str()); + } +} + +//----------------------------------------------------------------------------- +std::string DataLintNamespace::formatErrorMessage(WarningPair &warningPair, int ¤tErrorCount) +{ + std::string result; + char formatedError[4096]; + char text[4096]; + sprintf(text, "%s", warningPair.first.c_str()); + fixUpSlashes(text); + + char *assetError = strstr(text, " : "); + + if (assetError != NULL) + { + ++assetError; + ++assetError; + ++assetError; + } + + char *lineOfCode = &text[0]; + char *seperator = strstr(text, " : "); + + if (seperator) + { + *seperator = '\0'; + } + + if (assetError) + { + // Remove any trailing carriage returns + + int assetErrorLength = strlen(assetError); + + if (assetErrorLength > 0) + { + char *walkPtr = &assetError[0] + (assetErrorLength - 1); + + while ((assetErrorLength > 0) && (*walkPtr == '\n')) + { + --assetErrorLength; + *walkPtr = '\0'; + --walkPtr; + } + } + + sprintf(formatedError, "%3d Error: %s\n", currentErrorCount, assetError); + result += formatedError; + } + + if (lineOfCode) + { + sprintf(formatedError, " Line of Code: %s\n", lineOfCode); + result += formatedError; + } + + StringList::reverse_iterator stringListIter = warningPair.second.second.rbegin(); + + for (; stringListIter != warningPair.second.second.rend(); ++stringListIter) + { + std::string stackString(*stringListIter); + + sprintf(text, " Loaded From: %s\n", stackString.c_str()); + fixUpSlashes(text); + + sprintf(formatedError, "%s", text); + result += formatedError; + } + + result += "\n"; + ++currentErrorCount; + + return result; +} + +//----------------------------------------------------------------------------- +void DataLint::setEnabled(bool const enabled) +{ + m_enabled = enabled; +} + +//----------------------------------------------------------------------------- +bool DataLint::isEnabled() +{ + return m_enabled || ConfigSharedFoundation::getVerboseWarnings(); +} + +//----------------------------------------------------------------------------- +void DataLint::pushAsset(char const *assetPath) +{ + if (m_assetStack) + { + int const size = m_assetStack->size(); + UNREF(size); + m_assetStack->push_back(assetPath); + } +} + +//----------------------------------------------------------------------------- +void DataLint::popAsset() +{ + if (m_assetStack) + { + int const size = m_assetStack->size(); + UNREF(size); + DEBUG_FATAL(m_assetStack->empty(), ("DataLint::popAsset() - Trying to pop the asset stack when it is empty.")); + m_assetStack->pop_back(); + } +} + +//----------------------------------------------------------------------------- + +void DataLint::logWarning(std::string const &warning) +{ + if (m_enabled) + { + m_warningList->push_back(std::make_pair(warning, std::make_pair(m_currentAssetType, *m_assetStack))); + } +} + +//----------------------------------------------------------------------------- +void DataLint::clearAssetStack() +{ + if (m_assetStack) + m_assetStack->clear(); +} + +//----------------------------------------------------------------------------- +void DataLint::addFilePath(char const *filePath) +{ + if (filePath == NULL || (strlen(filePath) <= 0)) + { + return; + } + + if (m_assetList != NULL) + { + char text[4096]; + sprintf(text, "%s", filePath); + + char *seperator = strstr(text, " @ "); + char *longPath = seperator; + ++longPath; + ++longPath; + ++longPath; + char *shortPath = &text[0]; + *seperator = '\0'; + + m_assetList->push_back(std::make_pair(shortPath, longPath)); + } +} + +//----------------------------------------------------------------------------- +void DataLint::removeFilePath(char const *filePath) +{ + if (m_assetList != NULL) + { + StringPairList::iterator stringPairListIter = m_assetList->begin(); + + for (; stringPairListIter != m_assetList->end(); ++stringPairListIter) + { + char const *first = stringPairListIter->first.c_str(); + + if (strcmp(first, filePath) == 0) + { + m_assetList->erase(stringPairListIter); + } + } + } +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isAnAppearanceAsset(char const *text) +{ + bool const appearanceAsset = (strstr(text, "appearance/") != NULL); + bool const portalPropertyAsset = (strstr(text, ".pob") != NULL); + + return (appearanceAsset && !portalPropertyAsset); +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isAnArrangementDescriptorAsset(char const *text) +{ + bool const arrangementDescriptorAsset = (strstr(text, "slot/arrangement/") != NULL); + + return arrangementDescriptorAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isALocalizedStringAsset(char const *text) +{ + bool const localizedStringAsset = (strstr(text, ".stf") != NULL); + + return localizedStringAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isAnObjectTemplateAsset(char const *text) +{ + bool result = false; + UNREF(text); + bool const isInTheObjectDirectory = (strstr(text, "object/") != NULL); + bool const isInTheAbstractDirectory = (strstr(text, "abstract/") != NULL); + + if (isInTheObjectDirectory || isInTheAbstractDirectory) + { + bool const arrangementDescriptorAsset = isAnArrangementDescriptorAsset(text); + bool const slotDescriptorAsset = isASlotDescriptorAsset(text); + + result = (!arrangementDescriptorAsset) && (!slotDescriptorAsset); + } + + return result; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isAPortalProprtyAsset(char const *text) +{ + bool const portalPropertyAsset = (strstr(text, ".pob") != NULL); + + return portalPropertyAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isAShaderTemplateAsset(char const *text) +{ + bool const shaderTemplateAsset = (strstr(text, "shader/") != NULL); + + return shaderTemplateAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isASkyBoxAsset(char const *text) +{ + bool const skyBoxAsset = (strstr(text, "skybox/") != NULL); + + return skyBoxAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isASlotDescriptorAsset(char const *text) +{ + bool const slotDescriptorAsset = (strstr(text, "slot/descriptor/") != NULL); + + return slotDescriptorAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isASoundAsset(char const *text) +{ + bool const soundAsset = (strstr(text, "sound/") != NULL); + + return soundAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isATerrainAsset(char const *text) +{ + return strstr(text, ".trn") != 0; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isATextureAsset(char const *text) +{ + bool const textureAsset = (strstr(text, ".dds") != NULL); + + return textureAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isATextureRendererTemplateAsset(char const *text) +{ + bool const textureRendererAsset = (strstr(text, ".trt") != NULL); + + return textureRendererAsset; +} + +//----------------------------------------------------------------------------- +bool DataLintNamespace::isAnUnSupportedAsset(char const *text) +{ + bool const appearanceAsset = isAnAppearanceAsset(text); + bool const arrangementDescriptorAsset = isAnArrangementDescriptorAsset(text); + bool const localizedStringAsset = isALocalizedStringAsset(text); + bool const objectTemplateAsset = isAnObjectTemplateAsset(text); + bool const portalPropertyAsset = isAPortalProprtyAsset(text); + bool const shaderTemplateAsset = isAShaderTemplateAsset(text); + bool const skyBoxAsset = isASkyBoxAsset(text); + bool const slotDescriptorAsset = isASlotDescriptorAsset(text); + bool const soundAsset = isASoundAsset(text); + bool const terrainAsset = isATerrainAsset(text); + bool const textureAsset = isATextureAsset(text); + bool const textureRendererTemplateAsset = isATextureRendererTemplateAsset(text); + + bool const result = !(appearanceAsset || + arrangementDescriptorAsset || + localizedStringAsset || + objectTemplateAsset || + portalPropertyAsset || + shaderTemplateAsset || + skyBoxAsset || + slotDescriptorAsset || + soundAsset || + terrainAsset || + textureAsset || + textureRendererTemplateAsset); + + return result; +} + +//----------------------------------------------------------------------------- +DataLint::StringPairList DataLintNamespace::getList(int const reserveCount, AssetFunction assetTypeFunction) +{ + DEBUG_FATAL(!m_assetList, ("DataLint::getList() - m_assetList is NULL")); + + // Create the list of terrains + + DataLint::StringPairList stringPairList; + stringPairList.reserve(reserveCount); + + DataLint::StringPairList::iterator stringPairListIter = m_assetList->begin(); + + for (; stringPairListIter != m_assetList->end(); ++stringPairListIter) + { + char const *first = stringPairListIter->first.c_str(); + char const *second = stringPairListIter->second.c_str(); + + if (assetTypeFunction(first)) + { + stringPairList.push_back(std::make_pair(first, second)); + } + } + + return stringPairList; +} + +//----------------------------------------------------------------------------- +DataLint::StringPairList DataLint::getList(AssetType const assetType) +{ + switch (assetType) + { + case AT_appearance: + { + return DataLintNamespace::getList(8192, isAnAppearanceAsset); + } + break; + case AT_arrangementDescriptor: + { + return DataLintNamespace::getList(1024, isAnArrangementDescriptorAsset); + } + break; + case AT_localizedStringTable: + { + return DataLintNamespace::getList(1024, isALocalizedStringAsset); + } + break; + case AT_objectTemplate: + { + return DataLintNamespace::getList(8192, isAnObjectTemplateAsset); + } + break; + case AT_portalProperty: + { + return DataLintNamespace::getList(512, isAPortalProprtyAsset); + } + break; + case AT_shaderTemplate: + { + return DataLintNamespace::getList(4096, isAShaderTemplateAsset); + } + break; + case AT_skyBox: + { + return DataLintNamespace::getList(256, isASkyBoxAsset); + } + break; + case AT_slotDescriptor: + { + return DataLintNamespace::getList(1024, isASlotDescriptorAsset); + } + break; + case AT_soundTemplate: + { + return DataLintNamespace::getList(4096, isASoundAsset); + } + break; + case AT_terrain: + { + return DataLintNamespace::getList(32, isATerrainAsset); + } + break; + case AT_texture: + { + return DataLintNamespace::getList(8192, isATextureAsset); + } + break; + case AT_textureRendererTemplate: + { + return DataLintNamespace::getList(512, isATextureRendererTemplateAsset); + } + break; + case AT_unSupported: + { + return DataLintNamespace::getList(4096, isAnUnSupportedAsset); + } + break; + default: + { + DEBUG_FATAL(true, ("DataLint::getList() - Unknown list type.")); + } + } + + return StringPairList(); +} + +//----------------------------------------------------------------------------- +void DataLintNamespace::fixUpSlashes(char *text) +{ + char *slashEater = &text[0]; + + while (*slashEater != '\0') + { + if (*slashEater == '\\') + { + *slashEater = '/'; + } + + ++slashEater; + } +} + +//----------------------------------------------------------------------------- +void DataLintNamespace::writeToCategorizedFile(FILE *fp, char const *title, DataLint::AssetType const assetType) +{ + DataLint::StringPairList stringPairlist(DataLint::getList(assetType)); + + fprintf(fp, "-----------------%s (%d assets)-----------------\n", title, static_cast(stringPairlist.size())); + fprintf(fp, "\n"); + DataLint::StringPairList::const_iterator stringPairListIter = stringPairlist.begin(); + int count = 1; + + for (; stringPairListIter != stringPairlist.end(); ++stringPairListIter) + { + fprintf(fp, "%4d %s @ %s\n", count, stringPairListIter->first.c_str(), stringPairListIter->second.c_str()); + ++count; + } + + fprintf(fp, "\n"); +} + +//----------------------------------------------------------------------------- +void DataLint::setCurrentAssetType(AssetType const assetType) +{ + m_currentAssetType = assetType; +} + +//----------------------------------------------------------------------------- +void DataLint::setClientMode() +{ + m_mode = M_client; +} + +//----------------------------------------------------------------------------- +void DataLint::setServerMode() +{ + m_mode = M_server; +} + +// ============================================================================ diff --git a/src/engine/shared/library/sharedDebug/src/shared/PixCounter.cpp b/src/engine/shared/library/sharedDebug/src/shared/PixCounter.cpp index 5c67b80a4..dcb149667 100644 --- a/src/engine/shared/library/sharedDebug/src/shared/PixCounter.cpp +++ b/src/engine/shared/library/sharedDebug/src/shared/PixCounter.cpp @@ -461,7 +461,7 @@ void PixCounter::String::set(const char * format, ...) char buffer[512]; vsnprintf(buffer, sizeof(buffer), format, va); - buffer[sizeof(buffer-1)] = '\0'; + buffer[sizeof(buffer)-1] = '\0'; operator =(buffer); va_end(va); diff --git a/src/engine/shared/library/sharedDebug/src/shared/Profiler.cpp b/src/engine/shared/library/sharedDebug/src/shared/Profiler.cpp index e549b96bf..eb484451b 100644 --- a/src/engine/shared/library/sharedDebug/src/shared/Profiler.cpp +++ b/src/engine/shared/library/sharedDebug/src/shared/Profiler.cpp @@ -1,876 +1,876 @@ -// ====================================================================== -// -// Profiler.cpp -// -// Copyright 2003 Sony Online Entertainment -// All Rights Reserved -// -// ====================================================================== - -#include "sharedDebug/FirstSharedDebug.h" -#include "sharedDebug/Profiler.h" - -#include "sharedDebug/DebugFlags.h" -#include "sharedDebug/DebugKey.h" -#include "sharedDebug/ProfilerTimer.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/ExitChain.h" -#include "sharedFoundation/MemoryBlockManager.h" -#include "sharedFoundation/MemoryBlockManagerMacros.h" - -#include -#include - -// ====================================================================== - -namespace ProfilerNamespace -{ - struct ProfilerEntry - { - typedef std::vector Children; - - const char *name; - int parent; - Children children; - int totalCalls; - ProfilerTimer::Type totalTime; - }; - - class VisibleExpandableEntry - { - public: - - VisibleExpandableEntry(char const * name); - ~VisibleExpandableEntry(); - - char const * getName() const; - - bool isExpanded() const; - void setExpanded(bool opened); - void toggleExpanded(); - - void markAllChildrenInvisible(); - VisibleExpandableEntry * findOrAddExpandableChild(char const *name); - bool pruneInvisibleChildren(); - - private: - - typedef std::vector Children; - - private: - - static bool ms_destroyedSelected; - - private: - - char const * m_name; - Children m_children; - bool m_expanded; - bool m_visible; - }; - - typedef std::vector ProfilerEntries; - typedef std::vector SortedProfilerEntries; - - struct SortMultisiteEntries - { - bool operator()(ProfilerEntry const * lhs, ProfilerEntry const * rhs) const; - }; - - void formatInteger(int length, int value); - void formatString(const char *string); - bool formatEntry(int indent, ProfilerTimer::Type totalTime, int totalCalls, bool expandable, bool expanded, bool selected, char const *name); - void processEntry(char const *rootName, int indent, ProfilerEntry const & entry, VisibleExpandableEntry * opened); - void enterWithTime(char const *name, ProfilerTimer::Type time); - void leaveWithTime(char const *name, ProfilerTimer::Type time); - void generateReport(); - bool myCompare(const char *a, const char *b); - - - std::vector ms_profilerEntryStack; - ProfilerEntries * ms_profilerEntriesCurrent; - ProfilerEntries * ms_profilerEntriesLast; - ProfilerEntries ms_profilerEntries1; - ProfilerEntries ms_profilerEntries2; - - char const * ms_rootProfilerName; - - VisibleExpandableEntry * ms_rootVisibleExpandableEntry; - VisibleExpandableEntry * ms_beforeSelectedVisibleExpandableEntry; - VisibleExpandableEntry * ms_selectedVisibleExpandableEntry; - VisibleExpandableEntry * ms_afterSelectedVisibleExpandableEntry; - VisibleExpandableEntry * ms_previousVisibleExpandableEntry; - - std::vector ms_text; - ProfilerTimer::Type ms_timeDivisor; - ProfilerTimer::Type ms_percentageDivisor; - ProfilerTimer::Type ms_frequency; - bool ms_enabled = true; - bool ms_desiredEnabled = true; - bool ms_debugKeyContext; - bool ms_debugReportFlag; - bool ms_debugReportLogFlag; - bool ms_temporaryExpandAll; - bool ms_multisiteCallerSummary; - bool ms_setRoot; - bool ms_selectedUp; - bool ms_selectedDown; - bool ms_selectedExpand; - bool ms_selectedCollapse; - bool ms_selectedToggle; - int ms_displayPercentageMinimum; - int ms_stackDepth; - SortedProfilerEntries ms_sortedProfilerEntries; - -} -using namespace ProfilerNamespace; - -bool VisibleExpandableEntry::ms_destroyedSelected; - -// ====================================================================== - -VisibleExpandableEntry::VisibleExpandableEntry(char const * name) -: - m_name(name), - m_children(), - m_expanded(false), - m_visible(true) -{ -} - -// ---------------------------------------------------------------------- - -VisibleExpandableEntry::~VisibleExpandableEntry() -{ - // handle case where the selected item gets deleted - if (this == ms_selectedVisibleExpandableEntry) - ms_destroyedSelected = true; - - while (!m_children.empty()) - { - VisibleExpandableEntry *back = m_children.back(); - m_children.pop_back(); - delete back; - } -} - -// ---------------------------------------------------------------------- - -inline char const * VisibleExpandableEntry::getName() const -{ - return m_name; -} - -// ---------------------------------------------------------------------- - -inline bool VisibleExpandableEntry::isExpanded() const -{ - return m_expanded || ms_temporaryExpandAll; -} - -// ---------------------------------------------------------------------- - -inline void VisibleExpandableEntry::setExpanded(bool expanded) -{ - m_expanded = expanded; -} - -// ---------------------------------------------------------------------- - -inline void VisibleExpandableEntry::toggleExpanded() -{ - m_expanded = !m_expanded; -} - -// ---------------------------------------------------------------------- - -void VisibleExpandableEntry::markAllChildrenInvisible() -{ - Children::iterator const iEnd = m_children.end(); - for (Children::iterator i = m_children.begin(); i != iEnd; ++i) - (*i)->m_visible = false; -} - -// ---------------------------------------------------------------------- - -VisibleExpandableEntry * VisibleExpandableEntry::findOrAddExpandableChild(char const *name) -{ - Children::iterator const iEnd = m_children.end(); - for (Children::iterator i = m_children.begin(); i != iEnd; ++i) - { - VisibleExpandableEntry * child = *i; - if (child->m_name == name) - { - child->m_visible = true; - return child; - } - } - - m_children.push_back(new VisibleExpandableEntry(name)); - return m_children.back(); -} - -// ---------------------------------------------------------------------- - -bool VisibleExpandableEntry::pruneInvisibleChildren() -{ - for (Children::iterator i = m_children.begin(); i != m_children.end(); ) - { - if ((*i)->m_visible == false) - { - i = m_children.erase(i); - } - else - { - ++i; - } - } - bool const result = ms_destroyedSelected; - ms_destroyedSelected = false; - return result; -} - -// ====================================================================== - -void Profiler::install() -{ - ExitChain::add(Profiler::remove, "Profiler::remove"); - - ms_profilerEntriesCurrent = &ms_profilerEntries1; - ms_profilerEntriesLast = &ms_profilerEntries2; - ms_rootVisibleExpandableEntry = new VisibleExpandableEntry(NULL); - ms_rootVisibleExpandableEntry->setExpanded(true); - ms_selectedVisibleExpandableEntry = ms_rootVisibleExpandableEntry; -} - -// ---------------------------------------------------------------------- - -void Profiler::remove() -{ - delete ms_rootVisibleExpandableEntry; - ms_rootVisibleExpandableEntry = NULL; - ms_beforeSelectedVisibleExpandableEntry = NULL; - ms_selectedVisibleExpandableEntry = NULL; - ms_afterSelectedVisibleExpandableEntry = NULL; - ms_previousVisibleExpandableEntry = NULL; - ms_profilerEntriesCurrent = NULL; - ms_profilerEntriesLast = NULL; -} - -// ---------------------------------------------------------------------- - -void Profiler::registerDebugFlags() -{ - DebugKey::registerFlag(ms_debugKeyContext, "profiler"); - DebugFlags::registerFlag(ms_debugReportFlag, "SharedDebug/Profiler", "report", printLastFrameData); - DebugFlags::registerFlag(ms_desiredEnabled, "SharedDebug/Profiler", "enabled"); - DebugFlags::registerFlag(ms_debugReportLogFlag, "SharedDebug/Profiler", "logNextReport"); - DebugFlags::registerFlag(ms_temporaryExpandAll, "SharedDebug/Profiler", "temporaryExpandAll"); - ms_displayPercentageMinimum = ConfigFile::getKeyInt("SharedDebug/Profiler", "displayPercentageMinimum", 0); -} - -// ---------------------------------------------------------------------- - -void Profiler::enable(bool enable) -{ - ms_desiredEnabled = enable; -} - -// ---------------------------------------------------------------------- - -void Profiler::enableProfilerOutput(bool enableOutput) -{ - ms_debugReportFlag = enableOutput; -} - -// ---------------------------------------------------------------------- - -void ProfilerNamespace::formatInteger(int length, int value) -{ - // pad with spaces - for (int i = 0; i < length; ++i) - ms_text.push_back(' '); - - // get a pointer to the last character - char *buffer = &ms_text[ms_text.size()-1]; - - // write the value right to left - do - { - *buffer = static_cast('0' + (value % 10)); - --length; - --buffer; - value /= 10; - } while (length && value); -} - -// ---------------------------------------------------------------------- - -void ProfilerNamespace::formatString(char const *string) -{ - for ( ; *string; ++string) - ms_text.push_back(*string); -} - -// ---------------------------------------------------------------------- - -bool ProfilerNamespace::formatEntry(int indent, ProfilerTimer::Type totalTime, int totalCalls, bool expandable, bool expanded, bool selected, char const * name) -{ - int const percentage = static_cast(totalTime / ms_percentageDivisor); - - if (percentage < ms_displayPercentageMinimum) - return false; - - int const ticks = static_cast(totalTime / ms_timeDivisor); - - // indent - { - for (int i = 0; i < indent; ++i) - ms_text.push_back(' '); - } - - // print number of ticks - formatInteger(7, ticks); - ms_text.push_back(' '); - - // pring % of frame time - formatInteger(3, percentage); - ms_text.push_back('%'); - ms_text.push_back(' '); - - // print the number of calls - formatInteger(8, totalCalls); - ms_text.push_back(' '); - - if (expandable) - { - // print the expanded state - if (expanded) - ms_text.push_back('-'); - else - ms_text.push_back('+'); - - // print the selection marker - if (selected) - ms_text.push_back('>'); - else - ms_text.push_back(' '); - } - else - { - ms_text.push_back(' '); - ms_text.push_back(' '); - } - - // print the entry name - formatString(name); - ms_text.push_back('\n'); - - return true; -} - -// ---------------------------------------------------------------------- - -void ProfilerNamespace::processEntry(char const *rootName, int indent, ProfilerEntry const & entry, VisibleExpandableEntry * visibleExpandableEntry) -{ - if (rootName == entry.name) - rootName = NULL; - - if (!rootName) - { - if (!formatEntry(indent, entry.totalTime, entry.totalCalls, visibleExpandableEntry != NULL, visibleExpandableEntry && visibleExpandableEntry->isExpanded(), visibleExpandableEntry == ms_selectedVisibleExpandableEntry, entry.name)) - return; - } - - if (visibleExpandableEntry) - { - // keep track of before and after the selected entry - if (ms_selectedVisibleExpandableEntry == visibleExpandableEntry) - ms_beforeSelectedVisibleExpandableEntry = ms_previousVisibleExpandableEntry; - if (!entry.children.empty()) - { - if (ms_previousVisibleExpandableEntry == ms_selectedVisibleExpandableEntry) - ms_afterSelectedVisibleExpandableEntry = visibleExpandableEntry; - ms_previousVisibleExpandableEntry = visibleExpandableEntry; - } - - // process the children - visibleExpandableEntry->markAllChildrenInvisible(); - - // indent if we have already seen the root - if (!rootName) - indent += 2; - - if (visibleExpandableEntry->isExpanded()) - { - ProfilerEntry::Children::const_iterator iEnd = entry.children.end(); - for (ProfilerEntry::Children::const_iterator i = entry.children.begin(); i != iEnd; ++i) - { - ProfilerEntry const & child = (*ms_profilerEntriesLast)[*i]; - - if (child.children.empty()) - { - processEntry(rootName, indent, child, NULL); - } - else - { - VisibleExpandableEntry * childVisibleExpandableEntry = visibleExpandableEntry->findOrAddExpandableChild(child.name); - processEntry(rootName, indent, child, childVisibleExpandableEntry); - } - } - } - - if (visibleExpandableEntry->pruneInvisibleChildren()) - ms_selectedVisibleExpandableEntry = visibleExpandableEntry; - } -} - -// ---------------------------------------------------------------------- - -inline bool SortMultisiteEntries::operator()(ProfilerEntry const * lhs, ProfilerEntry const * rhs) const -{ - return lhs->name < rhs->name; -} - -// ---------------------------------------------------------------------- - -void ProfilerNamespace::generateReport() -{ - PROFILER_AUTO_BLOCK_DEFINE("Profiler::generateReport"); - - if (!ms_profilerEntriesLast->empty()) - { - if (ms_debugKeyContext) - { - if (DebugKey::isPressed(1)) - ms_desiredEnabled = !ms_desiredEnabled; - if (DebugKey::isPressed(2)) - ms_debugReportLogFlag = true; - if (DebugKey::isPressed(3)) - ms_temporaryExpandAll = !ms_temporaryExpandAll; - if (DebugKey::isPressed(4)) - ms_setRoot = true; - if (DebugKey::isPressed(5)) - ms_multisiteCallerSummary = !ms_multisiteCallerSummary; - if (DebugKey::isPressed(6)) - ms_displayPercentageMinimum = clamp(0, ms_displayPercentageMinimum - 1, 100); - if (DebugKey::isPressed(7)) - ms_displayPercentageMinimum = clamp(0, ms_displayPercentageMinimum + 1, 100); - if (DebugKey::isPressed(8)) - Profiler::selectionMoveUp(); - if (DebugKey::isPressed(9)) - Profiler::selectionMoveDown(); - if (DebugKey::isPressed(0)) - Profiler::selectionToggleExpanded(); - } - - // try to get the ticks to approximately 1 million per second - ms_timeDivisor = ms_frequency / static_cast(1000000); - if (ms_timeDivisor == 0) - ms_timeDivisor = 1; - - // figure out what to divide by to get the value in percent of total frame time - ms_percentageDivisor = (*ms_profilerEntriesLast)[0].totalTime / static_cast(100); - if (ms_percentageDivisor == 0) - ms_percentageDivisor = 1; - - formatString("Profiler (min "); - formatInteger(3, ms_displayPercentageMinimum); - formatString("%):\n"); - - ProfilerEntry const & rootEntry = (*ms_profilerEntriesLast)[0]; - - ms_rootVisibleExpandableEntry->markAllChildrenInvisible(); - ms_rootVisibleExpandableEntry->findOrAddExpandableChild(rootEntry.name); - - ms_previousVisibleExpandableEntry = NULL; - ms_beforeSelectedVisibleExpandableEntry = NULL; - ms_afterSelectedVisibleExpandableEntry = NULL; - processEntry(ms_rootProfilerName, 0, rootEntry, ms_rootVisibleExpandableEntry); - - if (ms_rootVisibleExpandableEntry->pruneInvisibleChildren()) - ms_selectedVisibleExpandableEntry = ms_rootVisibleExpandableEntry; - - if (ms_setRoot) - { - if (ms_rootProfilerName) - ms_rootProfilerName = NULL; - else - ms_rootProfilerName = ms_selectedVisibleExpandableEntry->getName(); - ms_setRoot = false; - } - - if (ms_selectedUp) - { - if (ms_beforeSelectedVisibleExpandableEntry) - ms_selectedVisibleExpandableEntry = ms_beforeSelectedVisibleExpandableEntry; - ms_selectedUp = false; - } - - if (ms_selectedDown) - { - if (ms_afterSelectedVisibleExpandableEntry) - ms_selectedVisibleExpandableEntry = ms_afterSelectedVisibleExpandableEntry; - ms_selectedDown = false; - } - - if (ms_selectedExpand) - { - ms_selectedVisibleExpandableEntry->setExpanded(true); - ms_selectedExpand= false; - } - - if (ms_selectedCollapse) - { - ms_selectedVisibleExpandableEntry->setExpanded(false); - ms_selectedCollapse = false; - } - - if (ms_selectedToggle) - { - ms_selectedVisibleExpandableEntry->toggleExpanded(); - ms_selectedToggle = false; - } - } - - if (ms_multisiteCallerSummary) - { - // generate a vector of all entries - { - ms_sortedProfilerEntries.clear(); - ProfilerEntries::iterator const iEnd = ms_profilerEntriesLast->end(); - for (ProfilerEntries::iterator i = ms_profilerEntriesLast->begin(); i != iEnd; ++i) - ms_sortedProfilerEntries.push_back(&(*i)); - } - - // sort them by name - std::sort(ms_sortedProfilerEntries.begin(), ms_sortedProfilerEntries.end(), SortMultisiteEntries()); - - // find multiple entries with the same name - { - formatString("Multisite entries:\n"); - - SortedProfilerEntries::iterator i = ms_sortedProfilerEntries.begin(); - SortedProfilerEntries::iterator const iEnd = ms_sortedProfilerEntries.end(); - do - { - char const * const iName = (*i)->name; - SortedProfilerEntries::iterator j = i + 1; - bool display = false; - int totalCalls = (*i)->totalCalls; - ProfilerTimer::Type totalTime = (*i)->totalTime; - - // find the span of entries with the same name - while (j != iEnd && iName == (*j)->name) - { - display = true; - totalCalls += (*j)->totalCalls; - totalTime += (*j)->totalTime; - ++j; - } - - // if the name had multiple entries, report so here - if (display) - formatEntry(2, totalTime, totalCalls, false, false, false, iName); - - i = j; - - } while (i != iEnd); - } - - } - - ms_text.push_back('\0'); -} - -// ---------------------------------------------------------------------- - -char const *Profiler::getLastFrameData() -{ - if (ms_text.empty()) - generateReport(); - - return &(ms_text[0]); -} - -// ---------------------------------------------------------------------- - -void Profiler::printLastFrameData() -{ - if (ms_text.empty()) - generateReport(); - - Report::setFlags(Report::RF_print | (ms_debugReportLogFlag ? Report::RF_log : 0)); - Report::puts(&ms_text[0]); - ms_debugReportLogFlag = false; -} - -// ---------------------------------------------------------------------- - -void Profiler::selectionMoveUp() -{ - ms_selectedUp = true; -} - -// ---------------------------------------------------------------------- - -void Profiler::selectionMoveDown() -{ - ms_selectedDown = true; -} - -// ---------------------------------------------------------------------- - -void Profiler::selectionExpand() -{ - ms_selectedExpand = true; -} - -// ---------------------------------------------------------------------- - -void Profiler::selectionCollapse() -{ - ms_selectedCollapse = true; -} - -// ---------------------------------------------------------------------- - -void Profiler::selectionToggleExpanded() -{ - ms_selectedToggle = true; -} - -// ---------------------------------------------------------------------- - -void Profiler::setTemporaryExpandAll(bool temporaryExpandAll) -{ - ms_temporaryExpandAll = temporaryExpandAll; -} - -// ---------------------------------------------------------------------- - -void Profiler::setDisplayPercentageMinimum(int percentage) -{ - ms_displayPercentageMinimum = percentage; -} - -// ---------------------------------------------------------------------- - -bool ProfilerNamespace::myCompare(const char *a, const char *b) -{ - while (*a && *b && tolower(*a) == tolower(*b)) - { - ++a; - ++b; - } - - return *a == '\0'; -} - -// ---------------------------------------------------------------------- - -void Profiler::handleOperation(char const *operation) -{ - if (_stricmp(operation, "up") == 0) - selectionMoveUp(); - else if (_stricmp(operation, "down") == 0) - selectionMoveDown(); - else if (_stricmp(operation, "toggle") == 0) - selectionToggleExpanded(); - else if (_stricmp(operation, "expand") == 0) - selectionExpand(); - else if (_stricmp(operation, "collapse") == 0) - selectionCollapse(); - else if (_stricmp(operation, "enable") == 0) - enable(true); - else if (_stricmp(operation, "disable") == 0) - enable(false); - else if (_stricmp(operation, "enableOutput") == 0) - enableProfilerOutput(true); - else if (_stricmp(operation, "disableOutput") == 0) - enableProfilerOutput(false); - else if (_stricmp(operation, "showAll") == 0) - setTemporaryExpandAll(true); - else if (_stricmp(operation, "showNormal") == 0) - setTemporaryExpandAll(false); - else if (myCompare("displayMinimum", operation)) - { - const char *result = strchr(operation, ' '); - if (result) - ms_displayPercentageMinimum = atoi(result+1); - } -} - -// ---------------------------------------------------------------------- - -void ProfilerNamespace::enterWithTime(char const *name, ProfilerTimer::Type time) -{ - if (ms_stackDepth == 0) - { - ms_enabled = ms_desiredEnabled; - if (!ms_enabled) - { - ms_text.clear(); - ms_text.push_back('\0'); - } - } - ++ms_stackDepth; - if (!ms_enabled) - return; - - // search for another call to this block from the parent - int entryIndex = -1; - ProfilerEntry *entry = NULL; - if (!ms_profilerEntryStack.empty()) - { - ProfilerEntry &parent = (*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()]; - ProfilerEntry::Children::iterator iEnd = parent.children.end(); - for (ProfilerEntry::Children::iterator i = parent.children.begin(); i != iEnd; ++i) - { - entryIndex = *i; - ProfilerEntry &check = (*ms_profilerEntriesCurrent)[entryIndex]; - if (check.name == name) - { - entry = ✓ - break; - } - } - } - - // no previous call to this block, so create a new entry - if (!entry) - { - entryIndex = ms_profilerEntriesCurrent->size(); - ms_profilerEntriesCurrent->push_back(ProfilerEntry()); - entry = &ms_profilerEntriesCurrent->back(); - - entry->name = name; - if (ms_profilerEntryStack.empty()) - { - entry->parent = -1; - } - else - { - entry->parent = ms_profilerEntryStack.back(); - (*ms_profilerEntriesCurrent)[entry->parent].children.push_back(entryIndex); - } - entry->totalCalls = 0; - entry->totalTime = 0; - - } - - // record the profiling time - entry->totalCalls += 1; - entry->totalTime -= time; - ms_profilerEntryStack.push_back(entryIndex); -} - -// ---------------------------------------------------------------------- - -void ProfilerNamespace::leaveWithTime(char const *name, ProfilerTimer::Type time) -{ - if (!ms_enabled) - return; - - UNREF(name); - if (ms_profilerEntryStack.empty()) - { - WARNING(true, ("Profiler::leave stack underflow leaving %s", name)); - return; - } - --ms_stackDepth; - - // pop the current entry off the stack - ProfilerEntry &entry= (*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()]; - ms_profilerEntryStack.pop_back(); - - DEBUG_FATAL(entry.name != name, ("Profiler::leave exiting '%s' but expected '%s'", name, entry.name)); - - // record the time in the entry - if (ms_profilerEntryStack.empty()) - { - // get the calibrated loop end time - ProfilerTimer::getCalibratedTime(time, ms_frequency); - entry.totalTime += time; - - // clear the text so we know the profile data must be regenerated if it is desired - ms_text.clear(); - - // swap the pointers - std::vector * temp = ms_profilerEntriesCurrent; - ms_profilerEntriesCurrent = ms_profilerEntriesLast; - ms_profilerEntriesLast = temp; - - // clear the entries for next frame - ms_profilerEntriesCurrent->clear(); - } - else - { - entry.totalTime += time; - } -} - -// ---------------------------------------------------------------------- - -void Profiler::enter(char const *name) -{ - ProfilerTimer::Type time; - ProfilerTimer::getTime(time); - enterWithTime(name, time); -} - -// ---------------------------------------------------------------------- - -void Profiler::leave(char const *name) -{ - ProfilerTimer::Type time; - ProfilerTimer::getTime(time); - leaveWithTime(name, time); -} - -// ---------------------------------------------------------------------- - -void Profiler::transfer(char const *leaveName, char const *enterName) -{ - ProfilerTimer::Type time; - ProfilerTimer::getTime(time); - leaveWithTime(leaveName, time); - enterWithTime(enterName, time); -} - -// ---------------------------------------------------------------------- - -void Profiler::adjustForLostBlocks(char const *expectingName) -{ - // This deals with cases where we've either missed closing a block or closed a block that wasn't open. - // We prefer to guess that we've failed to close a block, since that is the more common mistake, before - // trying to deal with it as though a block was closed but not opened. - - if (!ms_profilerEntryStack.empty()) - { - // if everything is correct, the back entry will be the expected one, so we don't have to do anything - if ((*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()].name == expectingName) - return; - for (int i = ms_profilerEntryStack.size()-2; i >= 0; --i) - { - if ((*ms_profilerEntriesCurrent)[ms_profilerEntryStack[i]].name == expectingName) - { - // we've got unclosed blocks, so close them - for (int j = ms_profilerEntryStack.size()-1; j > i; --j) - { - DEBUG_WARNING(true, ("Profiler adjusting for unclosed block '%s'.", (*ms_profilerEntriesCurrent)[ms_profilerEntryStack[j]].name)); - PROFILER_BLOCK_DEFINE(p, (*ms_profilerEntriesCurrent)[ms_profilerEntryStack[j]].name); - PROFILER_BLOCK_LEAVE(p); - } - return; - } - } - } - - DEBUG_WARNING(true, ("Profiler adjusting for unopened block '%s'.", expectingName)); - // we're about to close a block that was not open, so open it - PROFILER_BLOCK_DEFINE(p, expectingName); - PROFILER_BLOCK_ENTER(p); -} - -// ====================================================================== +// ====================================================================== +// +// Profiler.cpp +// +// Copyright 2003 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedDebug/FirstSharedDebug.h" +#include "sharedDebug/Profiler.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/DebugKey.h" +#include "sharedDebug/ProfilerTimer.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedFoundation/MemoryBlockManagerMacros.h" + +#include +#include + +// ====================================================================== + +namespace ProfilerNamespace +{ + struct ProfilerEntry + { + typedef std::vector Children; + + const char *name; + int parent; + Children children; + int totalCalls; + ProfilerTimer::Type totalTime; + }; + + class VisibleExpandableEntry + { + public: + + VisibleExpandableEntry(char const * name); + ~VisibleExpandableEntry(); + + char const * getName() const; + + bool isExpanded() const; + void setExpanded(bool opened); + void toggleExpanded(); + + void markAllChildrenInvisible(); + VisibleExpandableEntry * findOrAddExpandableChild(char const *name); + bool pruneInvisibleChildren(); + + private: + + typedef std::vector Children; + + private: + + static bool ms_destroyedSelected; + + private: + + char const * m_name; + Children m_children; + bool m_expanded; + bool m_visible; + }; + + typedef std::vector ProfilerEntries; + typedef std::vector SortedProfilerEntries; + + struct SortMultisiteEntries + { + bool operator()(ProfilerEntry const * lhs, ProfilerEntry const * rhs) const; + }; + + void formatInteger(int length, int value); + void formatString(const char *string); + bool formatEntry(int indent, ProfilerTimer::Type totalTime, int totalCalls, bool expandable, bool expanded, bool selected, char const *name); + void processEntry(char const *rootName, int indent, ProfilerEntry const & entry, VisibleExpandableEntry * opened); + void enterWithTime(char const *name, ProfilerTimer::Type time); + void leaveWithTime(char const *name, ProfilerTimer::Type time); + void generateReport(); + bool myCompare(const char *a, const char *b); + + + std::vector ms_profilerEntryStack; + ProfilerEntries * ms_profilerEntriesCurrent; + ProfilerEntries * ms_profilerEntriesLast; + ProfilerEntries ms_profilerEntries1; + ProfilerEntries ms_profilerEntries2; + + char const * ms_rootProfilerName; + + VisibleExpandableEntry * ms_rootVisibleExpandableEntry; + VisibleExpandableEntry * ms_beforeSelectedVisibleExpandableEntry; + VisibleExpandableEntry * ms_selectedVisibleExpandableEntry; + VisibleExpandableEntry * ms_afterSelectedVisibleExpandableEntry; + VisibleExpandableEntry * ms_previousVisibleExpandableEntry; + + std::vector ms_text; + ProfilerTimer::Type ms_timeDivisor; + ProfilerTimer::Type ms_percentageDivisor; + ProfilerTimer::Type ms_frequency; + bool ms_enabled = true; + bool ms_desiredEnabled = true; + bool ms_debugKeyContext; + bool ms_debugReportFlag; + bool ms_debugReportLogFlag; + bool ms_temporaryExpandAll; + bool ms_multisiteCallerSummary; + bool ms_setRoot; + bool ms_selectedUp; + bool ms_selectedDown; + bool ms_selectedExpand; + bool ms_selectedCollapse; + bool ms_selectedToggle; + int ms_displayPercentageMinimum; + int ms_stackDepth; + SortedProfilerEntries ms_sortedProfilerEntries; + +} +using namespace ProfilerNamespace; + +bool VisibleExpandableEntry::ms_destroyedSelected; + +// ====================================================================== + +VisibleExpandableEntry::VisibleExpandableEntry(char const * name) +: + m_name(name), + m_children(), + m_expanded(false), + m_visible(true) +{ +} + +// ---------------------------------------------------------------------- + +VisibleExpandableEntry::~VisibleExpandableEntry() +{ + // handle case where the selected item gets deleted + if (this == ms_selectedVisibleExpandableEntry) + ms_destroyedSelected = true; + + while (!m_children.empty()) + { + VisibleExpandableEntry *back = m_children.back(); + m_children.pop_back(); + delete back; + } +} + +// ---------------------------------------------------------------------- + +inline char const * VisibleExpandableEntry::getName() const +{ + return m_name; +} + +// ---------------------------------------------------------------------- + +inline bool VisibleExpandableEntry::isExpanded() const +{ + return m_expanded || ms_temporaryExpandAll; +} + +// ---------------------------------------------------------------------- + +inline void VisibleExpandableEntry::setExpanded(bool expanded) +{ + m_expanded = expanded; +} + +// ---------------------------------------------------------------------- + +inline void VisibleExpandableEntry::toggleExpanded() +{ + m_expanded = !m_expanded; +} + +// ---------------------------------------------------------------------- + +void VisibleExpandableEntry::markAllChildrenInvisible() +{ + Children::iterator const iEnd = m_children.end(); + for (Children::iterator i = m_children.begin(); i != iEnd; ++i) + (*i)->m_visible = false; +} + +// ---------------------------------------------------------------------- + +VisibleExpandableEntry * VisibleExpandableEntry::findOrAddExpandableChild(char const *name) +{ + Children::iterator const iEnd = m_children.end(); + for (Children::iterator i = m_children.begin(); i != iEnd; ++i) + { + VisibleExpandableEntry * child = *i; + if (child->m_name == name) + { + child->m_visible = true; + return child; + } + } + + m_children.push_back(new VisibleExpandableEntry(name)); + return m_children.back(); +} + +// ---------------------------------------------------------------------- + +bool VisibleExpandableEntry::pruneInvisibleChildren() +{ + for (Children::iterator i = m_children.begin(); i != m_children.end(); ) + { + if ((*i)->m_visible == false) + { + i = m_children.erase(i); + } + else + { + ++i; + } + } + bool const result = ms_destroyedSelected; + ms_destroyedSelected = false; + return result; +} + +// ====================================================================== + +void Profiler::install() +{ + ExitChain::add(Profiler::remove, "Profiler::remove"); + + ms_profilerEntriesCurrent = &ms_profilerEntries1; + ms_profilerEntriesLast = &ms_profilerEntries2; + ms_rootVisibleExpandableEntry = new VisibleExpandableEntry(NULL); + ms_rootVisibleExpandableEntry->setExpanded(true); + ms_selectedVisibleExpandableEntry = ms_rootVisibleExpandableEntry; +} + +// ---------------------------------------------------------------------- + +void Profiler::remove() +{ + delete ms_rootVisibleExpandableEntry; + ms_rootVisibleExpandableEntry = NULL; + ms_beforeSelectedVisibleExpandableEntry = NULL; + ms_selectedVisibleExpandableEntry = NULL; + ms_afterSelectedVisibleExpandableEntry = NULL; + ms_previousVisibleExpandableEntry = NULL; + ms_profilerEntriesCurrent = NULL; + ms_profilerEntriesLast = NULL; +} + +// ---------------------------------------------------------------------- + +void Profiler::registerDebugFlags() +{ + DebugKey::registerFlag(ms_debugKeyContext, "profiler"); + DebugFlags::registerFlag(ms_debugReportFlag, "SharedDebug/Profiler", "report", printLastFrameData); + DebugFlags::registerFlag(ms_desiredEnabled, "SharedDebug/Profiler", "enabled"); + DebugFlags::registerFlag(ms_debugReportLogFlag, "SharedDebug/Profiler", "logNextReport"); + DebugFlags::registerFlag(ms_temporaryExpandAll, "SharedDebug/Profiler", "temporaryExpandAll"); + ms_displayPercentageMinimum = ConfigFile::getKeyInt("SharedDebug/Profiler", "displayPercentageMinimum", 0); +} + +// ---------------------------------------------------------------------- + +void Profiler::enable(bool enable) +{ + ms_desiredEnabled = enable; +} + +// ---------------------------------------------------------------------- + +void Profiler::enableProfilerOutput(bool enableOutput) +{ + ms_debugReportFlag = enableOutput; +} + +// ---------------------------------------------------------------------- + +void ProfilerNamespace::formatInteger(int length, int value) +{ + // pad with spaces + for (int i = 0; i < length; ++i) + ms_text.push_back(' '); + + // get a pointer to the last character + char *buffer = &ms_text[ms_text.size()-1]; + + // write the value right to left + do + { + *buffer = static_cast('0' + (value % 10)); + --length; + --buffer; + value /= 10; + } while (length && value); +} + +// ---------------------------------------------------------------------- + +void ProfilerNamespace::formatString(char const *string) +{ + for ( ; *string; ++string) + ms_text.push_back(*string); +} + +// ---------------------------------------------------------------------- + +bool ProfilerNamespace::formatEntry(int indent, ProfilerTimer::Type totalTime, int totalCalls, bool expandable, bool expanded, bool selected, char const * name) +{ + int const percentage = static_cast(totalTime / ms_percentageDivisor); + + if (percentage < ms_displayPercentageMinimum) + return false; + + int const ticks = static_cast(totalTime / ms_timeDivisor); + + // indent + { + for (int i = 0; i < indent; ++i) + ms_text.push_back(' '); + } + + // print number of ticks + formatInteger(7, ticks); + ms_text.push_back(' '); + + // pring % of frame time + formatInteger(3, percentage); + ms_text.push_back('%'); + ms_text.push_back(' '); + + // print the number of calls + formatInteger(8, totalCalls); + ms_text.push_back(' '); + + if (expandable) + { + // print the expanded state + if (expanded) + ms_text.push_back('-'); + else + ms_text.push_back('+'); + + // print the selection marker + if (selected) + ms_text.push_back('>'); + else + ms_text.push_back(' '); + } + else + { + ms_text.push_back(' '); + ms_text.push_back(' '); + } + + // print the entry name + formatString(name); + ms_text.push_back('\n'); + + return true; +} + +// ---------------------------------------------------------------------- + +void ProfilerNamespace::processEntry(char const *rootName, int indent, ProfilerEntry const & entry, VisibleExpandableEntry * visibleExpandableEntry) +{ + if (rootName == entry.name) + rootName = NULL; + + if (!rootName) + { + if (!formatEntry(indent, entry.totalTime, entry.totalCalls, visibleExpandableEntry != NULL, visibleExpandableEntry && visibleExpandableEntry->isExpanded(), visibleExpandableEntry == ms_selectedVisibleExpandableEntry, entry.name)) + return; + } + + if (visibleExpandableEntry) + { + // keep track of before and after the selected entry + if (ms_selectedVisibleExpandableEntry == visibleExpandableEntry) + ms_beforeSelectedVisibleExpandableEntry = ms_previousVisibleExpandableEntry; + if (!entry.children.empty()) + { + if (ms_previousVisibleExpandableEntry == ms_selectedVisibleExpandableEntry) + ms_afterSelectedVisibleExpandableEntry = visibleExpandableEntry; + ms_previousVisibleExpandableEntry = visibleExpandableEntry; + } + + // process the children + visibleExpandableEntry->markAllChildrenInvisible(); + + // indent if we have already seen the root + if (!rootName) + indent += 2; + + if (visibleExpandableEntry->isExpanded()) + { + ProfilerEntry::Children::const_iterator iEnd = entry.children.end(); + for (ProfilerEntry::Children::const_iterator i = entry.children.begin(); i != iEnd; ++i) + { + ProfilerEntry const & child = (*ms_profilerEntriesLast)[*i]; + + if (child.children.empty()) + { + processEntry(rootName, indent, child, NULL); + } + else + { + VisibleExpandableEntry * childVisibleExpandableEntry = visibleExpandableEntry->findOrAddExpandableChild(child.name); + processEntry(rootName, indent, child, childVisibleExpandableEntry); + } + } + } + + if (visibleExpandableEntry->pruneInvisibleChildren()) + ms_selectedVisibleExpandableEntry = visibleExpandableEntry; + } +} + +// ---------------------------------------------------------------------- + +inline bool SortMultisiteEntries::operator()(ProfilerEntry const * lhs, ProfilerEntry const * rhs) const +{ + return lhs->name < rhs->name; +} + +// ---------------------------------------------------------------------- + +void ProfilerNamespace::generateReport() +{ + PROFILER_AUTO_BLOCK_DEFINE("Profiler::generateReport"); + + if (!ms_profilerEntriesLast->empty()) + { + if (ms_debugKeyContext) + { + if (DebugKey::isPressed(1)) + ms_desiredEnabled = !ms_desiredEnabled; + if (DebugKey::isPressed(2)) + ms_debugReportLogFlag = true; + if (DebugKey::isPressed(3)) + ms_temporaryExpandAll = !ms_temporaryExpandAll; + if (DebugKey::isPressed(4)) + ms_setRoot = true; + if (DebugKey::isPressed(5)) + ms_multisiteCallerSummary = !ms_multisiteCallerSummary; + if (DebugKey::isPressed(6)) + ms_displayPercentageMinimum = clamp(0, ms_displayPercentageMinimum - 1, 100); + if (DebugKey::isPressed(7)) + ms_displayPercentageMinimum = clamp(0, ms_displayPercentageMinimum + 1, 100); + if (DebugKey::isPressed(8)) + Profiler::selectionMoveUp(); + if (DebugKey::isPressed(9)) + Profiler::selectionMoveDown(); + if (DebugKey::isPressed(0)) + Profiler::selectionToggleExpanded(); + } + + // try to get the ticks to approximately 1 million per second + ms_timeDivisor = ms_frequency / static_cast(1000000); + if (ms_timeDivisor == 0) + ms_timeDivisor = 1; + + // figure out what to divide by to get the value in percent of total frame time + ms_percentageDivisor = (*ms_profilerEntriesLast)[0].totalTime / static_cast(100); + if (ms_percentageDivisor == 0) + ms_percentageDivisor = 1; + + formatString("Profiler (min "); + formatInteger(3, ms_displayPercentageMinimum); + formatString("%):\n"); + + ProfilerEntry const & rootEntry = (*ms_profilerEntriesLast)[0]; + + ms_rootVisibleExpandableEntry->markAllChildrenInvisible(); + ms_rootVisibleExpandableEntry->findOrAddExpandableChild(rootEntry.name); + + ms_previousVisibleExpandableEntry = NULL; + ms_beforeSelectedVisibleExpandableEntry = NULL; + ms_afterSelectedVisibleExpandableEntry = NULL; + processEntry(ms_rootProfilerName, 0, rootEntry, ms_rootVisibleExpandableEntry); + + if (ms_rootVisibleExpandableEntry->pruneInvisibleChildren()) + ms_selectedVisibleExpandableEntry = ms_rootVisibleExpandableEntry; + + if (ms_setRoot) + { + if (ms_rootProfilerName) + ms_rootProfilerName = NULL; + else + ms_rootProfilerName = ms_selectedVisibleExpandableEntry->getName(); + ms_setRoot = false; + } + + if (ms_selectedUp) + { + if (ms_beforeSelectedVisibleExpandableEntry) + ms_selectedVisibleExpandableEntry = ms_beforeSelectedVisibleExpandableEntry; + ms_selectedUp = false; + } + + if (ms_selectedDown) + { + if (ms_afterSelectedVisibleExpandableEntry) + ms_selectedVisibleExpandableEntry = ms_afterSelectedVisibleExpandableEntry; + ms_selectedDown = false; + } + + if (ms_selectedExpand) + { + ms_selectedVisibleExpandableEntry->setExpanded(true); + ms_selectedExpand= false; + } + + if (ms_selectedCollapse) + { + ms_selectedVisibleExpandableEntry->setExpanded(false); + ms_selectedCollapse = false; + } + + if (ms_selectedToggle) + { + ms_selectedVisibleExpandableEntry->toggleExpanded(); + ms_selectedToggle = false; + } + } + + if (ms_multisiteCallerSummary) + { + // generate a vector of all entries + { + ms_sortedProfilerEntries.clear(); + ProfilerEntries::iterator const iEnd = ms_profilerEntriesLast->end(); + for (ProfilerEntries::iterator i = ms_profilerEntriesLast->begin(); i != iEnd; ++i) + ms_sortedProfilerEntries.push_back(&(*i)); + } + + // sort them by name + std::sort(ms_sortedProfilerEntries.begin(), ms_sortedProfilerEntries.end(), SortMultisiteEntries()); + + // find multiple entries with the same name + { + formatString("Multisite entries:\n"); + + SortedProfilerEntries::iterator i = ms_sortedProfilerEntries.begin(); + SortedProfilerEntries::iterator const iEnd = ms_sortedProfilerEntries.end(); + do + { + char const * const iName = (*i)->name; + SortedProfilerEntries::iterator j = i + 1; + bool display = false; + int totalCalls = (*i)->totalCalls; + ProfilerTimer::Type totalTime = (*i)->totalTime; + + // find the span of entries with the same name + while (j != iEnd && iName == (*j)->name) + { + display = true; + totalCalls += (*j)->totalCalls; + totalTime += (*j)->totalTime; + ++j; + } + + // if the name had multiple entries, report so here + if (display) + formatEntry(2, totalTime, totalCalls, false, false, false, iName); + + i = j; + + } while (i != iEnd); + } + + } + + ms_text.push_back('\0'); +} + +// ---------------------------------------------------------------------- + +char const *Profiler::getLastFrameData() +{ + if (ms_text.empty()) + generateReport(); + + return &(ms_text[0]); +} + +// ---------------------------------------------------------------------- + +void Profiler::printLastFrameData() +{ + if (ms_text.empty()) + generateReport(); + + Report::setFlags(Report::RF_print | (ms_debugReportLogFlag ? Report::RF_log : 0)); + Report::puts(&ms_text[0]); + ms_debugReportLogFlag = false; +} + +// ---------------------------------------------------------------------- + +void Profiler::selectionMoveUp() +{ + ms_selectedUp = true; +} + +// ---------------------------------------------------------------------- + +void Profiler::selectionMoveDown() +{ + ms_selectedDown = true; +} + +// ---------------------------------------------------------------------- + +void Profiler::selectionExpand() +{ + ms_selectedExpand = true; +} + +// ---------------------------------------------------------------------- + +void Profiler::selectionCollapse() +{ + ms_selectedCollapse = true; +} + +// ---------------------------------------------------------------------- + +void Profiler::selectionToggleExpanded() +{ + ms_selectedToggle = true; +} + +// ---------------------------------------------------------------------- + +void Profiler::setTemporaryExpandAll(bool temporaryExpandAll) +{ + ms_temporaryExpandAll = temporaryExpandAll; +} + +// ---------------------------------------------------------------------- + +void Profiler::setDisplayPercentageMinimum(int percentage) +{ + ms_displayPercentageMinimum = percentage; +} + +// ---------------------------------------------------------------------- + +bool ProfilerNamespace::myCompare(const char *a, const char *b) +{ + while (*a && *b && tolower(*a) == tolower(*b)) + { + ++a; + ++b; + } + + return *a == '\0'; +} + +// ---------------------------------------------------------------------- + +void Profiler::handleOperation(char const *operation) +{ + if (_stricmp(operation, "up") == 0) + selectionMoveUp(); + else if (_stricmp(operation, "down") == 0) + selectionMoveDown(); + else if (_stricmp(operation, "toggle") == 0) + selectionToggleExpanded(); + else if (_stricmp(operation, "expand") == 0) + selectionExpand(); + else if (_stricmp(operation, "collapse") == 0) + selectionCollapse(); + else if (_stricmp(operation, "enable") == 0) + enable(true); + else if (_stricmp(operation, "disable") == 0) + enable(false); + else if (_stricmp(operation, "enableOutput") == 0) + enableProfilerOutput(true); + else if (_stricmp(operation, "disableOutput") == 0) + enableProfilerOutput(false); + else if (_stricmp(operation, "showAll") == 0) + setTemporaryExpandAll(true); + else if (_stricmp(operation, "showNormal") == 0) + setTemporaryExpandAll(false); + else if (myCompare("displayMinimum", operation)) + { + const char *result = strchr(operation, ' '); + if (result) + ms_displayPercentageMinimum = atoi(result+1); + } +} + +// ---------------------------------------------------------------------- + +void ProfilerNamespace::enterWithTime(char const *name, ProfilerTimer::Type time) +{ + if (ms_stackDepth == 0) + { + ms_enabled = ms_desiredEnabled; + if (!ms_enabled) + { + ms_text.clear(); + ms_text.push_back('\0'); + } + } + ++ms_stackDepth; + if (!ms_enabled) + return; + + // search for another call to this block from the parent + int entryIndex = -1; + ProfilerEntry *entry = NULL; + if (!ms_profilerEntryStack.empty()) + { + ProfilerEntry &parent = (*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()]; + ProfilerEntry::Children::iterator iEnd = parent.children.end(); + for (ProfilerEntry::Children::iterator i = parent.children.begin(); i != iEnd; ++i) + { + entryIndex = *i; + ProfilerEntry &check = (*ms_profilerEntriesCurrent)[entryIndex]; + if (check.name == name) + { + entry = ✓ + break; + } + } + } + + // no previous call to this block, so create a new entry + if (!entry) + { + entryIndex = ms_profilerEntriesCurrent->size(); + ms_profilerEntriesCurrent->push_back(ProfilerEntry()); + entry = &ms_profilerEntriesCurrent->back(); + + entry->name = name; + if (ms_profilerEntryStack.empty()) + { + entry->parent = -1; + } + else + { + entry->parent = ms_profilerEntryStack.back(); + (*ms_profilerEntriesCurrent)[entry->parent].children.push_back(entryIndex); + } + entry->totalCalls = 0; + entry->totalTime = 0; + + } + + // record the profiling time + entry->totalCalls += 1; + entry->totalTime -= time; + ms_profilerEntryStack.push_back(entryIndex); +} + +// ---------------------------------------------------------------------- + +void ProfilerNamespace::leaveWithTime(char const *name, ProfilerTimer::Type time) +{ + if (!ms_enabled) + return; + + UNREF(name); + if (ms_profilerEntryStack.empty()) + { + WARNING(true, ("Profiler::leave stack underflow leaving %s", name)); + return; + } + --ms_stackDepth; + + // pop the current entry off the stack + ProfilerEntry &entry= (*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()]; + ms_profilerEntryStack.pop_back(); + + DEBUG_FATAL(entry.name != name, ("Profiler::leave exiting '%s' but expected '%s'", name, entry.name)); + + // record the time in the entry + if (ms_profilerEntryStack.empty()) + { + // get the calibrated loop end time + ProfilerTimer::getCalibratedTime(time, ms_frequency); + entry.totalTime += time; + + // clear the text so we know the profile data must be regenerated if it is desired + ms_text.clear(); + + // swap the pointers + std::vector * temp = ms_profilerEntriesCurrent; + ms_profilerEntriesCurrent = ms_profilerEntriesLast; + ms_profilerEntriesLast = temp; + + // clear the entries for next frame + ms_profilerEntriesCurrent->clear(); + } + else + { + entry.totalTime += time; + } +} + +// ---------------------------------------------------------------------- + +void Profiler::enter(char const *name) +{ + ProfilerTimer::Type time; + ProfilerTimer::getTime(time); + enterWithTime(name, time); +} + +// ---------------------------------------------------------------------- + +void Profiler::leave(char const *name) +{ + ProfilerTimer::Type time; + ProfilerTimer::getTime(time); + leaveWithTime(name, time); +} + +// ---------------------------------------------------------------------- + +void Profiler::transfer(char const *leaveName, char const *enterName) +{ + ProfilerTimer::Type time; + ProfilerTimer::getTime(time); + leaveWithTime(leaveName, time); + enterWithTime(enterName, time); +} + +// ---------------------------------------------------------------------- + +void Profiler::adjustForLostBlocks(char const *expectingName) +{ + // This deals with cases where we've either missed closing a block or closed a block that wasn't open. + // We prefer to guess that we've failed to close a block, since that is the more common mistake, before + // trying to deal with it as though a block was closed but not opened. + + if (!ms_profilerEntryStack.empty()) + { + // if everything is correct, the back entry will be the expected one, so we don't have to do anything + if ((*ms_profilerEntriesCurrent)[ms_profilerEntryStack.back()].name == expectingName) + return; + for (int i = ms_profilerEntryStack.size()-2; i >= 0; --i) + { + if ((*ms_profilerEntriesCurrent)[ms_profilerEntryStack[i]].name == expectingName) + { + // we've got unclosed blocks, so close them + for (int j = ms_profilerEntryStack.size()-1; j > i; --j) + { + DEBUG_WARNING(true, ("Profiler adjusting for unclosed block '%s'.", (*ms_profilerEntriesCurrent)[ms_profilerEntryStack[j]].name)); + PROFILER_BLOCK_DEFINE(p, (*ms_profilerEntriesCurrent)[ms_profilerEntryStack[j]].name); + PROFILER_BLOCK_LEAVE(p); + } + return; + } + } + } + + DEBUG_WARNING(true, ("Profiler adjusting for unopened block '%s'.", expectingName)); + // we're about to close a block that was not open, so open it + PROFILER_BLOCK_DEFINE(p, expectingName); + PROFILER_BLOCK_ENTER(p); +} + +// ====================================================================== diff --git a/src/engine/shared/library/sharedDebug/src/shared/RemoteDebug.cpp b/src/engine/shared/library/sharedDebug/src/shared/RemoteDebug.cpp index 84163deb4..45294809f 100644 --- a/src/engine/shared/library/sharedDebug/src/shared/RemoteDebug.cpp +++ b/src/engine/shared/library/sharedDebug/src/shared/RemoteDebug.cpp @@ -674,7 +674,7 @@ void RemoteDebug::send(MESSAGE_TYPE type, const char* theName) if (explicitMessageLength != 0) messageLength = explicitMessageLength; - else if (ms_varArgs_buffer) + else if (strlen(ms_varArgs_buffer) > 0) { //only grab buffer sizes if needed messageLength = strlen(ms_varArgs_buffer)+1; @@ -688,7 +688,7 @@ void RemoteDebug::send(MESSAGE_TYPE type, const char* theName) uint32 packetLength = static_cast(messageTypeLength + channelNumberLength + messageLengthLength + static_cast(messageLength)); - if (ms_varArgs_buffer) + if (strlen(ms_varArgs_buffer) > 0) { //copy data into the packet memcpy(ms_buffer, &messageType, static_cast(messageTypeLength)); diff --git a/src/engine/shared/library/sharedFile/src/shared/FileManifest.cpp b/src/engine/shared/library/sharedFile/src/shared/FileManifest.cpp index b1a72a8a7..a9633dc1e 100644 --- a/src/engine/shared/library/sharedFile/src/shared/FileManifest.cpp +++ b/src/engine/shared/library/sharedFile/src/shared/FileManifest.cpp @@ -296,7 +296,7 @@ void FileManifest::addStoredManifestEntry(const char *fileName, const char * sce entry->size = fileSize; entry->accesses = 0; - std::pair insertReturn = s_manifest.insert(std::pair(crc, entry)); + s_manifest.insert(std::pair(crc, entry)); delete entry; } diff --git a/src/engine/shared/library/sharedFoundation/src/linux/Os.cpp b/src/engine/shared/library/sharedFoundation/src/linux/Os.cpp index e4dc14bf6..689957f3e 100644 --- a/src/engine/shared/library/sharedFoundation/src/linux/Os.cpp +++ b/src/engine/shared/library/sharedFoundation/src/linux/Os.cpp @@ -1,470 +1,470 @@ -// ====================================================================== -// -// Os.cpp -// jeff grills -// -// copyright 1998 Bootprint Entertainment -// -// ====================================================================== - -#include "sharedFoundation/FirstSharedFoundation.h" -#include "sharedFoundation/Os.h" - -#include "sharedFoundation/Clock.h" -#include "sharedFoundation/ConfigSharedFoundation.h" -#include "sharedDebug/DebugMonitor.h" -#include "sharedFoundation/ExitChain.h" -#include "sharedFoundation/FloatingPointUnit.h" -#include "sharedIoWin/IoWinManager.h" - -#include -#include - -// ====================================================================== - -bool Os::installed; -bool Os::runInBackground; -int Os::numberOfUpdates; -int Os::menuValue; -bool Os::paused; -bool Os::wasPaused; -bool Os::gameOver; -bool Os::shouldReturnFromAbort; -char Os::programName[PROGRAM_NAME_SIZE]; -char *Os::shortProgramName; -pthread_t Os::mainThreadId; -bool Os::threadDied; - -bool Os::isMp; -int Os::processorCount; - -// ---------------------------------------------------------------------- - -namespace OsNamespace -{ - class UncatchableException - { - }; -} - - -// ---------------------------------------------------------------------- -/** - * Install the Os subsystem for non-games. - * - * This routine is supported for all platforms, although different platforms may - * require different arguments to this routine. - * - * This routine will add Os::remove to the ExitChain. - * - * @see Os::remove() - */ - -void Os::install(void) -{ - installCommon(); -} - -// ---------------------------------------------------------------------- -/** - * This routine will remove the Os subsystem. - * - * This routine should not be called directly. It will be called from the ExitChain. - * - * @see Os::install() - */ - -void Os::remove(void) -{ - DEBUG_FATAL(!installed, ("not installed")); - installed = false; -} - -// ---------------------------------------------------------------------- - -void Os::installCommon(void) -{ - DEBUG_FATAL(installed, ("already installed")); - - ExitChain::add(Os::remove, "Os::remove", 0, true); - -#if 0 //TODO For now we won't screw with the priority of the process - HANDLE threadHandle = GetCurrentThread(); - DEBUG_FATAL(!SetThreadPriority(threadHandle, THREAD_PRIORITY_ABOVE_NORMAL), ("Failed to set game thread priority")); -#endif - - numberOfUpdates = 0; - mainThreadId = pthread_self(); - - // get the name of the executable -//Can't find UNIX call for this: DWORD result = GetModuleFileName(NULL, programName, sizeof(programName)); - strcpy(programName, "TempName"); - DWORD result = 1; - - - FATAL(result == 0, ("GetModuleFileName failed")); - - // get the file name without the path - shortProgramName = strrchr(programName, '\\'); - if (shortProgramName) - ++shortProgramName; - else - shortProgramName = programName; - - // determine the number of processors by parsing /proc/cpuinfo - processorCount = 1; - FILE * f = fopen("/proc/cpuinfo", "r"); - if (f) - { - char buffer[512]; - while (!feof(f)) - { - fgets(buffer, 512, f); - if (strncmp(buffer, "processor\t: ", 12)==0) - { - processorCount = atoi(buffer+12)+1; - } - } - fclose(f); - } - isMp = processorCount > 1; - - // switch into single-precision floating point mode - FloatingPointUnit::install(); - - installed = true; -} - -// ---------------------------------------------------------------------- - -bool Os::isMainThread(void) -{ - // if the Os class hasn't been installed, then assume we are the main thread. - // otherwise, check to see if our thread id is the main thread id - return !installed || (pthread_self() == mainThreadId); -} - -// ---------------------------------------------------------------------- -/** - * Terminate the application because of an error condition. - * - * This routine is supported for all platforms. - * - * This routine should not be called directly. The engine and game should use the - * FATAL macro to terminate the application because of an error. - * - * Calling Os::returnFromAbort() will cause the routine to do nothing but return - * immediately. - * - * @see Os::returnFromAbort(), FATAL() - */ -#include -void Os::abort(void) -{ - if (!isMainThread()) - { - threadDied = true; - pthread_exit(NULL); - } - - if (!shouldReturnFromAbort) - { - // let the C runtime deal with the abnormal termination - int * dummy = NULL; - int forceCrash = *dummy; - UNREF(forceCrash); - for (;;) - { - // One of these should work: - pthread_kill(pthread_self(), SIGSEGV); - ::kill(0,SIGSEGV); - ::abort(); - OsNamespace::UncatchableException ex; - throw ex; - sleep(10); - } - } -} -//----------------------------------------------------------------- -/** -* Create the specified directory and all of it's parents. -* @param directory the path to a directory -* @return always true currently -*/ - -bool Os::createDirectories (const char *directory) -{ - //-- construct list of subdirectories all the way down to root - std::stack directoryStack; - - std::string currentDirectory = directory; - - static const char path_seps [] = { '\\', '/', 0 }; - - // build the stack - while (!currentDirectory.empty()) - { - // remove trailing backslash - if (currentDirectory[currentDirectory.size()-1] == '\\' || currentDirectory[currentDirectory.size()-1] == '/') - IGNORE_RETURN(currentDirectory.erase(currentDirectory.size()-1)); - - if (currentDirectory[currentDirectory.size()-1] == ':') - { - // we've hit something like c: - break; - } - - if (!currentDirectory.empty()) - directoryStack.push(currentDirectory); - - // now strip off current directory - size_t previousDirIndex = currentDirectory.find_last_of (path_seps); - if (previousDirIndex == currentDirectory.npos) - break; - else - IGNORE_RETURN(currentDirectory.erase(previousDirIndex)); - } - - //-- build all directories specified by the initial directory - while (!directoryStack.empty()) - { - // get the directory - currentDirectory = directoryStack.top(); - directoryStack.pop(); - - // try to create it (don't pass any security attributes) - IGNORE_RETURN (mkdir (currentDirectory.c_str(), 0)); - } - - return true; -} -// ---------------------------------------------------------------------- -/** - * Write out a file. - * - * The file name and where the file is written is system-dependent. - * - * @param fileName Name of the file to write - * @param data Data buffer to write to the file - */ - -bool Os::writeFile(const char *fileName, const void *data, int length) // Length of the data bufferto write -{ - BOOL result; - HANDLE handle; - DWORD written; - - // open the file for writing - handle = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - - // check if it was opened - if (handle == INVALID_HANDLE_VALUE) - return false; - - // attempt to write the data - result = WriteFile(handle, data, static_cast(length), &written, NULL); - - // make sure the data was written okay - if (!result || written != static_cast(length)) - { - static_cast(CloseHandle(handle)); - return false; - } - - // close the file - result = CloseHandle(handle); - - // make sure the close was sucessful - if (!result) - return false; - - return true; -} - -// ---------------------------------------------------------------------- -/** - * Update the Os subsystem. - * - * This routine is supported for all platforms. - * - * For the Win* platforms, this routine will process the windows message pump. - */ - -bool Os::update(void) -{ - static int ppid = getppid(); - - FloatingPointUnit::update(); - - ++numberOfUpdates; - -#if 0 -#ifdef _DEBUG - - if (DEBUG_FLAG_PLATFORM(validateHeap)) - { - PROFILER_START("validate heap"); - MemoryManager::validate(); - PROFILER_STOP("validate heap"); - } - -#endif -#endif - - Clock::update(); - - wasPaused = false; - - // if our parent's pid has changed, we tell our caller it should exit - if (getppid() != ppid) - { - WARNING(true, ("Parent process exited!")); - // reset the parent process id, so we don't keep spamming warnings for processes that don't exit because of this - ppid = getppid(); - return false; - } - - return true; -} - -// ---------------------------------------------------------------------- -/** - * Formats a message error using GetLastError() and FormatMessge(). - * - * The buffer returned from this function is dynamically allocated to prevent - * issues with this routine being called from multiple threads. The caller - * must delete the buffer when it is done. - * - * @return A dynamically allocated buffer containing the error message - */ - -char *Os::getLastError(void) -{ - return DuplicateString(strerror(errno)); -} - -// ---------------------------------------------------------------------- - -bool Os::getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize) -{ - // realpath sucks and could cause a buffer overrun. however, it's better than writing it ourselves for now. - char *result = realpath(relativePath, absolutePath); - if (!result){ - free(result); - return false; - } - - FATAL(istrlen(absolutePath)+1 > absolutePathBufferSize, ("buffer overrun")); - return true; -} - -// ---------------------------------------------------------------------- -/** - * Get the actual system time, in seconds since the epoch. - * - * Do not use this for most game systems, since it does not take into account - * clock sku, game loop times, etc. - */ -time_t Os::getRealSystemTime(void) -{ - return time(0); -} - -// ---------------------------------------------------------------------- -/** - * Convert a time in seconds since the epoch to GMT. - * - */ - -void Os::convertTimeToGMT(const time_t &time, tm &zulu) -{ - zulu=*gmtime(&time); // gmtime uses a single static tm structure. Yuck! -} - -// ---------------------------------------------------------------------- -/** - * Convert a tm structure to the time in seconds since the epoch. - * - */ - -time_t Os::convertGMTToTime(const tm &zulu) -{ - return mktime(const_cast(&zulu)); -} - -// ---------------------------------------------------------------------- -/** - * Get a unique identifier for this thread. - * - * @return A unique identifier for this thread. - */ - -Os::ThreadId Os::getThreadId() -{ - return pthread_self(); -} - -// ---------------------------------------------------------------------- -/** - * Assign the given thread a reasonable name (only works for MSDev 6.0 debugger) - * Since this is Linux-specific, make sure this fuction does nothing - * - */ - -void Os::setThreadName(DWORD threadID, const char* threadName) -{ -} - -// ---------------------------------------------------------------------- -/** - * Cause the current thread to sleep for a period of time. If the period is - * zero, the current thread yields it's timeslice. - */ - -void Os::sleep(int ms) -{ - if (ms == 0) - { - sched_yield(); - } - else - { - usleep(ms * 1000); - } -} - -// ---------------------------------------------------------------------- -/** - * Copy text to the system clipboard. - * - * This routine can be used if the application wants to make some data easily available for pasting (like crash call stacks). - */ - -bool Os::copyTextToClipboard(const char *text) -{ - UNREF(text); - return false; -} - -// ---------------------------------------------------------------------- - -Os::OsPID_t Os::getProcessId() -{ - return getpid(); -} - -// ---------------------------------------------------------------------- - -void Os::setProgramName(const char * name) -{ - strncpy(programName, name, Os::PROGRAM_NAME_SIZE); -} - -// ---------------------------------------------------------------------- - -bool Os::isFocused() -{ - return true; -} - -// ---------------------------------------------------------------------- +// ====================================================================== +// +// Os.cpp +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" +#include "sharedFoundation/Os.h" + +#include "sharedFoundation/Clock.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedDebug/DebugMonitor.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/FloatingPointUnit.h" +#include "sharedIoWin/IoWinManager.h" + +#include +#include + +// ====================================================================== + +bool Os::installed; +bool Os::runInBackground; +int Os::numberOfUpdates; +int Os::menuValue; +bool Os::paused; +bool Os::wasPaused; +bool Os::gameOver; +bool Os::shouldReturnFromAbort; +char Os::programName[PROGRAM_NAME_SIZE]; +char *Os::shortProgramName; +pthread_t Os::mainThreadId; +bool Os::threadDied; + +bool Os::isMp; +int Os::processorCount; + +// ---------------------------------------------------------------------- + +namespace OsNamespace +{ + class UncatchableException + { + }; +} + + +// ---------------------------------------------------------------------- +/** + * Install the Os subsystem for non-games. + * + * This routine is supported for all platforms, although different platforms may + * require different arguments to this routine. + * + * This routine will add Os::remove to the ExitChain. + * + * @see Os::remove() + */ + +void Os::install(void) +{ + installCommon(); +} + +// ---------------------------------------------------------------------- +/** + * This routine will remove the Os subsystem. + * + * This routine should not be called directly. It will be called from the ExitChain. + * + * @see Os::install() + */ + +void Os::remove(void) +{ + DEBUG_FATAL(!installed, ("not installed")); + installed = false; +} + +// ---------------------------------------------------------------------- + +void Os::installCommon(void) +{ + DEBUG_FATAL(installed, ("already installed")); + + ExitChain::add(Os::remove, "Os::remove", 0, true); + +#if 0 //TODO For now we won't screw with the priority of the process + HANDLE threadHandle = GetCurrentThread(); + DEBUG_FATAL(!SetThreadPriority(threadHandle, THREAD_PRIORITY_ABOVE_NORMAL), ("Failed to set game thread priority")); +#endif + + numberOfUpdates = 0; + mainThreadId = pthread_self(); + + // get the name of the executable +//Can't find UNIX call for this: DWORD result = GetModuleFileName(NULL, programName, sizeof(programName)); + strcpy(programName, "TempName"); + DWORD result = 1; + + + FATAL(result == 0, ("GetModuleFileName failed")); + + // get the file name without the path + shortProgramName = strrchr(programName, '\\'); + if (shortProgramName) + ++shortProgramName; + else + shortProgramName = programName; + + // determine the number of processors by parsing /proc/cpuinfo + processorCount = 1; + FILE * f = fopen("/proc/cpuinfo", "r"); + if (f) + { + char buffer[512]; + while (!feof(f)) + { + fgets(buffer, 512, f); + if (strncmp(buffer, "processor\t: ", 12)==0) + { + processorCount = atoi(buffer+12)+1; + } + } + fclose(f); + } + isMp = processorCount > 1; + + // switch into single-precision floating point mode + FloatingPointUnit::install(); + + installed = true; +} + +// ---------------------------------------------------------------------- + +bool Os::isMainThread(void) +{ + // if the Os class hasn't been installed, then assume we are the main thread. + // otherwise, check to see if our thread id is the main thread id + return !installed || (pthread_self() == mainThreadId); +} + +// ---------------------------------------------------------------------- +/** + * Terminate the application because of an error condition. + * + * This routine is supported for all platforms. + * + * This routine should not be called directly. The engine and game should use the + * FATAL macro to terminate the application because of an error. + * + * Calling Os::returnFromAbort() will cause the routine to do nothing but return + * immediately. + * + * @see Os::returnFromAbort(), FATAL() + */ +#include +void Os::abort(void) +{ + if (!isMainThread()) + { + threadDied = true; + pthread_exit(NULL); + } + + if (!shouldReturnFromAbort) + { + // let the C runtime deal with the abnormal termination + int * dummy = NULL; + int forceCrash = *dummy; + UNREF(forceCrash); + for (;;) + { + // One of these should work: + pthread_kill(pthread_self(), SIGSEGV); + ::kill(0,SIGSEGV); + ::abort(); + OsNamespace::UncatchableException ex; + throw ex; + sleep(10); + } + } +} +//----------------------------------------------------------------- +/** +* Create the specified directory and all of it's parents. +* @param directory the path to a directory +* @return always true currently +*/ + +bool Os::createDirectories (const char *directory) +{ + //-- construct list of subdirectories all the way down to root + std::stack directoryStack; + + std::string currentDirectory = directory; + + static const char path_seps [] = { '\\', '/', 0 }; + + // build the stack + while (!currentDirectory.empty()) + { + // remove trailing backslash + if (currentDirectory[currentDirectory.size()-1] == '\\' || currentDirectory[currentDirectory.size()-1] == '/') + IGNORE_RETURN(currentDirectory.erase(currentDirectory.size()-1)); + + if (currentDirectory[currentDirectory.size()-1] == ':') + { + // we've hit something like c: + break; + } + + if (!currentDirectory.empty()) + directoryStack.push(currentDirectory); + + // now strip off current directory + size_t previousDirIndex = currentDirectory.find_last_of (path_seps); + if (previousDirIndex == currentDirectory.npos) + break; + else + IGNORE_RETURN(currentDirectory.erase(previousDirIndex)); + } + + //-- build all directories specified by the initial directory + while (!directoryStack.empty()) + { + // get the directory + currentDirectory = directoryStack.top(); + directoryStack.pop(); + + // try to create it (don't pass any security attributes) + IGNORE_RETURN (mkdir (currentDirectory.c_str(), 0)); + } + + return true; +} +// ---------------------------------------------------------------------- +/** + * Write out a file. + * + * The file name and where the file is written is system-dependent. + * + * @param fileName Name of the file to write + * @param data Data buffer to write to the file + */ + +bool Os::writeFile(const char *fileName, const void *data, int length) // Length of the data bufferto write +{ + BOOL result; + HANDLE handle; + DWORD written; + + // open the file for writing + handle = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + // check if it was opened + if (handle == INVALID_HANDLE_VALUE) + return false; + + // attempt to write the data + result = WriteFile(handle, data, static_cast(length), &written, NULL); + + // make sure the data was written okay + if (!result || written != static_cast(length)) + { + static_cast(CloseHandle(handle)); + return false; + } + + // close the file + result = CloseHandle(handle); + + // make sure the close was sucessful + if (!result) + return false; + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Update the Os subsystem. + * + * This routine is supported for all platforms. + * + * For the Win* platforms, this routine will process the windows message pump. + */ + +bool Os::update(void) +{ + static int ppid = getppid(); + + FloatingPointUnit::update(); + + ++numberOfUpdates; + +#if 0 +#ifdef _DEBUG + + if (DEBUG_FLAG_PLATFORM(validateHeap)) + { + PROFILER_START("validate heap"); + MemoryManager::validate(); + PROFILER_STOP("validate heap"); + } + +#endif +#endif + + Clock::update(); + + wasPaused = false; + + // if our parent's pid has changed, we tell our caller it should exit + if (getppid() != ppid) + { + WARNING(true, ("Parent process exited!")); + // reset the parent process id, so we don't keep spamming warnings for processes that don't exit because of this + ppid = getppid(); + return false; + } + + return true; +} + +// ---------------------------------------------------------------------- +/** + * Formats a message error using GetLastError() and FormatMessge(). + * + * The buffer returned from this function is dynamically allocated to prevent + * issues with this routine being called from multiple threads. The caller + * must delete the buffer when it is done. + * + * @return A dynamically allocated buffer containing the error message + */ + +char *Os::getLastError(void) +{ + return DuplicateString(strerror(errno)); +} + +// ---------------------------------------------------------------------- + +bool Os::getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize) +{ + // realpath sucks and could cause a buffer overrun. however, it's better than writing it ourselves for now. + char *result = realpath(relativePath, absolutePath); + if (!result){ + free(result); + return false; + } + + FATAL(istrlen(absolutePath)+1 > absolutePathBufferSize, ("buffer overrun")); + return true; +} + +// ---------------------------------------------------------------------- +/** + * Get the actual system time, in seconds since the epoch. + * + * Do not use this for most game systems, since it does not take into account + * clock sku, game loop times, etc. + */ +time_t Os::getRealSystemTime(void) +{ + return time(0); +} + +// ---------------------------------------------------------------------- +/** + * Convert a time in seconds since the epoch to GMT. + * + */ + +void Os::convertTimeToGMT(const time_t &time, tm &zulu) +{ + zulu=*gmtime(&time); // gmtime uses a single static tm structure. Yuck! +} + +// ---------------------------------------------------------------------- +/** + * Convert a tm structure to the time in seconds since the epoch. + * + */ + +time_t Os::convertGMTToTime(const tm &zulu) +{ + return mktime(const_cast(&zulu)); +} + +// ---------------------------------------------------------------------- +/** + * Get a unique identifier for this thread. + * + * @return A unique identifier for this thread. + */ + +Os::ThreadId Os::getThreadId() +{ + return pthread_self(); +} + +// ---------------------------------------------------------------------- +/** + * Assign the given thread a reasonable name (only works for MSDev 6.0 debugger) + * Since this is Linux-specific, make sure this fuction does nothing + * + */ + +void Os::setThreadName(DWORD threadID, const char* threadName) +{ +} + +// ---------------------------------------------------------------------- +/** + * Cause the current thread to sleep for a period of time. If the period is + * zero, the current thread yields it's timeslice. + */ + +void Os::sleep(int ms) +{ + if (ms == 0) + { + sched_yield(); + } + else + { + usleep(ms * 1000); + } +} + +// ---------------------------------------------------------------------- +/** + * Copy text to the system clipboard. + * + * This routine can be used if the application wants to make some data easily available for pasting (like crash call stacks). + */ + +bool Os::copyTextToClipboard(const char *text) +{ + UNREF(text); + return false; +} + +// ---------------------------------------------------------------------- + +Os::OsPID_t Os::getProcessId() +{ + return getpid(); +} + +// ---------------------------------------------------------------------- + +void Os::setProgramName(const char * name) +{ + strncpy(programName, name, Os::PROGRAM_NAME_SIZE); +} + +// ---------------------------------------------------------------------- + +bool Os::isFocused() +{ + return true; +} + +// ---------------------------------------------------------------------- diff --git a/src/engine/shared/library/sharedFoundation/src/linux/Os.h b/src/engine/shared/library/sharedFoundation/src/linux/Os.h index 4b551a415..972a93b7b 100644 --- a/src/engine/shared/library/sharedFoundation/src/linux/Os.h +++ b/src/engine/shared/library/sharedFoundation/src/linux/Os.h @@ -1,268 +1,268 @@ -// ====================================================================== -// -// Os.h -// jeff grills -// -// copyright 1998 Bootprint Entertainment -// -// ====================================================================== - -#ifndef OS_H -#define OS_H - -#include - -// ====================================================================== - -struct DebugMenuEntry; - -// ====================================================================== - -class Os -{ -public: - - typedef pthread_t ThreadId; - typedef pid_t OsPID_t; - - enum - { -#ifdef PATH_MAX - MAX_PATH_LENGTH = PATH_MAX+1 -#else - MAX_PATH_LENGTH = 512 -#endif - }; - - typedef void (*QueueCharacterHookFunction)(int keyboard, int character); - typedef void (*SetSystemMouseCursorPositionHookFunction)(int x, int y); - typedef void (*QueueKeyDownHookFunction)(int keyboard, int character); - - -private: - - Os(void); - Os(const Os &); - Os &operator =(const Os &); - - enum - { - PROGRAM_NAME_SIZE = 512 - }; - -private: - - static void remove(void); - - static void installCommon(void); - -private: - - static bool installed; - static bool runInBackground; - static int numberOfUpdates; - static int menuValue; - static DebugMenuEntry *debugMenuGame; - static bool paused; - static bool wasPaused; - static bool gameOver; - static bool shouldReturnFromAbort; - static bool wantPopupDebugMenu; - static char programName[PROGRAM_NAME_SIZE]; - static char *shortProgramName; - static pthread_t mainThreadId; - static bool threadDied; - static bool isMp; - static int processorCount; - - -public: - - static void install(void); - - static bool isGameOver(void); - static bool isMainThread(void); - static bool wasApplicationPaused(void); - - static bool update(void); - - static void returnFromAbort(void); - static void abort(void); - - static void requestPopupDebugMenu(); - - static bool createDirectories (const char *dirname); - - static bool writeFile(const char *fileName, const void *data, int length); - - static int getNumberOfUpdates(void); - - static char *getLastError(void); - - static void setThreadName(DWORD threadID, const char* name); - static ThreadId getThreadId(); - - static const char *getProgramName(void); - static const char *getShortProgramName(void); - static void setProgramName(const char * name); - - static bool getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize); - - static void sleep(int ms); - - static time_t getRealSystemTime(void); - static void convertTimeToGMT(const time_t &time, tm &zulu); - static time_t convertGMTToTime(const tm &zulu); - - static bool isMultiprocessor(); - static int getProcessorCount(); - - static bool copyTextToClipboard(const char *text); - - static bool wasFocusLost(); - static void setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction); - static void setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction); - static OsPID_t getProcessId(); - static bool isFocused(); - - static void setQueueKeyDownHookFunction(QueueKeyDownHookFunction queueKeyDownHookFunction); -}; - -// ---------------------------------------------------------------------- -/** - * Return the full name of the running executable. - * - * The program name will include the path as well. - * - * @return The full name of the running executable - * @see Os::getShortProgramName() - */ - -inline const char *Os::getProgramName(void) -{ - return programName; -} - -// ---------------------------------------------------------------------- -/** - * Return the short name of the running executable. - * - * The program name will not include the path, but will just be the file name. - * - * @return The short name of the running executable - * @see Os::getProgramName() - */ - -inline const char *Os::getShortProgramName(void) -{ - return shortProgramName; -} - -// ---------------------------------------------------------------------- -/** - * Cause Os::abort() to return instead of abort the process. - * - * This routine should not be called directly by users. - * - * This routine is provided so that structured exception handling can catch - * an exception, call Fatal to run the ExitChain, and rethrow the exception - * so that the debugger will catch it. - */ - -inline void Os::returnFromAbort(void) -{ - shouldReturnFromAbort = true; -} - -// ---------------------------------------------------------------------- -/** - * Check if the Os knows the game needs to shut down. - * - * The Os can decide that the game need to end for a number of reasons, - * including closing the application or shutting the machine down. - * - * @return True if the game should quit, otherwise false - */ - -inline bool Os::isGameOver(void) -{ - return gameOver; -} - -// ---------------------------------------------------------------------- -/** - * Return the number of updates that the have occurred. - * - * @return This value is updated during the Os::update() routine. - */ - -inline int Os::getNumberOfUpdates(void) -{ - return numberOfUpdates; -} - -// ---------------------------------------------------------------------- -/** - * Indicate whether or not the application was paused. - * - * @return True if the application was in the background (paused), otherwise false - */ - -inline bool Os::wasApplicationPaused(void) -{ - return wasPaused; -} - -// ---------------------------------------------------------------------- -/** - * Return a flag indicating whether we are running a multiprocessor machine or not. - * - * @return True if the machine has more than one processor, false if not. - */ - -inline bool Os::isMultiprocessor(void) -{ - return isMp; -} - -// ---------------------------------------------------------------------- -/** - * Return the number of processors. - * - * @return The number of processors in the machine. - */ - -inline int Os::getProcessorCount(void) -{ - return processorCount; -} - -// ---------------------------------------------------------------------- - -inline bool Os::wasFocusLost() -{ - return false; -} - -// ---------------------------------------------------------------------- - -inline void Os::setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction) -{ -} - -// ---------------------------------------------------------------------- - -inline void Os::setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction) -{ -} - -// ---------------------------------------------------------------------- - -inline void Os::setQueueKeyDownHookFunction(QueueKeyDownHookFunction) -{ -} - - -// ---------------------------------------------------------------------- - -#endif +// ====================================================================== +// +// Os.h +// jeff grills +// +// copyright 1998 Bootprint Entertainment +// +// ====================================================================== + +#ifndef OS_H +#define OS_H + +#include + +// ====================================================================== + +struct DebugMenuEntry; + +// ====================================================================== + +class Os +{ +public: + + typedef pthread_t ThreadId; + typedef pid_t OsPID_t; + + enum + { +#ifdef PATH_MAX + MAX_PATH_LENGTH = PATH_MAX+1 +#else + MAX_PATH_LENGTH = 512 +#endif + }; + + typedef void (*QueueCharacterHookFunction)(int keyboard, int character); + typedef void (*SetSystemMouseCursorPositionHookFunction)(int x, int y); + typedef void (*QueueKeyDownHookFunction)(int keyboard, int character); + + +private: + + Os(void); + Os(const Os &); + Os &operator =(const Os &); + + enum + { + PROGRAM_NAME_SIZE = 512 + }; + +private: + + static void remove(void); + + static void installCommon(void); + +private: + + static bool installed; + static bool runInBackground; + static int numberOfUpdates; + static int menuValue; + static DebugMenuEntry *debugMenuGame; + static bool paused; + static bool wasPaused; + static bool gameOver; + static bool shouldReturnFromAbort; + static bool wantPopupDebugMenu; + static char programName[PROGRAM_NAME_SIZE]; + static char *shortProgramName; + static pthread_t mainThreadId; + static bool threadDied; + static bool isMp; + static int processorCount; + + +public: + + static void install(void); + + static bool isGameOver(void); + static bool isMainThread(void); + static bool wasApplicationPaused(void); + + static bool update(void); + + static void returnFromAbort(void); + static void abort(void); + + static void requestPopupDebugMenu(); + + static bool createDirectories (const char *dirname); + + static bool writeFile(const char *fileName, const void *data, int length); + + static int getNumberOfUpdates(void); + + static char *getLastError(void); + + static void setThreadName(DWORD threadID, const char* name); + static ThreadId getThreadId(); + + static const char *getProgramName(void); + static const char *getShortProgramName(void); + static void setProgramName(const char * name); + + static bool getAbsolutePath(const char *relativePath, char *absolutePath, int absolutePathBufferSize); + + static void sleep(int ms); + + static time_t getRealSystemTime(void); + static void convertTimeToGMT(const time_t &time, tm &zulu); + static time_t convertGMTToTime(const tm &zulu); + + static bool isMultiprocessor(); + static int getProcessorCount(); + + static bool copyTextToClipboard(const char *text); + + static bool wasFocusLost(); + static void setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction); + static void setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction); + static OsPID_t getProcessId(); + static bool isFocused(); + + static void setQueueKeyDownHookFunction(QueueKeyDownHookFunction queueKeyDownHookFunction); +}; + +// ---------------------------------------------------------------------- +/** + * Return the full name of the running executable. + * + * The program name will include the path as well. + * + * @return The full name of the running executable + * @see Os::getShortProgramName() + */ + +inline const char *Os::getProgramName(void) +{ + return programName; +} + +// ---------------------------------------------------------------------- +/** + * Return the short name of the running executable. + * + * The program name will not include the path, but will just be the file name. + * + * @return The short name of the running executable + * @see Os::getProgramName() + */ + +inline const char *Os::getShortProgramName(void) +{ + return shortProgramName; +} + +// ---------------------------------------------------------------------- +/** + * Cause Os::abort() to return instead of abort the process. + * + * This routine should not be called directly by users. + * + * This routine is provided so that structured exception handling can catch + * an exception, call Fatal to run the ExitChain, and rethrow the exception + * so that the debugger will catch it. + */ + +inline void Os::returnFromAbort(void) +{ + shouldReturnFromAbort = true; +} + +// ---------------------------------------------------------------------- +/** + * Check if the Os knows the game needs to shut down. + * + * The Os can decide that the game need to end for a number of reasons, + * including closing the application or shutting the machine down. + * + * @return True if the game should quit, otherwise false + */ + +inline bool Os::isGameOver(void) +{ + return gameOver; +} + +// ---------------------------------------------------------------------- +/** + * Return the number of updates that the have occurred. + * + * @return This value is updated during the Os::update() routine. + */ + +inline int Os::getNumberOfUpdates(void) +{ + return numberOfUpdates; +} + +// ---------------------------------------------------------------------- +/** + * Indicate whether or not the application was paused. + * + * @return True if the application was in the background (paused), otherwise false + */ + +inline bool Os::wasApplicationPaused(void) +{ + return wasPaused; +} + +// ---------------------------------------------------------------------- +/** + * Return a flag indicating whether we are running a multiprocessor machine or not. + * + * @return True if the machine has more than one processor, false if not. + */ + +inline bool Os::isMultiprocessor(void) +{ + return isMp; +} + +// ---------------------------------------------------------------------- +/** + * Return the number of processors. + * + * @return The number of processors in the machine. + */ + +inline int Os::getProcessorCount(void) +{ + return processorCount; +} + +// ---------------------------------------------------------------------- + +inline bool Os::wasFocusLost() +{ + return false; +} + +// ---------------------------------------------------------------------- + +inline void Os::setQueueCharacterHookFunction(QueueCharacterHookFunction queueCharacterHookFunction) +{ +} + +// ---------------------------------------------------------------------- + +inline void Os::setSetSystemMouseCursorPositionHookFunction(SetSystemMouseCursorPositionHookFunction setSystemMouseCursorPositionHookFunction) +{ +} + +// ---------------------------------------------------------------------- + +inline void Os::setQueueKeyDownHookFunction(QueueKeyDownHookFunction) +{ +} + + +// ---------------------------------------------------------------------- + +#endif diff --git a/src/engine/shared/library/sharedFoundation/src/shared/ArrayList.h b/src/engine/shared/library/sharedFoundation/src/shared/ArrayList.h index ab3e2dd61..e70ff1968 100644 --- a/src/engine/shared/library/sharedFoundation/src/shared/ArrayList.h +++ b/src/engine/shared/library/sharedFoundation/src/shared/ArrayList.h @@ -41,8 +41,7 @@ public: void add (const T& newElement); void addIfNotExist (const T& newElement); void allocateNext (void); - int findOrAdd (const T& newElement); - + void insert (int index, const T& newElement); // remove an item from the list @@ -244,19 +243,6 @@ inline void ArrayList::addIfNotExist (const T& newElement) //------------------------------------------------------------------- -template -inline int ArrayList::findOrAdd (const T& newElement) -{ - if (existsInList (newElement, index)) - return index; - - add (newElement); - - return getNumberOfElements () - 1; -} - -//------------------------------------------------------------------- - template inline void ArrayList::insert (int index, const T& newElement) { diff --git a/src/engine/shared/library/sharedFoundation/src/shared/BitArray.h b/src/engine/shared/library/sharedFoundation/src/shared/BitArray.h index 4960eea21..70b04b417 100644 --- a/src/engine/shared/library/sharedFoundation/src/shared/BitArray.h +++ b/src/engine/shared/library/sharedFoundation/src/shared/BitArray.h @@ -63,8 +63,8 @@ public: void getAsDbTextString(std::string &result, int maxNibbleCount = 32767) const; void setFromDbTextString(const char * text); - friend void Archive::get (ReadIterator &source, BitArray &target); - friend void Archive::put (ByteStream &target, const BitArray &source); + friend void Archive::get (Archive::ReadIterator &source, BitArray &target); + friend void Archive::put (Archive::ByteStream &target, const BitArray &source); private: // *****WARNING***** *****WARNING***** *****WARNING***** *****WARNING***** diff --git a/src/engine/shared/library/sharedFoundation/src/shared/Fatal.h b/src/engine/shared/library/sharedFoundation/src/shared/Fatal.h index aa25bd48a..f33eb5ac5 100644 --- a/src/engine/shared/library/sharedFoundation/src/shared/Fatal.h +++ b/src/engine/shared/library/sharedFoundation/src/shared/Fatal.h @@ -68,7 +68,7 @@ void SetWarningCallback(WarningCallback); template inline T *NonNull(T *pointer, const char *name) { - FATAL(!pointer, ("%s pointer is null", name)); + WARNING(!pointer, ("%s pointer is null", name)); return pointer; } diff --git a/src/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.h b/src/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.h index fae077033..004de6fc2 100644 --- a/src/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.h +++ b/src/engine/shared/library/sharedFoundation/src/shared/dynamicVariable/DynamicVariable.h @@ -161,8 +161,8 @@ private: mutable bool m_cachedValueDirty; mutable void * m_cachedValue[2]; - friend void Archive::get(ReadIterator & source, DynamicVariable & target); - friend void Archive::put(ByteStream & target, const DynamicVariable & source); + friend void Archive::get(Archive::ReadIterator & source, DynamicVariable & target); + friend void Archive::put(Archive::ByteStream & target, const DynamicVariable & source); }; //======================================================================== diff --git a/src/engine/shared/library/sharedGame/src/shared/core/GameScheduler.cpp b/src/engine/shared/library/sharedGame/src/shared/core/GameScheduler.cpp index 8019d90f0..e0b848ba7 100644 --- a/src/engine/shared/library/sharedGame/src/shared/core/GameScheduler.cpp +++ b/src/engine/shared/library/sharedGame/src/shared/core/GameScheduler.cpp @@ -1,83 +1,83 @@ -// ====================================================================== -// -// GameScheduler.cpp -// Copyright 2002 Sony Online Entertainment Inc. -// All Rights Reserved. -// -// ====================================================================== - -#include "sharedGame/FirstSharedGame.h" -#include "sharedGame/GameScheduler.h" - -#include "sharedDebug/InstallTimer.h" -#include "sharedFoundation/ExitChain.h" -#include "sharedFoundation/Scheduler.h" - -// ====================================================================== - -namespace GameSchedulerNamespace -{ - const int cs_ticksPerSecond = 60; - //const float cs_secondsPerTick = 1.0f / static_cast(cs_ticksPerSecond); - - Scheduler *s_scheduler; - bool s_installed; -} - -using namespace GameSchedulerNamespace; - -// ====================================================================== -// class GameScheduler: public static member functions. -// ====================================================================== - -void GameScheduler::install() -{ - InstallTimer const installTimer("GameScheduler::install"); - - DEBUG_FATAL(s_installed, ("GameScheduler already installed.")); - - IS_NULL(s_scheduler); - s_scheduler = new Scheduler(); - - s_installed = true; - ExitChain::add(remove, "GameScheduler"); -} - -// ---------------------------------------------------------------------- - -void GameScheduler::addCallback(Callback callback, const void *context, float elapsedTime) -{ - DEBUG_FATAL(!s_installed, ("GameScheduler not installed.")); - NOT_NULL(s_scheduler); - - const unsigned long elapsedTickCount = static_cast(elapsedTime * static_cast(cs_ticksPerSecond)); - s_scheduler->setCallback(callback, context, elapsedTickCount); -} - -// ---------------------------------------------------------------------- - -void GameScheduler::alter(float elapsedTime) -{ - DEBUG_FATAL(!s_installed, ("GameScheduler not installed.")); - NOT_NULL(s_scheduler); - - const unsigned long schedulerTickCount = s_scheduler->getCurrentCount() + static_cast(elapsedTime * static_cast(cs_ticksPerSecond)); - s_scheduler->update(schedulerTickCount); -} - -// ====================================================================== -// class GameScheduler: private static member functions. -// ====================================================================== - -void GameScheduler::remove() -{ - DEBUG_FATAL(!s_installed, ("GameScheduler not installed.")); - - delete s_scheduler; - s_scheduler = NULL; - - s_installed = false; -} - -// ====================================================================== - +// ====================================================================== +// +// GameScheduler.cpp +// Copyright 2002 Sony Online Entertainment Inc. +// All Rights Reserved. +// +// ====================================================================== + +#include "sharedGame/FirstSharedGame.h" +#include "sharedGame/GameScheduler.h" + +#include "sharedDebug/InstallTimer.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/Scheduler.h" + +// ====================================================================== + +namespace GameSchedulerNamespace +{ + const int cs_ticksPerSecond = 60; + //const float cs_secondsPerTick = 1.0f / static_cast(cs_ticksPerSecond); + + Scheduler *s_scheduler; + bool s_installed; +} + +using namespace GameSchedulerNamespace; + +// ====================================================================== +// class GameScheduler: public static member functions. +// ====================================================================== + +void GameScheduler::install() +{ + InstallTimer const installTimer("GameScheduler::install"); + + DEBUG_FATAL(s_installed, ("GameScheduler already installed.")); + + IS_NULL(s_scheduler); + s_scheduler = new Scheduler(); + + s_installed = true; + ExitChain::add(remove, "GameScheduler"); +} + +// ---------------------------------------------------------------------- + +void GameScheduler::addCallback(Callback callback, const void *context, float elapsedTime) +{ + DEBUG_FATAL(!s_installed, ("GameScheduler not installed.")); + NOT_NULL(s_scheduler); + + const unsigned long elapsedTickCount = static_cast(elapsedTime * static_cast(cs_ticksPerSecond)); + s_scheduler->setCallback(callback, context, elapsedTickCount); +} + +// ---------------------------------------------------------------------- + +void GameScheduler::alter(float elapsedTime) +{ + DEBUG_FATAL(!s_installed, ("GameScheduler not installed.")); + NOT_NULL(s_scheduler); + + const unsigned long schedulerTickCount = s_scheduler->getCurrentCount() + static_cast(elapsedTime * static_cast(cs_ticksPerSecond)); + s_scheduler->update(schedulerTickCount); +} + +// ====================================================================== +// class GameScheduler: private static member functions. +// ====================================================================== + +void GameScheduler::remove() +{ + DEBUG_FATAL(!s_installed, ("GameScheduler not installed.")); + + delete s_scheduler; + s_scheduler = NULL; + + s_installed = false; +} + +// ====================================================================== + diff --git a/src/engine/shared/library/sharedGame/src/shared/core/LfgCharacterData.cpp b/src/engine/shared/library/sharedGame/src/shared/core/LfgCharacterData.cpp index 21d8d4b56..31a0e6550 100644 --- a/src/engine/shared/library/sharedGame/src/shared/core/LfgCharacterData.cpp +++ b/src/engine/shared/library/sharedGame/src/shared/core/LfgCharacterData.cpp @@ -616,7 +616,7 @@ Unicode::String const & LfgCharacterData::getProfessionDisplayString(LfgCharacte static Unicode::String empty; - if ((static_cast(profession) >= 0) && (static_cast(profession) < s_professionDisplayString.size())) + if ((static_cast(profession) >= 0) && (static_cast(profession) < s_professionDisplayString.size())) return s_professionDisplayString[static_cast(profession)]; return empty; diff --git a/src/engine/shared/library/sharedGame/src/shared/core/WearableEntry.h b/src/engine/shared/library/sharedGame/src/shared/core/WearableEntry.h index 6af2afdbe..454326126 100644 --- a/src/engine/shared/library/sharedGame/src/shared/core/WearableEntry.h +++ b/src/engine/shared/library/sharedGame/src/shared/core/WearableEntry.h @@ -28,8 +28,8 @@ namespace Archive class WearableEntry { - friend void Archive::get(ReadIterator & source, WearableEntry & target); - friend void Archive::put(ByteStream & target, const WearableEntry & source); + friend void Archive::get(Archive::ReadIterator & source, WearableEntry & target); + friend void Archive::put(Archive::ByteStream & target, const WearableEntry & source); public: WearableEntry(const std::string&, int, const NetworkId&, int); diff --git a/src/engine/shared/library/sharedGame/src/shared/objectTemplate/SharedCreatureObjectTemplate.cpp b/src/engine/shared/library/sharedGame/src/shared/objectTemplate/SharedCreatureObjectTemplate.cpp index 36f524dc2..5254f31cb 100644 --- a/src/engine/shared/library/sharedGame/src/shared/objectTemplate/SharedCreatureObjectTemplate.cpp +++ b/src/engine/shared/library/sharedGame/src/shared/objectTemplate/SharedCreatureObjectTemplate.cpp @@ -343,7 +343,7 @@ float SharedCreatureObjectTemplate::getAcceleration(MovementTypes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_acceleration[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -392,7 +392,7 @@ float SharedCreatureObjectTemplate::getAccelerationMin(MovementTypes index) cons base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_acceleration[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -441,7 +441,7 @@ float SharedCreatureObjectTemplate::getAccelerationMax(MovementTypes index) cons base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_acceleration[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -490,7 +490,7 @@ float SharedCreatureObjectTemplate::getSpeed(MovementTypes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_speed[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -539,7 +539,7 @@ float SharedCreatureObjectTemplate::getSpeedMin(MovementTypes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_speed[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -588,7 +588,7 @@ float SharedCreatureObjectTemplate::getSpeedMax(MovementTypes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_speed[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -637,7 +637,7 @@ float SharedCreatureObjectTemplate::getTurnRate(MovementTypes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_turnRate[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -686,7 +686,7 @@ float SharedCreatureObjectTemplate::getTurnRateMin(MovementTypes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_turnRate[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) @@ -735,7 +735,7 @@ float SharedCreatureObjectTemplate::getTurnRateMax(MovementTypes index) const base = dynamic_cast(m_baseData); } - DEBUG_FATAL(index < 0 || index >= 2, ("template param index out of range")); + DEBUG_FATAL(static_cast(index) < 0 || static_cast(index) >= 2, ("template param index out of range")); if (!m_turnRate[index].isLoaded()) { if (ms_allowDefaultTemplateParams && /*!m_versionOk &&*/ base == NULL) diff --git a/src/engine/shared/library/sharedGame/src/shared/quest/PlayerQuestData.h b/src/engine/shared/library/sharedGame/src/shared/quest/PlayerQuestData.h index 6cd7e7699..6a564e68d 100644 --- a/src/engine/shared/library/sharedGame/src/shared/quest/PlayerQuestData.h +++ b/src/engine/shared/library/sharedGame/src/shared/quest/PlayerQuestData.h @@ -74,8 +74,8 @@ class PlayerQuestData uint32 m_relativeAgeIndex; // This is not meant to be persisted bool m_hasReceivedReward; - friend void Archive::get(ReadIterator & source, PlayerQuestData & target); - friend void Archive::put(ByteStream & target, const PlayerQuestData & source); + friend void Archive::get(Archive::ReadIterator & source, PlayerQuestData & target); + friend void Archive::put(Archive::ByteStream & target, const PlayerQuestData & source); }; // ====================================================================== diff --git a/src/engine/shared/library/sharedGame/src/shared/space/NebulaManager.cpp b/src/engine/shared/library/sharedGame/src/shared/space/NebulaManager.cpp index b5035cb7b..568c44e2e 100644 --- a/src/engine/shared/library/sharedGame/src/shared/space/NebulaManager.cpp +++ b/src/engine/shared/library/sharedGame/src/shared/space/NebulaManager.cpp @@ -200,7 +200,7 @@ void NebulaManager::loadSceneData(std::string const & sceneId) { //-- apparently not a space scene // @todo: need better way to detect this - if (!strncmp(sceneId.c_str(), "space_", 6) != 0) + if (!(strncmp(sceneId.c_str(), "space_", 6) != 0)) WARNING(true, ("NebulaManager no such datatable [%s]", filename.c_str())); return; } diff --git a/src/engine/shared/library/sharedGame/src/shared/travel/TravelPoint.h b/src/engine/shared/library/sharedGame/src/shared/travel/TravelPoint.h index e90538dc3..31d8180ea 100644 --- a/src/engine/shared/library/sharedGame/src/shared/travel/TravelPoint.h +++ b/src/engine/shared/library/sharedGame/src/shared/travel/TravelPoint.h @@ -31,8 +31,8 @@ namespace Archive class TravelPoint { - friend void Archive::get(ReadIterator& source, TravelPoint& target); - friend void Archive::put(ByteStream& target, const TravelPoint& source); + friend void Archive::get(Archive::ReadIterator& source, TravelPoint& target); + friend void Archive::put(Archive::ByteStream& target, const TravelPoint& source); public: diff --git a/src/engine/shared/library/sharedLog/src/shared/ConfigSharedLog.cpp b/src/engine/shared/library/sharedLog/src/shared/ConfigSharedLog.cpp index 8d3fd11c2..bd44aad88 100644 --- a/src/engine/shared/library/sharedLog/src/shared/ConfigSharedLog.cpp +++ b/src/engine/shared/library/sharedLog/src/shared/ConfigSharedLog.cpp @@ -1,114 +1,114 @@ -// ====================================================================== -// -// ConfigSharedLog.cpp -// -// Copyright 2002 Sony Online Entertainment -// -// ====================================================================== - -#include "sharedLog/FirstSharedLog.h" -#include "sharedLog/ConfigSharedLog.h" - -#include "sharedFoundation/ConfigFile.h" - -#include - -// ====================================================================== - -namespace ConfigSharedLogNamespace -{ - typedef std::vector StringPtrArray; - int ms_logNetQueueSize; - int ms_logNetReconnectTimeMs; - bool ms_logReportLogs; - bool ms_logReportWarnings; - bool ms_logReportFatals; - bool ms_logStderr; - StringPtrArray ms_logTargets; // ConfigFile owns the pointer -} -using namespace ConfigSharedLogNamespace; - -#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedLog", #a, b)) -#define KEY_INT(a,b) (ms_ ## a = ConfigFile::getKeyInt("SharedLog", #a, b)) - -// ====================================================================== - -void ConfigSharedLog::install() -{ - KEY_INT (logNetQueueSize, 2000); - KEY_INT (logNetReconnectTimeMs, 10000); - KEY_BOOL(logReportLogs, false); - KEY_BOOL(logReportWarnings, false); - KEY_BOOL(logReportFatals, true); - KEY_BOOL(logStderr, false); - - int index = 0; - char const * result = 0; - do - { - result = ConfigFile::getKeyString("SharedLog", "logTarget", index++, 0); - if (result) - ms_logTargets.push_back(result); - } - while (result); -} - -// ---------------------------------------------------------------------- - -int ConfigSharedLog::getLogNetQueueSize() -{ - return ms_logNetQueueSize; -} - -// ---------------------------------------------------------------------- - -int ConfigSharedLog::getLogNetReconnectTimeMs() -{ - return ms_logNetReconnectTimeMs; -} - -// ---------------------------------------------------------------------- - -bool ConfigSharedLog::getLogReportLogs() -{ - return ms_logReportLogs; -} - -// ---------------------------------------------------------------------- - -bool ConfigSharedLog::getLogReportWarnings() -{ - return ms_logReportWarnings; -} - -// ---------------------------------------------------------------------- - -bool ConfigSharedLog::getLogReportFatals() -{ - return ms_logReportFatals; -} - -// ---------------------------------------------------------------------- - -bool ConfigSharedLog::getLogStderr() -{ - return ms_logStderr; -} - -// ---------------------------------------------------------------------- - -int ConfigSharedLog::getNumberOfLogTargets() -{ - return static_cast(ms_logTargets.size()); -} - -// ---------------------------------------------------------------------- - -char const * ConfigSharedLog::getLogTarget(int const index) -{ - VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfLogTargets()); - return ms_logTargets[static_cast(index)]; -} - -// ====================================================================== - +// ====================================================================== +// +// ConfigSharedLog.cpp +// +// Copyright 2002 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedLog/FirstSharedLog.h" +#include "sharedLog/ConfigSharedLog.h" + +#include "sharedFoundation/ConfigFile.h" + +#include + +// ====================================================================== + +namespace ConfigSharedLogNamespace +{ + typedef std::vector StringPtrArray; + int ms_logNetQueueSize; + int ms_logNetReconnectTimeMs; + bool ms_logReportLogs; + bool ms_logReportWarnings; + bool ms_logReportFatals; + bool ms_logStderr; + StringPtrArray ms_logTargets; // ConfigFile owns the pointer +} +using namespace ConfigSharedLogNamespace; + +#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool("SharedLog", #a, b)) +#define KEY_INT(a,b) (ms_ ## a = ConfigFile::getKeyInt("SharedLog", #a, b)) + +// ====================================================================== + +void ConfigSharedLog::install() +{ + KEY_INT (logNetQueueSize, 2000); + KEY_INT (logNetReconnectTimeMs, 10000); + KEY_BOOL(logReportLogs, false); + KEY_BOOL(logReportWarnings, false); + KEY_BOOL(logReportFatals, true); + KEY_BOOL(logStderr, false); + + int index = 0; + char const * result = 0; + do + { + result = ConfigFile::getKeyString("SharedLog", "logTarget", index++, 0); + if (result) + ms_logTargets.push_back(result); + } + while (result); +} + +// ---------------------------------------------------------------------- + +int ConfigSharedLog::getLogNetQueueSize() +{ + return ms_logNetQueueSize; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedLog::getLogNetReconnectTimeMs() +{ + return ms_logNetReconnectTimeMs; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedLog::getLogReportLogs() +{ + return ms_logReportLogs; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedLog::getLogReportWarnings() +{ + return ms_logReportWarnings; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedLog::getLogReportFatals() +{ + return ms_logReportFatals; +} + +// ---------------------------------------------------------------------- + +bool ConfigSharedLog::getLogStderr() +{ + return ms_logStderr; +} + +// ---------------------------------------------------------------------- + +int ConfigSharedLog::getNumberOfLogTargets() +{ + return static_cast(ms_logTargets.size()); +} + +// ---------------------------------------------------------------------- + +char const * ConfigSharedLog::getLogTarget(int const index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfLogTargets()); + return ms_logTargets[static_cast(index)]; +} + +// ====================================================================== + diff --git a/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h b/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h index 4dcf0b60f..254e405d9 100644 --- a/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h +++ b/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTree.h @@ -1,163 +1,163 @@ -// ====================================================================== -// -// MxCifQuadTree.h -// -// Copyright 2002, Sony Online Entertainment -// -// ====================================================================== - -#ifndef INCLUDED_MxCifQuadTree_H -#define INCLUDED_MxCifQuadTree_H - - -#include - - -//============================================================================== - -/******************************************************************************* - - An mx-cif quadtree is a quadtree that stores an object at the minimum quad - that completely contains the object. They are further sub-divided into a - one-dimentional variation of the mx-cif quadtree (mx-cif bintree) based on - if the object crosses the x or y axis of the quad (objects that cross both are - placed in the y-axis bintree). - - There is an optimization of the mx-cif quadtree that could be implemented (at - the expense of more memory) where the object is sub-divided and put into - a quad one lower than its normal level. This is very similar to what is done - in bsp trees. - - See http://www.cs.umd.edu/users/brabec/quadtree/rectangles/cifquad.html, or - "Design and Analysis of Spatial Data Structures" by H. Samet (which - unfortunately is out of print). - -*******************************************************************************/ - -//============================================================================== - -class MxCifQuadTreeBounds; - -//============================================================================== - -class MxCifQuadTree -{ -public: - MxCifQuadTree(float minX, float minY, float maxX, float maxY, int maxDepth); - ~MxCifQuadTree(); - - bool addObject(const MxCifQuadTreeBounds & object); - bool removeObject(const MxCifQuadTreeBounds & object); - void getObjectsAt(float x, float y, std::vector & objects) const; - void getAllObjects(std::vector & objects) const; - -private: - - /** - * A one-dimentional variation of an MxCifQuadTree - */ - class MxCifBinTree - { - public: - MxCifBinTree(float min, float max, int maxDepth); - virtual ~MxCifBinTree(); - - bool addObject(const MxCifQuadTreeBounds & object); - bool removeObject(const MxCifQuadTreeBounds & object); - virtual void getObjectsAt(float x, float y, std::vector & objects) const = 0; - void getAllObjects(std::vector & objects) const; - - protected: - - bool split(void); - - virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const = 0; - virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const = 0; - - protected: - float m_min; // min value of our range - float m_max; // max value of our range - float m_center; // center range value computed from the bounds - int m_maxDepth; // max depth we can recurse from our level - - MxCifBinTree * m_left; // left child - MxCifBinTree * m_right; // right child - - // @todo: use an unique_ptr here? - std::vector m_objects; // objects that are contained in our bounds - }; - - /** - * An MxCifBinTree optimized for searches in the X direction. - */ - class MxCifXBinTree : public MxCifBinTree - { - public: - MxCifXBinTree(float min, float max, int maxDepth); - virtual ~MxCifXBinTree(); - - virtual void getObjectsAt(float x, float y, std::vector & objects) const; - - protected: - - virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const - { - return new MxCifXBinTree(min, max, maxDepth); - } - - virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const; - }; - - /** - * An MxCifBinTree optimized for searches in the Y direction. - */ - class MxCifYBinTree : public MxCifBinTree - { - public: - MxCifYBinTree(float min, float max, int maxDepth); - virtual ~MxCifYBinTree(); - - virtual void getObjectsAt(float x, float y, std::vector & objects) const; - - protected: - - virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const - { - return new MxCifXBinTree(min, max, maxDepth); - } - virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const; - }; - -private: - - bool split(void); - -private: - float m_minX, m_minY; // lower-left bound - float m_maxX, m_maxY; // upper-right bound - float m_centerX, m_centerY; // center computed from the bounds - int m_maxDepth; // max depth we can recurse from our level - - MxCifQuadTree * m_urTree; // upper-right child - MxCifQuadTree * m_ulTree; // upper-left child - MxCifQuadTree * m_llTree; // lower-left child - MxCifQuadTree * m_lrTree; // lower-right child - - MxCifXBinTree m_xAxisTree; // objects that have a minimum intersection of the x-axis - MxCifYBinTree m_yAxisTree; // objects that have a minimum intersection of the -axis -}; - -//============================================================================== - - -inline MxCifQuadTree::MxCifXBinTree::MxCifXBinTree(float min, float max, int maxDepth) : - MxCifQuadTree::MxCifBinTree(min, max, maxDepth) -{ -} - -inline MxCifQuadTree::MxCifYBinTree::MxCifYBinTree(float min, float max, int maxDepth) : - MxCifQuadTree::MxCifBinTree(min, max, maxDepth) -{ -} - -#endif // INCLUDED_MxCifQuadTree_H +// ====================================================================== +// +// MxCifQuadTree.h +// +// Copyright 2002, Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_MxCifQuadTree_H +#define INCLUDED_MxCifQuadTree_H + + +#include + + +//============================================================================== + +/******************************************************************************* + + An mx-cif quadtree is a quadtree that stores an object at the minimum quad + that completely contains the object. They are further sub-divided into a + one-dimentional variation of the mx-cif quadtree (mx-cif bintree) based on + if the object crosses the x or y axis of the quad (objects that cross both are + placed in the y-axis bintree). + + There is an optimization of the mx-cif quadtree that could be implemented (at + the expense of more memory) where the object is sub-divided and put into + a quad one lower than its normal level. This is very similar to what is done + in bsp trees. + + See http://www.cs.umd.edu/users/brabec/quadtree/rectangles/cifquad.html, or + "Design and Analysis of Spatial Data Structures" by H. Samet (which + unfortunately is out of print). + +*******************************************************************************/ + +//============================================================================== + +class MxCifQuadTreeBounds; + +//============================================================================== + +class MxCifQuadTree +{ +public: + MxCifQuadTree(float minX, float minY, float maxX, float maxY, int maxDepth); + ~MxCifQuadTree(); + + bool addObject(const MxCifQuadTreeBounds & object); + bool removeObject(const MxCifQuadTreeBounds & object); + void getObjectsAt(float x, float y, std::vector & objects) const; + void getAllObjects(std::vector & objects) const; + +private: + + /** + * A one-dimentional variation of an MxCifQuadTree + */ + class MxCifBinTree + { + public: + MxCifBinTree(float min, float max, int maxDepth); + virtual ~MxCifBinTree(); + + bool addObject(const MxCifQuadTreeBounds & object); + bool removeObject(const MxCifQuadTreeBounds & object); + virtual void getObjectsAt(float x, float y, std::vector & objects) const = 0; + void getAllObjects(std::vector & objects) const; + + protected: + + bool split(void); + + virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const = 0; + virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const = 0; + + protected: + float m_min; // min value of our range + float m_max; // max value of our range + float m_center; // center range value computed from the bounds + int m_maxDepth; // max depth we can recurse from our level + + MxCifBinTree * m_left; // left child + MxCifBinTree * m_right; // right child + + // @todo: use an unique_ptr here? + std::vector m_objects; // objects that are contained in our bounds + }; + + /** + * An MxCifBinTree optimized for searches in the X direction. + */ + class MxCifXBinTree : public MxCifBinTree + { + public: + MxCifXBinTree(float min, float max, int maxDepth); + virtual ~MxCifXBinTree(); + + virtual void getObjectsAt(float x, float y, std::vector & objects) const; + + protected: + + virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const + { + return new MxCifXBinTree(min, max, maxDepth); + } + + virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const; + }; + + /** + * An MxCifBinTree optimized for searches in the Y direction. + */ + class MxCifYBinTree : public MxCifBinTree + { + public: + MxCifYBinTree(float min, float max, int maxDepth); + virtual ~MxCifYBinTree(); + + virtual void getObjectsAt(float x, float y, std::vector & objects) const; + + protected: + + virtual MxCifBinTree * createChild(float min, float max, int maxDepth) const + { + return new MxCifXBinTree(min, max, maxDepth); + } + virtual bool isObjectInRange(const MxCifQuadTreeBounds & object) const; + }; + +private: + + bool split(void); + +private: + float m_minX, m_minY; // lower-left bound + float m_maxX, m_maxY; // upper-right bound + float m_centerX, m_centerY; // center computed from the bounds + int m_maxDepth; // max depth we can recurse from our level + + MxCifQuadTree * m_urTree; // upper-right child + MxCifQuadTree * m_ulTree; // upper-left child + MxCifQuadTree * m_llTree; // lower-left child + MxCifQuadTree * m_lrTree; // lower-right child + + MxCifXBinTree m_xAxisTree; // objects that have a minimum intersection of the x-axis + MxCifYBinTree m_yAxisTree; // objects that have a minimum intersection of the -axis +}; + +//============================================================================== + + +inline MxCifQuadTree::MxCifXBinTree::MxCifXBinTree(float min, float max, int maxDepth) : + MxCifQuadTree::MxCifBinTree(min, max, maxDepth) +{ +} + +inline MxCifQuadTree::MxCifYBinTree::MxCifYBinTree(float min, float max, int maxDepth) : + MxCifQuadTree::MxCifBinTree(min, max, maxDepth) +{ +} + +#endif // INCLUDED_MxCifQuadTree_H diff --git a/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h b/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h index 5ac6d4db6..27006c078 100644 --- a/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h +++ b/src/engine/shared/library/sharedMath/src/shared/MxCifQuadTreeBounds.h @@ -20,6 +20,7 @@ class MxCifQuadTreeBounds { public: MxCifQuadTreeBounds(float minX, float minY, float maxX, float maxY, void * data = NULL); + virtual ~MxCifQuadTreeBounds(){}; const float getMinX(void) const; const float getMinY(void) const; diff --git a/src/engine/shared/library/sharedMath/src/shared/PolySolver.cpp b/src/engine/shared/library/sharedMath/src/shared/PolySolver.cpp index 2ca0720d5..872057d16 100644 --- a/src/engine/shared/library/sharedMath/src/shared/PolySolver.cpp +++ b/src/engine/shared/library/sharedMath/src/shared/PolySolver.cpp @@ -1,319 +1,319 @@ -// Polynomial solver code adapted from Graphics Gems version -// by Jochen Schwarze - -#include "sharedMath/FirstSharedMath.h" -#include "sharedMath/PolySolver.h" - -#include -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -double cuberoot( double x ) -{ - return ((x) > 0.0 ? pow(x, 1.0/3.0) : ((x) < 0.0 ? -pow(-x, 1.0/3.0) : 0.0)); -} - -int PolySolver::solveQuadratic( double const c[3], double s[2] ) -{ - double p, q, D; - - /* normal form: x^2 + px + q = 0 */ - - p = c[ 1 ] / (2 * c[ 2 ]); - q = c[ 0 ] / c[ 2 ]; - - D = p * p - q; - - if (D < 0) - { - return 0; - } - else - { - double sqrt_D = sqrt(D); - - s[ 0 ] = sqrt_D - p; - s[ 1 ] = - sqrt_D - p; - return 2; - } -} - -int PolySolver::solveCubic( double const c[4], double s[3] ) -{ - int i, num; - double sub; - double A, B, C; - double sq_A, p, q; - double cb_p, D; - - /* normal form: x^3 + Ax^2 + Bx + C = 0 */ - - A = c[ 2 ] / c[ 3 ]; - B = c[ 1 ] / c[ 3 ]; - C = c[ 0 ] / c[ 3 ]; - - /* substitute x = y - A/3 to eliminate quadric term: - x^3 +px + q = 0 */ - - sq_A = A * A; - p = (1.0/3) * (- (1.0/3) * sq_A + B); - q = (1.0/2) * (((2.0/27) * A * sq_A - ((1.0/3) * A * B)) + C); - - /* use Cardano's formula */ - - cb_p = p * p * p; - D = q * q + cb_p; - - if (D < 0) /* Casus irreducibilis: three real solutions */ - { - double phi = (1.0/3) * acos(-q / sqrt(-cb_p)); - double t = 2 * sqrt(-p); - - s[ 0 ] = t * cos(phi); - s[ 1 ] = - t * cos(phi + M_PI / 3); - s[ 2 ] = - t * cos(phi - M_PI / 3); - num = 3; - } - else /* one real solution */ - { - double sqrt_D = sqrt(D); - double u = cuberoot(sqrt_D - q); - double v = - cuberoot(sqrt_D + q); - - s[ 0 ] = u + v; - num = 1; - } - - /* resubstitute */ - - sub = (1.0/3) * A; - - for (i = 0; i < num; ++i) - s[ i ] -= sub; - - return num; -} - -double cubicError = 0.0f; -double cleanedCubicError = 0.0f; - -double quarticError = 0.0f; -double cleanedQuarticError = 0.0f; - -double evaluateCubic( double x, const double c[4] ) -{ - return ((x*c[3] + c[2]) * x + c[1]) * x + c[0]; -} - -double evaluateCubicDerivative ( double x, const double c[4] ) -{ - return (3.0*x + 2.0*c[2]) * x + c[1]; -} - -double cleanCubicRoot( double x, const double c[4] ) -{ - double e; - - e = evaluateCubic(x,c); - - if(fabs(e) > cubicError) cubicError = e; - - // ---------- - -// for(int i = 0; i < 10; i++) - { - e = evaluateCubic(x,c); - - e *= 0.8; - - double d = evaluateCubicDerivative(x,c); - - if(d != 0.0) - { - x = x - e/d; - } - } - - // ---------- - - e = evaluateCubic(x,c); - - if(fabs(e) > cleanedCubicError) cleanedCubicError = e; - - return x; -} - -double evaluateQuartic( double x, const double c[5] ) -{ - return (((x*c[4] + c[3]) * x + c[2]) * x + c[1]) * x + c[0]; -} - -double evaluateQuarticDerivative ( double x, const double c[5] ) -{ - return ((4.0*x*c[4] + 3.0*c[3]) * x + 2.0*c[2]) * x + c[1]; -} - -double cleanQuarticRoot( double x, const double c[5] ) -{ - double e; - - e = evaluateQuartic(x,c); - - if(fabs(e) > quarticError) quarticError = e; - - // ---------- - -// for(int i = 0; i < 10; i++) - { - e = evaluateQuartic(x,c); - - e *= 0.8; - - double d = evaluateQuarticDerivative(x,c); - - if(d != 0.0) - { - x = x - e/d; - } - } - - // ---------- - - e = evaluateQuartic(x,c); - - if(fabs(e) > cleanedQuarticError) cleanedQuarticError = e; - - return x; -} - -#ifdef WIN32 - #define isnan(a) _isnan(a) -#endif - -int PolySolver::solveQuartic( const double c[5], double s[4] ) -{ - double a3 = c[3] / c[4]; - double a2 = c[2] / c[4]; - double a1 = c[1] / c[4]; - double a0 = c[0] / c[4]; - - // ---------- - // solve the resolvent cubic to get a real root - - double y1 = 1.0f; - - { - double c[4]; - - c[3] = 1.0; - c[2] = -a2; - c[1] = (a1*a3) - (4.0)*(a0); - c[0] = (4.0)*(a2*a0) - (a1*a1) - (a3*a3*a0); - - double s[3]; - - int nRoots = PolySolver::solveCubic(c,s); - - for(int i = 0; i < nRoots; i++) - { - if(s[i] == s[i]) - { - // root is real - - y1 = cleanCubicRoot( s[i], c ); - - break; - } - } - } - - // ---------- - // use the root to find the roots of the quadric - - double t1 = (1.0/4.0)*(a3*a3) - a2 + y1; - - double R = sqrt(t1); - - double D; - - if(R == 0.0) - { - double t1 = (y1*y1) - (4.0)*(a0); - - double t2 = sqrt(t1); - - double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) + (2.0)*t2; - - D = sqrt(t3); - } - else - { - double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3); - - double t2 = t1 / (4.0 * R); - - double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) + t2; - - D = sqrt(t3); - } - - double E; - - if(R == 0.0) - { - double t1 = (y1*y1) - (4.0)*(a0); - - double t2 = sqrt(t1); - - double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) - (2.0)*(t2); - - E = sqrt(t3); - } - else - { - double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3); - - double t2 = t1 / (4.0 * R); - - double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) - t2; - - E = sqrt(t3); - } - - static const double nan = sqrt(-1.0f); - if (isnan(D)) - { - s[0] = nan; - s[1] = nan; - } - else - { - s[0] = (-1.0/4.0)*a3 + (1.0/2.0)*R + (1.0/2.0)*D; - s[1] = (-1.0/4.0)*a3 + (1.0/2.0)*R - (1.0/2.0)*D; - } - - if (isnan(E)) - { - s[2] = nan; - s[3] = nan; - } - else - { - s[2] = (-1.0/4.0)*a3 - (1.0/2.0)*R + (1.0/2.0)*E; - s[3] = (-1.0/4.0)*a3 - (1.0/2.0)*R - (1.0/2.0)*E; - } - -/* - // Perform one step of a Newton iteration in order to minimize round-off errors - - int i; - - for(i = 0; i < 4; i++) - { - s[i] = cleanQuarticRoot(s[i],c); - } - */ - - return 4; -} +// Polynomial solver code adapted from Graphics Gems version +// by Jochen Schwarze + +#include "sharedMath/FirstSharedMath.h" +#include "sharedMath/PolySolver.h" + +#include +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +double cuberoot( double x ) +{ + return ((x) > 0.0 ? pow(x, 1.0/3.0) : ((x) < 0.0 ? -pow(-x, 1.0/3.0) : 0.0)); +} + +int PolySolver::solveQuadratic( double const c[3], double s[2] ) +{ + double p, q, D; + + /* normal form: x^2 + px + q = 0 */ + + p = c[ 1 ] / (2 * c[ 2 ]); + q = c[ 0 ] / c[ 2 ]; + + D = p * p - q; + + if (D < 0) + { + return 0; + } + else + { + double sqrt_D = sqrt(D); + + s[ 0 ] = sqrt_D - p; + s[ 1 ] = - sqrt_D - p; + return 2; + } +} + +int PolySolver::solveCubic( double const c[4], double s[3] ) +{ + int i, num; + double sub; + double A, B, C; + double sq_A, p, q; + double cb_p, D; + + /* normal form: x^3 + Ax^2 + Bx + C = 0 */ + + A = c[ 2 ] / c[ 3 ]; + B = c[ 1 ] / c[ 3 ]; + C = c[ 0 ] / c[ 3 ]; + + /* substitute x = y - A/3 to eliminate quadric term: + x^3 +px + q = 0 */ + + sq_A = A * A; + p = (1.0/3) * (- (1.0/3) * sq_A + B); + q = (1.0/2) * (((2.0/27) * A * sq_A - ((1.0/3) * A * B)) + C); + + /* use Cardano's formula */ + + cb_p = p * p * p; + D = q * q + cb_p; + + if (D < 0) /* Casus irreducibilis: three real solutions */ + { + double phi = (1.0/3) * acos(-q / sqrt(-cb_p)); + double t = 2 * sqrt(-p); + + s[ 0 ] = t * cos(phi); + s[ 1 ] = - t * cos(phi + M_PI / 3); + s[ 2 ] = - t * cos(phi - M_PI / 3); + num = 3; + } + else /* one real solution */ + { + double sqrt_D = sqrt(D); + double u = cuberoot(sqrt_D - q); + double v = - cuberoot(sqrt_D + q); + + s[ 0 ] = u + v; + num = 1; + } + + /* resubstitute */ + + sub = (1.0/3) * A; + + for (i = 0; i < num; ++i) + s[ i ] -= sub; + + return num; +} + +double cubicError = 0.0f; +double cleanedCubicError = 0.0f; + +double quarticError = 0.0f; +double cleanedQuarticError = 0.0f; + +double evaluateCubic( double x, const double c[4] ) +{ + return ((x*c[3] + c[2]) * x + c[1]) * x + c[0]; +} + +double evaluateCubicDerivative ( double x, const double c[4] ) +{ + return (3.0*x + 2.0*c[2]) * x + c[1]; +} + +double cleanCubicRoot( double x, const double c[4] ) +{ + double e; + + e = evaluateCubic(x,c); + + if(fabs(e) > cubicError) cubicError = e; + + // ---------- + +// for(int i = 0; i < 10; i++) + { + e = evaluateCubic(x,c); + + e *= 0.8; + + double d = evaluateCubicDerivative(x,c); + + if(d != 0.0) + { + x = x - e/d; + } + } + + // ---------- + + e = evaluateCubic(x,c); + + if(fabs(e) > cleanedCubicError) cleanedCubicError = e; + + return x; +} + +double evaluateQuartic( double x, const double c[5] ) +{ + return (((x*c[4] + c[3]) * x + c[2]) * x + c[1]) * x + c[0]; +} + +double evaluateQuarticDerivative ( double x, const double c[5] ) +{ + return ((4.0*x*c[4] + 3.0*c[3]) * x + 2.0*c[2]) * x + c[1]; +} + +double cleanQuarticRoot( double x, const double c[5] ) +{ + double e; + + e = evaluateQuartic(x,c); + + if(fabs(e) > quarticError) quarticError = e; + + // ---------- + +// for(int i = 0; i < 10; i++) + { + e = evaluateQuartic(x,c); + + e *= 0.8; + + double d = evaluateQuarticDerivative(x,c); + + if(d != 0.0) + { + x = x - e/d; + } + } + + // ---------- + + e = evaluateQuartic(x,c); + + if(fabs(e) > cleanedQuarticError) cleanedQuarticError = e; + + return x; +} + +#ifdef WIN32 + #define isnan(a) _isnan(a) +#endif + +int PolySolver::solveQuartic( const double c[5], double s[4] ) +{ + double a3 = c[3] / c[4]; + double a2 = c[2] / c[4]; + double a1 = c[1] / c[4]; + double a0 = c[0] / c[4]; + + // ---------- + // solve the resolvent cubic to get a real root + + double y1 = 1.0f; + + { + double c[4]; + + c[3] = 1.0; + c[2] = -a2; + c[1] = (a1*a3) - (4.0)*(a0); + c[0] = (4.0)*(a2*a0) - (a1*a1) - (a3*a3*a0); + + double s[3]; + + int nRoots = PolySolver::solveCubic(c,s); + + for(int i = 0; i < nRoots; i++) + { + if(s[i] == s[i]) + { + // root is real + + y1 = cleanCubicRoot( s[i], c ); + + break; + } + } + } + + // ---------- + // use the root to find the roots of the quadric + + double t1 = (1.0/4.0)*(a3*a3) - a2 + y1; + + double R = sqrt(t1); + + double D; + + if(R == 0.0) + { + double t1 = (y1*y1) - (4.0)*(a0); + + double t2 = sqrt(t1); + + double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) + (2.0)*t2; + + D = sqrt(t3); + } + else + { + double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3); + + double t2 = t1 / (4.0 * R); + + double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) + t2; + + D = sqrt(t3); + } + + double E; + + if(R == 0.0) + { + double t1 = (y1*y1) - (4.0)*(a0); + + double t2 = sqrt(t1); + + double t3 = (3.0/4.0)*(a3*a3) - (2.0)*(a2) - (2.0)*(t2); + + E = sqrt(t3); + } + else + { + double t1 = (4.0)*(a3*a2) - (8.0)*(a1) - (a3*a3*a3); + + double t2 = t1 / (4.0 * R); + + double t3 = (3.0/4.0)*(a3*a3) - (R*R) - (2.0)*(a2) - t2; + + E = sqrt(t3); + } + + static const double nan = sqrt(-1.0f); + if (isnan(D)) + { + s[0] = nan; + s[1] = nan; + } + else + { + s[0] = (-1.0/4.0)*a3 + (1.0/2.0)*R + (1.0/2.0)*D; + s[1] = (-1.0/4.0)*a3 + (1.0/2.0)*R - (1.0/2.0)*D; + } + + if (isnan(E)) + { + s[2] = nan; + s[3] = nan; + } + else + { + s[2] = (-1.0/4.0)*a3 - (1.0/2.0)*R + (1.0/2.0)*E; + s[3] = (-1.0/4.0)*a3 - (1.0/2.0)*R - (1.0/2.0)*E; + } + +/* + // Perform one step of a Newton iteration in order to minimize round-off errors + + int i; + + for(i = 0; i < 4; i++) + { + s[i] = cleanQuarticRoot(s[i],c); + } + */ + + return 4; +} diff --git a/src/engine/shared/library/sharedMemoryManager/src/shared/MemoryManager.cpp b/src/engine/shared/library/sharedMemoryManager/src/shared/MemoryManager.cpp index 3732c7d5b..69a79c007 100644 --- a/src/engine/shared/library/sharedMemoryManager/src/shared/MemoryManager.cpp +++ b/src/engine/shared/library/sharedMemoryManager/src/shared/MemoryManager.cpp @@ -1,2239 +1,2239 @@ -// ====================================================================== -// -// MemoryManager.cpp -// Portions copyright 1998 Bootprint Entertainment -// Portions copyright 2002 Sony Online Entertainment -// All Rights Reserved -// -// ====================================================================== - -#include "sharedMemoryManager/FirstSharedMemoryManager.h" -#include "sharedMemoryManager/MemoryManager.h" -#include "sharedMemoryManager/OsMemory.h" - -#include "sharedFoundation/ConfigSharedFoundation.h" -#include "sharedFoundation/Production.h" -#include "sharedDebug/DebugFlags.h" -#include "sharedDebug/DebugMonitor.h" -#include "sharedDebug/PixCounter.h" -#include "sharedDebug/Profiler.h" -#include "sharedSynchronization/RecursiveMutex.h" -#include "sharedDebug/RemoteDebug.h" - -#include - -#ifdef _WIN32 -#include -#include -#else -#include -#endif - -#include -#include -#include -#include - -#ifdef _WIN32 -#define DISABLE_MEMORY_MANAGER 0 -#else -#define DISABLE_MEMORY_MANAGER 0 -#endif - -//lint -e826 // Suspicious pointer-to-pointer conversion (area too small) - -#if !DISABLE_MEMORY_MANAGER - -// ====================================================================== -// -#define DISABLED 0 - -#if PRODUCTION - - #define DO_TRACK 0 - #define DO_SCALAR 0 - #define DO_GUARDS 0 - #define DO_INITIALIZE_FILLS 0 - #define DO_FREE_FILLS 0 - -#else - - #if DEBUG_LEVEL == DEBUG_LEVEL_DEBUG - - #define DO_TRACK 1 - #define DO_SCALAR 1 - #define DO_GUARDS 1 - #define DO_INITIALIZE_FILLS 1 - #define DO_FREE_FILLS 1 - - #elif DEBUG_LEVEL == DEBUG_LEVEL_OPTIMIZED - - #define DO_TRACK 1 - #define DO_SCALAR 1 - #define DO_GUARDS 1 - #define DO_INITIALIZE_FILLS 1 - #define DO_FREE_FILLS 1 - - #elif DEBUG_LEVEL == DEBUG_LEVEL_RELEASE - - #define DO_TRACK 0 - #define DO_SCALAR 0 - #define DO_GUARDS 0 - #define DO_INITIALIZE_FILLS 0 - #define DO_FREE_FILLS 0 - - #else - - #error unknown DEBUG_LEVEL - - #endif - -#endif - -#ifdef PLATFORM_LINUX - #undef DO_TRACK - #define DO_TRACK 5 -#endif - -// ====================================================================== - -namespace MemoryManagerNamespace -{ - class Block; - - class SystemAllocation - { - public: - - SystemAllocation(int size); - ~SystemAllocation(); - - int getSize(); - - SystemAllocation * getNext(); - void setNext(SystemAllocation *); - - Block * getFirstMemoryBlock(); - Block * getLastMemoryBlock(); - - private: - - int m_size; - SystemAllocation * m_next; - int m_pad1; - int m_pad2; - }; - - - class Block - { - public: - - enum { cms_requestedSizeBits = 30 }; - - public: - - Block * getPrevious(); - Block const * getPrevious() const; - void setPrevious(Block *previous); - - Block * getNext(); - Block const * getNext() const; - void setNext(Block *previous); - - bool isFree() const; - void setFree(bool free); - - int getSize() const; - - private: - - Block * m_previous; - Block * m_next; - bool m_free:1; - - protected: - - // these are only in allocated blocks, but we can't expect a compiler to merge bitfields across multiple classes -#if DO_SCALAR - bool m_array:1; -#endif -#if DO_TRACK - bool m_leakTest:1; -#endif -#if DO_TRACK || DO_GUARDS - unsigned int m_requestedSize:cms_requestedSizeBits; -#endif - }; - - class FreeBlock; - - void addToFreeList(Block * block); - void removeFromFreeList(FreeBlock * block); - FreeBlock *searchFreeList(int blockSize); - - class FreeBlock : public Block - { - private: - - friend void addToFreeList(Block *block); - friend void removeFromFreeList(FreeBlock *block); - friend FreeBlock *searchFreeList(int blockSize); - - private: - FreeBlock * m_smallerFreeBlock; - FreeBlock * m_sameFreeBlock; - FreeBlock * m_largerFreeBlock; - FreeBlock * m_parentFreeBlock; - }; - - class AllocatedBlock : public Block - { - public: - -#if DO_SCALAR - bool isAllocatedAsArray() const; - void setAllocatedAsArray(bool array); -#endif - -#if DO_TRACK - bool checkForLeaks() const; - void setCheckForLeaks(bool checkForLeaks); - - uint32 getOwner(int index) const; - void setOwner(int index, uint32 owner); - void fillOwnerWithFreePattern(); - -#endif - -#if DO_TRACK || DO_GUARDS - int getRequestedSize() const; - void setRequestedSize(int requestedSize); -#endif - - private: - -#if DO_TRACK - uint32 m_owner[DO_TRACK]; -#endif - }; - -#ifdef _DEBUG - void logAllocationsNextFrame(); -#endif - - int convertBytesToMegabytesForSystemAllocation(int bytes); - void allocateSystemMemory(int megabytes); - - int min(int a, int b); - int max(int a, int b); - byte const * min(byte const * a, byte const * b); - byte const * max(byte const * a, byte const * b); - - int report(bool leak); - void report(AllocatedBlock const * block, bool leak); - - int quickGuessIsValidPointerFromHeap(void const *); - int authoritativeIsValidPointerFromHeap(void const *); - - void emitCharacters(char * & buffer, int blockSize, int & carryOverFree, int & carryOverUsed, int newFree, int newUsed, char const * const bufferOverrunAddress); - - bool reportToFile(char const *fileName, bool leak); - void outputDebugStringWrapper(char const * message); - void logMessageToFd(char const * message); - - int const cms_blockSize = (sizeof(Block) + 15) & (~15); - int const cms_freeBlockSize = (sizeof(FreeBlock) + 15) & (~15); - extern int const cms_allocatedBlockSize = (sizeof(AllocatedBlock) + 15) & (~15); - byte const cms_guardFillPattern = 0xAB; - byte const cms_initializeFillPattern = 0xCD; - byte const cms_freeFillPattern = 0xEF; - int const cms_guardBandSize = DO_GUARDS ? 16 : 0; - - int const cms_systemAllocationRoundSize = 4 * 1024 * 1024; - int const cms_systemAllocationMinimumSize = 4 * 1024 * 1024; - - bool ms_installed; - bool ms_limitSet; - bool ms_hardLimit; - int ms_limitMegabytes = 2047; - SystemAllocation * ms_firstSystemAllocation; - int ms_numberOfSystemAllocations; - int ms_systemMemoryAllocatedMegabytes; - bool ms_reportAllocations; -// bool ms_logEachAlloc; - -#if PRODUCTION == 0 - PixCounter::ResetInteger ms_allocationsPerFrame; - PixCounter::ResetInteger ms_bytesAllocatedPerFrame; - PixCounter::ResetInteger ms_freesPerFrame; - PixCounter::ResetInteger ms_bytesFreedPerFrame; -#endif - -#ifdef _DEBUG - bool ms_debugReportFlag; - bool ms_debugReportMapFlag; - bool ms_debugReportAllocations; - bool ms_debugReportLogMemoryAllocFreePointers; - bool ms_debugLogAllocations; - bool ms_debugLogAllocationsNextFrame; - bool ms_debugVerifyGuardPatterns; - bool ms_debugVerifyFreePatterns; - bool ms_debugProfileAllocate; - bool ms_debugLogAllocationsNextFrameStarted; -#endif - - RecursiveMutex * ms_criticalSection; - - char ms_memoryManagerBuffer[sizeof(MemoryManager)]; - - FreeBlock * ms_firstFreeBlock; - - int ms_allocateCalls; - unsigned long ms_allocateBytesTotal; -#ifndef _WIN32 - int ms_processVmSizeKBytes; -#endif - int ms_freeCalls; - - int ms_allocations; - int ms_maxAllocations; - - int ms_freeBlocks; - int ms_maxFreeBlocks; -#ifdef _DEBUG - int ms_maxTreeHeight; -#endif - -#if DO_TRACK || DO_GUARDS - unsigned long ms_currentBytesRequested; -#endif - unsigned long ms_currentBytesAllocated; -#if DO_TRACK - unsigned long ms_currentBytesAllocatedNoLeakTest; -#endif - unsigned long ms_maxBytesAllocated; - - bool ms_allowNameLookup = true; - int ms_logMessageFd = -1; - void (*LogMessage)(char const * message) = &outputDebugStringWrapper; - - PROFILER_BLOCK_DEFINE(ms_allocateProfilerBlock, "MemoryManager::allocate"); -} -using namespace MemoryManagerNamespace; - -// ====================================================================== - -SystemAllocation::SystemAllocation(int size) -: - m_size(size), - m_next(NULL), - m_pad1(0), - m_pad2(0) -{ - DEBUG_FATAL(sizeof(*this) != cms_blockSize, ("SystemAllocation size is not %d bytes", cms_blockSize)); - -#if DO_FREE_FILLS - // fill the newly allocated user memory with the free pattern - imemset(reinterpret_cast(this) + cms_blockSize, cms_freeFillPattern, m_size - cms_blockSize); -#endif - - Block * firstMemoryBlock = getFirstMemoryBlock(); - Block * firstFreeBlock = reinterpret_cast(reinterpret_cast(firstMemoryBlock) + cms_blockSize); - Block * lastMemoryBlock = getLastMemoryBlock(); - - // set up the prefix sentinel block - firstMemoryBlock->setPrevious(NULL); - firstMemoryBlock->setNext(firstFreeBlock); - firstMemoryBlock->setFree(false); - - firstFreeBlock->setPrevious(firstMemoryBlock); - firstFreeBlock->setNext(lastMemoryBlock); - firstFreeBlock->setFree(true); - - // set up the suffix sentinel block - lastMemoryBlock->setPrevious(firstFreeBlock); - lastMemoryBlock->setNext(NULL); - lastMemoryBlock->setFree(false); - - // put the first block on the free list - addToFreeList(firstFreeBlock); -} - -// ---------------------------------------------------------------------- - -SystemAllocation::~SystemAllocation() -{ - OsMemory::free(this, m_size); -} - -// ---------------------------------------------------------------------- - -int SystemAllocation::getSize() -{ - return m_size; -} - -// ---------------------------------------------------------------------- - -SystemAllocation * SystemAllocation::getNext() -{ - return m_next; -} - -// ---------------------------------------------------------------------- - -void SystemAllocation::setNext(SystemAllocation * next) -{ - m_next = next; -} - -// ---------------------------------------------------------------------- - -Block * SystemAllocation ::getFirstMemoryBlock() -{ - return reinterpret_cast(reinterpret_cast(this) + cms_blockSize); -} - -// ---------------------------------------------------------------------- - -Block * SystemAllocation ::getLastMemoryBlock() -{ - return reinterpret_cast(reinterpret_cast(this) + m_size - cms_blockSize); -} - -// ====================================================================== - -inline Block * Block::getPrevious() -{ - return m_previous; -} - -// ---------------------------------------------------------------------- - -inline Block const * Block::getPrevious() const -{ - return m_previous; -} - -// ---------------------------------------------------------------------- - -inline void Block::setPrevious(Block *previous) -{ - m_previous = previous; -} - -// ---------------------------------------------------------------------- - -inline Block * Block::getNext() -{ - return m_next; -} - -// ---------------------------------------------------------------------- - -inline Block const * Block::getNext() const -{ - return m_next; -} - -// ---------------------------------------------------------------------- - -inline void Block::setNext(Block *next) -{ - DEBUG_FATAL(next && reinterpret_cast(next) - reinterpret_cast(this) < cms_blockSize, ("too small")); - m_next = next; -} - -// ---------------------------------------------------------------------- - -inline bool Block::isFree() const -{ - return m_free; -} - -// ---------------------------------------------------------------------- - -inline void Block::setFree(bool free) -{ - m_free = free; -} - -// ---------------------------------------------------------------------- - -inline int Block::getSize() const -{ - return reinterpret_cast(m_next) - reinterpret_cast(this); -} - -// ====================================================================== - -#if DO_SCALAR - -inline bool AllocatedBlock::isAllocatedAsArray() const -{ - return m_array; -} - -// ---------------------------------------------------------------------- - -inline void AllocatedBlock::setAllocatedAsArray(bool array) -{ - m_array = array; -} - -#endif - -// ---------------------------------------------------------------------- - -#if DO_TRACK - -inline bool AllocatedBlock::checkForLeaks() const -{ - return m_leakTest; -} - -// ---------------------------------------------------------------------- - -inline void AllocatedBlock::setCheckForLeaks(bool checkForLeaks) -{ - m_leakTest = checkForLeaks; -} - -// ---------------------------------------------------------------------- - -inline uint32 AllocatedBlock::getOwner(int index) const -{ - return m_owner[index]; -} - -// ---------------------------------------------------------------------- - -inline void AllocatedBlock::setOwner(int index, uint32 owner) -{ - m_owner[index] = owner; -} - -// ---------------------------------------------------------------------- - -inline void AllocatedBlock::fillOwnerWithFreePattern() -{ - memset(m_owner, cms_freeFillPattern, sizeof(m_owner)); -} - -#endif - -// ---------------------------------------------------------------------- - -#if DO_TRACK || DO_GUARDS - -inline int AllocatedBlock::getRequestedSize() const -{ - return m_requestedSize; -} - -// ---------------------------------------------------------------------- - -inline void AllocatedBlock::setRequestedSize(int requestedSize) -{ - m_requestedSize = requestedSize; -} - -#endif - -// ====================================================================== - -inline int MemoryManagerNamespace::min(int a, int b) -{ - return (a < b) ? a : b; -} - -// ---------------------------------------------------------------------- - -inline int MemoryManagerNamespace::max(int a, int b) -{ - return (a > b) ? a : b; -} - -// ---------------------------------------------------------------------- - -inline byte const * MemoryManagerNamespace::min(byte const * a, byte const * b) -{ - return (a < b) ? a : b; -} - -// ---------------------------------------------------------------------- - -inline byte const * MemoryManagerNamespace::max(byte const * a, byte const * b) -{ - return (a > b) ? a : b; -} - -// ---------------------------------------------------------------------- -// this is here to get around linkage problems on win32 - -void MemoryManagerNamespace::outputDebugStringWrapper(char const * message) -{ - OutputDebugString(message); -} - -// ---------------------------------------------------------------------- - -void MemoryManager::setLimit(int megabytes, bool hardLimit, bool preallocate) -{ - DEBUG_FATAL(ms_limitSet, ("MemoryManager::setLimit may only be called once")); - ms_limitSet = true; - ms_limitMegabytes = megabytes; - ms_hardLimit = hardLimit; - DEBUG_FATAL(ms_hardLimit && ms_systemMemoryAllocatedMegabytes > ms_limitMegabytes, ("hard limit broken before being set %d/%d", ms_systemMemoryAllocatedMegabytes, ms_limitMegabytes)); - if (preallocate && ms_systemMemoryAllocatedMegabytes < ms_limitMegabytes) - allocateSystemMemory(ms_limitMegabytes - ms_systemMemoryAllocatedMegabytes); -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getLimit() -{ - return ms_limitMegabytes; -} - -// ---------------------------------------------------------------------- - -bool MemoryManager::isHardLimit() -{ - return ms_hardLimit; -} - -// ---------------------------------------------------------------------- -/** - * Install the MemoryManager. - * @param newMaxBytes Maximum number of bytes in the memory pool - * @param newMaxBlocks Number of blocks (free or allocated) - * @param commitAll Commit all the specified ram to the application - */ - -MemoryManager::MemoryManager() -{ - // any allocation will install the memory manager if it has yet to be, so we want to bail safely here - if (ms_installed) - return; - -#if defined(PLATFORM_WIN32) && defined(_DEBUG) - /* - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); - int crtHeapFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - crtHeapFlags &= ~_CRTDBG_ALLOC_MEM_DF; - crtHeapFlags &= ~_CRTDBG_CHECK_ALWAYS_DF; - crtHeapFlags &= ~_CRTDBG_CHECK_CRT_DF; - crtHeapFlags &= ~_CRTDBG_DELAY_FREE_MEM_DF; - crtHeapFlags &= ~_CRTDBG_LEAK_CHECK_DF; - _CrtSetDbgFlag(crtHeapFlags); - */ -#endif - - OsMemory::install(); - DebugHelp::install(); - -#if !DISABLED - - // this buffer must remain local to this function, otherwise it will get clobbered. - // the problem is this function gets called before the library gets properly initialized, - // and then when the library gets initialized, it will clear the global memory, thus - // wiping out our mutex. - static char s_criticalSectionBuffer[sizeof(RecursiveMutex)]; - ms_criticalSection = new(s_criticalSectionBuffer) RecursiveMutex; - - ms_reportAllocations = true; - ms_installed = true; -// ms_logEachAlloc = false; - -#endif -} - -// ---------------------------------------------------------------------- -/** - * Remove the MemoryManager. - */ - -MemoryManager::~MemoryManager() -{ -#if DISABLED - return; -#else - -#if PRODUCTION == 0 - ms_allocationsPerFrame.disable(); - ms_bytesAllocatedPerFrame.disable(); - ms_freesPerFrame.disable(); - ms_bytesFreedPerFrame.disable(); -#endif - - DEBUG_FATAL(!ms_installed, ("not installed")); - - ms_criticalSection->enter(); - - DEBUG_REPORT_LOG_PRINT(true, ("MM::remove %lu/%lu=bytes %d/%d=allocs\n", getCurrentNumberOfBytesAllocated(), getMaximumNumberOfBytesAllocated(), getCurrentNumberOfAllocations(), getMaximumNumberOfAllocations())); - DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("MM::remove %lu/%lu=bytes %d/%d=allocs\n", getCurrentNumberOfBytesAllocated(), getMaximumNumberOfBytesAllocated(), getCurrentNumberOfAllocations(), getMaximumNumberOfAllocations())); - -#if DO_TRACK - if (!ConfigSharedFoundation::getDemoMode() && ms_allocations && ms_reportAllocations) - { - ms_criticalSection->leave(); - int const leaks = MemoryManagerNamespace::report(true); - ms_criticalSection->enter(); - if (leaks) - REPORT(true, Report::RF_log | Report::RF_dialog, ("%d memory leak%s", leaks, leaks > 1 ? "s" : "")); - } -#endif - - // free all of the allocations from the OS - while (ms_firstSystemAllocation) - { - SystemAllocation * systemAllocation = ms_firstSystemAllocation; - ms_firstSystemAllocation = ms_firstSystemAllocation->getNext(); - systemAllocation->~SystemAllocation(); - } - - ms_criticalSection->leave(); - ms_installed = false; - -#ifdef _DEBUG - DebugMonitor::remove(); -#endif - - ms_criticalSection->~RecursiveMutex(); - -#endif - - DebugHelp::remove(); - OsMemory::remove(); -} - -// ---------------------------------------------------------------------- - -int MemoryManagerNamespace::convertBytesToMegabytesForSystemAllocation(int systemAllocationSize) -{ - if (systemAllocationSize < cms_systemAllocationMinimumSize) - systemAllocationSize = cms_systemAllocationMinimumSize; - - systemAllocationSize = (systemAllocationSize + (cms_systemAllocationRoundSize - 1)) & (~(cms_systemAllocationRoundSize - 1)); - - return systemAllocationSize / (1024 * 1024); -} - -// ---------------------------------------------------------------------- - -void MemoryManagerNamespace::allocateSystemMemory(int megabytes) -{ - if (ms_hardLimit && ms_systemMemoryAllocatedMegabytes + megabytes > ms_limitMegabytes) - { - megabytes = ms_limitMegabytes - ms_systemMemoryAllocatedMegabytes; - if (megabytes <= 0) - return; - } - - // allocate the system memory - size_t systemAllocationSize = static_cast(megabytes) * 1024 * 1024; - void * data = OsMemory::commit(0, systemAllocationSize); - - // failed to allocate virtual memory. there is insufficient virtual memory or address space to satisfy systemAllocationSize. - if (!data) - return; - - // Construct our tracking information - SystemAllocation * systemAllocation = new(data) SystemAllocation(systemAllocationSize); - ++ms_numberOfSystemAllocations; - ms_systemMemoryAllocatedMegabytes += megabytes; - - // insert the memory into the sorted linked list of system allocations - SystemAllocation * back = NULL; - SystemAllocation * front = ms_firstSystemAllocation; - for ( ; front && front->getFirstMemoryBlock() < systemAllocation->getFirstMemoryBlock(); back = front, front = front->getNext()) - {} - if (back) - back->setNext(systemAllocation); - else - ms_firstSystemAllocation = systemAllocation; - systemAllocation->setNext(front); -} - -// ---------------------------------------------------------------------- - -unsigned long MemoryManager::getCurrentNumberOfBytesAllocated(const int processId) -{ - UNREF(processId); - return ms_currentBytesAllocated; -} - -// ---------------------------------------------------------------------- - -unsigned long MemoryManager::getCurrentNumberOfBytesAllocatedNoLeakTest() -{ -#if DO_TRACK - return ms_currentBytesAllocatedNoLeakTest; -#else - return 0; -#endif -} - -// ---------------------------------------------------------------------- - -unsigned long MemoryManager::getMaximumNumberOfBytesAllocated() -{ - return ms_maxBytesAllocated; -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getSystemMemoryAllocatedMegabytes() -{ - return ms_systemMemoryAllocatedMegabytes; -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getCurrentNumberOfAllocations() -{ - return ms_allocations; -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getMaximumNumberOfAllocations() -{ - return ms_maxAllocations; -} - -// ---------------------------------------------------------------------- - -void MemoryManager::setReportAllocations(bool reportAllocations) -{ - ms_reportAllocations = reportAllocations; -} - -// ---------------------------------------------------------------------- - -void MemoryManager::registerDebugFlags() -{ -#if PRODUCTION == 0 - ms_allocationsPerFrame.bindToCounter("MemoryManagerAllocateCount"); - ms_bytesAllocatedPerFrame.bindToCounter("MemoryManagerAllocateBytes"); - ms_freesPerFrame.bindToCounter("MemoryManagerFreeCount"); - ms_bytesFreedPerFrame.bindToCounter("MemoryManagerFreeBytes"); -#endif - -#ifdef _DEBUG - DebugFlags::registerFlag(ms_debugReportFlag, "SharedMemoryManager", "reportMemory", debugReport); - DebugFlags::registerFlag(ms_debugReportMapFlag, "SharedMemoryManager", "reportMemoryMap", debugReportMap); - DebugFlags::registerFlag(ms_debugReportAllocations, "SharedMemoryManager", "reportMemoryAllocations"); - DebugFlags::registerFlag(ms_debugReportLogMemoryAllocFreePointers, "SharedMemoryManager", "reportLogMemoryAllocFreePointers"); - DebugFlags::registerFlag(ms_debugLogAllocations, "SharedMemoryManager", "reportLogAllocations"); - DebugFlags::registerFlag(ms_debugLogAllocationsNextFrame, "SharedMemoryManager", "reportLogAllocationsNextFrame", logAllocationsNextFrame); - DebugFlags::registerFlag(ms_debugVerifyGuardPatterns, "SharedMemoryManager", "verifyGuardPatterns"); - DebugFlags::registerFlag(ms_debugVerifyFreePatterns, "SharedMemoryManager", "verifyFreePatterns"); - DebugFlags::registerFlag(ms_debugProfileAllocate, "SharedMemoryManager", "profileAllocate"); -#endif -} - -// ---------------------------------------------------------------------- -/** - * Dump debugging information about the MemoryManager. - */ - -void MemoryManager::debugReport() -{ -#if !DISABLED - DEBUG_FATAL(!ms_installed, ("not installed")); - DEBUG_REPORT_PRINT(ms_limitSet, ("MM: %9dmb (%s limit)\n", ms_limitMegabytes, ms_hardLimit ? "hard" : "soft")); - DEBUG_REPORT_PRINT(true, ("MM: %9d/%9d/%9d cur/max/tot allocs\n", ms_allocations, ms_maxAllocations, ms_allocateCalls)); - DEBUG_REPORT_PRINT(true, ("MM: %9lu/%9lu/%9lu cur/max/tot bytes\n", ms_currentBytesAllocated, ms_maxBytesAllocated, ms_allocateBytesTotal)); -#endif -} - -// ---------------------------------------------------------------------- - -#ifdef _DEBUG -void MemoryManagerNamespace::logAllocationsNextFrame() -{ - if (!ms_debugLogAllocationsNextFrameStarted) - { - REPORT_LOG_PRINT(true, ("MemoryManager::logAllocationsNextFrame start\n")); - ms_debugLogAllocations = true; - ms_debugLogAllocationsNextFrameStarted = true; - } - else - { - REPORT_LOG_PRINT(true, ("MemoryManager::logAllocationsNextFrame end\n")); - ms_debugLogAllocations = false; - ms_debugLogAllocationsNextFrameStarted = false; - ms_debugLogAllocationsNextFrame = false; - } -} -#endif - -// ---------------------------------------------------------------------- - -void MemoryManagerNamespace::emitCharacters(char * & buffer, int blockSize, int & carryOverFree, int & carryOverUsed, int newFree, int newUsed, char const * const bufferOverrunAddress) -{ - while (carryOverFree + carryOverUsed + newFree + newUsed >= blockSize) - { - int const absorbNew = blockSize - (carryOverUsed + carryOverFree); - if (newFree) - { - carryOverFree += absorbNew; - newFree -= absorbNew; - } - else - { - carryOverUsed += absorbNew; - newUsed -= absorbNew; - } - - if (carryOverFree == blockSize) - *buffer = '_'; - else - if (carryOverUsed == blockSize) - *buffer = '*'; - else - { - int const letter = (carryOverUsed * 26) / blockSize; - *buffer = static_cast('A' + letter); - } - ++buffer; - - FATAL(buffer == bufferOverrunAddress, ("Buffer overrun! 0x%0X", buffer)); - - carryOverFree = 0; - carryOverUsed = 0; - } - - carryOverFree += newFree; - carryOverUsed += newUsed; -} - -// ---------------------------------------------------------------------- -/** - * Dump an image of the memory state to the report system. - */ - -void MemoryManager::debugReportMap() -{ - for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) - { - char buffer[128]; - int const numberOfCharactersPerRow = 64; - - snprintf(buffer, sizeof(buffer)-1, "%8p %3dmb : ", systemAllocation, systemAllocation->getSize() / (1024 * 1024)); - buffer[sizeof(buffer)-1] = '\0'; - - int const headerLength = strlen(buffer); - int const characterSize = systemAllocation->getSize() / numberOfCharactersPerRow; - - int carryOverUsed = 0; - int carryOverFree = 0; - char * b = buffer + headerLength; - char const * const bufferOverrunAddress = buffer + sizeof(buffer); - for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) - { - if (block->isFree()) - emitCharacters(b, characterSize, carryOverFree, carryOverUsed, block->getSize(), 0, bufferOverrunAddress); - else - emitCharacters(b, characterSize, carryOverFree, carryOverUsed, 0, block->getSize(), bufferOverrunAddress); - } - - if (carryOverFree || carryOverUsed) - emitCharacters(b, carryOverFree + carryOverUsed, carryOverFree, carryOverUsed, 0, 0, bufferOverrunAddress); - - b[0] = '\0'; - - DEBUG_REPORT_PRINT(true, ("%s\n", buffer)); - } -} - -// ---------------------------------------------------------------------- -/** - * Add a block to the free memory chain list. - * - * @param block Block of memory that is being - */ - -void MemoryManagerNamespace::addToFreeList(Block * block) -{ - NOT_NULL(block); - - // @todo consider making the ternary search tree balanced - - FreeBlock * freeBlock = static_cast(block); - int const freeBlockSize = freeBlock->getSize(); - FreeBlock * parent = NULL; - FreeBlock * * next = &ms_firstFreeBlock; - FreeBlock * same = 0; - - for (FreeBlock * current = ms_firstFreeBlock; current; parent = current, current = *next) - { - int const currentBlockSize = current->getSize(); - if (freeBlockSize < currentBlockSize) - next = ¤t->m_smallerFreeBlock; - else - if (freeBlockSize > currentBlockSize) - next = ¤t->m_largerFreeBlock; - else - { - // quick out for same size blocks - same = current; - break; - } - } - - if (same) - { - - freeBlock->m_smallerFreeBlock = same->m_smallerFreeBlock; - same->m_smallerFreeBlock = NULL; - if (freeBlock->m_smallerFreeBlock) - freeBlock->m_smallerFreeBlock->m_parentFreeBlock = freeBlock; - - freeBlock->m_sameFreeBlock = same; - same->m_parentFreeBlock = freeBlock; - - freeBlock->m_largerFreeBlock = same->m_largerFreeBlock; - same->m_largerFreeBlock = NULL; - if (freeBlock->m_largerFreeBlock) - freeBlock->m_largerFreeBlock->m_parentFreeBlock = freeBlock; - - *next = freeBlock; - freeBlock->m_parentFreeBlock = parent; - } - else - { - *next = freeBlock; - freeBlock->m_smallerFreeBlock = NULL; - freeBlock->m_sameFreeBlock = NULL; - freeBlock->m_largerFreeBlock = NULL; - freeBlock->m_parentFreeBlock = parent; - } - - if (++ms_freeBlocks > ms_maxFreeBlocks) - ms_maxFreeBlocks = ms_freeBlocks; - -#ifdef _DEBUG - int treeHeight = 0; - while (freeBlock) - { - ++treeHeight; - freeBlock = freeBlock->m_parentFreeBlock; - } - if (treeHeight > ms_maxTreeHeight) - ms_maxTreeHeight = treeHeight; -#endif -} - -// ---------------------------------------------------------------------- -/** - * Remove a block from the free memory chain list. - * - * @param block Block of memory that is being allocated - */ - -void MemoryManagerNamespace::removeFromFreeList(FreeBlock * block) -{ - NOT_NULL(block); - - // find the pointer that points to block - FreeBlock * * parentPointer = NULL; - FreeBlock * parent = block->m_parentFreeBlock; - if (parent) - { - if (parent->m_smallerFreeBlock == block) - parentPointer = &parent->m_smallerFreeBlock; - else - if (parent->m_sameFreeBlock == block) - parentPointer = &parent->m_sameFreeBlock; - else - { - DEBUG_FATAL(parent->m_largerFreeBlock != block, ("parent doesn't know about child")); - parentPointer = &parent->m_largerFreeBlock; - } - } - else - { - DEBUG_FATAL(ms_firstFreeBlock != block, ("no parent but not first")); - parentPointer = &ms_firstFreeBlock; - } - - // now we need to replace our node with one from underneath us - FreeBlock * same = block->m_sameFreeBlock; - if (same) - { - // making use of the same size block is pretty easy and doesn't disturb tree balance so its our prefered choice - same->m_smallerFreeBlock = block->m_smallerFreeBlock; - if (same->m_smallerFreeBlock) - same->m_smallerFreeBlock->m_parentFreeBlock = same; - - same->m_largerFreeBlock = block->m_largerFreeBlock; - if (same->m_largerFreeBlock) - same->m_largerFreeBlock->m_parentFreeBlock = same; - - same->m_parentFreeBlock = parent; - - *parentPointer = same; - } - else - { - if (block->m_smallerFreeBlock) - { - if (block->m_largerFreeBlock) - { - // this is the worst case. this free block has smaller and larger children, but not any same sized children - // we're going to take the smallest block off the larger list and use that to replace the current node - FreeBlock * back = NULL; - FreeBlock * replacement = block->m_largerFreeBlock; - while (replacement->m_smallerFreeBlock) - { - back = replacement; - replacement = replacement->m_smallerFreeBlock; - } - - // disconnect the link between its parent and out replacement block - if (back) - { - back->m_smallerFreeBlock = replacement->m_largerFreeBlock; - if (back->m_smallerFreeBlock) - back->m_smallerFreeBlock->m_parentFreeBlock = back; - - replacement->m_largerFreeBlock = block->m_largerFreeBlock; - replacement->m_largerFreeBlock->m_parentFreeBlock = replacement; - } - - // put the replacement block in its new place - replacement->m_smallerFreeBlock = block->m_smallerFreeBlock; - replacement->m_smallerFreeBlock->m_parentFreeBlock = replacement; - - replacement->m_parentFreeBlock = parent; - - *parentPointer = replacement; - } - else - { - // this block only has one child, which is smaller. an easy case. - block->m_smallerFreeBlock->m_parentFreeBlock = parent; - *parentPointer = block->m_smallerFreeBlock; - } - } - else - { - if (block->m_largerFreeBlock) - { - // this block only has one child, which is larger. an easy case. - block->m_largerFreeBlock->m_parentFreeBlock = parent; - *parentPointer = block->m_largerFreeBlock; - } - else - { - // this block has no children - *parentPointer = NULL; - } - } - } - - // remove all the pointers the block may have had - block->m_smallerFreeBlock = NULL; - block->m_sameFreeBlock = NULL; - block->m_largerFreeBlock = NULL; - block->m_parentFreeBlock = NULL; - - --ms_freeBlocks; -} - -// ---------------------------------------------------------------------- - -FreeBlock *MemoryManagerNamespace::searchFreeList(int blockSize) -{ - FreeBlock * result = NULL; - FreeBlock * current = ms_firstFreeBlock; - while (current) - { - int const currentBlockSize = current->getSize(); - - if (currentBlockSize < blockSize) - { - // this block is too small so check blocks larger than this - current = current->m_largerFreeBlock; - } - else - if (currentBlockSize > blockSize) - { - // this block is too large but will be the best fit so far. continue checking smaller blocks. - result = current; - current = current->m_smallerFreeBlock; - } - else - { - // this block is a perfect fit, return it immediately. - return current; - } - } - - return result; -} - -// ---------------------------------------------------------------------- -/** - * Dynamically allocate memory. - * - * Users should not call this routine directly. It should only be called - * by operator new. - * - * @param size Number of bytes to allocate - * @param owner Line number on which the allocation was made - * @param array True if the array form of operator new was used, false if the scalar form was used - */ - -void * MemoryManager::allocate(size_t size, uint32 owner, bool array, bool leakTest) -{ - if (!ms_installed) - new(ms_memoryManagerBuffer) MemoryManager; - - UNREF(owner); - UNREF(array); - UNREF(leakTest); - -#if DISABLED - return operator new(size); -#else - - DEBUG_FATAL(!ms_installed, ("not installed")); - -#if PRODUCTION == 0 - ++ms_allocationsPerFrame; - ms_bytesAllocatedPerFrame += size; -#endif - -#ifdef _DEBUG - if (ms_debugProfileAllocate) - PROFILER_BLOCK_ENTER(ms_allocateProfilerBlock); - - if (ms_debugVerifyGuardPatterns || ms_debugVerifyFreePatterns) - verify(ms_debugVerifyGuardPatterns, ms_debugVerifyFreePatterns); - - if (ms_debugReportAllocations || ms_debugLogAllocations) - { - char libName[256]; - char fileName[256]; - int line; - if (ms_allowNameLookup && DebugHelp::lookupAddress(owner, libName, fileName, sizeof(fileName), line)) - { - DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), ("%s(%d): alloc %d=bytes %d=array\n", fileName, line, size, static_cast(array))); - } - else - { - DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), ("%08x: alloc %d=bytes %d=array\n", static_cast(owner), size, static_cast(array))); - } - } -#endif - - ms_criticalSection->enter(); - - // get the size of the allocation - int allocSize = (cms_allocatedBlockSize + cms_guardBandSize + (size ? static_cast(size) : 1) + cms_guardBandSize + 15) & ~15; - - FreeBlock * bestFreeBlock = NULL; - for (int tries = 0; !bestFreeBlock && tries < 2; ++tries) - { - bestFreeBlock = searchFreeList(allocSize); - - // if the memory allocation failed, try to get some more memory - if (!bestFreeBlock) - allocateSystemMemory(convertBytesToMegabytesForSystemAllocation(cms_blockSize + cms_blockSize + allocSize + cms_blockSize)); - } - - // make sure memory was available - if (!bestFreeBlock) - { - if (ConfigSharedFoundation::getMemoryManagerReportOnOutOfMemory()) - { - // avoid deadlock from FATAL calling free - (*LogMessage)("Out of memory, dumping current allocations:\n"); - IGNORE_RETURN(MemoryManagerNamespace::report(false)); - } - - ms_criticalSection->leave(); - FATAL(true, ("failed allocation attempt for %d (%d actual)", allocSize, size)); - } - - removeFromFreeList(bestFreeBlock); - - // setup the allocation record - bestFreeBlock->setFree(false); - - // check to see if we should subdivide this block - if (bestFreeBlock->getSize() > (allocSize + cms_allocatedBlockSize + cms_guardBandSize + 1 + cms_guardBandSize)) - { - Block *block = reinterpret_cast(reinterpret_cast(bestFreeBlock) + allocSize); - block->setPrevious(bestFreeBlock); - block->setNext(bestFreeBlock->getNext()); - block->setFree(true); - - bestFreeBlock->getNext()->setPrevious(block); - bestFreeBlock->setNext(block); - - addToFreeList(block); - } - - AllocatedBlock * best = reinterpret_cast(bestFreeBlock); - -#if DO_SCALAR - best->setAllocatedAsArray(array); -#endif - -#if DO_TRACK - best->setCheckForLeaks(leakTest); - best->setOwner(0, owner); -#endif -#if DO_TRACK > 1 - { - enum { OFFSET = 3 }; - uint32 owners[DO_TRACK + OFFSET]; - DebugHelp::getCallStack(owners, DO_TRACK + OFFSET); - - for (int i = 1; i < DO_TRACK; ++i) - { - best->setOwner(i, owners[i + OFFSET]); - -#ifdef _DEBUG - if (ms_debugReportAllocations || ms_debugLogAllocations) - { - char libName[256]; - char fileName[256]; - int line; - if (ms_allowNameLookup && DebugHelp::lookupAddress(owners[i + OFFSET], libName, fileName, sizeof(fileName), line)) - { - DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), (" %s(%d): caller %d\n", fileName, line, i)); - } - else - { - DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), (" %08x: caller %d\n", static_cast(owners[i + OFFSET]), i)); - } - } -#endif - } - } -#endif -#if DO_TRACK || DO_GUARDS - best->setRequestedSize(static_cast(size)); - ms_currentBytesRequested += size; - DEBUG_FATAL(best->getRequestedSize() != static_cast(size), ("allocated more memory at once than the memory manager supports (%d)", (1 << Block::cms_requestedSizeBits) - 1)); -#endif - - // update the size of the allocation because our block may not have been large enough to subdivide - allocSize = best->getSize(); - - // update the number of bytes allocated - ++ms_allocateCalls; - ms_allocateBytesTotal += allocSize; - ms_currentBytesAllocated += allocSize; - -#if DO_TRACK - if (!leakTest) - ms_currentBytesAllocatedNoLeakTest += allocSize; -#endif - - if (++ms_allocations > ms_maxAllocations) - ms_maxAllocations = ms_allocations; - if (ms_currentBytesAllocated > ms_maxBytesAllocated) - ms_maxBytesAllocated = ms_currentBytesAllocated; - - // get another pointer to the memory we allocated so we can tinker with it - byte * memory = reinterpret_cast(best) + cms_allocatedBlockSize + cms_guardBandSize; - -#if DO_GUARDS - // fill the prefix guard band - memset(memory - cms_guardBandSize, cms_guardFillPattern, cms_guardBandSize); -#endif - - // fill the user memory with the initialize pattern -#if DO_INITIALIZE_FILLS - memset(memory, cms_initializeFillPattern, size); -#endif - -#if DO_GUARDS - // fill the suffix guard band - memset(memory+size, cms_guardFillPattern, cms_guardBandSize); -#endif - - ms_criticalSection->leave(); - - DEBUG_REPORT_LOG_PRINT(ms_debugReportLogMemoryAllocFreePointers, ("MM::alloc %08x\n", reinterpret_cast(memory))); - -#ifdef _DEBUG - if (ms_debugProfileAllocate) - PROFILER_BLOCK_LEAVE(ms_allocateProfilerBlock); -#endif - -// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::allocate() requested_size=%d, alloc_size=%d, ptr=%p\n", size, allocSize, memory)); - - return memory; -#endif -} - -// ---------------------------------------------------------------------- - -void *MemoryManager::reallocate(void *userPointer, size_t newSize) -{ - AllocatedBlock *allocatedBlock = 0; - bool array = false; - int oldSize = 0; - - if (userPointer) - { - allocatedBlock = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); - #if DO_SCALAR - array = allocatedBlock->isAllocatedAsArray(); - #endif - if (!newSize) - { - MemoryManager::free(userPointer, array); - -// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::reallocate() new_requested_size=%d, org ptr=%p, new ptr=NULL\n", newSize, userPointer)); - - return 0; - } - #if DO_TRACK || DO_GUARDS - oldSize = allocatedBlock->getRequestedSize(); - #else - oldSize = allocatedBlock->getSize()-cms_allocatedBlockSize; - #endif - } - - if (newSize <= static_cast(oldSize)) - { -// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::reallocate() new_requested_size=%d, org ptr=%p, new ptr=%p\n", newSize, userPointer, userPointer)); - - return userPointer; - } - -#if DO_TRACK - uint32 owner = allocatedBlock->getOwner(0); - bool leakTest = allocatedBlock->checkForLeaks(); -#else - uint32 owner = 0; - bool leakTest = false; -#endif - - void *newPointer = allocate(newSize, owner, array, leakTest); - if (oldSize) - memcpy(newPointer, userPointer, oldSize); - if (userPointer) - MemoryManager::free(userPointer, array); - -// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::reallocate() new_requested_size=%d, org ptr=%p, new ptr=%p\n", newSize, userPointer, newPointer)); - - return newPointer; -} - -// ---------------------------------------------------------------------- -/** - * Free dynamically allocated memory. - * - * Users should not call this routine directly. It should only be called - * by operator delete. - * - * This routine should not be called with the NULL pointer. - * - * @param userPointer Pointer to the memory - * @param array True if the array form of operator new was used, false if the scalar form was used - */ - -void MemoryManager::free(void * userPointer, bool array) -{ -#if DISABLED - UNREF(array); - operator delete(userPointer); - return; -#else - - DEBUG_FATAL(!ms_installed, ("not installed")); - NOT_NULL(userPointer); - -#ifdef _DEBUG - if (ms_debugVerifyGuardPatterns || ms_debugVerifyFreePatterns) - verify(ms_debugVerifyGuardPatterns, ms_debugVerifyFreePatterns); -#endif - - DEBUG_REPORT_LOG_PRINT(ms_debugReportLogMemoryAllocFreePointers, ("MM::free %08x\n", reinterpret_cast(userPointer))); - - UNREF(array); - - ms_criticalSection->enter(); - - AllocatedBlock * allocatedBlock = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); - -#if DEBUG_LEVEL == DEBUG_LEVEL_DEBUG - DEBUG_FATAL(allocatedBlock->getNext()->getPrevious() != allocatedBlock, ("Bad free (1) %p", userPointer)); - DEBUG_FATAL(allocatedBlock->getPrevious()->getNext() != allocatedBlock, ("Bad free (2) %p", userPointer)); - DEBUG_FATAL(allocatedBlock->isFree(), ("Freeing already free block %p", userPointer)); -#endif - -#if PRODUCTION == 0 - ++ms_freesPerFrame; -#if DO_TRACK - ms_bytesFreedPerFrame += allocatedBlock->getRequestedSize(); -#endif -#endif - -#if DO_GUARDS - { - // verify the guard bands - byte * guard = reinterpret_cast(allocatedBlock) + cms_allocatedBlockSize; - bool corrupt = false; - - // check the prefix guard band - for (int i = 0; i < cms_guardBandSize; ++i, ++guard) - if (*guard != cms_guardFillPattern) - { - corrupt = true; - DEBUG_REPORT_LOG_PRINT(true, ("MemoryManager::free corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); - DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("MemoryManager::free corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); - } - - // advance past the user memory - guard += allocatedBlock->getRequestedSize(); - - // check the suffix guard band - for (int j = 0; j < cms_guardBandSize; ++j, ++guard) - if (*guard != cms_guardFillPattern) - { - corrupt = true; - DEBUG_REPORT_LOG_PRINT(true, ("MemoryManager::free corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); - DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("MemoryManager::free corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); - } - - if (corrupt) - { - MemoryManagerNamespace::report(allocatedBlock, false); - ms_criticalSection->leave(); - DEBUG_FATAL(true, ("corrupted guard pattern")); - return; //lint !e527 // Unreachable - } - } -#endif - -#if DO_SCALAR - if (allocatedBlock->isAllocatedAsArray() != array) //lint !e731 // Info -- Boolean argument to equal/not equal - { - MemoryManagerNamespace::report(allocatedBlock, false); - #ifdef _DEBUG - bool const blockArray = allocatedBlock->isAllocatedAsArray(); - ms_criticalSection->leave(); - FATAL(true, ("allocated %s deleted %s", blockArray ? "array" : "scalar", array ? "array" : "scalar")); //lint !e731 // Info -- Boolean argument to equal/not equal - #endif - } -#endif - - int const memorySize = allocatedBlock->getSize(); - - // wipe the user memory -#if DO_FREE_FILLS - imemset(reinterpret_cast(allocatedBlock) + cms_allocatedBlockSize, cms_freeFillPattern, memorySize - cms_allocatedBlockSize); -#endif - - allocatedBlock->setFree(true); -#if DO_SCALAR - allocatedBlock->setAllocatedAsArray(false); -#endif - - // clear out the block records -#if DO_TRACK - allocatedBlock->fillOwnerWithFreePattern(); -#endif - -#if DO_TRACK || DO_GUARDS - ms_currentBytesRequested -= allocatedBlock->getRequestedSize(); - allocatedBlock->setRequestedSize(0); - DEBUG_FATAL(allocatedBlock->getRequestedSize() != 0, ("bad size")); -#endif - - // update the number of bytes allocated - ++ms_freeCalls; - --ms_allocations; - - DEBUG_FATAL((ms_currentBytesAllocated < static_cast(memorySize)), ("currentBytesAllocated underflow")); - ms_currentBytesAllocated -= memorySize; -#if DO_TRACK - if (!allocatedBlock->checkForLeaks()) - ms_currentBytesAllocatedNoLeakTest -= memorySize; -#endif - DEBUG_FATAL(ms_allocations < 0, ("allocations underflow")); - -// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::free() requested_size=%d, alloc_size=%d, userPointer=%p, allocatedBlock=%p\n", requestedSize, memorySize, userPointer, allocatedBlock)); - - Block *block = allocatedBlock; - - // recombine with the previous block - if (block->getPrevious()->isFree()) - { - FreeBlock * const previous = static_cast(block->getPrevious()); - removeFromFreeList(previous); - previous->setNext(block->getNext()); - block->getNext()->setPrevious(previous); - -#if DO_FREE_FILLS - memset(block, cms_freeFillPattern, cms_freeBlockSize); -#endif - block = previous; - } - - // recombine with the following block - if (block->getNext()->isFree()) - { - FreeBlock * const next = static_cast(block->getNext()); - removeFromFreeList(next); - block->setNext(next->getNext()); - next->getNext()->setPrevious(block); - -#if DO_FREE_FILLS - memset(next, cms_freeFillPattern, cms_freeBlockSize); -#endif - } - - addToFreeList(block); - - ms_criticalSection->leave(); -#endif -} - -// ---------------------------------------------------------------------- - -int MemoryManagerNamespace::quickGuessIsValidPointerFromHeap(void const * userPointer) -{ - int result = 0; - AllocatedBlock const * allocatedBlock = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); - - ms_criticalSection->enter(); - if (!result && allocatedBlock->getNext()->getPrevious() != allocatedBlock) result = 1; - if (!result && allocatedBlock->getPrevious()->getNext() != allocatedBlock) result = 2; - if (!result && allocatedBlock->isFree()) result = 3; - ms_criticalSection->leave(); - - return result; -} - -// ---------------------------------------------------------------------- - -int MemoryManagerNamespace::authoritativeIsValidPointerFromHeap(void const * userPointer) -{ - ms_criticalSection->enter(); - - int result = quickGuessIsValidPointerFromHeap(userPointer); - if (result != 0) - return result; - - result = 16; - for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) - for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); result != 0 && block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) - if (!block->isFree()) - { - byte const * memory = reinterpret_cast(block) + cms_allocatedBlockSize + cms_guardBandSize; - if (memory == userPointer) - result = 0; - } - - ms_criticalSection->leave(); - - return result; -} - -// ---------------------------------------------------------------------- -/** - * Take ownership for a block of memory. - * - * @param userPointer Memory to take ownership of - */ - -void MemoryManager::own(void * userPointer) -{ - UNREF(userPointer); - -#if DISABLED || !DO_TRACK - return; -#else - - DEBUG_FATAL(!ms_installed, ("not installed")); - - if (!userPointer) - return; - - ms_criticalSection->enter(); - - // fetch the block pointer - AllocatedBlock * block = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); - DEBUG_FATAL(block->isFree(), ("cannot own a free block")); - - // update the owners - { - enum { OFFSET = 2 }; - uint32 owners[DO_TRACK + OFFSET]; - DebugHelp::getCallStack(owners, DO_TRACK + OFFSET); - - for (int i = 0; i < DO_TRACK; ++i) - block->setOwner(i, owners[i + OFFSET]); - } - - ms_criticalSection->leave(); -#endif -} - -// ---------------------------------------------------------------------- - -void MemoryManager::verify(bool guardPatterns, bool freePatterns) -{ - UNREF(guardPatterns); - UNREF(freePatterns); - -#if DO_FREE_FILLS || DO_GUARDS - - ms_criticalSection->enter(); - - // search for the memory pointer - for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) - for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) - if (block->isFree()) - { -#if DO_FREE_FILLS - if (freePatterns) - { - bool corrupt = false; - byte * memory = reinterpret_cast(block) + cms_freeBlockSize; - int freeSize = block->getSize() - cms_freeBlockSize; - - for (int i = 0; i < freeSize; ++i, ++memory) - if (*memory != cms_freeFillPattern) - { - corrupt = true; - DEBUG_REPORT_LOG_PRINT(true, ("corrupted free pattern at position %3d [membase=0x%x, memaddr=0x%x] = %02x\n", i, reinterpret_cast(reinterpret_cast(block) + cms_freeBlockSize), reinterpret_cast(reinterpret_cast(block) + cms_freeBlockSize + i), static_cast(*memory))); - DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("corrupted free pattern at position %3d = %02x\n", i, static_cast(*memory))); - } - - if (corrupt) - { - ms_criticalSection->leave(); - DEBUG_FATAL(true, ("corrupted free pattern")); - } - } -#endif - } - else - if (guardPatterns) - { -#if DO_GUARDS - // verify the guard bands - byte * guard = reinterpret_cast(block) + cms_allocatedBlockSize; - bool corrupt = false; - - // check the prefix guard band - for (int i = 0; i < cms_guardBandSize; ++i, ++guard) - if (*guard != cms_guardFillPattern) - { - corrupt = true; - DEBUG_REPORT_LOG_PRINT(true, ("corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); - DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); - } - - // advance past the user memory - guard += static_cast(block)->getRequestedSize(); - - // check the suffix guard band - for (int j = 0; j < cms_guardBandSize; ++j, ++guard) - if (*guard != cms_guardFillPattern) - { - corrupt = true; - DEBUG_REPORT_LOG_PRINT(true, ("corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); - DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); - } - - if (corrupt) - { - MemoryManagerNamespace::report(static_cast(block), false); - ms_criticalSection->leave(); - DEBUG_FATAL(true, ("corrupted guard pattern")); - } -#endif - } - - ms_criticalSection->leave(); - -#endif -} - -// ---------------------------------------------------------------------- -/** - * @internal - */ - -void MemoryManagerNamespace::report(AllocatedBlock const * block, bool leak) -{ -#if DO_TRACK - uint32 const owner = block->getOwner(0); -#else - uint32 const owner = 0; -#endif -#if DO_TRACK || DO_GUARDS - int const requestedSize = block->getRequestedSize();; -#else - int const requestedSize = 0; -#endif - - char buffer[256]; - char libName[256]; - char fileName[256]; - int line = 0; - int const memory = reinterpret_cast(reinterpret_cast(block) + cms_allocatedBlockSize + cms_guardBandSize); - - if (ms_allowNameLookup && DebugHelp::lookupAddress(owner, libName, fileName, sizeof(fileName), line)) - { - sprintf(buffer, "%s(%d) : %08X memory %s, %d bytes\n", fileName, line, memory, leak ? "leak" : "allocation", static_cast(requestedSize)); - } - else - { - sprintf(buffer, "unknown(0x%08X) : %08X memory %s, %d bytes\n", static_cast(owner), memory, leak ? "leak" : "allocation", static_cast(requestedSize)); - } - - (*LogMessage)(buffer); - -#if DO_TRACK > 1 - { - for (int i = 1; i < DO_TRACK; ++i) - if (block->getOwner(i)) - { - if (ms_allowNameLookup && DebugHelp::lookupAddress(block->getOwner(i), libName, fileName, sizeof(fileName), line)) - sprintf(buffer, " %s(%d) : caller %d\n", fileName, line, i); - else - sprintf(buffer, " 0x%08X : caller %d\n", static_cast(block->getOwner(i)), i); - (*LogMessage)(buffer); - } - } -#endif -} - -// ---------------------------------------------------------------------- -/** - * Dump information about all outstanding allocations. - */ - -int MemoryManagerNamespace::report(bool leak) -{ - DEBUG_FATAL(!ms_installed, ("not installed")); - - int count = 0; - ms_criticalSection->enter(); - - // search for the memory pointer - for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) - for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) - if (!block->isFree()) - { -#if DO_TRACK - if (!leak || static_cast(block)->checkForLeaks()) -#else - if (!leak) -#endif - { - report(static_cast(block), leak); - ++count; - } - } - - ms_criticalSection->leave(); - - return count; -} - -// ---------------------------------------------------------------------- -/** - * Dump information about all outstanding allocations. - */ - -void MemoryManager::report() -{ - IGNORE_RETURN(MemoryManagerNamespace::report(false)); -} - -//----------------------------------------------------------------------- - -void MemoryManagerNamespace::logMessageToFd(char const *message) -{ - if (ms_logMessageFd >= 0) - _write(ms_logMessageFd, message, strlen(message)); -} - -//----------------------------------------------------------------------- - -bool MemoryManagerNamespace::reportToFile(char const *fileName, bool leak) -{ - if (ms_logMessageFd >= 0) - return false; - - ms_logMessageFd = _open(fileName, O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); - if (ms_logMessageFd < 0) - return false; - - void (*oldLogMessage)(char const * message) = LogMessage; - LogMessage = &logMessageToFd; - - report(leak); - - LogMessage = oldLogMessage; - - _close(ms_logMessageFd); - ms_logMessageFd = -1; - - return true; -} - -//----------------------------------------------------------------------- - -bool MemoryManager::reportToFile(char const *fileName, bool leak) -{ - return MemoryManagerNamespace::reportToFile(fileName, leak); -} - -// ====================================================================== -// DISABLE_MEMORY_MANAGER -#else -// ====================================================================== -namespace MemoryManagerNamespace -{ - // Memory tracking variables avialble when memory manger is running - // in disabled mode for linux - int ms_allocateCalls; - int ms_freeCalls; - unsigned long ms_allocateBytesTotal; -#ifndef _WIN32 - int ms_processVmSizeKBytes; -#endif - unsigned long ms_maxBytesAllocated; - int ms_allocations; - int ms_maxAllocations; - bool ms_installed; - - struct Statm //cache for /proc/statm data - { - int tpsr; //total program size resident - int rss; //resident set size share - }; - - Statm s_statm; - int s_pagesize; - - RecursiveMutex * ms_criticalSection; -} - -using namespace MemoryManagerNamespace; - -// ---------------------------------------------------------------------- - -MemoryManager::MemoryManager() -{ - // Initialize all memory tracking vars - MemoryManagerNamespace::ms_allocateCalls = 0; - MemoryManagerNamespace::ms_freeCalls = 0; - MemoryManagerNamespace::ms_allocateBytesTotal = 0; -#ifndef _WIN32 - MemoryManagerNamespace::ms_processVmSizeKBytes = 0; -#endif - MemoryManagerNamespace::ms_maxBytesAllocated = 0; - MemoryManagerNamespace::ms_allocations = 0; - MemoryManagerNamespace::ms_maxAllocations= 0; - - DEBUG_FATAL(MemoryManagerNamespace::ms_installed, ("already installed")); - - ms_criticalSection = new RecursiveMutex; - - MemoryManagerNamespace::ms_installed = true; - -#if defined(PLATFORM_WIN32) && defined(_DEBUG) - _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); - _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); - _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); - - int crtHeapFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); - crtHeapFlags |= _CRTDBG_ALLOC_MEM_DF; - //crtHeapFlags |= _CRTDBG_CHECK_ALWAYS_DF; - crtHeapFlags |= _CRTDBG_LEAK_CHECK_DF; - _CrtSetDbgFlag(crtHeapFlags); -#endif -} - -// ---------------------------------------------------------------------- - -MemoryManager::~MemoryManager() -{ - delete ms_criticalSection; -} - -// ---------------------------------------------------------------------- - -void MemoryManager::verify(bool, bool) -{ -#if defined(PLATFORM_WIN32) && defined(_DEBUG) - const int result = _CrtCheckMemory(); - FATAL(result==FALSE, ("Heap corruption detected!\n")); -#endif -} - -// ---------------------------------------------------------------------- - -unsigned long MemoryManager::getCurrentNumberOfBytesAllocated(const int processId) -{ - -#ifdef _WIN32 - UNREF(processId); - return 0; -#else - - static char filename[30]; - static FILE *inStatmFile; - static time_t seconds = 0; - - unsigned long retVal = 0; - - ms_criticalSection->enter(); - - if (processId) - { - if ((time (0) - seconds) > 60 ) - { - if (seconds == 0) - { - snprintf(filename, sizeof(filename)-1, "/proc/%d/statm", processId); - filename[sizeof(filename)-1] = '\0'; - s_pagesize = getpagesize(); - } - - seconds = time (0); - - inStatmFile = fopen(filename,"rt"); - - if (inStatmFile) - { - if (fscanf (inStatmFile, "%d %d", &s_statm.tpsr, &s_statm.rss) == 2) - { - retVal = static_cast(s_statm.tpsr) * static_cast(s_pagesize); - } - else - { - retVal = 0; - } - fclose(inStatmFile); - } - else - { - retVal = 0; - } - } - else - { - retVal = static_cast(s_statm.tpsr) * static_cast(s_pagesize); - } - } - - ms_criticalSection->leave(); - - return retVal; -#endif -} - -// ---------------------------------------------------------------------- - -unsigned long MemoryManager::getCurrentNumberOfBytesAllocatedNoLeakTest() -{ - return 0; -} - -// ---------------------------------------------------------------------- - -unsigned long MemoryManager::getMaximumNumberOfBytesAllocated() -{ -#ifdef _WIN32 - return 0; -#else - return MemoryManagerNamespace::ms_maxBytesAllocated; -#endif -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getSystemMemoryAllocatedMegabytes() -{ - return 0; -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getCurrentNumberOfAllocations() -{ -#ifdef _WIN32 - return 0; -#else - return MemoryManagerNamespace::ms_allocations; -#endif -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getMaximumNumberOfAllocations() -{ -#ifdef _WIN32 - return 0; -#else - return MemoryManagerNamespace::ms_maxAllocations; -#endif -} - -// ---------------------------------------------------------------------- - -void MemoryManager::setLimit(int, bool, bool) -{ -} - -// ---------------------------------------------------------------------- - -int MemoryManager::getLimit() -{ - return 768; -} - -// ---------------------------------------------------------------------- - -void MemoryManager::own(void * userPointer) -{ - UNREF(userPointer); -// __asm int 3; -} - -// ---------------------------------------------------------------------- - -void MemoryManager::setReportAllocations(bool) -{ -} - -// ---------------------------------------------------------------------- - -void MemoryManager::registerDebugFlags() -{ -} - -// ---------------------------------------------------------------------- - -void MemoryManager::report() -{ -} - -// ---------------------------------------------------------------------- - -void * MemoryManager::allocate(size_t size, uint32, bool, bool) -{ -#ifdef _WIN32 - return _malloc_dbg(size, _NORMAL_BLOCK, __FILE__, __LINE__); - //return (void *)LocalAlloc(LMEM_FIXED, size); -#else - return ::malloc(size); -#endif -} - -// ---------------------------------------------------------------------- - -void MemoryManager::free(void * userPointer, bool) -{ -#ifdef _WIN32 - _free_dbg(userPointer, _NORMAL_BLOCK); - //LocalFree((HLOCAL)userPointer); -#else - ::free(userPointer); - -#endif -} - -// ---------------------------------------------------------------------- - -void *MemoryManager::reallocate(void *userPointer, size_t newSize) -{ -#ifdef _WIN32 - return _realloc_dbg(userPointer, newSize, _NORMAL_BLOCK, __FILE__, __LINE__); - //return (void *)LocalReAlloc((HLOCAL)userPointer, newSize, 0); -#else - return ::realloc(userPointer, newSize); -#endif -} - -// ---------------------------------------------------------------------- - -void MemoryManager::debugReport(void) -{ - -} - -// ---------------------------------------------------------------------- - -void MemoryManager::debugReportMap(void) -{ - -} -#endif - -// ---------------------------------------------------------------------- -// this function is available regardless of the DISABLE_MEMORY_MANAGER setting - -#ifndef _WIN32 -int MemoryManager::getProcessVmSizeKBytes(const int processId) -{ - static char filename[30]; - static FILE *inStatusFile; - static char buffer[128]; - static time_t seconds = 0; - - ms_criticalSection->enter(); - - if (processId) - { - if ((time (0) - seconds) > 60) - { - MemoryManagerNamespace::ms_processVmSizeKBytes = 0; - - if (seconds == 0) - { - snprintf(filename, sizeof(filename)-1, "/proc/%d/status", processId); - filename[sizeof(filename)-1] = '\0'; - } - - seconds = time(0); - - inStatusFile = fopen(filename,"rt"); - - if (inStatusFile) - { - int temp; - - while (fgets(buffer, sizeof(buffer), inStatusFile)) - { - if (1 == sscanf(buffer, "VmSize: %d", &temp)) - { - MemoryManagerNamespace::ms_processVmSizeKBytes = temp; - break; - } - } - - fclose(inStatusFile); - } - } - } - - ms_criticalSection->leave(); - - return MemoryManagerNamespace::ms_processVmSizeKBytes; -} -#endif - -// ====================================================================== +// ====================================================================== +// +// MemoryManager.cpp +// Portions copyright 1998 Bootprint Entertainment +// Portions copyright 2002 Sony Online Entertainment +// All Rights Reserved +// +// ====================================================================== + +#include "sharedMemoryManager/FirstSharedMemoryManager.h" +#include "sharedMemoryManager/MemoryManager.h" +#include "sharedMemoryManager/OsMemory.h" + +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedFoundation/Production.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/DebugMonitor.h" +#include "sharedDebug/PixCounter.h" +#include "sharedDebug/Profiler.h" +#include "sharedSynchronization/RecursiveMutex.h" +#include "sharedDebug/RemoteDebug.h" + +#include + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +#include +#include +#include +#include + +#ifdef _WIN32 +#define DISABLE_MEMORY_MANAGER 0 +#else +#define DISABLE_MEMORY_MANAGER 0 +#endif + +//lint -e826 // Suspicious pointer-to-pointer conversion (area too small) + +#if !DISABLE_MEMORY_MANAGER + +// ====================================================================== +// +#define DISABLED 0 + +#if PRODUCTION + + #define DO_TRACK 0 + #define DO_SCALAR 0 + #define DO_GUARDS 0 + #define DO_INITIALIZE_FILLS 0 + #define DO_FREE_FILLS 0 + +#else + + #if DEBUG_LEVEL == DEBUG_LEVEL_DEBUG + + #define DO_TRACK 1 + #define DO_SCALAR 1 + #define DO_GUARDS 1 + #define DO_INITIALIZE_FILLS 1 + #define DO_FREE_FILLS 1 + + #elif DEBUG_LEVEL == DEBUG_LEVEL_OPTIMIZED + + #define DO_TRACK 1 + #define DO_SCALAR 1 + #define DO_GUARDS 1 + #define DO_INITIALIZE_FILLS 1 + #define DO_FREE_FILLS 1 + + #elif DEBUG_LEVEL == DEBUG_LEVEL_RELEASE + + #define DO_TRACK 0 + #define DO_SCALAR 0 + #define DO_GUARDS 0 + #define DO_INITIALIZE_FILLS 0 + #define DO_FREE_FILLS 0 + + #else + + #error unknown DEBUG_LEVEL + + #endif + +#endif + +#ifdef PLATFORM_LINUX + #undef DO_TRACK + #define DO_TRACK 5 +#endif + +// ====================================================================== + +namespace MemoryManagerNamespace +{ + class Block; + + class SystemAllocation + { + public: + + SystemAllocation(int size); + ~SystemAllocation(); + + int getSize(); + + SystemAllocation * getNext(); + void setNext(SystemAllocation *); + + Block * getFirstMemoryBlock(); + Block * getLastMemoryBlock(); + + private: + + int m_size; + SystemAllocation * m_next; + int m_pad1; + int m_pad2; + }; + + + class Block + { + public: + + enum { cms_requestedSizeBits = 30 }; + + public: + + Block * getPrevious(); + Block const * getPrevious() const; + void setPrevious(Block *previous); + + Block * getNext(); + Block const * getNext() const; + void setNext(Block *previous); + + bool isFree() const; + void setFree(bool free); + + int getSize() const; + + private: + + Block * m_previous; + Block * m_next; + bool m_free:1; + + protected: + + // these are only in allocated blocks, but we can't expect a compiler to merge bitfields across multiple classes +#if DO_SCALAR + bool m_array:1; +#endif +#if DO_TRACK + bool m_leakTest:1; +#endif +#if DO_TRACK || DO_GUARDS + unsigned int m_requestedSize:cms_requestedSizeBits; +#endif + }; + + class FreeBlock; + + void addToFreeList(Block * block); + void removeFromFreeList(FreeBlock * block); + FreeBlock *searchFreeList(int blockSize); + + class FreeBlock : public Block + { + private: + + friend void addToFreeList(Block *block); + friend void removeFromFreeList(FreeBlock *block); + friend FreeBlock *searchFreeList(int blockSize); + + private: + FreeBlock * m_smallerFreeBlock; + FreeBlock * m_sameFreeBlock; + FreeBlock * m_largerFreeBlock; + FreeBlock * m_parentFreeBlock; + }; + + class AllocatedBlock : public Block + { + public: + +#if DO_SCALAR + bool isAllocatedAsArray() const; + void setAllocatedAsArray(bool array); +#endif + +#if DO_TRACK + bool checkForLeaks() const; + void setCheckForLeaks(bool checkForLeaks); + + uint32 getOwner(int index) const; + void setOwner(int index, uint32 owner); + void fillOwnerWithFreePattern(); + +#endif + +#if DO_TRACK || DO_GUARDS + int getRequestedSize() const; + void setRequestedSize(int requestedSize); +#endif + + private: + +#if DO_TRACK + uint32 m_owner[DO_TRACK]; +#endif + }; + +#ifdef _DEBUG + void logAllocationsNextFrame(); +#endif + + int convertBytesToMegabytesForSystemAllocation(int bytes); + void allocateSystemMemory(int megabytes); + + int min(int a, int b); + int max(int a, int b); + byte const * min(byte const * a, byte const * b); + byte const * max(byte const * a, byte const * b); + + int report(bool leak); + void report(AllocatedBlock const * block, bool leak); + + int quickGuessIsValidPointerFromHeap(void const *); + int authoritativeIsValidPointerFromHeap(void const *); + + void emitCharacters(char * & buffer, int blockSize, int & carryOverFree, int & carryOverUsed, int newFree, int newUsed, char const * const bufferOverrunAddress); + + bool reportToFile(char const *fileName, bool leak); + void outputDebugStringWrapper(char const * message); + void logMessageToFd(char const * message); + + int const cms_blockSize = (sizeof(Block) + 15) & (~15); + int const cms_freeBlockSize = (sizeof(FreeBlock) + 15) & (~15); + extern int const cms_allocatedBlockSize = (sizeof(AllocatedBlock) + 15) & (~15); + byte const cms_guardFillPattern = 0xAB; + byte const cms_initializeFillPattern = 0xCD; + byte const cms_freeFillPattern = 0xEF; + int const cms_guardBandSize = DO_GUARDS ? 16 : 0; + + int const cms_systemAllocationRoundSize = 4 * 1024 * 1024; + int const cms_systemAllocationMinimumSize = 4 * 1024 * 1024; + + bool ms_installed; + bool ms_limitSet; + bool ms_hardLimit; + int ms_limitMegabytes = 2047; + SystemAllocation * ms_firstSystemAllocation; + int ms_numberOfSystemAllocations; + int ms_systemMemoryAllocatedMegabytes; + bool ms_reportAllocations; +// bool ms_logEachAlloc; + +#if PRODUCTION == 0 + PixCounter::ResetInteger ms_allocationsPerFrame; + PixCounter::ResetInteger ms_bytesAllocatedPerFrame; + PixCounter::ResetInteger ms_freesPerFrame; + PixCounter::ResetInteger ms_bytesFreedPerFrame; +#endif + +#ifdef _DEBUG + bool ms_debugReportFlag; + bool ms_debugReportMapFlag; + bool ms_debugReportAllocations; + bool ms_debugReportLogMemoryAllocFreePointers; + bool ms_debugLogAllocations; + bool ms_debugLogAllocationsNextFrame; + bool ms_debugVerifyGuardPatterns; + bool ms_debugVerifyFreePatterns; + bool ms_debugProfileAllocate; + bool ms_debugLogAllocationsNextFrameStarted; +#endif + + RecursiveMutex * ms_criticalSection; + + char ms_memoryManagerBuffer[sizeof(MemoryManager)]; + + FreeBlock * ms_firstFreeBlock; + + int ms_allocateCalls; + unsigned long ms_allocateBytesTotal; +#ifndef _WIN32 + int ms_processVmSizeKBytes; +#endif + int ms_freeCalls; + + int ms_allocations; + int ms_maxAllocations; + + int ms_freeBlocks; + int ms_maxFreeBlocks; +#ifdef _DEBUG + int ms_maxTreeHeight; +#endif + +#if DO_TRACK || DO_GUARDS + unsigned long ms_currentBytesRequested; +#endif + unsigned long ms_currentBytesAllocated; +#if DO_TRACK + unsigned long ms_currentBytesAllocatedNoLeakTest; +#endif + unsigned long ms_maxBytesAllocated; + + bool ms_allowNameLookup = true; + int ms_logMessageFd = -1; + void (*LogMessage)(char const * message) = &outputDebugStringWrapper; + + PROFILER_BLOCK_DEFINE(ms_allocateProfilerBlock, "MemoryManager::allocate"); +} +using namespace MemoryManagerNamespace; + +// ====================================================================== + +SystemAllocation::SystemAllocation(int size) +: + m_size(size), + m_next(NULL), + m_pad1(0), + m_pad2(0) +{ + DEBUG_FATAL(sizeof(*this) != cms_blockSize, ("SystemAllocation size is not %d bytes", cms_blockSize)); + +#if DO_FREE_FILLS + // fill the newly allocated user memory with the free pattern + imemset(reinterpret_cast(this) + cms_blockSize, cms_freeFillPattern, m_size - cms_blockSize); +#endif + + Block * firstMemoryBlock = getFirstMemoryBlock(); + Block * firstFreeBlock = reinterpret_cast(reinterpret_cast(firstMemoryBlock) + cms_blockSize); + Block * lastMemoryBlock = getLastMemoryBlock(); + + // set up the prefix sentinel block + firstMemoryBlock->setPrevious(NULL); + firstMemoryBlock->setNext(firstFreeBlock); + firstMemoryBlock->setFree(false); + + firstFreeBlock->setPrevious(firstMemoryBlock); + firstFreeBlock->setNext(lastMemoryBlock); + firstFreeBlock->setFree(true); + + // set up the suffix sentinel block + lastMemoryBlock->setPrevious(firstFreeBlock); + lastMemoryBlock->setNext(NULL); + lastMemoryBlock->setFree(false); + + // put the first block on the free list + addToFreeList(firstFreeBlock); +} + +// ---------------------------------------------------------------------- + +SystemAllocation::~SystemAllocation() +{ + OsMemory::free(this, m_size); +} + +// ---------------------------------------------------------------------- + +int SystemAllocation::getSize() +{ + return m_size; +} + +// ---------------------------------------------------------------------- + +SystemAllocation * SystemAllocation::getNext() +{ + return m_next; +} + +// ---------------------------------------------------------------------- + +void SystemAllocation::setNext(SystemAllocation * next) +{ + m_next = next; +} + +// ---------------------------------------------------------------------- + +Block * SystemAllocation ::getFirstMemoryBlock() +{ + return reinterpret_cast(reinterpret_cast(this) + cms_blockSize); +} + +// ---------------------------------------------------------------------- + +Block * SystemAllocation ::getLastMemoryBlock() +{ + return reinterpret_cast(reinterpret_cast(this) + m_size - cms_blockSize); +} + +// ====================================================================== + +inline Block * Block::getPrevious() +{ + return m_previous; +} + +// ---------------------------------------------------------------------- + +inline Block const * Block::getPrevious() const +{ + return m_previous; +} + +// ---------------------------------------------------------------------- + +inline void Block::setPrevious(Block *previous) +{ + m_previous = previous; +} + +// ---------------------------------------------------------------------- + +inline Block * Block::getNext() +{ + return m_next; +} + +// ---------------------------------------------------------------------- + +inline Block const * Block::getNext() const +{ + return m_next; +} + +// ---------------------------------------------------------------------- + +inline void Block::setNext(Block *next) +{ + DEBUG_FATAL(next && reinterpret_cast(next) - reinterpret_cast(this) < cms_blockSize, ("too small")); + m_next = next; +} + +// ---------------------------------------------------------------------- + +inline bool Block::isFree() const +{ + return m_free; +} + +// ---------------------------------------------------------------------- + +inline void Block::setFree(bool free) +{ + m_free = free; +} + +// ---------------------------------------------------------------------- + +inline int Block::getSize() const +{ + return reinterpret_cast(m_next) - reinterpret_cast(this); +} + +// ====================================================================== + +#if DO_SCALAR + +inline bool AllocatedBlock::isAllocatedAsArray() const +{ + return m_array; +} + +// ---------------------------------------------------------------------- + +inline void AllocatedBlock::setAllocatedAsArray(bool array) +{ + m_array = array; +} + +#endif + +// ---------------------------------------------------------------------- + +#if DO_TRACK + +inline bool AllocatedBlock::checkForLeaks() const +{ + return m_leakTest; +} + +// ---------------------------------------------------------------------- + +inline void AllocatedBlock::setCheckForLeaks(bool checkForLeaks) +{ + m_leakTest = checkForLeaks; +} + +// ---------------------------------------------------------------------- + +inline uint32 AllocatedBlock::getOwner(int index) const +{ + return m_owner[index]; +} + +// ---------------------------------------------------------------------- + +inline void AllocatedBlock::setOwner(int index, uint32 owner) +{ + m_owner[index] = owner; +} + +// ---------------------------------------------------------------------- + +inline void AllocatedBlock::fillOwnerWithFreePattern() +{ + memset(m_owner, cms_freeFillPattern, sizeof(m_owner)); +} + +#endif + +// ---------------------------------------------------------------------- + +#if DO_TRACK || DO_GUARDS + +inline int AllocatedBlock::getRequestedSize() const +{ + return m_requestedSize; +} + +// ---------------------------------------------------------------------- + +inline void AllocatedBlock::setRequestedSize(int requestedSize) +{ + m_requestedSize = requestedSize; +} + +#endif + +// ====================================================================== + +inline int MemoryManagerNamespace::min(int a, int b) +{ + return (a < b) ? a : b; +} + +// ---------------------------------------------------------------------- + +inline int MemoryManagerNamespace::max(int a, int b) +{ + return (a > b) ? a : b; +} + +// ---------------------------------------------------------------------- + +inline byte const * MemoryManagerNamespace::min(byte const * a, byte const * b) +{ + return (a < b) ? a : b; +} + +// ---------------------------------------------------------------------- + +inline byte const * MemoryManagerNamespace::max(byte const * a, byte const * b) +{ + return (a > b) ? a : b; +} + +// ---------------------------------------------------------------------- +// this is here to get around linkage problems on win32 + +void MemoryManagerNamespace::outputDebugStringWrapper(char const * message) +{ + OutputDebugString(message); +} + +// ---------------------------------------------------------------------- + +void MemoryManager::setLimit(int megabytes, bool hardLimit, bool preallocate) +{ + DEBUG_FATAL(ms_limitSet, ("MemoryManager::setLimit may only be called once")); + ms_limitSet = true; + ms_limitMegabytes = megabytes; + ms_hardLimit = hardLimit; + DEBUG_FATAL(ms_hardLimit && ms_systemMemoryAllocatedMegabytes > ms_limitMegabytes, ("hard limit broken before being set %d/%d", ms_systemMemoryAllocatedMegabytes, ms_limitMegabytes)); + if (preallocate && ms_systemMemoryAllocatedMegabytes < ms_limitMegabytes) + allocateSystemMemory(ms_limitMegabytes - ms_systemMemoryAllocatedMegabytes); +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getLimit() +{ + return ms_limitMegabytes; +} + +// ---------------------------------------------------------------------- + +bool MemoryManager::isHardLimit() +{ + return ms_hardLimit; +} + +// ---------------------------------------------------------------------- +/** + * Install the MemoryManager. + * @param newMaxBytes Maximum number of bytes in the memory pool + * @param newMaxBlocks Number of blocks (free or allocated) + * @param commitAll Commit all the specified ram to the application + */ + +MemoryManager::MemoryManager() +{ + // any allocation will install the memory manager if it has yet to be, so we want to bail safely here + if (ms_installed) + return; + +#if defined(PLATFORM_WIN32) && defined(_DEBUG) + /* + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); + int crtHeapFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + crtHeapFlags &= ~_CRTDBG_ALLOC_MEM_DF; + crtHeapFlags &= ~_CRTDBG_CHECK_ALWAYS_DF; + crtHeapFlags &= ~_CRTDBG_CHECK_CRT_DF; + crtHeapFlags &= ~_CRTDBG_DELAY_FREE_MEM_DF; + crtHeapFlags &= ~_CRTDBG_LEAK_CHECK_DF; + _CrtSetDbgFlag(crtHeapFlags); + */ +#endif + + OsMemory::install(); + DebugHelp::install(); + +#if !DISABLED + + // this buffer must remain local to this function, otherwise it will get clobbered. + // the problem is this function gets called before the library gets properly initialized, + // and then when the library gets initialized, it will clear the global memory, thus + // wiping out our mutex. + static char s_criticalSectionBuffer[sizeof(RecursiveMutex)]; + ms_criticalSection = new(s_criticalSectionBuffer) RecursiveMutex; + + ms_reportAllocations = true; + ms_installed = true; +// ms_logEachAlloc = false; + +#endif +} + +// ---------------------------------------------------------------------- +/** + * Remove the MemoryManager. + */ + +MemoryManager::~MemoryManager() +{ +#if DISABLED + return; +#else + +#if PRODUCTION == 0 + ms_allocationsPerFrame.disable(); + ms_bytesAllocatedPerFrame.disable(); + ms_freesPerFrame.disable(); + ms_bytesFreedPerFrame.disable(); +#endif + + DEBUG_FATAL(!ms_installed, ("not installed")); + + ms_criticalSection->enter(); + + DEBUG_REPORT_LOG_PRINT(true, ("MM::remove %lu/%lu=bytes %d/%d=allocs\n", getCurrentNumberOfBytesAllocated(), getMaximumNumberOfBytesAllocated(), getCurrentNumberOfAllocations(), getMaximumNumberOfAllocations())); + DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("MM::remove %lu/%lu=bytes %d/%d=allocs\n", getCurrentNumberOfBytesAllocated(), getMaximumNumberOfBytesAllocated(), getCurrentNumberOfAllocations(), getMaximumNumberOfAllocations())); + +#if DO_TRACK + if (!ConfigSharedFoundation::getDemoMode() && ms_allocations && ms_reportAllocations) + { + ms_criticalSection->leave(); + int const leaks = MemoryManagerNamespace::report(true); + ms_criticalSection->enter(); + if (leaks) + REPORT(true, Report::RF_log | Report::RF_dialog, ("%d memory leak%s", leaks, leaks > 1 ? "s" : "")); + } +#endif + + // free all of the allocations from the OS + while (ms_firstSystemAllocation) + { + SystemAllocation * systemAllocation = ms_firstSystemAllocation; + ms_firstSystemAllocation = ms_firstSystemAllocation->getNext(); + systemAllocation->~SystemAllocation(); + } + + ms_criticalSection->leave(); + ms_installed = false; + +#ifdef _DEBUG + DebugMonitor::remove(); +#endif + + ms_criticalSection->~RecursiveMutex(); + +#endif + + DebugHelp::remove(); + OsMemory::remove(); +} + +// ---------------------------------------------------------------------- + +int MemoryManagerNamespace::convertBytesToMegabytesForSystemAllocation(int systemAllocationSize) +{ + if (systemAllocationSize < cms_systemAllocationMinimumSize) + systemAllocationSize = cms_systemAllocationMinimumSize; + + systemAllocationSize = (systemAllocationSize + (cms_systemAllocationRoundSize - 1)) & (~(cms_systemAllocationRoundSize - 1)); + + return systemAllocationSize / (1024 * 1024); +} + +// ---------------------------------------------------------------------- + +void MemoryManagerNamespace::allocateSystemMemory(int megabytes) +{ + if (ms_hardLimit && ms_systemMemoryAllocatedMegabytes + megabytes > ms_limitMegabytes) + { + megabytes = ms_limitMegabytes - ms_systemMemoryAllocatedMegabytes; + if (megabytes <= 0) + return; + } + + // allocate the system memory + size_t systemAllocationSize = static_cast(megabytes) * 1024 * 1024; + void * data = OsMemory::commit(0, systemAllocationSize); + + // failed to allocate virtual memory. there is insufficient virtual memory or address space to satisfy systemAllocationSize. + if (!data) + return; + + // Construct our tracking information + SystemAllocation * systemAllocation = new(data) SystemAllocation(systemAllocationSize); + ++ms_numberOfSystemAllocations; + ms_systemMemoryAllocatedMegabytes += megabytes; + + // insert the memory into the sorted linked list of system allocations + SystemAllocation * back = NULL; + SystemAllocation * front = ms_firstSystemAllocation; + for ( ; front && front->getFirstMemoryBlock() < systemAllocation->getFirstMemoryBlock(); back = front, front = front->getNext()) + {} + if (back) + back->setNext(systemAllocation); + else + ms_firstSystemAllocation = systemAllocation; + systemAllocation->setNext(front); +} + +// ---------------------------------------------------------------------- + +unsigned long MemoryManager::getCurrentNumberOfBytesAllocated(const int processId) +{ + UNREF(processId); + return ms_currentBytesAllocated; +} + +// ---------------------------------------------------------------------- + +unsigned long MemoryManager::getCurrentNumberOfBytesAllocatedNoLeakTest() +{ +#if DO_TRACK + return ms_currentBytesAllocatedNoLeakTest; +#else + return 0; +#endif +} + +// ---------------------------------------------------------------------- + +unsigned long MemoryManager::getMaximumNumberOfBytesAllocated() +{ + return ms_maxBytesAllocated; +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getSystemMemoryAllocatedMegabytes() +{ + return ms_systemMemoryAllocatedMegabytes; +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getCurrentNumberOfAllocations() +{ + return ms_allocations; +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getMaximumNumberOfAllocations() +{ + return ms_maxAllocations; +} + +// ---------------------------------------------------------------------- + +void MemoryManager::setReportAllocations(bool reportAllocations) +{ + ms_reportAllocations = reportAllocations; +} + +// ---------------------------------------------------------------------- + +void MemoryManager::registerDebugFlags() +{ +#if PRODUCTION == 0 + ms_allocationsPerFrame.bindToCounter("MemoryManagerAllocateCount"); + ms_bytesAllocatedPerFrame.bindToCounter("MemoryManagerAllocateBytes"); + ms_freesPerFrame.bindToCounter("MemoryManagerFreeCount"); + ms_bytesFreedPerFrame.bindToCounter("MemoryManagerFreeBytes"); +#endif + +#ifdef _DEBUG + DebugFlags::registerFlag(ms_debugReportFlag, "SharedMemoryManager", "reportMemory", debugReport); + DebugFlags::registerFlag(ms_debugReportMapFlag, "SharedMemoryManager", "reportMemoryMap", debugReportMap); + DebugFlags::registerFlag(ms_debugReportAllocations, "SharedMemoryManager", "reportMemoryAllocations"); + DebugFlags::registerFlag(ms_debugReportLogMemoryAllocFreePointers, "SharedMemoryManager", "reportLogMemoryAllocFreePointers"); + DebugFlags::registerFlag(ms_debugLogAllocations, "SharedMemoryManager", "reportLogAllocations"); + DebugFlags::registerFlag(ms_debugLogAllocationsNextFrame, "SharedMemoryManager", "reportLogAllocationsNextFrame", logAllocationsNextFrame); + DebugFlags::registerFlag(ms_debugVerifyGuardPatterns, "SharedMemoryManager", "verifyGuardPatterns"); + DebugFlags::registerFlag(ms_debugVerifyFreePatterns, "SharedMemoryManager", "verifyFreePatterns"); + DebugFlags::registerFlag(ms_debugProfileAllocate, "SharedMemoryManager", "profileAllocate"); +#endif +} + +// ---------------------------------------------------------------------- +/** + * Dump debugging information about the MemoryManager. + */ + +void MemoryManager::debugReport() +{ +#if !DISABLED + DEBUG_FATAL(!ms_installed, ("not installed")); + DEBUG_REPORT_PRINT(ms_limitSet, ("MM: %9dmb (%s limit)\n", ms_limitMegabytes, ms_hardLimit ? "hard" : "soft")); + DEBUG_REPORT_PRINT(true, ("MM: %9d/%9d/%9d cur/max/tot allocs\n", ms_allocations, ms_maxAllocations, ms_allocateCalls)); + DEBUG_REPORT_PRINT(true, ("MM: %9lu/%9lu/%9lu cur/max/tot bytes\n", ms_currentBytesAllocated, ms_maxBytesAllocated, ms_allocateBytesTotal)); +#endif +} + +// ---------------------------------------------------------------------- + +#ifdef _DEBUG +void MemoryManagerNamespace::logAllocationsNextFrame() +{ + if (!ms_debugLogAllocationsNextFrameStarted) + { + REPORT_LOG_PRINT(true, ("MemoryManager::logAllocationsNextFrame start\n")); + ms_debugLogAllocations = true; + ms_debugLogAllocationsNextFrameStarted = true; + } + else + { + REPORT_LOG_PRINT(true, ("MemoryManager::logAllocationsNextFrame end\n")); + ms_debugLogAllocations = false; + ms_debugLogAllocationsNextFrameStarted = false; + ms_debugLogAllocationsNextFrame = false; + } +} +#endif + +// ---------------------------------------------------------------------- + +void MemoryManagerNamespace::emitCharacters(char * & buffer, int blockSize, int & carryOverFree, int & carryOverUsed, int newFree, int newUsed, char const * const bufferOverrunAddress) +{ + while (carryOverFree + carryOverUsed + newFree + newUsed >= blockSize) + { + int const absorbNew = blockSize - (carryOverUsed + carryOverFree); + if (newFree) + { + carryOverFree += absorbNew; + newFree -= absorbNew; + } + else + { + carryOverUsed += absorbNew; + newUsed -= absorbNew; + } + + if (carryOverFree == blockSize) + *buffer = '_'; + else + if (carryOverUsed == blockSize) + *buffer = '*'; + else + { + int const letter = (carryOverUsed * 26) / blockSize; + *buffer = static_cast('A' + letter); + } + ++buffer; + + FATAL(buffer == bufferOverrunAddress, ("Buffer overrun! 0x%0X", buffer)); + + carryOverFree = 0; + carryOverUsed = 0; + } + + carryOverFree += newFree; + carryOverUsed += newUsed; +} + +// ---------------------------------------------------------------------- +/** + * Dump an image of the memory state to the report system. + */ + +void MemoryManager::debugReportMap() +{ + for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) + { + char buffer[128]; + int const numberOfCharactersPerRow = 64; + + snprintf(buffer, sizeof(buffer)-1, "%8p %3dmb : ", systemAllocation, systemAllocation->getSize() / (1024 * 1024)); + buffer[sizeof(buffer)-1] = '\0'; + + int const headerLength = strlen(buffer); + int const characterSize = systemAllocation->getSize() / numberOfCharactersPerRow; + + int carryOverUsed = 0; + int carryOverFree = 0; + char * b = buffer + headerLength; + char const * const bufferOverrunAddress = buffer + sizeof(buffer); + for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) + { + if (block->isFree()) + emitCharacters(b, characterSize, carryOverFree, carryOverUsed, block->getSize(), 0, bufferOverrunAddress); + else + emitCharacters(b, characterSize, carryOverFree, carryOverUsed, 0, block->getSize(), bufferOverrunAddress); + } + + if (carryOverFree || carryOverUsed) + emitCharacters(b, carryOverFree + carryOverUsed, carryOverFree, carryOverUsed, 0, 0, bufferOverrunAddress); + + b[0] = '\0'; + + DEBUG_REPORT_PRINT(true, ("%s\n", buffer)); + } +} + +// ---------------------------------------------------------------------- +/** + * Add a block to the free memory chain list. + * + * @param block Block of memory that is being + */ + +void MemoryManagerNamespace::addToFreeList(Block * block) +{ + NOT_NULL(block); + + // @todo consider making the ternary search tree balanced + + FreeBlock * freeBlock = static_cast(block); + int const freeBlockSize = freeBlock->getSize(); + FreeBlock * parent = NULL; + FreeBlock * * next = &ms_firstFreeBlock; + FreeBlock * same = 0; + + for (FreeBlock * current = ms_firstFreeBlock; current; parent = current, current = *next) + { + int const currentBlockSize = current->getSize(); + if (freeBlockSize < currentBlockSize) + next = ¤t->m_smallerFreeBlock; + else + if (freeBlockSize > currentBlockSize) + next = ¤t->m_largerFreeBlock; + else + { + // quick out for same size blocks + same = current; + break; + } + } + + if (same) + { + + freeBlock->m_smallerFreeBlock = same->m_smallerFreeBlock; + same->m_smallerFreeBlock = NULL; + if (freeBlock->m_smallerFreeBlock) + freeBlock->m_smallerFreeBlock->m_parentFreeBlock = freeBlock; + + freeBlock->m_sameFreeBlock = same; + same->m_parentFreeBlock = freeBlock; + + freeBlock->m_largerFreeBlock = same->m_largerFreeBlock; + same->m_largerFreeBlock = NULL; + if (freeBlock->m_largerFreeBlock) + freeBlock->m_largerFreeBlock->m_parentFreeBlock = freeBlock; + + *next = freeBlock; + freeBlock->m_parentFreeBlock = parent; + } + else + { + *next = freeBlock; + freeBlock->m_smallerFreeBlock = NULL; + freeBlock->m_sameFreeBlock = NULL; + freeBlock->m_largerFreeBlock = NULL; + freeBlock->m_parentFreeBlock = parent; + } + + if (++ms_freeBlocks > ms_maxFreeBlocks) + ms_maxFreeBlocks = ms_freeBlocks; + +#ifdef _DEBUG + int treeHeight = 0; + while (freeBlock) + { + ++treeHeight; + freeBlock = freeBlock->m_parentFreeBlock; + } + if (treeHeight > ms_maxTreeHeight) + ms_maxTreeHeight = treeHeight; +#endif +} + +// ---------------------------------------------------------------------- +/** + * Remove a block from the free memory chain list. + * + * @param block Block of memory that is being allocated + */ + +void MemoryManagerNamespace::removeFromFreeList(FreeBlock * block) +{ + NOT_NULL(block); + + // find the pointer that points to block + FreeBlock * * parentPointer = NULL; + FreeBlock * parent = block->m_parentFreeBlock; + if (parent) + { + if (parent->m_smallerFreeBlock == block) + parentPointer = &parent->m_smallerFreeBlock; + else + if (parent->m_sameFreeBlock == block) + parentPointer = &parent->m_sameFreeBlock; + else + { + DEBUG_FATAL(parent->m_largerFreeBlock != block, ("parent doesn't know about child")); + parentPointer = &parent->m_largerFreeBlock; + } + } + else + { + DEBUG_FATAL(ms_firstFreeBlock != block, ("no parent but not first")); + parentPointer = &ms_firstFreeBlock; + } + + // now we need to replace our node with one from underneath us + FreeBlock * same = block->m_sameFreeBlock; + if (same) + { + // making use of the same size block is pretty easy and doesn't disturb tree balance so its our prefered choice + same->m_smallerFreeBlock = block->m_smallerFreeBlock; + if (same->m_smallerFreeBlock) + same->m_smallerFreeBlock->m_parentFreeBlock = same; + + same->m_largerFreeBlock = block->m_largerFreeBlock; + if (same->m_largerFreeBlock) + same->m_largerFreeBlock->m_parentFreeBlock = same; + + same->m_parentFreeBlock = parent; + + *parentPointer = same; + } + else + { + if (block->m_smallerFreeBlock) + { + if (block->m_largerFreeBlock) + { + // this is the worst case. this free block has smaller and larger children, but not any same sized children + // we're going to take the smallest block off the larger list and use that to replace the current node + FreeBlock * back = NULL; + FreeBlock * replacement = block->m_largerFreeBlock; + while (replacement->m_smallerFreeBlock) + { + back = replacement; + replacement = replacement->m_smallerFreeBlock; + } + + // disconnect the link between its parent and out replacement block + if (back) + { + back->m_smallerFreeBlock = replacement->m_largerFreeBlock; + if (back->m_smallerFreeBlock) + back->m_smallerFreeBlock->m_parentFreeBlock = back; + + replacement->m_largerFreeBlock = block->m_largerFreeBlock; + replacement->m_largerFreeBlock->m_parentFreeBlock = replacement; + } + + // put the replacement block in its new place + replacement->m_smallerFreeBlock = block->m_smallerFreeBlock; + replacement->m_smallerFreeBlock->m_parentFreeBlock = replacement; + + replacement->m_parentFreeBlock = parent; + + *parentPointer = replacement; + } + else + { + // this block only has one child, which is smaller. an easy case. + block->m_smallerFreeBlock->m_parentFreeBlock = parent; + *parentPointer = block->m_smallerFreeBlock; + } + } + else + { + if (block->m_largerFreeBlock) + { + // this block only has one child, which is larger. an easy case. + block->m_largerFreeBlock->m_parentFreeBlock = parent; + *parentPointer = block->m_largerFreeBlock; + } + else + { + // this block has no children + *parentPointer = NULL; + } + } + } + + // remove all the pointers the block may have had + block->m_smallerFreeBlock = NULL; + block->m_sameFreeBlock = NULL; + block->m_largerFreeBlock = NULL; + block->m_parentFreeBlock = NULL; + + --ms_freeBlocks; +} + +// ---------------------------------------------------------------------- + +FreeBlock *MemoryManagerNamespace::searchFreeList(int blockSize) +{ + FreeBlock * result = NULL; + FreeBlock * current = ms_firstFreeBlock; + while (current) + { + int const currentBlockSize = current->getSize(); + + if (currentBlockSize < blockSize) + { + // this block is too small so check blocks larger than this + current = current->m_largerFreeBlock; + } + else + if (currentBlockSize > blockSize) + { + // this block is too large but will be the best fit so far. continue checking smaller blocks. + result = current; + current = current->m_smallerFreeBlock; + } + else + { + // this block is a perfect fit, return it immediately. + return current; + } + } + + return result; +} + +// ---------------------------------------------------------------------- +/** + * Dynamically allocate memory. + * + * Users should not call this routine directly. It should only be called + * by operator new. + * + * @param size Number of bytes to allocate + * @param owner Line number on which the allocation was made + * @param array True if the array form of operator new was used, false if the scalar form was used + */ + +void * MemoryManager::allocate(size_t size, uint32 owner, bool array, bool leakTest) +{ + if (!ms_installed) + new(ms_memoryManagerBuffer) MemoryManager; + + UNREF(owner); + UNREF(array); + UNREF(leakTest); + +#if DISABLED + return operator new(size); +#else + + DEBUG_FATAL(!ms_installed, ("not installed")); + +#if PRODUCTION == 0 + ++ms_allocationsPerFrame; + ms_bytesAllocatedPerFrame += size; +#endif + +#ifdef _DEBUG + if (ms_debugProfileAllocate) + PROFILER_BLOCK_ENTER(ms_allocateProfilerBlock); + + if (ms_debugVerifyGuardPatterns || ms_debugVerifyFreePatterns) + verify(ms_debugVerifyGuardPatterns, ms_debugVerifyFreePatterns); + + if (ms_debugReportAllocations || ms_debugLogAllocations) + { + char libName[256]; + char fileName[256]; + int line; + if (ms_allowNameLookup && DebugHelp::lookupAddress(owner, libName, fileName, sizeof(fileName), line)) + { + DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), ("%s(%d): alloc %d=bytes %d=array\n", fileName, line, size, static_cast(array))); + } + else + { + DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), ("%08x: alloc %d=bytes %d=array\n", static_cast(owner), size, static_cast(array))); + } + } +#endif + + ms_criticalSection->enter(); + + // get the size of the allocation + int allocSize = (cms_allocatedBlockSize + cms_guardBandSize + (size ? static_cast(size) : 1) + cms_guardBandSize + 15) & ~15; + + FreeBlock * bestFreeBlock = NULL; + for (int tries = 0; !bestFreeBlock && tries < 2; ++tries) + { + bestFreeBlock = searchFreeList(allocSize); + + // if the memory allocation failed, try to get some more memory + if (!bestFreeBlock) + allocateSystemMemory(convertBytesToMegabytesForSystemAllocation(cms_blockSize + cms_blockSize + allocSize + cms_blockSize)); + } + + // make sure memory was available + if (!bestFreeBlock) + { + if (ConfigSharedFoundation::getMemoryManagerReportOnOutOfMemory()) + { + // avoid deadlock from FATAL calling free + (*LogMessage)("Out of memory, dumping current allocations:\n"); + IGNORE_RETURN(MemoryManagerNamespace::report(false)); + } + + ms_criticalSection->leave(); + FATAL(true, ("failed allocation attempt for %d (%d actual)", allocSize, size)); + } + + removeFromFreeList(bestFreeBlock); + + // setup the allocation record + bestFreeBlock->setFree(false); + + // check to see if we should subdivide this block + if (bestFreeBlock->getSize() > (allocSize + cms_allocatedBlockSize + cms_guardBandSize + 1 + cms_guardBandSize)) + { + Block *block = reinterpret_cast(reinterpret_cast(bestFreeBlock) + allocSize); + block->setPrevious(bestFreeBlock); + block->setNext(bestFreeBlock->getNext()); + block->setFree(true); + + bestFreeBlock->getNext()->setPrevious(block); + bestFreeBlock->setNext(block); + + addToFreeList(block); + } + + AllocatedBlock * best = reinterpret_cast(bestFreeBlock); + +#if DO_SCALAR + best->setAllocatedAsArray(array); +#endif + +#if DO_TRACK + best->setCheckForLeaks(leakTest); + best->setOwner(0, owner); +#endif +#if DO_TRACK > 1 + { + enum { OFFSET = 3 }; + uint32 owners[DO_TRACK + OFFSET]; + DebugHelp::getCallStack(owners, DO_TRACK + OFFSET); + + for (int i = 1; i < DO_TRACK; ++i) + { + best->setOwner(i, owners[i + OFFSET]); + +#ifdef _DEBUG + if (ms_debugReportAllocations || ms_debugLogAllocations) + { + char libName[256]; + char fileName[256]; + int line; + if (ms_allowNameLookup && DebugHelp::lookupAddress(owners[i + OFFSET], libName, fileName, sizeof(fileName), line)) + { + DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), (" %s(%d): caller %d\n", fileName, line, i)); + } + else + { + DEBUG_REPORT(true, (ms_debugReportAllocations ? Report::RF_print : 0) | (ms_debugLogAllocations ? Report::RF_log : 0), (" %08x: caller %d\n", static_cast(owners[i + OFFSET]), i)); + } + } +#endif + } + } +#endif +#if DO_TRACK || DO_GUARDS + best->setRequestedSize(static_cast(size)); + ms_currentBytesRequested += size; + DEBUG_FATAL(best->getRequestedSize() != static_cast(size), ("allocated more memory at once than the memory manager supports (%d)", (1 << Block::cms_requestedSizeBits) - 1)); +#endif + + // update the size of the allocation because our block may not have been large enough to subdivide + allocSize = best->getSize(); + + // update the number of bytes allocated + ++ms_allocateCalls; + ms_allocateBytesTotal += allocSize; + ms_currentBytesAllocated += allocSize; + +#if DO_TRACK + if (!leakTest) + ms_currentBytesAllocatedNoLeakTest += allocSize; +#endif + + if (++ms_allocations > ms_maxAllocations) + ms_maxAllocations = ms_allocations; + if (ms_currentBytesAllocated > ms_maxBytesAllocated) + ms_maxBytesAllocated = ms_currentBytesAllocated; + + // get another pointer to the memory we allocated so we can tinker with it + byte * memory = reinterpret_cast(best) + cms_allocatedBlockSize + cms_guardBandSize; + +#if DO_GUARDS + // fill the prefix guard band + memset(memory - cms_guardBandSize, cms_guardFillPattern, cms_guardBandSize); +#endif + + // fill the user memory with the initialize pattern +#if DO_INITIALIZE_FILLS + memset(memory, cms_initializeFillPattern, size); +#endif + +#if DO_GUARDS + // fill the suffix guard band + memset(memory+size, cms_guardFillPattern, cms_guardBandSize); +#endif + + ms_criticalSection->leave(); + + DEBUG_REPORT_LOG_PRINT(ms_debugReportLogMemoryAllocFreePointers, ("MM::alloc %08x\n", reinterpret_cast(memory))); + +#ifdef _DEBUG + if (ms_debugProfileAllocate) + PROFILER_BLOCK_LEAVE(ms_allocateProfilerBlock); +#endif + +// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::allocate() requested_size=%d, alloc_size=%d, ptr=%p\n", size, allocSize, memory)); + + return memory; +#endif +} + +// ---------------------------------------------------------------------- + +void *MemoryManager::reallocate(void *userPointer, size_t newSize) +{ + AllocatedBlock *allocatedBlock = 0; + bool array = false; + int oldSize = 0; + + if (userPointer) + { + allocatedBlock = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); + #if DO_SCALAR + array = allocatedBlock->isAllocatedAsArray(); + #endif + if (!newSize) + { + MemoryManager::free(userPointer, array); + +// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::reallocate() new_requested_size=%d, org ptr=%p, new ptr=NULL\n", newSize, userPointer)); + + return 0; + } + #if DO_TRACK || DO_GUARDS + oldSize = allocatedBlock->getRequestedSize(); + #else + oldSize = allocatedBlock->getSize()-cms_allocatedBlockSize; + #endif + } + + if (newSize <= static_cast(oldSize)) + { +// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::reallocate() new_requested_size=%d, org ptr=%p, new ptr=%p\n", newSize, userPointer, userPointer)); + + return userPointer; + } + +#if DO_TRACK + uint32 owner = allocatedBlock->getOwner(0); + bool leakTest = allocatedBlock->checkForLeaks(); +#else + uint32 owner = 0; + bool leakTest = false; +#endif + + void *newPointer = allocate(newSize, owner, array, leakTest); + if (oldSize) + memcpy(newPointer, userPointer, oldSize); + if (userPointer) + MemoryManager::free(userPointer, array); + +// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::reallocate() new_requested_size=%d, org ptr=%p, new ptr=%p\n", newSize, userPointer, newPointer)); + + return newPointer; +} + +// ---------------------------------------------------------------------- +/** + * Free dynamically allocated memory. + * + * Users should not call this routine directly. It should only be called + * by operator delete. + * + * This routine should not be called with the NULL pointer. + * + * @param userPointer Pointer to the memory + * @param array True if the array form of operator new was used, false if the scalar form was used + */ + +void MemoryManager::free(void * userPointer, bool array) +{ +#if DISABLED + UNREF(array); + operator delete(userPointer); + return; +#else + + DEBUG_FATAL(!ms_installed, ("not installed")); + NOT_NULL(userPointer); + +#ifdef _DEBUG + if (ms_debugVerifyGuardPatterns || ms_debugVerifyFreePatterns) + verify(ms_debugVerifyGuardPatterns, ms_debugVerifyFreePatterns); +#endif + + DEBUG_REPORT_LOG_PRINT(ms_debugReportLogMemoryAllocFreePointers, ("MM::free %08x\n", reinterpret_cast(userPointer))); + + UNREF(array); + + ms_criticalSection->enter(); + + AllocatedBlock * allocatedBlock = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); + +#if DEBUG_LEVEL == DEBUG_LEVEL_DEBUG + DEBUG_FATAL(allocatedBlock->getNext()->getPrevious() != allocatedBlock, ("Bad free (1) %p", userPointer)); + DEBUG_FATAL(allocatedBlock->getPrevious()->getNext() != allocatedBlock, ("Bad free (2) %p", userPointer)); + DEBUG_FATAL(allocatedBlock->isFree(), ("Freeing already free block %p", userPointer)); +#endif + +#if PRODUCTION == 0 + ++ms_freesPerFrame; +#if DO_TRACK + ms_bytesFreedPerFrame += allocatedBlock->getRequestedSize(); +#endif +#endif + +#if DO_GUARDS + { + // verify the guard bands + byte * guard = reinterpret_cast(allocatedBlock) + cms_allocatedBlockSize; + bool corrupt = false; + + // check the prefix guard band + for (int i = 0; i < cms_guardBandSize; ++i, ++guard) + if (*guard != cms_guardFillPattern) + { + corrupt = true; + DEBUG_REPORT_LOG_PRINT(true, ("MemoryManager::free corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); + DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("MemoryManager::free corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); + } + + // advance past the user memory + guard += allocatedBlock->getRequestedSize(); + + // check the suffix guard band + for (int j = 0; j < cms_guardBandSize; ++j, ++guard) + if (*guard != cms_guardFillPattern) + { + corrupt = true; + DEBUG_REPORT_LOG_PRINT(true, ("MemoryManager::free corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); + DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("MemoryManager::free corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); + } + + if (corrupt) + { + MemoryManagerNamespace::report(allocatedBlock, false); + ms_criticalSection->leave(); + DEBUG_FATAL(true, ("corrupted guard pattern")); + return; //lint !e527 // Unreachable + } + } +#endif + +#if DO_SCALAR + if (allocatedBlock->isAllocatedAsArray() != array) //lint !e731 // Info -- Boolean argument to equal/not equal + { + MemoryManagerNamespace::report(allocatedBlock, false); + #ifdef _DEBUG + bool const blockArray = allocatedBlock->isAllocatedAsArray(); + ms_criticalSection->leave(); + FATAL(true, ("allocated %s deleted %s", blockArray ? "array" : "scalar", array ? "array" : "scalar")); //lint !e731 // Info -- Boolean argument to equal/not equal + #endif + } +#endif + + int const memorySize = allocatedBlock->getSize(); + + // wipe the user memory +#if DO_FREE_FILLS + imemset(reinterpret_cast(allocatedBlock) + cms_allocatedBlockSize, cms_freeFillPattern, memorySize - cms_allocatedBlockSize); +#endif + + allocatedBlock->setFree(true); +#if DO_SCALAR + allocatedBlock->setAllocatedAsArray(false); +#endif + + // clear out the block records +#if DO_TRACK + allocatedBlock->fillOwnerWithFreePattern(); +#endif + +#if DO_TRACK || DO_GUARDS + ms_currentBytesRequested -= allocatedBlock->getRequestedSize(); + allocatedBlock->setRequestedSize(0); + DEBUG_FATAL(allocatedBlock->getRequestedSize() != 0, ("bad size")); +#endif + + // update the number of bytes allocated + ++ms_freeCalls; + --ms_allocations; + + DEBUG_FATAL((ms_currentBytesAllocated < static_cast(memorySize)), ("currentBytesAllocated underflow")); + ms_currentBytesAllocated -= memorySize; +#if DO_TRACK + if (!allocatedBlock->checkForLeaks()) + ms_currentBytesAllocatedNoLeakTest -= memorySize; +#endif + DEBUG_FATAL(ms_allocations < 0, ("allocations underflow")); + +// DEBUG_REPORT_LOG(ms_logEachAlloc, ("MemoryManager::free() requested_size=%d, alloc_size=%d, userPointer=%p, allocatedBlock=%p\n", requestedSize, memorySize, userPointer, allocatedBlock)); + + Block *block = allocatedBlock; + + // recombine with the previous block + if (block->getPrevious()->isFree()) + { + FreeBlock * const previous = static_cast(block->getPrevious()); + removeFromFreeList(previous); + previous->setNext(block->getNext()); + block->getNext()->setPrevious(previous); + +#if DO_FREE_FILLS + memset(block, cms_freeFillPattern, cms_freeBlockSize); +#endif + block = previous; + } + + // recombine with the following block + if (block->getNext()->isFree()) + { + FreeBlock * const next = static_cast(block->getNext()); + removeFromFreeList(next); + block->setNext(next->getNext()); + next->getNext()->setPrevious(block); + +#if DO_FREE_FILLS + memset(next, cms_freeFillPattern, cms_freeBlockSize); +#endif + } + + addToFreeList(block); + + ms_criticalSection->leave(); +#endif +} + +// ---------------------------------------------------------------------- + +int MemoryManagerNamespace::quickGuessIsValidPointerFromHeap(void const * userPointer) +{ + int result = 0; + AllocatedBlock const * allocatedBlock = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); + + ms_criticalSection->enter(); + if (!result && allocatedBlock->getNext()->getPrevious() != allocatedBlock) result = 1; + if (!result && allocatedBlock->getPrevious()->getNext() != allocatedBlock) result = 2; + if (!result && allocatedBlock->isFree()) result = 3; + ms_criticalSection->leave(); + + return result; +} + +// ---------------------------------------------------------------------- + +int MemoryManagerNamespace::authoritativeIsValidPointerFromHeap(void const * userPointer) +{ + ms_criticalSection->enter(); + + int result = quickGuessIsValidPointerFromHeap(userPointer); + if (result != 0) + return result; + + result = 16; + for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) + for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); result != 0 && block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) + if (!block->isFree()) + { + byte const * memory = reinterpret_cast(block) + cms_allocatedBlockSize + cms_guardBandSize; + if (memory == userPointer) + result = 0; + } + + ms_criticalSection->leave(); + + return result; +} + +// ---------------------------------------------------------------------- +/** + * Take ownership for a block of memory. + * + * @param userPointer Memory to take ownership of + */ + +void MemoryManager::own(void * userPointer) +{ + UNREF(userPointer); + +#if DISABLED || !DO_TRACK + return; +#else + + DEBUG_FATAL(!ms_installed, ("not installed")); + + if (!userPointer) + return; + + ms_criticalSection->enter(); + + // fetch the block pointer + AllocatedBlock * block = reinterpret_cast(reinterpret_cast(userPointer) - (cms_allocatedBlockSize + cms_guardBandSize)); + DEBUG_FATAL(block->isFree(), ("cannot own a free block")); + + // update the owners + { + enum { OFFSET = 2 }; + uint32 owners[DO_TRACK + OFFSET]; + DebugHelp::getCallStack(owners, DO_TRACK + OFFSET); + + for (int i = 0; i < DO_TRACK; ++i) + block->setOwner(i, owners[i + OFFSET]); + } + + ms_criticalSection->leave(); +#endif +} + +// ---------------------------------------------------------------------- + +void MemoryManager::verify(bool guardPatterns, bool freePatterns) +{ + UNREF(guardPatterns); + UNREF(freePatterns); + +#if DO_FREE_FILLS || DO_GUARDS + + ms_criticalSection->enter(); + + // search for the memory pointer + for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) + for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) + if (block->isFree()) + { +#if DO_FREE_FILLS + if (freePatterns) + { + bool corrupt = false; + byte * memory = reinterpret_cast(block) + cms_freeBlockSize; + int freeSize = block->getSize() - cms_freeBlockSize; + + for (int i = 0; i < freeSize; ++i, ++memory) + if (*memory != cms_freeFillPattern) + { + corrupt = true; + DEBUG_REPORT_LOG_PRINT(true, ("corrupted free pattern at position %3d [membase=0x%x, memaddr=0x%x] = %02x\n", i, reinterpret_cast(reinterpret_cast(block) + cms_freeBlockSize), reinterpret_cast(reinterpret_cast(block) + cms_freeBlockSize + i), static_cast(*memory))); + DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("corrupted free pattern at position %3d = %02x\n", i, static_cast(*memory))); + } + + if (corrupt) + { + ms_criticalSection->leave(); + DEBUG_FATAL(true, ("corrupted free pattern")); + } + } +#endif + } + else + if (guardPatterns) + { +#if DO_GUARDS + // verify the guard bands + byte * guard = reinterpret_cast(block) + cms_allocatedBlockSize; + bool corrupt = false; + + // check the prefix guard band + for (int i = 0; i < cms_guardBandSize; ++i, ++guard) + if (*guard != cms_guardFillPattern) + { + corrupt = true; + DEBUG_REPORT_LOG_PRINT(true, ("corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); + DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("corrupted guard prefix at position %3d = %02x\n", i - cms_guardBandSize, static_cast(*guard))); + } + + // advance past the user memory + guard += static_cast(block)->getRequestedSize(); + + // check the suffix guard band + for (int j = 0; j < cms_guardBandSize; ++j, ++guard) + if (*guard != cms_guardFillPattern) + { + corrupt = true; + DEBUG_REPORT_LOG_PRINT(true, ("corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); + DEBUG_OUTPUT_CHANNEL("Foundation\\MemoryManager", ("corrupted guard suffix at position %3d = %02x\n", j, static_cast(*guard))); + } + + if (corrupt) + { + MemoryManagerNamespace::report(static_cast(block), false); + ms_criticalSection->leave(); + DEBUG_FATAL(true, ("corrupted guard pattern")); + } +#endif + } + + ms_criticalSection->leave(); + +#endif +} + +// ---------------------------------------------------------------------- +/** + * @internal + */ + +void MemoryManagerNamespace::report(AllocatedBlock const * block, bool leak) +{ +#if DO_TRACK + uint32 const owner = block->getOwner(0); +#else + uint32 const owner = 0; +#endif +#if DO_TRACK || DO_GUARDS + int const requestedSize = block->getRequestedSize();; +#else + int const requestedSize = 0; +#endif + + char buffer[256]; + char libName[256]; + char fileName[256]; + int line = 0; + int const memory = reinterpret_cast(reinterpret_cast(block) + cms_allocatedBlockSize + cms_guardBandSize); + + if (ms_allowNameLookup && DebugHelp::lookupAddress(owner, libName, fileName, sizeof(fileName), line)) + { + sprintf(buffer, "%s(%d) : %08X memory %s, %d bytes\n", fileName, line, memory, leak ? "leak" : "allocation", static_cast(requestedSize)); + } + else + { + sprintf(buffer, "unknown(0x%08X) : %08X memory %s, %d bytes\n", static_cast(owner), memory, leak ? "leak" : "allocation", static_cast(requestedSize)); + } + + (*LogMessage)(buffer); + +#if DO_TRACK > 1 + { + for (int i = 1; i < DO_TRACK; ++i) + if (block->getOwner(i)) + { + if (ms_allowNameLookup && DebugHelp::lookupAddress(block->getOwner(i), libName, fileName, sizeof(fileName), line)) + sprintf(buffer, " %s(%d) : caller %d\n", fileName, line, i); + else + sprintf(buffer, " 0x%08X : caller %d\n", static_cast(block->getOwner(i)), i); + (*LogMessage)(buffer); + } + } +#endif +} + +// ---------------------------------------------------------------------- +/** + * Dump information about all outstanding allocations. + */ + +int MemoryManagerNamespace::report(bool leak) +{ + DEBUG_FATAL(!ms_installed, ("not installed")); + + int count = 0; + ms_criticalSection->enter(); + + // search for the memory pointer + for (SystemAllocation * systemAllocation = ms_firstSystemAllocation; systemAllocation; systemAllocation = systemAllocation->getNext()) + for (Block * block = systemAllocation->getFirstMemoryBlock()->getNext(); block != systemAllocation->getLastMemoryBlock(); block = block->getNext()) + if (!block->isFree()) + { +#if DO_TRACK + if (!leak || static_cast(block)->checkForLeaks()) +#else + if (!leak) +#endif + { + report(static_cast(block), leak); + ++count; + } + } + + ms_criticalSection->leave(); + + return count; +} + +// ---------------------------------------------------------------------- +/** + * Dump information about all outstanding allocations. + */ + +void MemoryManager::report() +{ + IGNORE_RETURN(MemoryManagerNamespace::report(false)); +} + +//----------------------------------------------------------------------- + +void MemoryManagerNamespace::logMessageToFd(char const *message) +{ + if (ms_logMessageFd >= 0) + _write(ms_logMessageFd, message, strlen(message)); +} + +//----------------------------------------------------------------------- + +bool MemoryManagerNamespace::reportToFile(char const *fileName, bool leak) +{ + if (ms_logMessageFd >= 0) + return false; + + ms_logMessageFd = _open(fileName, O_CREAT | O_TRUNC | O_WRONLY, S_IREAD | S_IWRITE); + if (ms_logMessageFd < 0) + return false; + + void (*oldLogMessage)(char const * message) = LogMessage; + LogMessage = &logMessageToFd; + + report(leak); + + LogMessage = oldLogMessage; + + _close(ms_logMessageFd); + ms_logMessageFd = -1; + + return true; +} + +//----------------------------------------------------------------------- + +bool MemoryManager::reportToFile(char const *fileName, bool leak) +{ + return MemoryManagerNamespace::reportToFile(fileName, leak); +} + +// ====================================================================== +// DISABLE_MEMORY_MANAGER +#else +// ====================================================================== +namespace MemoryManagerNamespace +{ + // Memory tracking variables avialble when memory manger is running + // in disabled mode for linux + int ms_allocateCalls; + int ms_freeCalls; + unsigned long ms_allocateBytesTotal; +#ifndef _WIN32 + int ms_processVmSizeKBytes; +#endif + unsigned long ms_maxBytesAllocated; + int ms_allocations; + int ms_maxAllocations; + bool ms_installed; + + struct Statm //cache for /proc/statm data + { + int tpsr; //total program size resident + int rss; //resident set size share + }; + + Statm s_statm; + int s_pagesize; + + RecursiveMutex * ms_criticalSection; +} + +using namespace MemoryManagerNamespace; + +// ---------------------------------------------------------------------- + +MemoryManager::MemoryManager() +{ + // Initialize all memory tracking vars + MemoryManagerNamespace::ms_allocateCalls = 0; + MemoryManagerNamespace::ms_freeCalls = 0; + MemoryManagerNamespace::ms_allocateBytesTotal = 0; +#ifndef _WIN32 + MemoryManagerNamespace::ms_processVmSizeKBytes = 0; +#endif + MemoryManagerNamespace::ms_maxBytesAllocated = 0; + MemoryManagerNamespace::ms_allocations = 0; + MemoryManagerNamespace::ms_maxAllocations= 0; + + DEBUG_FATAL(MemoryManagerNamespace::ms_installed, ("already installed")); + + ms_criticalSection = new RecursiveMutex; + + MemoryManagerNamespace::ms_installed = true; + +#if defined(PLATFORM_WIN32) && defined(_DEBUG) + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_WNDW); + + int crtHeapFlags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); + crtHeapFlags |= _CRTDBG_ALLOC_MEM_DF; + //crtHeapFlags |= _CRTDBG_CHECK_ALWAYS_DF; + crtHeapFlags |= _CRTDBG_LEAK_CHECK_DF; + _CrtSetDbgFlag(crtHeapFlags); +#endif +} + +// ---------------------------------------------------------------------- + +MemoryManager::~MemoryManager() +{ + delete ms_criticalSection; +} + +// ---------------------------------------------------------------------- + +void MemoryManager::verify(bool, bool) +{ +#if defined(PLATFORM_WIN32) && defined(_DEBUG) + const int result = _CrtCheckMemory(); + FATAL(result==FALSE, ("Heap corruption detected!\n")); +#endif +} + +// ---------------------------------------------------------------------- + +unsigned long MemoryManager::getCurrentNumberOfBytesAllocated(const int processId) +{ + +#ifdef _WIN32 + UNREF(processId); + return 0; +#else + + static char filename[30]; + static FILE *inStatmFile; + static time_t seconds = 0; + + unsigned long retVal = 0; + + ms_criticalSection->enter(); + + if (processId) + { + if ((time (0) - seconds) > 60 ) + { + if (seconds == 0) + { + snprintf(filename, sizeof(filename)-1, "/proc/%d/statm", processId); + filename[sizeof(filename)-1] = '\0'; + s_pagesize = getpagesize(); + } + + seconds = time (0); + + inStatmFile = fopen(filename,"rt"); + + if (inStatmFile) + { + if (fscanf (inStatmFile, "%d %d", &s_statm.tpsr, &s_statm.rss) == 2) + { + retVal = static_cast(s_statm.tpsr) * static_cast(s_pagesize); + } + else + { + retVal = 0; + } + fclose(inStatmFile); + } + else + { + retVal = 0; + } + } + else + { + retVal = static_cast(s_statm.tpsr) * static_cast(s_pagesize); + } + } + + ms_criticalSection->leave(); + + return retVal; +#endif +} + +// ---------------------------------------------------------------------- + +unsigned long MemoryManager::getCurrentNumberOfBytesAllocatedNoLeakTest() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +unsigned long MemoryManager::getMaximumNumberOfBytesAllocated() +{ +#ifdef _WIN32 + return 0; +#else + return MemoryManagerNamespace::ms_maxBytesAllocated; +#endif +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getSystemMemoryAllocatedMegabytes() +{ + return 0; +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getCurrentNumberOfAllocations() +{ +#ifdef _WIN32 + return 0; +#else + return MemoryManagerNamespace::ms_allocations; +#endif +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getMaximumNumberOfAllocations() +{ +#ifdef _WIN32 + return 0; +#else + return MemoryManagerNamespace::ms_maxAllocations; +#endif +} + +// ---------------------------------------------------------------------- + +void MemoryManager::setLimit(int, bool, bool) +{ +} + +// ---------------------------------------------------------------------- + +int MemoryManager::getLimit() +{ + return 768; +} + +// ---------------------------------------------------------------------- + +void MemoryManager::own(void * userPointer) +{ + UNREF(userPointer); +// __asm int 3; +} + +// ---------------------------------------------------------------------- + +void MemoryManager::setReportAllocations(bool) +{ +} + +// ---------------------------------------------------------------------- + +void MemoryManager::registerDebugFlags() +{ +} + +// ---------------------------------------------------------------------- + +void MemoryManager::report() +{ +} + +// ---------------------------------------------------------------------- + +void * MemoryManager::allocate(size_t size, uint32, bool, bool) +{ +#ifdef _WIN32 + return _malloc_dbg(size, _NORMAL_BLOCK, __FILE__, __LINE__); + //return (void *)LocalAlloc(LMEM_FIXED, size); +#else + return ::malloc(size); +#endif +} + +// ---------------------------------------------------------------------- + +void MemoryManager::free(void * userPointer, bool) +{ +#ifdef _WIN32 + _free_dbg(userPointer, _NORMAL_BLOCK); + //LocalFree((HLOCAL)userPointer); +#else + ::free(userPointer); + +#endif +} + +// ---------------------------------------------------------------------- + +void *MemoryManager::reallocate(void *userPointer, size_t newSize) +{ +#ifdef _WIN32 + return _realloc_dbg(userPointer, newSize, _NORMAL_BLOCK, __FILE__, __LINE__); + //return (void *)LocalReAlloc((HLOCAL)userPointer, newSize, 0); +#else + return ::realloc(userPointer, newSize); +#endif +} + +// ---------------------------------------------------------------------- + +void MemoryManager::debugReport(void) +{ + +} + +// ---------------------------------------------------------------------- + +void MemoryManager::debugReportMap(void) +{ + +} +#endif + +// ---------------------------------------------------------------------- +// this function is available regardless of the DISABLE_MEMORY_MANAGER setting + +#ifndef _WIN32 +int MemoryManager::getProcessVmSizeKBytes(const int processId) +{ + static char filename[30]; + static FILE *inStatusFile; + static char buffer[128]; + static time_t seconds = 0; + + ms_criticalSection->enter(); + + if (processId) + { + if ((time (0) - seconds) > 60) + { + MemoryManagerNamespace::ms_processVmSizeKBytes = 0; + + if (seconds == 0) + { + snprintf(filename, sizeof(filename)-1, "/proc/%d/status", processId); + filename[sizeof(filename)-1] = '\0'; + } + + seconds = time(0); + + inStatusFile = fopen(filename,"rt"); + + if (inStatusFile) + { + int temp; + + while (fgets(buffer, sizeof(buffer), inStatusFile)) + { + if (1 == sscanf(buffer, "VmSize: %d", &temp)) + { + MemoryManagerNamespace::ms_processVmSizeKBytes = temp; + break; + } + } + + fclose(inStatusFile); + } + } + } + + ms_criticalSection->leave(); + + return MemoryManagerNamespace::ms_processVmSizeKBytes; +} +#endif + +// ====================================================================== diff --git a/src/engine/shared/library/sharedNetwork/src/linux/NetworkGetHostName.cpp b/src/engine/shared/library/sharedNetwork/src/linux/NetworkGetHostName.cpp index aeaf66bff..f9884aca0 100644 --- a/src/engine/shared/library/sharedNetwork/src/linux/NetworkGetHostName.cpp +++ b/src/engine/shared/library/sharedNetwork/src/linux/NetworkGetHostName.cpp @@ -1,141 +1,141 @@ -// NetworkGetHostName.cpp -// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. -// Author: Justin Randall - -//----------------------------------------------------------------------- - -#include "FirstSharedNetwork.h" -#include "Address.h" -#include "sharedNetwork/NetworkHandler.h" -#include -#include -#include -#include -#include -#include -#include - -//----------------------------------------------------------------------- - -struct HN -{ - HN(); - std::string hostName; -}; - -//----------------------------------------------------------------------- - -HN::HN() -{ - char name[512] = {"\0"}; - if(gethostname(name, sizeof(name)) == 0) - { - Address a(name, 0); - //hostName = name; - hostName = a.getHostAddress(); - } -} - -//----------------------------------------------------------------------- - -const std::string & NetworkHandler::getHostName() -{ - static HN hn; - return hn.hostName; -} - -//----------------------------------------------------------------------- - -const std::string & NetworkHandler::getHumanReadableHostName() -{ - char name[512] = {"\0"}; - static std::string nameString; - if(nameString.empty()) - { - if(gethostname(name, sizeof(name)) == 0) - { - name[sizeof(name) - 1] = 0; - //hostName = name; - nameString = name; - } - } - return nameString; -} - -//----------------------------------------------------------------------- - -struct HL -{ - HL(); - std::vector > addrList; -}; - -//----------------------------------------------------------------------- - -HL::HL() : -addrList() -{ - struct ifconf ifc; - int sock = socket(AF_INET, SOCK_DGRAM, 0); - - // create a socket to perform SIOCGIFCONF on - if(sock > -1) - { - // determine buffer size to receive array of if_req's, initialize it - // when length is appropriate - int reqSize = 100 * sizeof(struct ifreq); - int lastReqSize = reqSize; - for(;;) - { - char * buf = new char[reqSize]; - ifc.ifc_len = reqSize; - ifc.ifc_buf = buf; - memset(ifc.ifc_buf, 0, reqSize); - if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) - { - if (errno != EINVAL || lastReqSize != 0) - { - WARNING(true, ("Error getting interface list: %s", strerror(errno))); - delete[] buf; - return; - } - } - else - { - if(ifc.ifc_len == lastReqSize) - break; // we have the reqs - lastReqSize = ifc.ifc_len; - } - - // need more buffer space for request - reqSize += sizeof(struct ifreq); - delete [] buf; - } - - int reqCount = reqSize / sizeof(struct ifreq); - int i; - ifreq * reqs = (struct ifreq *)ifc.ifc_buf; - for(i = 0; i < reqCount; ++i) - { - struct sockaddr_in * sa = (struct sockaddr_in *)&reqs[i].ifr_addr; - if(sa->sin_family == AF_INET) - { - char addrbuf[17] = {"\0"}; - unsigned char * a = (unsigned char *)&sa->sin_addr; - snprintf(addrbuf, sizeof(addrbuf), "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); - addrList.push_back(std::make_pair(std::string(reqs[i].ifr_name), std::string(addrbuf))); - } - } - - } -} - -//----------------------------------------------------------------------- - -const std::vector > & NetworkHandler::getInterfaceAddresses() -{ - static HL hl; - return hl.addrList; -} - -//----------------------------------------------------------------------- +// NetworkGetHostName.cpp +// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "FirstSharedNetwork.h" +#include "Address.h" +#include "sharedNetwork/NetworkHandler.h" +#include +#include +#include +#include +#include +#include +#include + +//----------------------------------------------------------------------- + +struct HN +{ + HN(); + std::string hostName; +}; + +//----------------------------------------------------------------------- + +HN::HN() +{ + char name[512] = {"\0"}; + if(gethostname(name, sizeof(name)) == 0) + { + Address a(name, 0); + //hostName = name; + hostName = a.getHostAddress(); + } +} + +//----------------------------------------------------------------------- + +const std::string & NetworkHandler::getHostName() +{ + static HN hn; + return hn.hostName; +} + +//----------------------------------------------------------------------- + +const std::string & NetworkHandler::getHumanReadableHostName() +{ + char name[512] = {"\0"}; + static std::string nameString; + if(nameString.empty()) + { + if(gethostname(name, sizeof(name)) == 0) + { + name[sizeof(name) - 1] = 0; + //hostName = name; + nameString = name; + } + } + return nameString; +} + +//----------------------------------------------------------------------- + +struct HL +{ + HL(); + std::vector > addrList; +}; + +//----------------------------------------------------------------------- + +HL::HL() : +addrList() +{ + struct ifconf ifc; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + + // create a socket to perform SIOCGIFCONF on + if(sock > -1) + { + // determine buffer size to receive array of if_req's, initialize it + // when length is appropriate + int reqSize = 100 * sizeof(struct ifreq); + int lastReqSize = reqSize; + for(;;) + { + char * buf = new char[reqSize]; + ifc.ifc_len = reqSize; + ifc.ifc_buf = buf; + memset(ifc.ifc_buf, 0, reqSize); + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) + { + if (errno != EINVAL || lastReqSize != 0) + { + WARNING(true, ("Error getting interface list: %s", strerror(errno))); + delete[] buf; + return; + } + } + else + { + if(ifc.ifc_len == lastReqSize) + break; // we have the reqs + lastReqSize = ifc.ifc_len; + } + + // need more buffer space for request + reqSize += sizeof(struct ifreq); + delete [] buf; + } + + int reqCount = reqSize / sizeof(struct ifreq); + int i; + ifreq * reqs = (struct ifreq *)ifc.ifc_buf; + for(i = 0; i < reqCount; ++i) + { + struct sockaddr_in * sa = (struct sockaddr_in *)&reqs[i].ifr_addr; + if(sa->sin_family == AF_INET) + { + char addrbuf[17] = {"\0"}; + unsigned char * a = (unsigned char *)&sa->sin_addr; + snprintf(addrbuf, sizeof(addrbuf), "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); + addrList.push_back(std::make_pair(std::string(reqs[i].ifr_name), std::string(addrbuf))); + } + } + + } +} + +//----------------------------------------------------------------------- + +const std::vector > & NetworkHandler::getInterfaceAddresses() +{ + static HL hl; + return hl.addrList; +} + +//----------------------------------------------------------------------- diff --git a/src/engine/shared/library/sharedNetwork/src/shared/UdpLibraryMT/UdpConnectionMT.cpp b/src/engine/shared/library/sharedNetwork/src/shared/UdpLibraryMT/UdpConnectionMT.cpp index ce7159f25..9b7b72824 100644 --- a/src/engine/shared/library/sharedNetwork/src/shared/UdpLibraryMT/UdpConnectionMT.cpp +++ b/src/engine/shared/library/sharedNetwork/src/shared/UdpLibraryMT/UdpConnectionMT.cpp @@ -18,6 +18,7 @@ class UdpConnectionHandlerInternal: public UdpConnectionHandler { public: UdpConnectionHandlerInternal(); + virtual ~UdpConnectionHandlerInternal(); void setOwner(UdpConnectionHandlerMT *owner); void processReceive(UdpConnectionMT *conMT, unsigned char const *data, int dataLen); @@ -43,6 +44,8 @@ UdpConnectionHandlerInternal::UdpConnectionHandlerInternal() : { } +UdpConnectionHandlerInternal::~UdpConnectionHandlerInternal(){} + // ---------------------------------------------------------------------- void UdpConnectionHandlerInternal::setOwner(UdpConnectionHandlerMT *owner) diff --git a/src/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp b/src/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp index 9ae447a43..e09b9c37a 100644 --- a/src/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp +++ b/src/engine/shared/library/sharedObject/src/shared/object/AlterScheduler.cpp @@ -1184,7 +1184,7 @@ void AlterScheduler::moveObjectsFromAlterNextFrameListToAlterNowList(int schedul { PROFILER_AUTO_BLOCK_DEFINE("copy next frame"); - if (s_alterNextFrameListFirst != NULL) { + //if (s_alterNextFrameListFirst != NULL) { for (Object *object = s_alterNextFrameListFirst[schedulePhaseIndex]->getNextFromAlterNextFrameList(); object != NULL; ) { //-- Add object to alter now list. This removes the object from the alter next frame list. @@ -1203,7 +1203,7 @@ void AlterScheduler::moveObjectsFromAlterNextFrameListToAlterNowList(int schedul //-- Increment loop. object = nextObject; } - } + //} } } diff --git a/src/engine/shared/library/sharedRemoteDebugServer/src/shared/SharedRemoteDebugServer.cpp b/src/engine/shared/library/sharedRemoteDebugServer/src/shared/SharedRemoteDebugServer.cpp index 470ea97d3..0e305c96e 100644 --- a/src/engine/shared/library/sharedRemoteDebugServer/src/shared/SharedRemoteDebugServer.cpp +++ b/src/engine/shared/library/sharedRemoteDebugServer/src/shared/SharedRemoteDebugServer.cpp @@ -1,101 +1,101 @@ -// ====================================================================== -// -// SharedRemoteDebugServer.cpp -// Copyright 2002 Sony Online Entertainment -// -// ====================================================================== - -#include "sharedRemoteDebugServer/FirstSharedRemoteDebugServer.h" -#include "Archive/ByteStream.h" -#include "sharedRemoteDebugServer/SharedRemoteDebugServer.h" -#include "sharedRemoteDebugServer/SharedRemoteDebugServerConnection.h" -#include "sharedFoundation/ConfigSharedFoundation.h" -#include "sharedNetwork/Service.h" -#include "sharedNetwork/Connection.h" -#include "sharedNetwork/NetworkSetupData.h" -#include "sharedDebug/RemoteDebug_inner.h" - -//------------------------------------------------------------------- - -//static definitions -Service * SharedRemoteDebugServer::ms_serviceHandle; -SharedRemoteDebugServerConnection * SharedRemoteDebugServer::ms_connection; -bool SharedRemoteDebugServer::ms_installed; -unsigned int SharedRemoteDebugServer::ms_remoteDebugToolChannelID; - -//------------------------------------------------------------------- - -void SharedRemoteDebugServer::install() -{ - ms_serviceHandle = NULL; - ms_connection = NULL; - - if (!ConfigSharedFoundation::getUseRemoteDebug()) - return; - - DEBUG_FATAL(ms_installed, ("sharedRemoteDebugServer already installed")); - - NetworkSetupData setup; - setup.port = static_cast(ConfigSharedFoundation::getDefaultRemoteDebugPort()); - setup.maxConnections = 5; - ms_serviceHandle = new Service(ConnectionAllocator(), setup); - - //even though this is the game client, this is a remoteDebug *server*, since it sends data to a Qt app for viewing - RemoteDebugServer::install(NULL, open, close, send, NULL); - - //this value needs to be true before the call to RemoteDebugServer::open - ms_installed = true; - - //try to connect to a localhost instance of the remotedebug app - RemoteDebugServer::open("127.0.0.1", 4444); -} - -//------------------------------------------------------------------- - -void SharedRemoteDebugServer::remove(void) -{ - if(!ms_installed) - return; - - close(); - - NOT_NULL(ms_serviceHandle); - delete ms_serviceHandle; - delete ms_connection; - - RemoteDebugServer::remove(); - ms_installed = false; -} - -//------------------------------------------------------------------- - -void SharedRemoteDebugServer::open(const char *server, uint16 port) -{ - DEBUG_FATAL(!ms_installed, ("sharedRemoteDebugServer not installed")); - - //attempt to auto-connect to a localhost client app (if it's auto-listening) - - ms_connection = new SharedRemoteDebugServerConnection(server, port); -} - -//------------------------------------------------------------------- - -void SharedRemoteDebugServer::close(void) -{ - DEBUG_FATAL(!ms_installed, ("sharedRemoteDebugServer not installed")); - delete ms_connection; - ms_connection = NULL; -} - -//------------------------------------------------------------------- - -void SharedRemoteDebugServer::send(void *buffer, uint32 bufferLen) -{ - DEBUG_FATAL(!ms_installed, ("sharedRemoteDebugServer not installed")); - - NOT_NULL(ms_connection); - ms_connection->send(Archive::ByteStream(reinterpret_cast(buffer), bufferLen), false); - //always send on VNL channel 0, send the buffer, it's length, and unreliable -} - -//------------------------------------------------------------------- +// ====================================================================== +// +// SharedRemoteDebugServer.cpp +// Copyright 2002 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedRemoteDebugServer/FirstSharedRemoteDebugServer.h" +#include "Archive/ByteStream.h" +#include "sharedRemoteDebugServer/SharedRemoteDebugServer.h" +#include "sharedRemoteDebugServer/SharedRemoteDebugServerConnection.h" +#include "sharedFoundation/ConfigSharedFoundation.h" +#include "sharedNetwork/Service.h" +#include "sharedNetwork/Connection.h" +#include "sharedNetwork/NetworkSetupData.h" +#include "sharedDebug/RemoteDebug_inner.h" + +//------------------------------------------------------------------- + +//static definitions +Service * SharedRemoteDebugServer::ms_serviceHandle; +SharedRemoteDebugServerConnection * SharedRemoteDebugServer::ms_connection; +bool SharedRemoteDebugServer::ms_installed; +unsigned int SharedRemoteDebugServer::ms_remoteDebugToolChannelID; + +//------------------------------------------------------------------- + +void SharedRemoteDebugServer::install() +{ + ms_serviceHandle = NULL; + ms_connection = NULL; + + if (!ConfigSharedFoundation::getUseRemoteDebug()) + return; + + DEBUG_FATAL(ms_installed, ("sharedRemoteDebugServer already installed")); + + NetworkSetupData setup; + setup.port = static_cast(ConfigSharedFoundation::getDefaultRemoteDebugPort()); + setup.maxConnections = 5; + ms_serviceHandle = new Service(ConnectionAllocator(), setup); + + //even though this is the game client, this is a remoteDebug *server*, since it sends data to a Qt app for viewing + RemoteDebugServer::install(NULL, open, close, send, NULL); + + //this value needs to be true before the call to RemoteDebugServer::open + ms_installed = true; + + //try to connect to a localhost instance of the remotedebug app + RemoteDebugServer::open("127.0.0.1", 4444); +} + +//------------------------------------------------------------------- + +void SharedRemoteDebugServer::remove(void) +{ + if(!ms_installed) + return; + + close(); + + NOT_NULL(ms_serviceHandle); + delete ms_serviceHandle; + delete ms_connection; + + RemoteDebugServer::remove(); + ms_installed = false; +} + +//------------------------------------------------------------------- + +void SharedRemoteDebugServer::open(const char *server, uint16 port) +{ + DEBUG_FATAL(!ms_installed, ("sharedRemoteDebugServer not installed")); + + //attempt to auto-connect to a localhost client app (if it's auto-listening) + + ms_connection = new SharedRemoteDebugServerConnection(server, port); +} + +//------------------------------------------------------------------- + +void SharedRemoteDebugServer::close(void) +{ + DEBUG_FATAL(!ms_installed, ("sharedRemoteDebugServer not installed")); + delete ms_connection; + ms_connection = NULL; +} + +//------------------------------------------------------------------- + +void SharedRemoteDebugServer::send(void *buffer, uint32 bufferLen) +{ + DEBUG_FATAL(!ms_installed, ("sharedRemoteDebugServer not installed")); + + NOT_NULL(ms_connection); + ms_connection->send(Archive::ByteStream(reinterpret_cast(buffer), bufferLen), false); + //always send on VNL channel 0, send the buffer, it's length, and unreliable +} + +//------------------------------------------------------------------- diff --git a/src/engine/shared/library/sharedSkillSystem/src/shared/SkillManager.h b/src/engine/shared/library/sharedSkillSystem/src/shared/SkillManager.h index 46c5cd4d8..61f552741 100644 --- a/src/engine/shared/library/sharedSkillSystem/src/shared/SkillManager.h +++ b/src/engine/shared/library/sharedSkillSystem/src/shared/SkillManager.h @@ -1,62 +1,62 @@ -// SkillManager.h -// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. -// Author: Justin Randall - -#ifndef _SkillManager_H -#define _SkillManager_H - -#include - -//--------------------------------------------------------------------- -#pragma warning (disable : 4786 ) - -class SkillObject; -class DataTable; - -//--------------------------------------------------------------------- - -class SkillManager -{ -public: - typedef stdunordered_map::fwd SkillMap; - typedef stdunordered_map::fwd XpLimitMap; - - virtual ~SkillManager (); - - const SkillObject * getSkill (const std::string & skillName); - const SkillMap & getSkillMap () const; - const SkillObject * getRoot (); - uint32 getDefaultXpLimit(const std::string & experienceType); - - static SkillManager & getInstance (); - - static void install (); - static void remove (); - -protected: - SkillManager (); -private: - SkillManager (const SkillManager & source); - SkillManager & operator = (const SkillManager & rhs); - const SkillObject * loadSkill (const std::string & skillName); - void initXpLimits (); - -private: - SkillMap * m_skillMap; - DataTable * m_skillTable; - XpLimitMap * m_xpLimitMap; - DataTable * m_xpLimitTable; - static SkillManager * ms_instance; - static const std::string & cms_skillsDatatableName; -}; - -//----------------------------------------------------------------------- - -inline const SkillManager::SkillMap & SkillManager::getSkillMap() const -{ - return *(m_skillMap); -} - -//--------------------------------------------------------------------- - -#endif // _SkillManager_H +// SkillManager.h +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +#ifndef _SkillManager_H +#define _SkillManager_H + +#include + +//--------------------------------------------------------------------- +#pragma warning (disable : 4786 ) + +class SkillObject; +class DataTable; + +//--------------------------------------------------------------------- + +class SkillManager +{ +public: + typedef stdunordered_map::fwd SkillMap; + typedef stdunordered_map::fwd XpLimitMap; + + virtual ~SkillManager (); + + const SkillObject * getSkill (const std::string & skillName); + const SkillMap & getSkillMap () const; + const SkillObject * getRoot (); + uint32 getDefaultXpLimit(const std::string & experienceType); + + static SkillManager & getInstance (); + + static void install (); + static void remove (); + +protected: + SkillManager (); +private: + SkillManager (const SkillManager & source); + SkillManager & operator = (const SkillManager & rhs); + const SkillObject * loadSkill (const std::string & skillName); + void initXpLimits (); + +private: + SkillMap * m_skillMap; + DataTable * m_skillTable; + XpLimitMap * m_xpLimitMap; + DataTable * m_xpLimitTable; + static SkillManager * ms_instance; + static const std::string & cms_skillsDatatableName; +}; + +//----------------------------------------------------------------------- + +inline const SkillManager::SkillMap & SkillManager::getSkillMap() const +{ + return *(m_skillMap); +} + +//--------------------------------------------------------------------- + +#endif // _SkillManager_H diff --git a/src/engine/shared/library/sharedSkillSystem/src/shared/SkillObject.cpp b/src/engine/shared/library/sharedSkillSystem/src/shared/SkillObject.cpp index 33624d545..4a86abb49 100644 --- a/src/engine/shared/library/sharedSkillSystem/src/shared/SkillObject.cpp +++ b/src/engine/shared/library/sharedSkillSystem/src/shared/SkillObject.cpp @@ -1,556 +1,556 @@ -// SkillObject.cpp -// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. -// Author: Justin Randall - -//----------------------------------------------------------------------- - -#include "sharedSkillSystem/FirstSharedSkillSystem.h" -#include "sharedSkillSystem/SkillObject.h" - -#include "sharedSkillSystem/SkillManager.h" -#include "sharedUtility/DataTable.h" - -#include "UnicodeUtils.h" - -#include - -const std::string SkillObject::ms_skillLabel = "NAME"; -const std::string SkillObject::ms_prerequisiteSkillsLabel = "SKILLS_REQUIRED"; -const std::string SkillObject::ms_prerequisiteExperienceTypeLabel = "XP_TYPE"; -const std::string SkillObject::ms_prerequisiteExperienceAmountLabel = "XP_COST"; -const std::string SkillObject::ms_prerequisiteExperienceLimitLabel = "XP_CAP"; -const std::string SkillObject::ms_prerequisiteSpeciesLabel = "SPECIES_REQUIRED"; -const std::string SkillObject::ms_commandsLabel = "COMMANDS"; -const std::string SkillObject::ms_statisticsModifiersLabel = "SKILL_MODS"; -const std::string SkillObject::ms_parentLabel = "PARENT"; -const std::string SkillObject::ms_schematicsGrantedLabel = "SCHEMATICS_GRANTED"; -const std::string SkillObject::ms_isTitleLabel = "IS_TITLE"; -const std::string SkillObject::ms_isProfessionLabel = "IS_PROFESSION"; -const std::string SkillObject::ms_isSearchableLabel = "SEARCHABLE"; - -//----------------------------------------------------------------- - -namespace -{ - int s_recursionCountDepends = 0; - const int s_recursionCountDependsMax = 7; - - //---------------------------------------------------------------------- - - typedef stdvector::fwd StringVector; - inline void tokenizeList (const std::string & str, StringVector & sv, int row, const std::string & columnName) - { - UNREF (row); - UNREF (columnName); - - size_t endpos = 0; - std::string token; - static const char * const whitespace = ","; - - DEBUG_WARNING (str.find (" \n\r\t") != std::string::npos, ("SkillObject Cell string [%s] row %d column [%s] contains spaces or other invalid characters", row, columnName.c_str ())); - - while (Unicode::getFirstToken (str, endpos, endpos, token, whitespace)) - { - sv.push_back (token); - if (endpos == std::string::npos) - break; - - ++endpos; - } - } -} - -//--------------------------------------------------------------------- - -SkillObject::SkillData::SkillData() : -prerequisiteSkills (), -prerequisiteExperience (), -prerequisiteSpecies (), -prerequisiteFactionStanding (), -skillName ("UNINITIALIZED SKILL"), -nextSkillBoxes (), -prevSkill (0), -commandsProvided (), -schematicsGranted (), -statisticModifiers (), -isProfession (false), -isTitle (false), -isSearchable (false) -{ -} - -//--------------------------------------------------------------------- - -SkillObject::SkillData::SkillData(const SkillData & source) : -prerequisiteSkills (source.prerequisiteSkills), -prerequisiteExperience (source.prerequisiteExperience), -prerequisiteSpecies (source.prerequisiteSpecies), -prerequisiteFactionStanding (source.prerequisiteFactionStanding), -skillName (source.skillName), -nextSkillBoxes (source.nextSkillBoxes), -prevSkill (0), -commandsProvided (source.commandsProvided), -schematicsGranted (source.schematicsGranted), -statisticModifiers (source.statisticModifiers), -isProfession (source.isProfession), -isTitle (source.isTitle), -isSearchable (source.isSearchable) -{ -} - -//--------------------------------------------------------------------- - -SkillObject::SkillData::~SkillData() -{ -} - -//--------------------------------------------------------------------- - -SkillObject::SkillData & SkillObject::SkillData::operator = (const SkillData & rhs) -{ - if(&rhs != this) - { - prerequisiteSkills = rhs.prerequisiteSkills; - prerequisiteExperience = rhs.prerequisiteExperience; - prerequisiteSpecies = rhs.prerequisiteSpecies; - prerequisiteFactionStanding = rhs.prerequisiteFactionStanding; - skillName = rhs.skillName; - nextSkillBoxes = rhs.nextSkillBoxes; - commandsProvided = rhs.commandsProvided; - schematicsGranted = rhs.schematicsGranted; - statisticModifiers = rhs.statisticModifiers; - isProfession = rhs.isProfession; - isTitle = rhs.isTitle; - isSearchable = rhs.isSearchable; - } - return *this; -} - -//--------------------------------------------------------------------- - -SkillObject::SkillObject() : -skillData() -{ -} - -//--------------------------------------------------------------------- - -SkillObject::~SkillObject() -{ -} - -//--------------------------------------------------------------------- - -const SkillObject::SkillVector & SkillObject::getNextSkillBoxes() const -{ - return skillData.nextSkillBoxes; -} - -//----------------------------------------------------------------------- - -const SkillObject * SkillObject::getPrevSkill() const -{ - return skillData.prevSkill; -} - -//--------------------------------------------------------------------- - -const SkillObject::SkillData & SkillObject::getSkillData() const -{ - return skillData; -} - -//--------------------------------------------------------------------- - -const SkillObject::ExperienceVector & SkillObject::getPrerequisiteExperienceVector () const -{ - return skillData.prerequisiteExperience; -} - -//----------------------------------------------------------------- - -const SkillObject::ExperiencePair * SkillObject::getPrerequisiteExperience () const -{ - if (skillData.prerequisiteExperience.empty ()) - return 0; - else - return &skillData.prerequisiteExperience.front (); -} - -//--------------------------------------------------------------------- - -const SkillObject::SpeciesFlagVector & SkillObject::getPrerequisiteSpecies() const -{ - return skillData.prerequisiteSpecies; -} - -//--------------------------------------------------------------------- - -const SkillObject::GenericModVector & SkillObject::getPrerequisiteFactionStanding() const -{ - return skillData.prerequisiteFactionStanding; -} - -//--------------------------------------------------------------------- - -const SkillObject::SkillVector & SkillObject::getPrerequisiteSkills() const -{ - return skillData.prerequisiteSkills; -} - -//--------------------------------------------------------------------- - -const std::string & SkillObject::getSkillName() const -{ - return skillData.skillName; -} - -//--------------------------------------------------------------------- - -const SkillObject::StringVector & SkillObject::getCommandsProvided() const -{ - return skillData.commandsProvided; -} - -//--------------------------------------------------------------------- - -const SkillObject::StringVector & SkillObject::getSchematicsGranted() const -{ - return skillData.schematicsGranted; -} - -//--------------------------------------------------------------------- - -const std::vector > & SkillObject::getStatisticModifiers() const -{ - return skillData.statisticModifiers; -} - -//----------------------------------------------------------------------- - -SkillObject::SkillData & SkillObject::getSkillData() -{ - return skillData; -} - -//----------------------------------------------------------------------- - -const bool SkillObject::hasCommand(const std::string & commandName) const -{ - return std::binary_search (skillData.commandsProvided.begin (), skillData.commandsProvided.end (), commandName); -} - -//----------------------------------------------------------------------- -/** get primary category for this skill */ - -const SkillObject * SkillObject::findCategory() const -{ - const SkillObject * p = this; - - for (;;) - { - if (p) - { - //-- the categories are at the 2nd level of the heirarchy - - if (p->skillData.prevSkill && p->skillData.prevSkill->skillData.prevSkill == 0) - { - return p; - } - - p = p->skillData.prevSkill; - } - else - { - break; - } - } - - return 0; -} - -//----------------------------------------------------------------------- - -const bool SkillObject::isProfession() const -{ - return skillData.isProfession; -} - -//----------------------------------------------------------------------- - -const bool SkillObject::isTitle() const -{ - return skillData.isTitle; -} - -//----------------------------------------------------------------------- - -const bool SkillObject::isSearchable() const -{ - return skillData.isSearchable; -} - -//--------------------------------------------------------------------- - -void SkillObject::loadPrerequisiteSkills(DataTable &dataTable, int skillRow) -{ - const std::string & cellString = dataTable.getStringValue(SkillObject::ms_prerequisiteSkillsLabel, skillRow); - StringVector sv; - sv.clear (); - tokenizeList (cellString, sv, skillRow, SkillObject::ms_prerequisiteSkillsLabel); - skillData.prerequisiteSkills.reserve (sv.size ()); - - SkillManager & manager = SkillManager::getInstance (); - - for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) - { - const std::string & skillName = *it; - const SkillObject * const skill = manager.getSkill (skillName); - if (skill) - skillData.prerequisiteSkills.push_back(skill); - else - WARNING (true, ("prerequisiteSkills skill [%s] does not exist", skillName.c_str ())); - } - - std::sort (skillData.prerequisiteSkills.begin (), skillData.prerequisiteSkills.end ()); -} - -//---------------------------------------------------------------------- - -void SkillObject::loadPrerequisiteExperience(DataTable &dataTable, int skillRow) -{ - const int xpAmount = dataTable.getIntValue(SkillObject::ms_prerequisiteExperienceAmountLabel, skillRow); - const int xpLimit = dataTable.getIntValue(SkillObject::ms_prerequisiteExperienceLimitLabel, skillRow); - if (xpAmount > 0 || xpLimit > 0) - { - const std::string & experienceType = dataTable.getStringValue(SkillObject::ms_prerequisiteExperienceTypeLabel, skillRow); - if (!experienceType.empty ()) - skillData.prerequisiteExperience.push_back(std::make_pair(experienceType, std::make_pair(xpAmount, xpLimit))); - else - WARNING (true, ("Nonzero experience specified but empty experience name on row %d", skillRow)); - } -} - -//--------------------------------------------------------------------- - -void SkillObject::loadPrerequisiteSpecies(DataTable &dataTable, int skillRow) -{ - const std::string & cellString = dataTable.getStringValue(SkillObject::ms_prerequisiteSpeciesLabel, skillRow); - static StringVector sv; - sv.clear (); - tokenizeList (cellString, sv, skillRow, SkillObject::ms_prerequisiteSpeciesLabel); - skillData.prerequisiteSpecies.reserve (sv.size ()); - - for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) - skillData.prerequisiteSpecies.push_back (std::make_pair (*it, true)); -} - -//--------------------------------------------------------------------- - -void SkillObject::loadCommands(DataTable &dataTable, int skillRow) -{ - const std::string & cellString = dataTable.getStringValue(SkillObject::ms_commandsLabel, skillRow); - static StringVector sv; - sv.clear (); - tokenizeList (cellString, sv, skillRow, SkillObject::ms_commandsLabel); - skillData.commandsProvided.reserve (sv.size ()); - - for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) - skillData.commandsProvided.push_back (*it); - - std::sort (skillData.commandsProvided.begin (), skillData.commandsProvided.end ()); -} - -//--------------------------------------------------------------------- - -void SkillObject::loadSchematicsGranted(DataTable &dataTable, int skillRow) -{ - const std::string & cellString = dataTable.getStringValue(SkillObject::ms_schematicsGrantedLabel, skillRow); - static StringVector sv; - sv.clear (); - tokenizeList (cellString, sv, skillRow, SkillObject::ms_schematicsGrantedLabel); - skillData.schematicsGranted.reserve (sv.size ()); - - for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) - skillData.schematicsGranted.push_back (*it); - - std::sort (skillData.schematicsGranted.begin (), skillData.schematicsGranted.end ()); -} - -//--------------------------------------------------------------------- - -void SkillObject::loadStatisticsModifiers(DataTable &dataTable, int skillRow) -{ - const std::string & cellString = dataTable.getStringValue(SkillObject::ms_statisticsModifiersLabel, skillRow); - static StringVector sv; - sv.clear (); - tokenizeList (cellString, sv, skillRow, SkillObject::ms_statisticsModifiersLabel); - skillData.statisticModifiers.reserve (sv.size ()); - - for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) - { - const std::string & statEntry = *it; - const size_t splitPos = statEntry.find ('='); - - if (splitPos == std::string::npos) - WARNING (true, ("Statistic modifier without an = [%s], skill=%s", statEntry.c_str(), skillData.skillName.c_str())); - else - { - const char * const statValueString = statEntry.c_str () + splitPos + 1; - const std::string & statValueName = statEntry.substr (0, splitPos); - const int32 modifier = atoi (statValueString); - skillData.statisticModifiers.push_back(std::make_pair(statValueName, modifier)); - } - } -} - -//--------------------------------------------------------------------- - -void SkillObject::connectLinks(DataTable &dataTable, const std::string & parentName) -{ - if (!parentName.empty ()) - { - const SkillObject * const parent = SkillManager::getInstance().getSkill (parentName); - if (parent) - { - skillData.prevSkill = parent; - } - } - - std::string nextSkillSearchName = skillData.skillName; - if (nextSkillSearchName == "skill_system_root") - { - nextSkillSearchName.clear (); - } - - int rows = dataTable.getNumRows(); - for (int i = 0; i < rows; i++) - { - const std::string & tmpParent = dataTable.getStringValue(SkillObject::ms_parentLabel, i); - - if (tmpParent == nextSkillSearchName) - { - const std::string & nextSkillName = dataTable.getStringValue(SkillObject::ms_skillLabel, i); - const SkillObject * const nextSkill = SkillManager::getInstance().getSkill(nextSkillName); - if (nextSkill) - { - skillData.nextSkillBoxes.push_back(nextSkill); - } - } - } - -} - -//--------------------------------------------------------------------- - -bool SkillObject::load(DataTable & dataTable, const std::string & skillName) -{ - if (skillName == "skill_system_root") - { - skillData = SkillData(); - skillData.skillName = skillName; - connectLinks (dataTable, ""); - return true; - } - - const int skillColumn = dataTable.findColumnNumber (SkillObject::ms_skillLabel); - if (skillColumn == -1) - { - WARNING (true, ("SkillObject::load Could not find column %s in DataTable", SkillObject::ms_skillLabel.c_str())); - return false; - } - - const int skillRow = dataTable.searchColumnString (skillColumn, skillName); - if (skillRow == -1) - { - skillData = SkillData(); - return false; - } - - skillData = SkillData(); - - skillData.skillName = skillName; - - loadPrerequisiteSkills (dataTable, skillRow); - loadPrerequisiteExperience (dataTable, skillRow); - loadPrerequisiteSpecies (dataTable, skillRow); - - std::string parent = dataTable.getStringValue(SkillObject::ms_parentLabel, skillRow); - if (parent.empty ()) - { - parent = "skill_system_root"; - } - connectLinks (dataTable, parent); - - loadCommands (dataTable, skillRow); - loadSchematicsGranted (dataTable, skillRow); - loadStatisticsModifiers (dataTable, skillRow); - - skillData.isTitle = dataTable.getIntValue(SkillObject::ms_isTitleLabel, skillRow) != 0; - skillData.isProfession = dataTable.getIntValue(SkillObject::ms_isProfessionLabel, skillRow) != 0; - skillData.isSearchable = dataTable.getIntValue(SkillObject::ms_isSearchableLabel, skillRow) != 0; - - return true; -} - -//---------------------------------------------------------------------- - -const SkillObject * SkillObject::findProfessionForSkill () const -{ - const SkillObject * s = this; - - while (s) - { - if (s->isProfession ()) - return s; - - s = s->getPrevSkill (); - } - - return 0; -} - -//----------------------------------------------------------------- - -bool SkillObject::dependsUponSkill (const SkillObject & skill, bool immediatePrereqsOnly) const -{ - bool result = false; - - ++s_recursionCountDepends; - - if (s_recursionCountDepends >= s_recursionCountDependsMax) - { - WARNING (true, ("recursion max hit in skill dependency check")); - } - else if (this == &skill) - { - result = true; - } - else - { - const SkillVector & preReqs = getPrerequisiteSkills(); - for (SkillVector::const_iterator it = preReqs.begin (); it != preReqs.end (); ++it) - { - const SkillObject * const prereq = NON_NULL (*it); - - if(immediatePrereqsOnly) - { - if(prereq == &skill) - result = true; - } - else - { - if (prereq->dependsUponSkill (skill)) - { - result = true; - } - } - } - } - - --s_recursionCountDepends; - - return result; -} - -//--------------------------------------------------------------------- +// SkillObject.cpp +// Copyright 2000-01, Sony Online Entertainment Inc., all rights reserved. +// Author: Justin Randall + +//----------------------------------------------------------------------- + +#include "sharedSkillSystem/FirstSharedSkillSystem.h" +#include "sharedSkillSystem/SkillObject.h" + +#include "sharedSkillSystem/SkillManager.h" +#include "sharedUtility/DataTable.h" + +#include "UnicodeUtils.h" + +#include + +const std::string SkillObject::ms_skillLabel = "NAME"; +const std::string SkillObject::ms_prerequisiteSkillsLabel = "SKILLS_REQUIRED"; +const std::string SkillObject::ms_prerequisiteExperienceTypeLabel = "XP_TYPE"; +const std::string SkillObject::ms_prerequisiteExperienceAmountLabel = "XP_COST"; +const std::string SkillObject::ms_prerequisiteExperienceLimitLabel = "XP_CAP"; +const std::string SkillObject::ms_prerequisiteSpeciesLabel = "SPECIES_REQUIRED"; +const std::string SkillObject::ms_commandsLabel = "COMMANDS"; +const std::string SkillObject::ms_statisticsModifiersLabel = "SKILL_MODS"; +const std::string SkillObject::ms_parentLabel = "PARENT"; +const std::string SkillObject::ms_schematicsGrantedLabel = "SCHEMATICS_GRANTED"; +const std::string SkillObject::ms_isTitleLabel = "IS_TITLE"; +const std::string SkillObject::ms_isProfessionLabel = "IS_PROFESSION"; +const std::string SkillObject::ms_isSearchableLabel = "SEARCHABLE"; + +//----------------------------------------------------------------- + +namespace +{ + int s_recursionCountDepends = 0; + const int s_recursionCountDependsMax = 7; + + //---------------------------------------------------------------------- + + typedef stdvector::fwd StringVector; + inline void tokenizeList (const std::string & str, StringVector & sv, int row, const std::string & columnName) + { + UNREF (row); + UNREF (columnName); + + size_t endpos = 0; + std::string token; + static const char * const whitespace = ","; + + DEBUG_WARNING (str.find (" \n\r\t") != std::string::npos, ("SkillObject Cell string [%s] row %d column [%s] contains spaces or other invalid characters", row, columnName.c_str ())); + + while (Unicode::getFirstToken (str, endpos, endpos, token, whitespace)) + { + sv.push_back (token); + if (endpos == std::string::npos) + break; + + ++endpos; + } + } +} + +//--------------------------------------------------------------------- + +SkillObject::SkillData::SkillData() : +prerequisiteSkills (), +prerequisiteExperience (), +prerequisiteSpecies (), +prerequisiteFactionStanding (), +skillName ("UNINITIALIZED SKILL"), +nextSkillBoxes (), +prevSkill (0), +commandsProvided (), +schematicsGranted (), +statisticModifiers (), +isProfession (false), +isTitle (false), +isSearchable (false) +{ +} + +//--------------------------------------------------------------------- + +SkillObject::SkillData::SkillData(const SkillData & source) : +prerequisiteSkills (source.prerequisiteSkills), +prerequisiteExperience (source.prerequisiteExperience), +prerequisiteSpecies (source.prerequisiteSpecies), +prerequisiteFactionStanding (source.prerequisiteFactionStanding), +skillName (source.skillName), +nextSkillBoxes (source.nextSkillBoxes), +prevSkill (0), +commandsProvided (source.commandsProvided), +schematicsGranted (source.schematicsGranted), +statisticModifiers (source.statisticModifiers), +isProfession (source.isProfession), +isTitle (source.isTitle), +isSearchable (source.isSearchable) +{ +} + +//--------------------------------------------------------------------- + +SkillObject::SkillData::~SkillData() +{ +} + +//--------------------------------------------------------------------- + +SkillObject::SkillData & SkillObject::SkillData::operator = (const SkillData & rhs) +{ + if(&rhs != this) + { + prerequisiteSkills = rhs.prerequisiteSkills; + prerequisiteExperience = rhs.prerequisiteExperience; + prerequisiteSpecies = rhs.prerequisiteSpecies; + prerequisiteFactionStanding = rhs.prerequisiteFactionStanding; + skillName = rhs.skillName; + nextSkillBoxes = rhs.nextSkillBoxes; + commandsProvided = rhs.commandsProvided; + schematicsGranted = rhs.schematicsGranted; + statisticModifiers = rhs.statisticModifiers; + isProfession = rhs.isProfession; + isTitle = rhs.isTitle; + isSearchable = rhs.isSearchable; + } + return *this; +} + +//--------------------------------------------------------------------- + +SkillObject::SkillObject() : +skillData() +{ +} + +//--------------------------------------------------------------------- + +SkillObject::~SkillObject() +{ +} + +//--------------------------------------------------------------------- + +const SkillObject::SkillVector & SkillObject::getNextSkillBoxes() const +{ + return skillData.nextSkillBoxes; +} + +//----------------------------------------------------------------------- + +const SkillObject * SkillObject::getPrevSkill() const +{ + return skillData.prevSkill; +} + +//--------------------------------------------------------------------- + +const SkillObject::SkillData & SkillObject::getSkillData() const +{ + return skillData; +} + +//--------------------------------------------------------------------- + +const SkillObject::ExperienceVector & SkillObject::getPrerequisiteExperienceVector () const +{ + return skillData.prerequisiteExperience; +} + +//----------------------------------------------------------------- + +const SkillObject::ExperiencePair * SkillObject::getPrerequisiteExperience () const +{ + if (skillData.prerequisiteExperience.empty ()) + return 0; + else + return &skillData.prerequisiteExperience.front (); +} + +//--------------------------------------------------------------------- + +const SkillObject::SpeciesFlagVector & SkillObject::getPrerequisiteSpecies() const +{ + return skillData.prerequisiteSpecies; +} + +//--------------------------------------------------------------------- + +const SkillObject::GenericModVector & SkillObject::getPrerequisiteFactionStanding() const +{ + return skillData.prerequisiteFactionStanding; +} + +//--------------------------------------------------------------------- + +const SkillObject::SkillVector & SkillObject::getPrerequisiteSkills() const +{ + return skillData.prerequisiteSkills; +} + +//--------------------------------------------------------------------- + +const std::string & SkillObject::getSkillName() const +{ + return skillData.skillName; +} + +//--------------------------------------------------------------------- + +const SkillObject::StringVector & SkillObject::getCommandsProvided() const +{ + return skillData.commandsProvided; +} + +//--------------------------------------------------------------------- + +const SkillObject::StringVector & SkillObject::getSchematicsGranted() const +{ + return skillData.schematicsGranted; +} + +//--------------------------------------------------------------------- + +const std::vector > & SkillObject::getStatisticModifiers() const +{ + return skillData.statisticModifiers; +} + +//----------------------------------------------------------------------- + +SkillObject::SkillData & SkillObject::getSkillData() +{ + return skillData; +} + +//----------------------------------------------------------------------- + +const bool SkillObject::hasCommand(const std::string & commandName) const +{ + return std::binary_search (skillData.commandsProvided.begin (), skillData.commandsProvided.end (), commandName); +} + +//----------------------------------------------------------------------- +/** get primary category for this skill */ + +const SkillObject * SkillObject::findCategory() const +{ + const SkillObject * p = this; + + for (;;) + { + if (p) + { + //-- the categories are at the 2nd level of the heirarchy + + if (p->skillData.prevSkill && p->skillData.prevSkill->skillData.prevSkill == 0) + { + return p; + } + + p = p->skillData.prevSkill; + } + else + { + break; + } + } + + return 0; +} + +//----------------------------------------------------------------------- + +const bool SkillObject::isProfession() const +{ + return skillData.isProfession; +} + +//----------------------------------------------------------------------- + +const bool SkillObject::isTitle() const +{ + return skillData.isTitle; +} + +//----------------------------------------------------------------------- + +const bool SkillObject::isSearchable() const +{ + return skillData.isSearchable; +} + +//--------------------------------------------------------------------- + +void SkillObject::loadPrerequisiteSkills(DataTable &dataTable, int skillRow) +{ + const std::string & cellString = dataTable.getStringValue(SkillObject::ms_prerequisiteSkillsLabel, skillRow); + StringVector sv; + sv.clear (); + tokenizeList (cellString, sv, skillRow, SkillObject::ms_prerequisiteSkillsLabel); + skillData.prerequisiteSkills.reserve (sv.size ()); + + SkillManager & manager = SkillManager::getInstance (); + + for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) + { + const std::string & skillName = *it; + const SkillObject * const skill = manager.getSkill (skillName); + if (skill) + skillData.prerequisiteSkills.push_back(skill); + else + WARNING (true, ("prerequisiteSkills skill [%s] does not exist", skillName.c_str ())); + } + + std::sort (skillData.prerequisiteSkills.begin (), skillData.prerequisiteSkills.end ()); +} + +//---------------------------------------------------------------------- + +void SkillObject::loadPrerequisiteExperience(DataTable &dataTable, int skillRow) +{ + const int xpAmount = dataTable.getIntValue(SkillObject::ms_prerequisiteExperienceAmountLabel, skillRow); + const int xpLimit = dataTable.getIntValue(SkillObject::ms_prerequisiteExperienceLimitLabel, skillRow); + if (xpAmount > 0 || xpLimit > 0) + { + const std::string & experienceType = dataTable.getStringValue(SkillObject::ms_prerequisiteExperienceTypeLabel, skillRow); + if (!experienceType.empty ()) + skillData.prerequisiteExperience.push_back(std::make_pair(experienceType, std::make_pair(xpAmount, xpLimit))); + else + WARNING (true, ("Nonzero experience specified but empty experience name on row %d", skillRow)); + } +} + +//--------------------------------------------------------------------- + +void SkillObject::loadPrerequisiteSpecies(DataTable &dataTable, int skillRow) +{ + const std::string & cellString = dataTable.getStringValue(SkillObject::ms_prerequisiteSpeciesLabel, skillRow); + static StringVector sv; + sv.clear (); + tokenizeList (cellString, sv, skillRow, SkillObject::ms_prerequisiteSpeciesLabel); + skillData.prerequisiteSpecies.reserve (sv.size ()); + + for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) + skillData.prerequisiteSpecies.push_back (std::make_pair (*it, true)); +} + +//--------------------------------------------------------------------- + +void SkillObject::loadCommands(DataTable &dataTable, int skillRow) +{ + const std::string & cellString = dataTable.getStringValue(SkillObject::ms_commandsLabel, skillRow); + static StringVector sv; + sv.clear (); + tokenizeList (cellString, sv, skillRow, SkillObject::ms_commandsLabel); + skillData.commandsProvided.reserve (sv.size ()); + + for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) + skillData.commandsProvided.push_back (*it); + + std::sort (skillData.commandsProvided.begin (), skillData.commandsProvided.end ()); +} + +//--------------------------------------------------------------------- + +void SkillObject::loadSchematicsGranted(DataTable &dataTable, int skillRow) +{ + const std::string & cellString = dataTable.getStringValue(SkillObject::ms_schematicsGrantedLabel, skillRow); + static StringVector sv; + sv.clear (); + tokenizeList (cellString, sv, skillRow, SkillObject::ms_schematicsGrantedLabel); + skillData.schematicsGranted.reserve (sv.size ()); + + for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) + skillData.schematicsGranted.push_back (*it); + + std::sort (skillData.schematicsGranted.begin (), skillData.schematicsGranted.end ()); +} + +//--------------------------------------------------------------------- + +void SkillObject::loadStatisticsModifiers(DataTable &dataTable, int skillRow) +{ + const std::string & cellString = dataTable.getStringValue(SkillObject::ms_statisticsModifiersLabel, skillRow); + static StringVector sv; + sv.clear (); + tokenizeList (cellString, sv, skillRow, SkillObject::ms_statisticsModifiersLabel); + skillData.statisticModifiers.reserve (sv.size ()); + + for (StringVector::const_iterator it = sv.begin (); it != sv.end (); ++it) + { + const std::string & statEntry = *it; + const size_t splitPos = statEntry.find ('='); + + if (splitPos == std::string::npos) + WARNING (true, ("Statistic modifier without an = [%s], skill=%s", statEntry.c_str(), skillData.skillName.c_str())); + else + { + const char * const statValueString = statEntry.c_str () + splitPos + 1; + const std::string & statValueName = statEntry.substr (0, splitPos); + const int32 modifier = atoi (statValueString); + skillData.statisticModifiers.push_back(std::make_pair(statValueName, modifier)); + } + } +} + +//--------------------------------------------------------------------- + +void SkillObject::connectLinks(DataTable &dataTable, const std::string & parentName) +{ + if (!parentName.empty ()) + { + const SkillObject * const parent = SkillManager::getInstance().getSkill (parentName); + if (parent) + { + skillData.prevSkill = parent; + } + } + + std::string nextSkillSearchName = skillData.skillName; + if (nextSkillSearchName == "skill_system_root") + { + nextSkillSearchName.clear (); + } + + int rows = dataTable.getNumRows(); + for (int i = 0; i < rows; i++) + { + const std::string & tmpParent = dataTable.getStringValue(SkillObject::ms_parentLabel, i); + + if (tmpParent == nextSkillSearchName) + { + const std::string & nextSkillName = dataTable.getStringValue(SkillObject::ms_skillLabel, i); + const SkillObject * const nextSkill = SkillManager::getInstance().getSkill(nextSkillName); + if (nextSkill) + { + skillData.nextSkillBoxes.push_back(nextSkill); + } + } + } + +} + +//--------------------------------------------------------------------- + +bool SkillObject::load(DataTable & dataTable, const std::string & skillName) +{ + if (skillName == "skill_system_root") + { + skillData = SkillData(); + skillData.skillName = skillName; + connectLinks (dataTable, ""); + return true; + } + + const int skillColumn = dataTable.findColumnNumber (SkillObject::ms_skillLabel); + if (skillColumn == -1) + { + WARNING (true, ("SkillObject::load Could not find column %s in DataTable", SkillObject::ms_skillLabel.c_str())); + return false; + } + + const int skillRow = dataTable.searchColumnString (skillColumn, skillName); + if (skillRow == -1) + { + skillData = SkillData(); + return false; + } + + skillData = SkillData(); + + skillData.skillName = skillName; + + loadPrerequisiteSkills (dataTable, skillRow); + loadPrerequisiteExperience (dataTable, skillRow); + loadPrerequisiteSpecies (dataTable, skillRow); + + std::string parent = dataTable.getStringValue(SkillObject::ms_parentLabel, skillRow); + if (parent.empty ()) + { + parent = "skill_system_root"; + } + connectLinks (dataTable, parent); + + loadCommands (dataTable, skillRow); + loadSchematicsGranted (dataTable, skillRow); + loadStatisticsModifiers (dataTable, skillRow); + + skillData.isTitle = dataTable.getIntValue(SkillObject::ms_isTitleLabel, skillRow) != 0; + skillData.isProfession = dataTable.getIntValue(SkillObject::ms_isProfessionLabel, skillRow) != 0; + skillData.isSearchable = dataTable.getIntValue(SkillObject::ms_isSearchableLabel, skillRow) != 0; + + return true; +} + +//---------------------------------------------------------------------- + +const SkillObject * SkillObject::findProfessionForSkill () const +{ + const SkillObject * s = this; + + while (s) + { + if (s->isProfession ()) + return s; + + s = s->getPrevSkill (); + } + + return 0; +} + +//----------------------------------------------------------------- + +bool SkillObject::dependsUponSkill (const SkillObject & skill, bool immediatePrereqsOnly) const +{ + bool result = false; + + ++s_recursionCountDepends; + + if (s_recursionCountDepends >= s_recursionCountDependsMax) + { + WARNING (true, ("recursion max hit in skill dependency check")); + } + else if (this == &skill) + { + result = true; + } + else + { + const SkillVector & preReqs = getPrerequisiteSkills(); + for (SkillVector::const_iterator it = preReqs.begin (); it != preReqs.end (); ++it) + { + const SkillObject * const prereq = NON_NULL (*it); + + if(immediatePrereqsOnly) + { + if(prereq == &skill) + result = true; + } + else + { + if (prereq->dependsUponSkill (skill)) + { + result = true; + } + } + } + } + + --s_recursionCountDepends; + + return result; +} + +//--------------------------------------------------------------------- diff --git a/src/engine/shared/library/sharedTemplateDefinition/src/shared/core/TemplateDefinitionFile.cpp b/src/engine/shared/library/sharedTemplateDefinition/src/shared/core/TemplateDefinitionFile.cpp index 12cd2caec..4a7964a30 100644 --- a/src/engine/shared/library/sharedTemplateDefinition/src/shared/core/TemplateDefinitionFile.cpp +++ b/src/engine/shared/library/sharedTemplateDefinition/src/shared/core/TemplateDefinitionFile.cpp @@ -1,632 +1,632 @@ -//======================================================================== -// -// TemplateDefinitionFile.cpp - a template definition file interpreter. -// -// copyright 2001 Sony Online Entertainment -// -//======================================================================== - -#include "sharedTemplateDefinition/FirstSharedTemplateDefinition.h" -#include "File.h" -#include "TemplateGlobals.h" -#include "TemplateDefinitionFile.h" -#include "TemplateData.h" -#include "sharedRegex/RegexServices.h" -#include "sharedFoundation/SetupSharedFoundation.h" - -//============================================================================== - -/** - * Class constructor. - */ -TemplateDefinitionFile::TemplateDefinitionFile(void) : - m_baseDefinitionFile(NULL), - m_writeForCompilerFlag(false), - m_filterCompiledRegex(NULL) -{ - cleanup(); -} // TemplateDefinitionFile::TemplateDefinitionFile - -/** - * Class destructor. - */ -TemplateDefinitionFile::~TemplateDefinitionFile() -{ - cleanup(); -} // TemplateDefinitionFile::~TemplateDefinitionFile - -/** - * Resets all the class data. - */ -void TemplateDefinitionFile::cleanup(void) -{ - m_highestVersion = 0; - m_templateId.tag = NO_TAG; - m_templateId.tagString = NO_TAG_STRING; - m_templateLocation = LOC_NONE; - IGNORE_RETURN(m_templateName.erase()); - IGNORE_RETURN(m_baseName.erase()); - IGNORE_RETURN(m_templateNameFilter.erase()); - m_path.clear(); - m_compilerPath.clear(); - m_fileComments.clear(); - - if (m_baseDefinitionFile != NULL) - { - delete m_baseDefinitionFile; - m_baseDefinitionFile = NULL; - } - - std::map::iterator iter; - for (iter = m_templateMap.begin(); iter != m_templateMap.end(); ++iter) - { - delete (*iter).second; - (*iter).second = NULL; - } - m_templateMap.clear(); - - if (m_filterCompiledRegex != NULL) - { - RegexServices::freeMemory(m_filterCompiledRegex); - m_filterCompiledRegex = NULL; - } -} // TemplateDefinitionFile::cleanup - -/** - * Sets the write for compile flags on the tamplate data instances. - * - * @param flag flag that we are going to write code for the template compiler - */ -void TemplateDefinitionFile::setWriteForCompiler(bool flag) -{ - m_writeForCompilerFlag = flag; - if (flag && m_baseName.size() == 0) - { - m_baseName = COMPILER_ROOT_TEMPLATE_NAME; - } - else if (!flag && m_baseName == COMPILER_ROOT_TEMPLATE_NAME) - { - m_baseName = ""; - } - - std::map::iterator iter; - for (iter = m_templateMap.begin(); iter != m_templateMap.end(); ++iter) - (*iter).second->setWriteForCompiler(flag); -} // TemplateDefinitionFile::setWriteForCompiler - -/** - * Returns the template file name filter for this definition. - */ -const std::string & TemplateDefinitionFile::getTemplateNameFilter(void) const -{ -static const std::string wildcard = "*"; - - if (!m_templateNameFilter.empty()) - return m_templateNameFilter; - - if (m_baseDefinitionFile != NULL) - return m_baseDefinitionFile->getTemplateNameFilter(); - - return wildcard; -} // TemplateDefinitionFile::getTemplateNameFileter - -/** - * Tests if a template file name is valid for this definition. - * - * @param name the template file name - * - * @return true if the name is valid, false if not - */ -bool TemplateDefinitionFile::isValidTemplateName(const Filename & name) const -{ - if (m_templateNameFilter.empty()) - { - if (m_baseDefinitionFile != NULL) - return m_baseDefinitionFile->isValidTemplateName(name); - else - return true; - } - - int const maxCaptureCount = 10; - int const matchDataElementCount = maxCaptureCount * 3; - int matchData[matchDataElementCount]; - - int const matchCode = pcre_exec(m_filterCompiledRegex, NULL, name.getName().c_str(), name.getName().length(), 0, 0, matchData, matchDataElementCount); - bool const result = (matchCode >= 0); - - if (matchCode < -1) - { - fprintf(stderr, "ERROR: pcre_exec() failed, error code [%d].\n", matchCode); - return false; - } - - return result; -} // TemplateDefinitionFile::isValidTemplateName - -/** - * Writes file-level comments. - * - * @param fp the file to write to - */ -void TemplateDefinitionFile::writeFileComments(File &fp) const -{ - std::vector::const_iterator iter; - for (iter = getFileComments().begin(); iter != getFileComments().end(); ++iter) - { - fp.print("%s\n", (*iter).c_str()); - } -} // TemplateDefinitionFile::writeFileComments - -/** - * Writes the template id tag definition. - * - * @param fp the file to write to - */ -void TemplateDefinitionFile::writeTemplateId(File &fp) const -{ - fp.print("%s\n", TDF_ID_BEGIN); - fp.print("\tenum\n"); - fp.print("\t{\n"); - fp.print("\t\t%s_tag = %s\n", getTemplateName().c_str(), getTemplateId().tagString.c_str()); - fp.print("\t};\n"); - fp.print("%s\n", TDF_ID_END); -} // TemplateDefinitionFile::writeTemplateId - -/** - * Writes the beginning of a class header file. - * - * @param fp the file to write to - */ -void TemplateDefinitionFile::writeClassHeaderBegin(File &fp) const -{ - const char * name = getTemplateName().c_str(); - std::string bn = getBaseName(); - const char * baseName = bn.c_str(); - const char * baseNamePath = ""; - if (baseName[0] == '\0' && m_templateLocation != LOC_NONE) - { - baseNamePath = "sharedObject/"; - baseName = ROOT_TEMPLATE_NAME; - } - else if(_stricmp(baseName, "tpfTemplate") == 0) - { - baseNamePath = "sharedTemplateDefinition/"; - } - - fp.print("//========================================================================\n"); - fp.print("//\n"); - fp.print("// %s.h\n", name); - fp.print("//\n"); - fp.print("//IMPORTANT: Any code between //@BEGIN TFD... and //@END TFD... will be\n"); - fp.print("//overwritten the next time the template definition is compiled. Do not\n"); - fp.print("//make changes to code inside these blocks.\n"); - fp.print("//\n"); - if (getFileComments().size() > 0) - { - writeFileComments(fp); - fp.print("//\n"); - } - fp.print("// copyright 2001 Sony Online Entertainment\n"); - fp.print("//\n"); - fp.print("//========================================================================\n"); - fp.print("\n"); - fp.print("#ifndef _INCLUDED_%s_H\n", name); - fp.print("#define _INCLUDED_%s_H\n", name); - fp.print("\n"); - fp.print("#include \"%s%s.h\"\n", baseNamePath, baseName); - fp.print("#include \"sharedFoundation/DynamicVariable.h\"\n"); - if (m_writeForCompilerFlag) - fp.print("#include \"sharedTemplateDefinition/TpfTemplate.h\"\n"); - else - fp.print("#include \"sharedUtility/TemplateParameter.h\"\n"); - fp.print("\n"); - fp.print("\n"); - fp.print("class Vector;\n"); - fp.print("typedef StructParam StructParamOT;\n"); - if (!m_writeForCompilerFlag) - { - std::map::const_iterator iter; - iter = m_templateMap.find(m_highestVersion); - if (iter != m_templateMap.end()) - (*iter).second->writeHeaderFwdDecls(fp); - } - fp.print("\n"); - fp.print("\n"); - fp.print("class %s : public %s\n", name, baseName); - fp.print("{\n"); - fp.print("public:\n"); - writeTemplateId(fp); - fp.print("public:\n"); - fp.print("\t %s(const std::string & filename);\n", name); - fp.print("\tvirtual ~%s();\n", name); - fp.print("\n"); - fp.print("\tvirtual Tag getId(void) const;\n"); - fp.print("\tvirtual Tag getTemplateVersion(void) const;\n"); - fp.print("\tvirtual Tag getHighestTemplateVersion(void) const;\n"); - if (m_writeForCompilerFlag) - fp.print("\tstatic void install(void);\n"); - else - fp.print("\tstatic void install(bool allowDefaultTemplateParams = true);\n"); - fp.print("\n"); -} // writeClassHeaderBegin - -/** - * Writes the ending of a class header file. - * - * @param fp the file to write to - * @param sourceTemplate the template we are writing code for - */ -void TemplateDefinitionFile::writeClassHeaderEnd(File &fp, const TemplateData & sourceTemplate) const -{ - UNREF(sourceTemplate); - - const char *name = getTemplateName().c_str(); - - fp.print("\n"); - fp.print("private:\n"); - fp.print("\tTag m_templateVersion;\t// the template version\n"); - fp.print("\tbool m_versionOk;\t// flag that the template version loaded is " - "the one we expect\n"); - if (!m_writeForCompilerFlag) - fp.print("\tstatic bool ms_allowDefaultTemplateParams;\t// flag to allow defaut params instead of fataling\n"); - fp.print("\n"); - fp.print("\tstatic void registerMe(void);\n"); - fp.print("\tstatic ObjectTemplate * create(const std::string & filename);\n"); - fp.print("\n"); - fp.print("\t// no copying\n"); - fp.print("\t%s(const %s &);\n", name, name); - fp.print("\t%s & operator =(const %s &);\n", name, name); - fp.print("};\n"); - fp.print("\n"); - fp.print("\n"); - if (m_writeForCompilerFlag) - { - fp.print("inline void %s::install(void)\n", name); - fp.print("{\n"); - } - else - { - fp.print("inline void %s::install(bool allowDefaultTemplateParams)\n", name); - fp.print("{\n"); - fp.print("\tms_allowDefaultTemplateParams = allowDefaultTemplateParams;\n"); - } - sourceTemplate.writeRegisterTemplate(fp, "\t"); - fp.print("}\n"); - fp.print("\n"); - fp.print("\n"); - fp.print("#endif\t// _INCLUDED_%s_H\n", name); -} // TemplateDefinitionFile::writeClassHeaderEnd - -/** - * Writes the beginning of a class source file. - * - * @param fp the file to write to - * @param sourceTemplate the template we are writing code for - */ -void TemplateDefinitionFile::writeClassSourceBegin(File &fp, const TemplateData & sourceTemplate) const -{ - const char *name = getTemplateName().c_str(); - - fp.print("//========================================================================\n"); - fp.print("//\n"); - fp.print("// %s.cpp\n", name); - fp.print("//\n"); - fp.print("//IMPORTANT: Any code between //@BEGIN TFD... and //@END TFD... will be\n"); - fp.print("//overwritten the next time the template definition is compiled. Do not\n"); - fp.print("//make changes to code inside these blocks.\n"); - fp.print("//\n"); - if (getFileComments().size() > 0) - { - writeFileComments(fp); - fp.print("//\n"); - } - fp.print("// copyright 2001 Sony Online Entertainment\n"); - fp.print("//\n"); - fp.print("//========================================================================\n"); - fp.print("\n"); - if (m_writeForCompilerFlag) - { - fp.print("#include \"sharedTemplate/FirstSharedTemplate.h\"\n"); - fp.print("#include \"sharedTemplateDefinition/TemplateData.h\"\n"); - fp.print("#include \"sharedTemplateDefinition/TemplateGlobals.h\"\n", name); - } - else if (m_templateLocation == LOC_CLIENT) - fp.print("#include \"%s\"\n", CLIENT_TEMPLATE_PRECOMPILED_HEADER_NAME); - else if (m_templateLocation == LOC_SERVER) - fp.print("#include \"%s\"\n", SERVER_TEMPLATE_PRECOMPILED_HEADER_NAME); - else - fp.print("#include \"%s\"\n", SHARED_TEMPLATE_PRECOMPILED_HEADER_NAME); - fp.print("#include \"%s.h\"\n", name); - fp.print("#include \"sharedDebug/DataLint.h\"\n"); - fp.print("#include \"sharedFile/Iff.h\"\n"); - if (m_writeForCompilerFlag) - fp.print("#include \"sharedTemplateDefinition/ObjectTemplate.h\"\n"); - else - { - fp.print("#include \"sharedObject/ObjectTemplate.h\"\n"); - fp.print("#include \"sharedObject/ObjectTemplateList.h\"\n"); - sourceTemplate.writeSourceTemplateIncludes(fp); - } - fp.print("#include \n"); - fp.print("\n"); - - if (!m_writeForCompilerFlag) - { - fp.print("const std::string DefaultString(\"\");\n"); - fp.print("const StringId DefaultStringId(\"\", 0);\n"); - fp.print("const Vector DefaultVector(0,0,0);\n"); - fp.print("const TriggerVolumeData DefaultTriggerVolumeData;\n"); - fp.print("\n"); - fp.print("bool %s::ms_allowDefaultTemplateParams = true;\n", name); - } - - fp.print("\n"); - fp.print("\n"); - fp.print("/**\n"); - fp.print(" * Class constructor.\n"); - fp.print(" */\n"); - fp.print("%s::%s(const std::string & filename)\n", name, name); -// if (sourceTemplate.hasList()) - sourceTemplate.writeSourceLoadedFlagInit(fp); - fp.print("{\n"); -// fp.print("\tsetId(%s);\n", getTemplateId().tagString.c_str()); - fp.print("} // %s::%s\n", name, name); - fp.print("\n"); - fp.print("/**\n"); - fp.print(" * Class destructor.\n"); - fp.print(" */\n"); - fp.print("%s::~%s()\n", name, name); - fp.print("{\n"); - sourceTemplate.writeSourceCleanup(fp); - fp.print("} // %s::~%s\n", name, name); - fp.print("\n"); - fp.print("/**\n"); - fp.print(" * Static function used to register this template.\n"); - fp.print(" */\n"); - fp.print("void %s::registerMe(void)\n", name); - fp.print("{\n"); - fp.print("\tObjectTemplateList::registerTemplate(%s_tag, create);\n", name); - fp.print("} // %s::registerMe\n", name); - fp.print("\n"); - fp.print("/**\n"); - fp.print(" * Creates a %s template.\n", name); - fp.print(" *\n"); - fp.print(" * @return a new instance of the template\n"); - fp.print(" */\n"); - fp.print("ObjectTemplate * %s::create(const std::string & filename)\n", name); - fp.print("{\n"); - fp.print("\treturn new %s(filename);\n", name); - fp.print("} // %s::create\n", name); - fp.print("\n"); - fp.print("/**\n"); - fp.print(" * Returns the template id.\n"); - fp.print(" *\n"); - fp.print(" * @return the template id\n"); - fp.print(" */\n"); - fp.print("Tag %s::getId(void) const\n", name); - fp.print("{\n"); - fp.print("\treturn %s_tag;\n", name); - fp.print("} // %s::getId\n", name); - fp.print("\n"); - fp.print("/**\n"); - fp.print(" * Returns this template's version.\n"); - fp.print(" *\n"); - fp.print(" * @return the version\n"); - fp.print(" */\n"); - fp.print("Tag %s::getTemplateVersion(void) const\n", name); - fp.print("{\n"); - fp.print("\treturn m_templateVersion;\n"); - fp.print("} // %s::getTemplateVersion\n", name); - fp.print("\n"); - fp.print("/**\n"); - fp.print(" * Returns the highest version of this template or it's base templates.\n"); - fp.print(" *\n"); - fp.print(" * @return the highest version\n"); - fp.print(" */\n"); - fp.print("Tag %s::getHighestTemplateVersion(void) const\n", name); - fp.print("{\n"); - fp.print("\tif (m_baseData == NULL)\n"); - fp.print("\t\treturn m_templateVersion;\n"); - fp.print("\tconst %s * base = dynamic_cast(m_baseData);\n", name, name); - fp.print("\tif (base == NULL)\n"); - fp.print("\t\treturn m_templateVersion;\n"); - fp.print("\treturn std::max(m_templateVersion, base->getHighestTemplateVersion());\n"); - fp.print("} // %s::getHighestTemplateVersion\n", name); - fp.print("\n"); -} // TemplateDefinitionFile::writeClassSourceBegin - -/** - * Main parser for a tdf file. Parses initialization data, creates the header and - * source files, and passes parameter definitions to the appropriate function. - * - * @param fp file to parse - * - * @return 0 on success, -1 on fail - */ -int TemplateDefinitionFile::parse(File &fp) -{ -static const int BUFFER_SIZE = 1024; -int lineLen; -char buffer[BUFFER_SIZE]; -char token[BUFFER_SIZE]; -TemplateData *currentTemplate = NULL; - - cleanup(); - - setTemplateFilename(fp.getFilename().getName()); - - for (;;) - { - lineLen = fp.readLine(buffer, BUFFER_SIZE); - if (lineLen == -1) - break; - else if (lineLen == -2) - return -1; - - const char *line = buffer; - line = getNextWhitespaceToken(line, token); - if (*token == '\0') - break; - - if (strcmp(token, "version") == 0) - { - if (m_templateName.size() == 0) - { - fp.printError("no template name defined"); - return -1; - } - else if (m_templateId.tag == NO_TAG) - { - fp.printError("no template id defined"); - return -1; - } - else if (m_path.getPath().size() == 0) - { - fp.printError("no path defined"); - return -1; - } - else if (m_compilerPath.getPath().size() == 0) - { - fp.printError("no compiler path defined"); - return -1; - } -// if (m_baseName.size() == 0 && m_templateName != ROOT_TEMPLATE_NAME) -// m_baseName = ROOT_TEMPLATE_NAME; - line = getNextWhitespaceToken(line, token); - int version = atoi(token); - if (version < 0 || version > 9999) - { - fp.printError("version out of range"); - return -1; - } - if (m_templateMap.find(version) != m_templateMap.end()) - { - fp.printError("version already defined"); - return -1; - } - if (version > m_highestVersion) - m_highestVersion = version; - - currentTemplate = new TemplateData(version, *this); - m_templateMap[version] = currentTemplate; - } - else if (currentTemplate != NULL) - { - line = currentTemplate->parseLine(fp, buffer, token); - if (line == CHAR_ERROR) - return -1; - } - else if (*token == '/' && *(token + 1) == '/') - { - if (m_baseName.size() == 0 && m_templateId.tag == NO_TAG) - m_fileComments.push_back(buffer); - } - else if (strcmp(token, "base") == 0) - { - if (m_baseName.size() != 0) - { - fp.printError("base name already defined"); - return -1; - } - line = getNextWhitespaceToken(line, token); - setBaseFilename(token); - - // load and parse the base template - Filename baseFileName = fp.getFilename(); - baseFileName.setName(token); - File baseFp(baseFileName, "rt"); - if (!baseFp.isOpened()) - { - fp.printError("unable to open base template definition"); - return -1; - } - if (m_baseDefinitionFile == NULL) - m_baseDefinitionFile = new TemplateDefinitionFile; - else - m_baseDefinitionFile->cleanup(); - int result = m_baseDefinitionFile->parse(baseFp); - if (result != 0) - return result; - } - else if (strcmp(token, "id") == 0) - { - if (m_templateId.tag != NO_TAG) - { - fp.printError("template id already defined"); - return -1; - } - line = getNextWhitespaceToken(line, token); - if (strlen(token) != 4) - { - fp.printError("id not 4 characters"); - return -1; - } - m_templateId.tag = ConvertStringToTag(token); - m_templateId.tagString = ConvertStringToTagString(token); - } - else if (strcmp(token, "templatename") == 0) - { - line = getNextWhitespaceToken(line, token); - m_templateNameFilter = token; - - //-- Attempt to compile the regex. - if (m_filterCompiledRegex != NULL) - { - // First free the existing compiled regex. - RegexServices::freeMemory(m_filterCompiledRegex); - m_filterCompiledRegex = NULL; - } - - //-- Compile the new regex. - char const *errorString = NULL; - int errorOffset = 0; - - m_filterCompiledRegex = pcre_compile(m_templateNameFilter.c_str(), 0, &errorString, &errorOffset, NULL); - WARNING(m_filterCompiledRegex == NULL, ("TemplateDefinitionFile::parse(): pcre_compile() failed, error=[%s], errorOffset=[%d], regex text=[%s].", errorString, errorOffset, m_templateNameFilter.c_str())); - } - else if (strcmp(token, "clientpath") == 0 || - strcmp(token, "serverpath") == 0 || - strcmp(token, "sharedpath") == 0) - { - if (m_path.getPath().size() != 0) - { - fp.printError("path already defined"); - return -1; - } - if (strcmp(token, "clientpath") == 0) - m_templateLocation = LOC_CLIENT; - else if (strcmp(token, "serverpath") == 0) - m_templateLocation = LOC_SERVER; - else - m_templateLocation = LOC_SHARED; - line = getNextWhitespaceToken(line, token); - m_path.setPath(token); - m_path.prependPath(fp.getFilename()); - // reset the template name to add the corrent prefix to the template - // name - setTemplateFilename(m_templateFilename); - if (!m_baseFilename.empty()) - setBaseFilename(m_baseFilename); - } - else if (strcmp(token, "compilerpath") == 0) - { - if (m_compilerPath.getPath().size() != 0) - { - fp.printError("compiler path already defined"); - return -1; - } - line = getNextWhitespaceToken(line, token); - m_compilerPath.setPath(token); - m_compilerPath.prependPath(fp.getFilename()); - } - else - { - char errbuf[2048]; - sprintf(errbuf, "I don't know how to handle this line!: <%s>. " - "Barfed on token <%s>.", buffer, token); - fp.printError(errbuf); - return -1; - } - } - return 0; -} // TemplateDefinitionFile::parse +//======================================================================== +// +// TemplateDefinitionFile.cpp - a template definition file interpreter. +// +// copyright 2001 Sony Online Entertainment +// +//======================================================================== + +#include "sharedTemplateDefinition/FirstSharedTemplateDefinition.h" +#include "File.h" +#include "TemplateGlobals.h" +#include "TemplateDefinitionFile.h" +#include "TemplateData.h" +#include "sharedRegex/RegexServices.h" +#include "sharedFoundation/SetupSharedFoundation.h" + +//============================================================================== + +/** + * Class constructor. + */ +TemplateDefinitionFile::TemplateDefinitionFile(void) : + m_baseDefinitionFile(NULL), + m_writeForCompilerFlag(false), + m_filterCompiledRegex(NULL) +{ + cleanup(); +} // TemplateDefinitionFile::TemplateDefinitionFile + +/** + * Class destructor. + */ +TemplateDefinitionFile::~TemplateDefinitionFile() +{ + cleanup(); +} // TemplateDefinitionFile::~TemplateDefinitionFile + +/** + * Resets all the class data. + */ +void TemplateDefinitionFile::cleanup(void) +{ + m_highestVersion = 0; + m_templateId.tag = NO_TAG; + m_templateId.tagString = NO_TAG_STRING; + m_templateLocation = LOC_NONE; + IGNORE_RETURN(m_templateName.erase()); + IGNORE_RETURN(m_baseName.erase()); + IGNORE_RETURN(m_templateNameFilter.erase()); + m_path.clear(); + m_compilerPath.clear(); + m_fileComments.clear(); + + if (m_baseDefinitionFile != NULL) + { + delete m_baseDefinitionFile; + m_baseDefinitionFile = NULL; + } + + std::map::iterator iter; + for (iter = m_templateMap.begin(); iter != m_templateMap.end(); ++iter) + { + delete (*iter).second; + (*iter).second = NULL; + } + m_templateMap.clear(); + + if (m_filterCompiledRegex != NULL) + { + RegexServices::freeMemory(m_filterCompiledRegex); + m_filterCompiledRegex = NULL; + } +} // TemplateDefinitionFile::cleanup + +/** + * Sets the write for compile flags on the tamplate data instances. + * + * @param flag flag that we are going to write code for the template compiler + */ +void TemplateDefinitionFile::setWriteForCompiler(bool flag) +{ + m_writeForCompilerFlag = flag; + if (flag && m_baseName.size() == 0) + { + m_baseName = COMPILER_ROOT_TEMPLATE_NAME; + } + else if (!flag && m_baseName == COMPILER_ROOT_TEMPLATE_NAME) + { + m_baseName = ""; + } + + std::map::iterator iter; + for (iter = m_templateMap.begin(); iter != m_templateMap.end(); ++iter) + (*iter).second->setWriteForCompiler(flag); +} // TemplateDefinitionFile::setWriteForCompiler + +/** + * Returns the template file name filter for this definition. + */ +const std::string & TemplateDefinitionFile::getTemplateNameFilter(void) const +{ +static const std::string wildcard = "*"; + + if (!m_templateNameFilter.empty()) + return m_templateNameFilter; + + if (m_baseDefinitionFile != NULL) + return m_baseDefinitionFile->getTemplateNameFilter(); + + return wildcard; +} // TemplateDefinitionFile::getTemplateNameFileter + +/** + * Tests if a template file name is valid for this definition. + * + * @param name the template file name + * + * @return true if the name is valid, false if not + */ +bool TemplateDefinitionFile::isValidTemplateName(const Filename & name) const +{ + if (m_templateNameFilter.empty()) + { + if (m_baseDefinitionFile != NULL) + return m_baseDefinitionFile->isValidTemplateName(name); + else + return true; + } + + int const maxCaptureCount = 10; + int const matchDataElementCount = maxCaptureCount * 3; + int matchData[matchDataElementCount]; + + int const matchCode = pcre_exec(m_filterCompiledRegex, NULL, name.getName().c_str(), name.getName().length(), 0, 0, matchData, matchDataElementCount); + bool const result = (matchCode >= 0); + + if (matchCode < -1) + { + fprintf(stderr, "ERROR: pcre_exec() failed, error code [%d].\n", matchCode); + return false; + } + + return result; +} // TemplateDefinitionFile::isValidTemplateName + +/** + * Writes file-level comments. + * + * @param fp the file to write to + */ +void TemplateDefinitionFile::writeFileComments(File &fp) const +{ + std::vector::const_iterator iter; + for (iter = getFileComments().begin(); iter != getFileComments().end(); ++iter) + { + fp.print("%s\n", (*iter).c_str()); + } +} // TemplateDefinitionFile::writeFileComments + +/** + * Writes the template id tag definition. + * + * @param fp the file to write to + */ +void TemplateDefinitionFile::writeTemplateId(File &fp) const +{ + fp.print("%s\n", TDF_ID_BEGIN); + fp.print("\tenum\n"); + fp.print("\t{\n"); + fp.print("\t\t%s_tag = %s\n", getTemplateName().c_str(), getTemplateId().tagString.c_str()); + fp.print("\t};\n"); + fp.print("%s\n", TDF_ID_END); +} // TemplateDefinitionFile::writeTemplateId + +/** + * Writes the beginning of a class header file. + * + * @param fp the file to write to + */ +void TemplateDefinitionFile::writeClassHeaderBegin(File &fp) const +{ + const char * name = getTemplateName().c_str(); + std::string bn = getBaseName(); + const char * baseName = bn.c_str(); + const char * baseNamePath = ""; + if (baseName[0] == '\0' && m_templateLocation != LOC_NONE) + { + baseNamePath = "sharedObject/"; + baseName = ROOT_TEMPLATE_NAME; + } + else if(_stricmp(baseName, "tpfTemplate") == 0) + { + baseNamePath = "sharedTemplateDefinition/"; + } + + fp.print("//========================================================================\n"); + fp.print("//\n"); + fp.print("// %s.h\n", name); + fp.print("//\n"); + fp.print("//IMPORTANT: Any code between //@BEGIN TFD... and //@END TFD... will be\n"); + fp.print("//overwritten the next time the template definition is compiled. Do not\n"); + fp.print("//make changes to code inside these blocks.\n"); + fp.print("//\n"); + if (getFileComments().size() > 0) + { + writeFileComments(fp); + fp.print("//\n"); + } + fp.print("// copyright 2001 Sony Online Entertainment\n"); + fp.print("//\n"); + fp.print("//========================================================================\n"); + fp.print("\n"); + fp.print("#ifndef _INCLUDED_%s_H\n", name); + fp.print("#define _INCLUDED_%s_H\n", name); + fp.print("\n"); + fp.print("#include \"%s%s.h\"\n", baseNamePath, baseName); + fp.print("#include \"sharedFoundation/DynamicVariable.h\"\n"); + if (m_writeForCompilerFlag) + fp.print("#include \"sharedTemplateDefinition/TpfTemplate.h\"\n"); + else + fp.print("#include \"sharedUtility/TemplateParameter.h\"\n"); + fp.print("\n"); + fp.print("\n"); + fp.print("class Vector;\n"); + fp.print("typedef StructParam StructParamOT;\n"); + if (!m_writeForCompilerFlag) + { + std::map::const_iterator iter; + iter = m_templateMap.find(m_highestVersion); + if (iter != m_templateMap.end()) + (*iter).second->writeHeaderFwdDecls(fp); + } + fp.print("\n"); + fp.print("\n"); + fp.print("class %s : public %s\n", name, baseName); + fp.print("{\n"); + fp.print("public:\n"); + writeTemplateId(fp); + fp.print("public:\n"); + fp.print("\t %s(const std::string & filename);\n", name); + fp.print("\tvirtual ~%s();\n", name); + fp.print("\n"); + fp.print("\tvirtual Tag getId(void) const;\n"); + fp.print("\tvirtual Tag getTemplateVersion(void) const;\n"); + fp.print("\tvirtual Tag getHighestTemplateVersion(void) const;\n"); + if (m_writeForCompilerFlag) + fp.print("\tstatic void install(void);\n"); + else + fp.print("\tstatic void install(bool allowDefaultTemplateParams = true);\n"); + fp.print("\n"); +} // writeClassHeaderBegin + +/** + * Writes the ending of a class header file. + * + * @param fp the file to write to + * @param sourceTemplate the template we are writing code for + */ +void TemplateDefinitionFile::writeClassHeaderEnd(File &fp, const TemplateData & sourceTemplate) const +{ + UNREF(sourceTemplate); + + const char *name = getTemplateName().c_str(); + + fp.print("\n"); + fp.print("private:\n"); + fp.print("\tTag m_templateVersion;\t// the template version\n"); + fp.print("\tbool m_versionOk;\t// flag that the template version loaded is " + "the one we expect\n"); + if (!m_writeForCompilerFlag) + fp.print("\tstatic bool ms_allowDefaultTemplateParams;\t// flag to allow defaut params instead of fataling\n"); + fp.print("\n"); + fp.print("\tstatic void registerMe(void);\n"); + fp.print("\tstatic ObjectTemplate * create(const std::string & filename);\n"); + fp.print("\n"); + fp.print("\t// no copying\n"); + fp.print("\t%s(const %s &);\n", name, name); + fp.print("\t%s & operator =(const %s &);\n", name, name); + fp.print("};\n"); + fp.print("\n"); + fp.print("\n"); + if (m_writeForCompilerFlag) + { + fp.print("inline void %s::install(void)\n", name); + fp.print("{\n"); + } + else + { + fp.print("inline void %s::install(bool allowDefaultTemplateParams)\n", name); + fp.print("{\n"); + fp.print("\tms_allowDefaultTemplateParams = allowDefaultTemplateParams;\n"); + } + sourceTemplate.writeRegisterTemplate(fp, "\t"); + fp.print("}\n"); + fp.print("\n"); + fp.print("\n"); + fp.print("#endif\t// _INCLUDED_%s_H\n", name); +} // TemplateDefinitionFile::writeClassHeaderEnd + +/** + * Writes the beginning of a class source file. + * + * @param fp the file to write to + * @param sourceTemplate the template we are writing code for + */ +void TemplateDefinitionFile::writeClassSourceBegin(File &fp, const TemplateData & sourceTemplate) const +{ + const char *name = getTemplateName().c_str(); + + fp.print("//========================================================================\n"); + fp.print("//\n"); + fp.print("// %s.cpp\n", name); + fp.print("//\n"); + fp.print("//IMPORTANT: Any code between //@BEGIN TFD... and //@END TFD... will be\n"); + fp.print("//overwritten the next time the template definition is compiled. Do not\n"); + fp.print("//make changes to code inside these blocks.\n"); + fp.print("//\n"); + if (getFileComments().size() > 0) + { + writeFileComments(fp); + fp.print("//\n"); + } + fp.print("// copyright 2001 Sony Online Entertainment\n"); + fp.print("//\n"); + fp.print("//========================================================================\n"); + fp.print("\n"); + if (m_writeForCompilerFlag) + { + fp.print("#include \"sharedTemplate/FirstSharedTemplate.h\"\n"); + fp.print("#include \"sharedTemplateDefinition/TemplateData.h\"\n"); + fp.print("#include \"sharedTemplateDefinition/TemplateGlobals.h\"\n", name); + } + else if (m_templateLocation == LOC_CLIENT) + fp.print("#include \"%s\"\n", CLIENT_TEMPLATE_PRECOMPILED_HEADER_NAME); + else if (m_templateLocation == LOC_SERVER) + fp.print("#include \"%s\"\n", SERVER_TEMPLATE_PRECOMPILED_HEADER_NAME); + else + fp.print("#include \"%s\"\n", SHARED_TEMPLATE_PRECOMPILED_HEADER_NAME); + fp.print("#include \"%s.h\"\n", name); + fp.print("#include \"sharedDebug/DataLint.h\"\n"); + fp.print("#include \"sharedFile/Iff.h\"\n"); + if (m_writeForCompilerFlag) + fp.print("#include \"sharedTemplateDefinition/ObjectTemplate.h\"\n"); + else + { + fp.print("#include \"sharedObject/ObjectTemplate.h\"\n"); + fp.print("#include \"sharedObject/ObjectTemplateList.h\"\n"); + sourceTemplate.writeSourceTemplateIncludes(fp); + } + fp.print("#include \n"); + fp.print("\n"); + + if (!m_writeForCompilerFlag) + { + fp.print("const std::string DefaultString(\"\");\n"); + fp.print("const StringId DefaultStringId(\"\", 0);\n"); + fp.print("const Vector DefaultVector(0,0,0);\n"); + fp.print("const TriggerVolumeData DefaultTriggerVolumeData;\n"); + fp.print("\n"); + fp.print("bool %s::ms_allowDefaultTemplateParams = true;\n", name); + } + + fp.print("\n"); + fp.print("\n"); + fp.print("/**\n"); + fp.print(" * Class constructor.\n"); + fp.print(" */\n"); + fp.print("%s::%s(const std::string & filename)\n", name, name); +// if (sourceTemplate.hasList()) + sourceTemplate.writeSourceLoadedFlagInit(fp); + fp.print("{\n"); +// fp.print("\tsetId(%s);\n", getTemplateId().tagString.c_str()); + fp.print("} // %s::%s\n", name, name); + fp.print("\n"); + fp.print("/**\n"); + fp.print(" * Class destructor.\n"); + fp.print(" */\n"); + fp.print("%s::~%s()\n", name, name); + fp.print("{\n"); + sourceTemplate.writeSourceCleanup(fp); + fp.print("} // %s::~%s\n", name, name); + fp.print("\n"); + fp.print("/**\n"); + fp.print(" * Static function used to register this template.\n"); + fp.print(" */\n"); + fp.print("void %s::registerMe(void)\n", name); + fp.print("{\n"); + fp.print("\tObjectTemplateList::registerTemplate(%s_tag, create);\n", name); + fp.print("} // %s::registerMe\n", name); + fp.print("\n"); + fp.print("/**\n"); + fp.print(" * Creates a %s template.\n", name); + fp.print(" *\n"); + fp.print(" * @return a new instance of the template\n"); + fp.print(" */\n"); + fp.print("ObjectTemplate * %s::create(const std::string & filename)\n", name); + fp.print("{\n"); + fp.print("\treturn new %s(filename);\n", name); + fp.print("} // %s::create\n", name); + fp.print("\n"); + fp.print("/**\n"); + fp.print(" * Returns the template id.\n"); + fp.print(" *\n"); + fp.print(" * @return the template id\n"); + fp.print(" */\n"); + fp.print("Tag %s::getId(void) const\n", name); + fp.print("{\n"); + fp.print("\treturn %s_tag;\n", name); + fp.print("} // %s::getId\n", name); + fp.print("\n"); + fp.print("/**\n"); + fp.print(" * Returns this template's version.\n"); + fp.print(" *\n"); + fp.print(" * @return the version\n"); + fp.print(" */\n"); + fp.print("Tag %s::getTemplateVersion(void) const\n", name); + fp.print("{\n"); + fp.print("\treturn m_templateVersion;\n"); + fp.print("} // %s::getTemplateVersion\n", name); + fp.print("\n"); + fp.print("/**\n"); + fp.print(" * Returns the highest version of this template or it's base templates.\n"); + fp.print(" *\n"); + fp.print(" * @return the highest version\n"); + fp.print(" */\n"); + fp.print("Tag %s::getHighestTemplateVersion(void) const\n", name); + fp.print("{\n"); + fp.print("\tif (m_baseData == NULL)\n"); + fp.print("\t\treturn m_templateVersion;\n"); + fp.print("\tconst %s * base = dynamic_cast(m_baseData);\n", name, name); + fp.print("\tif (base == NULL)\n"); + fp.print("\t\treturn m_templateVersion;\n"); + fp.print("\treturn std::max(m_templateVersion, base->getHighestTemplateVersion());\n"); + fp.print("} // %s::getHighestTemplateVersion\n", name); + fp.print("\n"); +} // TemplateDefinitionFile::writeClassSourceBegin + +/** + * Main parser for a tdf file. Parses initialization data, creates the header and + * source files, and passes parameter definitions to the appropriate function. + * + * @param fp file to parse + * + * @return 0 on success, -1 on fail + */ +int TemplateDefinitionFile::parse(File &fp) +{ +static const int BUFFER_SIZE = 1024; +int lineLen; +char buffer[BUFFER_SIZE]; +char token[BUFFER_SIZE]; +TemplateData *currentTemplate = NULL; + + cleanup(); + + setTemplateFilename(fp.getFilename().getName()); + + for (;;) + { + lineLen = fp.readLine(buffer, BUFFER_SIZE); + if (lineLen == -1) + break; + else if (lineLen == -2) + return -1; + + const char *line = buffer; + line = getNextWhitespaceToken(line, token); + if (*token == '\0') + break; + + if (strcmp(token, "version") == 0) + { + if (m_templateName.size() == 0) + { + fp.printError("no template name defined"); + return -1; + } + else if (m_templateId.tag == NO_TAG) + { + fp.printError("no template id defined"); + return -1; + } + else if (m_path.getPath().size() == 0) + { + fp.printError("no path defined"); + return -1; + } + else if (m_compilerPath.getPath().size() == 0) + { + fp.printError("no compiler path defined"); + return -1; + } +// if (m_baseName.size() == 0 && m_templateName != ROOT_TEMPLATE_NAME) +// m_baseName = ROOT_TEMPLATE_NAME; + line = getNextWhitespaceToken(line, token); + int version = atoi(token); + if (version < 0 || version > 9999) + { + fp.printError("version out of range"); + return -1; + } + if (m_templateMap.find(version) != m_templateMap.end()) + { + fp.printError("version already defined"); + return -1; + } + if (version > m_highestVersion) + m_highestVersion = version; + + currentTemplate = new TemplateData(version, *this); + m_templateMap[version] = currentTemplate; + } + else if (currentTemplate != NULL) + { + line = currentTemplate->parseLine(fp, buffer, token); + if (line == CHAR_ERROR) + return -1; + } + else if (*token == '/' && *(token + 1) == '/') + { + if (m_baseName.size() == 0 && m_templateId.tag == NO_TAG) + m_fileComments.push_back(buffer); + } + else if (strcmp(token, "base") == 0) + { + if (m_baseName.size() != 0) + { + fp.printError("base name already defined"); + return -1; + } + line = getNextWhitespaceToken(line, token); + setBaseFilename(token); + + // load and parse the base template + Filename baseFileName = fp.getFilename(); + baseFileName.setName(token); + File baseFp(baseFileName, "rt"); + if (!baseFp.isOpened()) + { + fp.printError("unable to open base template definition"); + return -1; + } + if (m_baseDefinitionFile == NULL) + m_baseDefinitionFile = new TemplateDefinitionFile; + else + m_baseDefinitionFile->cleanup(); + int result = m_baseDefinitionFile->parse(baseFp); + if (result != 0) + return result; + } + else if (strcmp(token, "id") == 0) + { + if (m_templateId.tag != NO_TAG) + { + fp.printError("template id already defined"); + return -1; + } + line = getNextWhitespaceToken(line, token); + if (strlen(token) != 4) + { + fp.printError("id not 4 characters"); + return -1; + } + m_templateId.tag = ConvertStringToTag(token); + m_templateId.tagString = ConvertStringToTagString(token); + } + else if (strcmp(token, "templatename") == 0) + { + line = getNextWhitespaceToken(line, token); + m_templateNameFilter = token; + + //-- Attempt to compile the regex. + if (m_filterCompiledRegex != NULL) + { + // First free the existing compiled regex. + RegexServices::freeMemory(m_filterCompiledRegex); + m_filterCompiledRegex = NULL; + } + + //-- Compile the new regex. + char const *errorString = NULL; + int errorOffset = 0; + + m_filterCompiledRegex = pcre_compile(m_templateNameFilter.c_str(), 0, &errorString, &errorOffset, NULL); + WARNING(m_filterCompiledRegex == NULL, ("TemplateDefinitionFile::parse(): pcre_compile() failed, error=[%s], errorOffset=[%d], regex text=[%s].", errorString, errorOffset, m_templateNameFilter.c_str())); + } + else if (strcmp(token, "clientpath") == 0 || + strcmp(token, "serverpath") == 0 || + strcmp(token, "sharedpath") == 0) + { + if (m_path.getPath().size() != 0) + { + fp.printError("path already defined"); + return -1; + } + if (strcmp(token, "clientpath") == 0) + m_templateLocation = LOC_CLIENT; + else if (strcmp(token, "serverpath") == 0) + m_templateLocation = LOC_SERVER; + else + m_templateLocation = LOC_SHARED; + line = getNextWhitespaceToken(line, token); + m_path.setPath(token); + m_path.prependPath(fp.getFilename()); + // reset the template name to add the corrent prefix to the template + // name + setTemplateFilename(m_templateFilename); + if (!m_baseFilename.empty()) + setBaseFilename(m_baseFilename); + } + else if (strcmp(token, "compilerpath") == 0) + { + if (m_compilerPath.getPath().size() != 0) + { + fp.printError("compiler path already defined"); + return -1; + } + line = getNextWhitespaceToken(line, token); + m_compilerPath.setPath(token); + m_compilerPath.prependPath(fp.getFilename()); + } + else + { + char errbuf[2048]; + sprintf(errbuf, "I don't know how to handle this line!: <%s>. " + "Barfed on token <%s>.", buffer, token); + fp.printError(errbuf); + return -1; + } + } + return 0; +} // TemplateDefinitionFile::parse diff --git a/src/external/3rd/library/OCI/include/oratypes.h b/src/external/3rd/library/OCI/include/oratypes.h index e33654cd7..37803bcb8 100644 --- a/src/external/3rd/library/OCI/include/oratypes.h +++ b/src/external/3rd/library/OCI/include/oratypes.h @@ -1,322 +1,296 @@ -/* - Copyright (c) 1982, 2012, Oracle and/or its affiliates. All rights reserved. -*/ - -/* - * $Header: oracore3/public/oratypes.h /nt/22 2012/03/30 05:32:52 vtalluru Exp $ - */ - - - -#ifndef ORATYPES -# define ORATYPES -# define SX_ORACLE -# define SX3_ORACLE - - -#ifndef ORASTDDEF -# include -# define ORASTDDEF -#endif - -#ifndef ORALIMITS -# include -# define ORALIMITS -#endif - - -#ifndef TRUE -# define TRUE 1 -# define FALSE 0 -#endif - - -#ifndef lint -typedef unsigned char ub1; -typedef signed char sb1; -#else -#define ub1 unsigned char -#define sb1 signed char -#endif - -#define UB1MAXVAL ((ub1)UCHAR_MAX) -#define UB1MINVAL ((ub1) 0) -#define SB1MAXVAL ((sb1)SCHAR_MAX) -#define SB1MINVAL ((sb1)SCHAR_MIN) -#define MINUB1MAXVAL ((ub1) 255) -#define MAXUB1MINVAL ((ub1) 0) -#define MINSB1MAXVAL ((sb1) 127) -#define MAXSB1MINVAL ((sb1) -127) - - - - -#ifndef lint -typedef unsigned short ub2; -typedef signed short sb2; -#else -#define ub2 unsigned short -#define sb2 signed short -#endif - -#define UB2MAXVAL ((ub2)USHRT_MAX) -#define UB2MINVAL ((ub2) 0) -#define SB2MAXVAL ((sb2) SHRT_MAX) -#define SB2MINVAL ((sb2) SHRT_MIN) -#define MINUB2MAXVAL ((ub2) 65535) -#define MAXUB2MINVAL ((ub2) 0) -#define MINSB2MAXVAL ((sb2) 32767) -#define MAXSB2MINVAL ((sb2)-32767) - - - - -#ifndef lint -typedef unsigned int ub4; -typedef signed int sb4; -#else -#define eb4 int -#define ub4 unsigned int -#define sb4 signed int -#endif - -#define UB4MAXVAL ((ub4)UINT_MAX) -#define UB4MINVAL ((ub4) 0) -#define SB4MAXVAL ((sb4) INT_MAX) -#define SB4MINVAL ((sb4) INT_MIN) -#define MINUB4MAXVAL ((ub4) 4294967295) -#define MAXUB4MINVAL ((ub4) 0) -#define MINSB4MAXVAL ((sb4) 2147483647) -#define MAXSB4MINVAL ((sb4)-2147483647) - - -/* --- Signed/Unsigned eight-byte scalar (orasb8/oraub8) --- */ - -#define ORAXB8_DEFINED -#ifndef lint -#ifndef __GNUC__ -#ifdef __BORLANDC__ - typedef unsigned __int64 oraub8; - typedef signed __int64 orasb8; -#else - typedef unsigned _int64 oraub8; - typedef signed _int64 orasb8; -#endif /* __BORLANDC__ */ -#else - typedef unsigned long long oraub8; - typedef signed long long orasb8; -#endif - typedef oraub8 ub8; - typedef orasb8 sb8; -#else -# define ub8 oraub8 -# define sb8 orasb8 -# define oraub8 unsigned _int64 -# define orasb8 signed _int64 -#endif /* !lint */ - -#define ORAUB8MINVAL ((oraub8)0) -#define ORAUB8MAXVAL ((oraub8)18446744073709551615) -#define ORASB8MINVAL ((orasb8)-9223372036854775808) -#define ORASB8MAXVAL ((orasb8) 9223372036854775807) - -#define MAXORAUB8MINVAL ((oraub8)0) -#define MINORAUB8MAXVAL ((oraub8)18446744073709551615) -#define MAXORASB8MINVAL ((orasb8)-9223372036854775807) -#define MINORASB8MAXVAL ((orasb8) 9223372036854775807) - - -#define UB1BITS CHAR_BIT -#define UB1MASK ((1 << ((uword)CHAR_BIT)) - 1) - - -#ifdef lint -# define oratext unsigned char -#else - typedef unsigned char oratext; -#endif - - -#ifndef lint -typedef char eb1; -typedef short eb2; -typedef int eb4; -#else -# define eb1 char -# define eb2 short -# define eb4 int -#endif - -#define EB1MAXVAL ((eb1)SCHAR_MAX) -#define EB1MINVAL ((eb1) 0) -#define MINEB1MAXVAL ((eb1) 127) -#define MAXEB1MINVAL ((eb1) 0) -#define EB2MAXVAL ((eb2) SHRT_MAX) -#define EB2MINVAL ((eb2) 0) -#define MINEB2MAXVAL ((eb2) 32767) -#define MAXEB2MINVAL ((eb2) 0) -#define EB4MAXVAL ((eb4) INT_MAX) -#define EB4MINVAL ((eb4) 0) -#define MINEB4MAXVAL ((eb4) 2147483647) -#define MAXEB4MINVAL ((eb4) 0) - - - - -#ifndef lint -typedef sb1 b1; -#else -#define b1 sb1 -#endif -#define B1MAXVAL SB1MAXVAL -#define B1MINVAL SB1MINVAL - -#ifndef lint -typedef sb2 b2; -#else -#define b2 sb2 -#endif -#define B2MAXVAL SB2MAXVAL -#define B2MINVAL SB2MINVAL - -#ifndef lint -typedef sb4 b4; -#else -#define b4 sb4 -#endif -# define B4MAXVAL SB4MAXVAL -# define B4MINVAL SB4MINVAL - - -#if !defined(LUSEMFC) -# ifdef lint -# define text unsigned char -# else - typedef oratext text; -# endif -#endif - -#ifdef lint -# define OraText unsigned char -#else - typedef oratext OraText; -#endif - -#ifndef lint -typedef int eword; -typedef unsigned int uword; -typedef signed int sword; -#else -#define eword int -#define uword unsigned int -#define sword signed int -#endif - -#define EWORDMAXVAL ((eword) INT_MAX) -#define EWORDMINVAL ((eword) 0) -#define UWORDMAXVAL ((uword)UINT_MAX) -#define UWORDMINVAL ((uword) 0) -#define SWORDMAXVAL ((sword) INT_MAX) -#define SWORDMINVAL ((sword) INT_MIN) -#define MINEWORDMAXVAL ((eword) 2147483647) -#define MAXEWORDMINVAL ((eword) 0) -#define MINUWORDMAXVAL ((uword) 4294967295) -#define MAXUWORDMINVAL ((uword) 0) -#define MINSWORDMAXVAL ((sword) 2147483647) -#define MAXSWORDMINVAL ((sword) -2147483647) - - -#ifdef _WIN64 - -#ifndef lint -#if defined(__BORLANDC__) || defined(__MINGW64__) -typedef unsigned __int64 ubig_ora; -typedef signed __int64 sbig_ora; -#else -typedef unsigned _int64 ubig_ora; -typedef signed _int64 sbig_ora; -#endif /* End of __BORLANDC__ */ -#else -#define ubig_ora unsigned _int64 -#define sbig_ora signed _int64 -#endif /* End of lint */ - -#define UBIG_ORAMAXVAL ((ubig_ora)_UI64_MAX) -#define UBIG_ORAMINVAL ((ubig_ora) 0) -#define SBIG_ORAMAXVAL ((sbig_ora) _I64_MAX) -#define SBIG_ORAMINVAL ((sbig_ora) _I64_MIN) -#define MINUBIG_ORAMAXVAL ((ubig_ora) 4294967295) -#define MAXUBIG_ORAMINVAL ((ubig_ora) 0) -#define MINSBIG_ORAMAXVAL ((sbig_ora) 2147483647) -#define MAXSBIG_ORAMINVAL ((sbig_ora)-2147483647) - -#else - -#ifndef lint -typedef unsigned long ubig_ora; -typedef signed long sbig_ora; -#else -#define ubig_ora unsigned long -#define sbig_ora signed long -#endif - -#define UBIG_ORAMAXVAL ((ubig_ora)ULONG_MAX) -#define UBIG_ORAMINVAL ((ubig_ora) 0) -#define SBIG_ORAMAXVAL ((sbig_ora) LONG_MAX) -#define SBIG_ORAMINVAL ((sbig_ora) LONG_MIN) -#define MINUBIG_ORAMAXVAL ((ubig_ora) 4294967295) -#define MAXUBIG_ORAMINVAL ((ubig_ora) 0) -#define MINSBIG_ORAMAXVAL ((sbig_ora) 2147483647) -#define MAXSBIG_ORAMINVAL ((sbig_ora)-2147483647) - -#endif /* _WIN64 */ - -#define UBIGORABITS (UB1BITS * sizeof(ubig_ora)) - - -#undef CONST -#define CONST const - - -#define dvoid void - - -typedef void (*lgenfp_t)( void ); - - - -#ifndef ORASYS_TYPES -# include -# define ORASYS_TYPES -#endif - - - -#ifndef boolean -# define boolean int -#endif - - - -#ifdef sparc -# define SIZE_TMAXVAL SB4MAXVAL -#else -# define SIZE_TMAXVAL UB4MAXVAL -#endif - -#define MINSIZE_TMAXVAL (size_t)4294967295 - - -#if !defined(MOTIF) && !defined(LISPL) && !defined(__cplusplus) && !defined(LUSEMFC) -typedef oratext *string; -#endif - -#ifndef lint -typedef unsigned short utext; -#else -#define utext unsigned short -#endif - - -#endif - +/* $RCSfile: oratypes.h $ $Date: 20-jul-00.13:44:19 + ---------------------------------------------------------------------- + Copyright (c) 1982, 2008, Oracle and/or its affiliates. All rights reserved. + ---------------------------------------------------------------------- */ + +#ifndef ORATYPES +# define ORATYPES +# define SX_ORACLE +# define SX3_ORACLE + +#ifndef ORASTDDEF +# include +# define ORASTDDEF +#endif + +#ifndef ORALIMITS +# include +# define ORALIMITS +#endif + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +#endif + +/* --- Signed/Unsigned one-byte scalar (sb1/ub1) --- */ + +#ifndef lint + typedef unsigned char ub1; + typedef signed char sb1; + typedef char eb1; +#else +# define ub1 unsigned char +# define sb1 signed char +# define eb1 char +#endif + +#define UB1MAXVAL ((ub1)UCHAR_MAX) +#define UB1MINVAL ((ub1) 0) +#define SB1MAXVAL ((sb1)SCHAR_MAX) +#define SB1MINVAL ((sb1)SCHAR_MIN) + +#define MINUB1MAXVAL ((ub1) 255) +#define MAXUB1MINVAL ((ub1) 0) +#define MINSB1MAXVAL ((sb1) 127) +#define MAXSB1MINVAL ((sb1) -127) + +#define EB1MAXVAL ((eb1)SCHAR_MAX) +#define EB1MINVAL ((eb1) 0) + +#define MINEB1MAXVAL ((eb1) 127) +#define MAXEB1MINVAL ((eb1) 0) + +#define UB1BITS CHAR_BIT +#define UB1MASK ((1 << ((uword)CHAR_BIT)) - 1) + +/* backwards compatibility */ + +#ifndef lint + typedef sb1 b1; +#else +# define b1 sb1 +#endif + +#define B1MAXVAL SB1MAXVAL +#define B1MINVAL SB1MINVAL + +/* --- Signed/Unsigned two-byte scalar (sb2/ub2) --- */ + +#ifndef lint + typedef unsigned short ub2; + typedef signed short sb2; + typedef short eb2; +#else +# define ub2 unsigned short +# define sb2 signed short +# define eb2 short +#endif + +#define UB2MAXVAL ((ub2)USHRT_MAX) +#define UB2MINVAL ((ub2) 0) +#define SB2MAXVAL ((sb2) SHRT_MAX) +#define SB2MINVAL ((sb2) SHRT_MIN) + +#define MINUB2MAXVAL ((ub2) 65535) +#define MAXUB2MINVAL ((ub2) 0) +#define MINSB2MAXVAL ((sb2) 32767) +#define MAXSB2MINVAL ((sb2)-32767) + +#define EB2MAXVAL ((eb2) SHRT_MAX) +#define EB2MINVAL ((eb2) 0) + +#define MINEB2MAXVAL ((eb2) 32767) +#define MAXEB2MINVAL ((eb2) 0) + +/* backwards compatibility */ + +#ifndef lint + typedef sb2 b2; +#else +# define b2 sb2 +#endif + +#define B2MAXVAL SB2MAXVAL +#define B2MINVAL SB2MINVAL + +/* --- Signed/Unsigned four-byte scalar (sb4/ub4) --- */ + +#ifndef lint + typedef unsigned int ub4; + typedef signed int sb4; + typedef int eb4; +#else +# define ub4 unsigned int +# define sb4 signed int +# define eb4 int +#endif + +#define UB4MAXVAL ((ub4)UINT_MAX) +#define UB4MINVAL ((ub4) 0) +#define SB4MAXVAL ((sb4) INT_MAX) +#define SB4MINVAL ((sb4) INT_MIN) + +#define MINUB4MAXVAL ((ub4) 4294967295) +#define MAXUB4MINVAL ((ub4) 0) +#define MINSB4MAXVAL ((sb4) 2147483647) +#define MAXSB4MINVAL ((sb4)-2147483647) + +#define EB4MAXVAL ((eb4) INT_MAX) +#define EB4MINVAL ((eb4) 0) + +#define MINEB4MAXVAL ((eb4) 2147483647) +#define MAXEB4MINVAL ((eb4) 0) + +/* --- Signed/Unsigned eight-byte scalar (orasb8/oraub8) --- */ + +# define ORAXB8_DEFINED +# ifndef lint +# ifdef __LP64__ + typedef unsigned long oraub8; + typedef signed long orasb8; +# else + typedef unsigned long long oraub8; + typedef signed long long orasb8; +# endif /* __LP64__ */ + typedef oraub8 ub8; + typedef orasb8 sb8; +# else +# define ub8 oraub8 +# define sb8 orasb8 +# ifdef __LP64__ +# define oraub8 unsigned long +# define orasb8 signed long +# else +# define oraub8 unsigned long long +# define orasb8 signed long long +# endif /* __LP64__ */ +# endif /* !lint */ + +# define ORAUB8MINVAL ((oraub8)0) +# define ORAUB8MAXVAL ((oraub8)18446744073709551615) +# define ORASB8MINVAL ((orasb8)-9223372036854775808) +# define ORASB8MAXVAL ((orasb8) 9223372036854775807) + +# define MAXORAUB8MINVAL ((oraub8)0) +# define MINORAUB8MAXVAL ((oraub8)18446744073709551615) +# define MAXORASB8MINVAL ((orasb8)-9223372036854775807) +# define MINORASB8MAXVAL ((orasb8) 9223372036854775807) + +/* backwards compatibility */ + +#ifndef lint + typedef sb4 b4; +#else +# define b4 sb4 +#endif + +#define B4MAXVAL SB4MAXVAL +#define B4MINVAL SB4MINVAL + +/* --- Character pointer --- */ + +#ifdef lint +# define oratext unsigned char +#else + typedef unsigned char oratext; +#endif + +#if !defined(LUSEMFC) +# ifdef lint +# define text unsigned char +# define OraText oratext +# else + typedef oratext text; + typedef oratext OraText; +# endif +#endif + +#if !defined(MOTIF) && !defined(LISPL) && !defined(__cplusplus) && \ + !defined(LUSEMFC) + typedef OraText *string; +#endif + +#ifndef lint + typedef unsigned short utext; +#else +# define utext unsigned short +#endif + +/* --- Boolean --- */ + +#ifndef boolean +# ifndef lint + typedef int boolean; +# else +# define boolean int +# endif +#endif + +/* --- Other data types --- */ + +#ifndef lint + typedef int eword; + typedef unsigned int uword; + typedef signed int sword; +#else +# define eword int +# define uword unsigned int +# define sword signed int +#endif + +#define EWORDMAXVAL ((eword) INT_MAX) +#define EWORDMINVAL ((eword) 0) + +#define UWORDMAXVAL ((uword)UINT_MAX) +#define UWORDMINVAL ((uword) 0) + +#define SWORDMAXVAL ((sword) INT_MAX) +#define SWORDMINVAL ((sword) INT_MIN) + +#define MINEWORDMAXVAL ((eword) 2147483647) +#define MAXEWORDMINVAL ((eword) 0) + +#define MINUWORDMAXVAL ((uword) 4294967295) +#define MAXUWORDMINVAL ((uword) 0) + +#define MINSWORDMAXVAL ((sword) 2147483647) +#define MAXSWORDMINVAL ((sword) -2147483647) + +#ifndef lint + typedef unsigned long ubig_ora; + typedef signed long sbig_ora; +#else +# define ubig_ora unsigned long +# define sbig_ora signed long +#endif + +#define UBIG_ORAMAXVAL ((ubig_ora)ULONG_MAX) +#define UBIG_ORAMINVAL ((ubig_ora) 0) + +#define SBIG_ORAMAXVAL ((sbig_ora) LONG_MAX) +#define SBIG_ORAMINVAL ((sbig_ora) LONG_MIN) + +#define MINUBIG_ORAMAXVAL ((ubig_ora) 4294967295) +#define MAXUBIG_ORAMINVAL ((ubig_ora) 0) + +#define MINSBIG_ORAMAXVAL ((sbig_ora) 2147483647) +#define MAXSBIG_ORAMINVAL ((sbig_ora)-2147483647) + +#define UBIGORABITS (UB1BITS * sizeof(ubig_ora)) + +/* --- Const --- */ + +#undef CONST +#define CONST const + +/* --- Misc --- */ + +#define dvoid void + +typedef void (*lgenfp_t)( void ); + +#ifndef ORASYS_TYPES +# include +# define ORASYS_TYPES +#endif + +#ifndef SIZE_TMAXVAL +# define SIZE_TMAXVAL UBIG_ORAMAXVAL +#endif + +#ifndef MINSIZE_TMAXVAL +# define MINSIZE_TMAXVAL (size_t)4294967295 +#endif + +#endif /* ORATYPES */ diff --git a/src/external/3rd/library/boost/boost/asio/detail/wince_thread.hpp b/src/external/3rd/library/boost/boost/asio/detail/wince_thread.hpp index 0d1ed082d..a36ee0188 100644 --- a/src/external/3rd/library/boost/boost/asio/detail/wince_thread.hpp +++ b/src/external/3rd/library/boost/boost/asio/detail/wince_thread.hpp @@ -1,118 +1,118 @@ -// -// detail/wince_thread.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_DETAIL_WINCE_THREAD_HPP -#define BOOST_ASIO_DETAIL_WINCE_THREAD_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include - -#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) - -#include -#include -#include -#include -#include - -#include - -namespace boost { -namespace asio { -namespace detail { - -DWORD WINAPI wince_thread_function(LPVOID arg); - -class wince_thread - : private noncopyable -{ -public: - // Constructor. - template - wince_thread(Function f, unsigned int = 0) - { - std::unique_ptr arg(new func(f)); - DWORD thread_id = 0; - thread_ = ::CreateThread(0, 0, wince_thread_function, - arg.get(), 0, &thread_id); - if (!thread_) - { - DWORD last_error = ::GetLastError(); - boost::system::error_code ec(last_error, - boost::asio::error::get_system_category()); - boost::asio::detail::throw_error(ec, "thread"); - } - arg.release(); - } - - // Destructor. - ~wince_thread() - { - ::CloseHandle(thread_); - } - - // Wait for the thread to exit. - void join() - { - ::WaitForSingleObject(thread_, INFINITE); - } - -private: - friend DWORD WINAPI wince_thread_function(LPVOID arg); - - class func_base - { - public: - virtual ~func_base() {} - virtual void run() = 0; - }; - - template - class func - : public func_base - { - public: - func(Function f) - : f_(f) - { - } - - virtual void run() - { - f_(); - } - - private: - Function f_; - }; - - ::HANDLE thread_; -}; - -inline DWORD WINAPI wince_thread_function(LPVOID arg) -{ - std::unique_ptr func( - static_cast(arg)); - func->run(); - return 0; -} - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) - -#endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP +// +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINCE_THREAD_HPP +#define BOOST_ASIO_DETAIL_WINCE_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +DWORD WINAPI wince_thread_function(LPVOID arg); + +class wince_thread + : private noncopyable +{ +public: + // Constructor. + template + wince_thread(Function f, unsigned int = 0) + { + std::unique_ptr arg(new func(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, wince_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~wince_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObject(thread_, INFINITE); + } + +private: + friend DWORD WINAPI wince_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI wince_thread_function(LPVOID arg) +{ + std::unique_ptr func( + static_cast(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/src/external/3rd/library/boost/boost/asio/io_service.hpp b/src/external/3rd/library/boost/boost/asio/io_service.hpp index a8be06181..6b543b4c8 100644 --- a/src/external/3rd/library/boost/boost/asio/io_service.hpp +++ b/src/external/3rd/library/boost/boost/asio/io_service.hpp @@ -1,772 +1,772 @@ -// -// io_service.hpp -// ~~~~~~~~~~~~~~ -// -// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_IO_SERVICE_HPP -#define BOOST_ASIO_IO_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) -# include -#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ - || defined(__osf__) -# include -#endif - -#include - -namespace boost { -namespace asio { - -class io_service; -template Service& use_service(io_service& ios); -template void add_service(io_service& ios, Service* svc); -template bool has_service(io_service& ios); - -namespace detail { -#if defined(BOOST_ASIO_HAS_IOCP) - typedef class win_iocp_io_service io_service_impl; - class win_iocp_overlapped_ptr; -#else - typedef class task_io_service io_service_impl; -#endif - class service_registry; -} // namespace detail - -/// Provides core I/O functionality. -/** - * The io_service class provides the core I/O functionality for users of the - * asynchronous I/O objects, including: - * - * @li boost::asio::ip::tcp::socket - * @li boost::asio::ip::tcp::acceptor - * @li boost::asio::ip::udp::socket - * @li boost::asio::deadline_timer. - * - * The io_service class also includes facilities intended for developers of - * custom asynchronous services. - * - * @par Thread Safety - * @e Distinct @e objects: Safe.@n - * @e Shared @e objects: Safe, with the specific exceptions of the reset() and - * notify_fork() functions. Calling reset() while there are unfinished run(), - * run_one(), poll() or poll_one() calls results in undefined behaviour. The - * notify_fork() function should not be called while any io_service function, - * or any function on an I/O object that is associated with the io_service, is - * being called in another thread. - * - * @par Concepts: - * Dispatcher. - * - * @par Synchronous and asynchronous operations - * - * Synchronous operations on I/O objects implicitly run the io_service object - * for an individual operation. The io_service functions run(), run_one(), - * poll() or poll_one() must be called for the io_service to perform - * asynchronous operations on behalf of a C++ program. Notification that an - * asynchronous operation has completed is delivered by invocation of the - * associated handler. Handlers are invoked only by a thread that is currently - * calling any overload of run(), run_one(), poll() or poll_one() for the - * io_service. - * - * @par Effect of exceptions thrown from handlers - * - * If an exception is thrown from a handler, the exception is allowed to - * propagate through the throwing thread's invocation of run(), run_one(), - * poll() or poll_one(). No other threads that are calling any of these - * functions are affected. It is then the responsibility of the application to - * catch the exception. - * - * After the exception has been caught, the run(), run_one(), poll() or - * poll_one() call may be restarted @em without the need for an intervening - * call to reset(). This allows the thread to rejoin the io_service object's - * thread pool without impacting any other threads in the pool. - * - * For example: - * - * @code - * boost::asio::io_service io_service; - * ... - * for (;;) - * { - * try - * { - * io_service.run(); - * break; // run() exited normally - * } - * catch (my_exception& e) - * { - * // Deal with exception as appropriate. - * } - * } - * @endcode - * - * @par Stopping the io_service from running out of work - * - * Some applications may need to prevent an io_service object's run() call from - * returning when there is no more work to do. For example, the io_service may - * be being run in a background thread that is launched prior to the - * application's asynchronous operations. The run() call may be kept running by - * creating an object of type boost::asio::io_service::work: - * - * @code boost::asio::io_service io_service; - * boost::asio::io_service::work work(io_service); - * ... @endcode - * - * To effect a shutdown, the application will then need to call the io_service - * object's stop() member function. This will cause the io_service run() call - * to return as soon as possible, abandoning unfinished operations and without - * permitting ready handlers to be dispatched. - * - * Alternatively, if the application requires that all operations and handlers - * be allowed to finish normally, the work object may be explicitly destroyed. - * - * @code boost::asio::io_service io_service; - * unique_ptr work( - * new boost::asio::io_service::work(io_service)); - * ... - * work.reset(); // Allow run() to exit. @endcode - * - * @par The io_service class and I/O services - * - * Class io_service implements an extensible, type-safe, polymorphic set of I/O - * services, indexed by service type. An object of class io_service must be - * initialised before I/O objects such as sockets, resolvers and timers can be - * used. These I/O objects are distinguished by having constructors that accept - * an @c io_service& parameter. - * - * I/O services exist to manage the logical interface to the operating system on - * behalf of the I/O objects. In particular, there are resources that are shared - * across a class of I/O objects. For example, timers may be implemented in - * terms of a single timer queue. The I/O services manage these shared - * resources. - * - * Access to the services of an io_service is via three function templates, - * use_service(), add_service() and has_service(). - * - * In a call to @c use_service(), the type argument chooses a service, - * making available all members of the named type. If @c Service is not present - * in an io_service, an object of type @c Service is created and added to the - * io_service. A C++ program can check if an io_service implements a - * particular service with the function template @c has_service(). - * - * Service objects may be explicitly added to an io_service using the function - * template @c add_service(). If the @c Service is already present, the - * service_already_exists exception is thrown. If the owner of the service is - * not the same object as the io_service parameter, the invalid_service_owner - * exception is thrown. - * - * Once a service reference is obtained from an io_service object by calling - * use_service(), that reference remains usable as long as the owning io_service - * object exists. - * - * All I/O service implementations have io_service::service as a public base - * class. Custom I/O services may be implemented by deriving from this class and - * then added to an io_service using the facilities described above. - */ -class io_service - : private noncopyable -{ -private: - typedef detail::io_service_impl impl_type; -#if defined(BOOST_ASIO_HAS_IOCP) - friend class detail::win_iocp_overlapped_ptr; -#endif - -public: - class work; - friend class work; - - class id; - - class service; - - class strand; - - /// Constructor. - BOOST_ASIO_DECL io_service(); - - /// Constructor. - /** - * Construct with a hint about the required level of concurrency. - * - * @param concurrency_hint A suggestion to the implementation on how many - * threads it should allow to run simultaneously. - */ - BOOST_ASIO_DECL explicit io_service(std::size_t concurrency_hint); - - /// Destructor. - /** - * On destruction, the io_service performs the following sequence of - * operations: - * - * @li For each service object @c svc in the io_service set, in reverse order - * of the beginning of service object lifetime, performs - * @c svc->shutdown_service(). - * - * @li Uninvoked handler objects that were scheduled for deferred invocation - * on the io_service, or any associated strand, are destroyed. - * - * @li For each service object @c svc in the io_service set, in reverse order - * of the beginning of service object lifetime, performs - * delete static_cast(svc). - * - * @note The destruction sequence described above permits programs to - * simplify their resource management by using @c shared_ptr<>. Where an - * object's lifetime is tied to the lifetime of a connection (or some other - * sequence of asynchronous operations), a @c shared_ptr to the object would - * be bound into the handlers for all asynchronous operations associated with - * it. This works as follows: - * - * @li When a single connection ends, all associated asynchronous operations - * complete. The corresponding handler objects are destroyed, and all - * @c shared_ptr references to the objects are destroyed. - * - * @li To shut down the whole program, the io_service function stop() is - * called to terminate any run() calls as soon as possible. The io_service - * destructor defined above destroys all handlers, causing all @c shared_ptr - * references to all connection objects to be destroyed. - */ - BOOST_ASIO_DECL ~io_service(); - - /// Run the io_service object's event processing loop. - /** - * The run() function blocks until all work has finished and there are no - * more handlers to be dispatched, or until the io_service has been stopped. - * - * Multiple threads may call the run() function to set up a pool of threads - * from which the io_service may execute handlers. All threads that are - * waiting in the pool are equivalent and the io_service may choose any one - * of them to invoke a handler. - * - * A normal exit from the run() function implies that the io_service object - * is stopped (the stopped() function returns @c true). Subsequent calls to - * run(), run_one(), poll() or poll_one() will return immediately unless there - * is a prior call to reset(). - * - * @return The number of handlers that were executed. - * - * @throws boost::system::system_error Thrown on failure. - * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_service object. - * - * The poll() function may also be used to dispatch ready handlers, but - * without blocking. - */ - BOOST_ASIO_DECL std::size_t run(); - - /// Run the io_service object's event processing loop. - /** - * The run() function blocks until all work has finished and there are no - * more handlers to be dispatched, or until the io_service has been stopped. - * - * Multiple threads may call the run() function to set up a pool of threads - * from which the io_service may execute handlers. All threads that are - * waiting in the pool are equivalent and the io_service may choose any one - * of them to invoke a handler. - * - * A normal exit from the run() function implies that the io_service object - * is stopped (the stopped() function returns @c true). Subsequent calls to - * run(), run_one(), poll() or poll_one() will return immediately unless there - * is a prior call to reset(). - * - * @param ec Set to indicate what error occurred, if any. - * - * @return The number of handlers that were executed. - * - * @note The run() function must not be called from a thread that is currently - * calling one of run(), run_one(), poll() or poll_one() on the same - * io_service object. - * - * The poll() function may also be used to dispatch ready handlers, but - * without blocking. - */ - BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); - - /// Run the io_service object's event processing loop to execute at most one - /// handler. - /** - * The run_one() function blocks until one handler has been dispatched, or - * until the io_service has been stopped. - * - * @return The number of handlers that were executed. A zero return value - * implies that the io_service object is stopped (the stopped() function - * returns @c true). Subsequent calls to run(), run_one(), poll() or - * poll_one() will return immediately unless there is a prior call to - * reset(). - * - * @throws boost::system::system_error Thrown on failure. - */ - BOOST_ASIO_DECL std::size_t run_one(); - - /// Run the io_service object's event processing loop to execute at most one - /// handler. - /** - * The run_one() function blocks until one handler has been dispatched, or - * until the io_service has been stopped. - * - * @return The number of handlers that were executed. A zero return value - * implies that the io_service object is stopped (the stopped() function - * returns @c true). Subsequent calls to run(), run_one(), poll() or - * poll_one() will return immediately unless there is a prior call to - * reset(). - * - * @return The number of handlers that were executed. - */ - BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); - - /// Run the io_service object's event processing loop to execute ready - /// handlers. - /** - * The poll() function runs handlers that are ready to run, without blocking, - * until the io_service has been stopped or there are no more ready handlers. - * - * @return The number of handlers that were executed. - * - * @throws boost::system::system_error Thrown on failure. - */ - BOOST_ASIO_DECL std::size_t poll(); - - /// Run the io_service object's event processing loop to execute ready - /// handlers. - /** - * The poll() function runs handlers that are ready to run, without blocking, - * until the io_service has been stopped or there are no more ready handlers. - * - * @param ec Set to indicate what error occurred, if any. - * - * @return The number of handlers that were executed. - */ - BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); - - /// Run the io_service object's event processing loop to execute one ready - /// handler. - /** - * The poll_one() function runs at most one handler that is ready to run, - * without blocking. - * - * @return The number of handlers that were executed. - * - * @throws boost::system::system_error Thrown on failure. - */ - BOOST_ASIO_DECL std::size_t poll_one(); - - /// Run the io_service object's event processing loop to execute one ready - /// handler. - /** - * The poll_one() function runs at most one handler that is ready to run, - * without blocking. - * - * @param ec Set to indicate what error occurred, if any. - * - * @return The number of handlers that were executed. - */ - BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); - - /// Stop the io_service object's event processing loop. - /** - * This function does not block, but instead simply signals the io_service to - * stop. All invocations of its run() or run_one() member functions should - * return as soon as possible. Subsequent calls to run(), run_one(), poll() - * or poll_one() will return immediately until reset() is called. - */ - BOOST_ASIO_DECL void stop(); - - /// Determine whether the io_service object has been stopped. - /** - * This function is used to determine whether an io_service object has been - * stopped, either through an explicit call to stop(), or due to running out - * of work. When an io_service object is stopped, calls to run(), run_one(), - * poll() or poll_one() will return immediately without invoking any - * handlers. - * - * @return @c true if the io_service object is stopped, otherwise @c false. - */ - BOOST_ASIO_DECL bool stopped() const; - - /// Reset the io_service in preparation for a subsequent run() invocation. - /** - * This function must be called prior to any second or later set of - * invocations of the run(), run_one(), poll() or poll_one() functions when a - * previous invocation of these functions returned due to the io_service - * being stopped or running out of work. After a call to reset(), the - * io_service object's stopped() function will return @c false. - * - * This function must not be called while there are any unfinished calls to - * the run(), run_one(), poll() or poll_one() functions. - */ - BOOST_ASIO_DECL void reset(); - - /// Request the io_service to invoke the given handler. - /** - * This function is used to ask the io_service to execute the given handler. - * - * The io_service guarantees that the handler will only be called in a thread - * in which the run(), run_one(), poll() or poll_one() member functions is - * currently being invoked. The handler may be executed inside this function - * if the guarantee can be met. - * - * @param handler The handler to be called. The io_service will make - * a copy of the handler object as required. The function signature of the - * handler must be: @code void handler(); @endcode - * - * @note This function throws an exception only if: - * - * @li the handler's @c asio_handler_allocate function; or - * - * @li the handler's copy constructor - * - * throws an exception. - */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); - - /// Request the io_service to invoke the given handler and return immediately. - /** - * This function is used to ask the io_service to execute the given handler, - * but without allowing the io_service to call the handler from inside this - * function. - * - * The io_service guarantees that the handler will only be called in a thread - * in which the run(), run_one(), poll() or poll_one() member functions is - * currently being invoked. - * - * @param handler The handler to be called. The io_service will make - * a copy of the handler object as required. The function signature of the - * handler must be: @code void handler(); @endcode - * - * @note This function throws an exception only if: - * - * @li the handler's @c asio_handler_allocate function; or - * - * @li the handler's copy constructor - * - * throws an exception. - */ - template - BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) - post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); - - /// Create a new handler that automatically dispatches the wrapped handler - /// on the io_service. - /** - * This function is used to create a new handler function object that, when - * invoked, will automatically pass the wrapped handler to the io_service - * object's dispatch function. - * - * @param handler The handler to be wrapped. The io_service will make a copy - * of the handler object as required. The function signature of the handler - * must be: @code void handler(A1 a1, ... An an); @endcode - * - * @return A function object that, when invoked, passes the wrapped handler to - * the io_service object's dispatch function. Given a function object with the - * signature: - * @code R f(A1 a1, ... An an); @endcode - * If this function object is passed to the wrap function like so: - * @code io_service.wrap(f); @endcode - * then the return value is a function object with the signature - * @code void g(A1 a1, ... An an); @endcode - * that, when invoked, executes code equivalent to: - * @code io_service.dispatch(boost::bind(f, a1, ... an)); @endcode - */ - template -#if defined(GENERATING_DOCUMENTATION) - unspecified -#else - detail::wrapped_handler -#endif - wrap(Handler handler); - - /// Fork-related event notifications. - enum fork_event - { - /// Notify the io_service that the process is about to fork. - fork_prepare, - - /// Notify the io_service that the process has forked and is the parent. - fork_parent, - - /// Notify the io_service that the process has forked and is the child. - fork_child - }; - - /// Notify the io_service of a fork-related event. - /** - * This function is used to inform the io_service that the process is about - * to fork, or has just forked. This allows the io_service, and the services - * it contains, to perform any necessary housekeeping to ensure correct - * operation following a fork. - * - * This function must not be called while any other io_service function, or - * any function on an I/O object associated with the io_service, is being - * called in another thread. It is, however, safe to call this function from - * within a completion handler, provided no other thread is accessing the - * io_service. - * - * @param event A fork-related event. - * - * @throws boost::system::system_error Thrown on failure. If the notification - * fails the io_service object should no longer be used and should be - * destroyed. - * - * @par Example - * The following code illustrates how to incorporate the notify_fork() - * function: - * @code my_io_service.notify_fork(boost::asio::io_service::fork_prepare); - * if (fork() == 0) - * { - * // This is the child process. - * my_io_service.notify_fork(boost::asio::io_service::fork_child); - * } - * else - * { - * // This is the parent process. - * my_io_service.notify_fork(boost::asio::io_service::fork_parent); - * } @endcode - * - * @note For each service object @c svc in the io_service set, performs - * svc->fork_service();. When processing the fork_prepare event, - * services are visited in reverse order of the beginning of service object - * lifetime. Otherwise, services are visited in order of the beginning of - * service object lifetime. - */ - BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event event); - - /// Obtain the service object corresponding to the given type. - /** - * This function is used to locate a service object that corresponds to - * the given service type. If there is no existing implementation of the - * service, then the io_service will create a new instance of the service. - * - * @param ios The io_service object that owns the service. - * - * @return The service interface implementing the specified service type. - * Ownership of the service interface is not transferred to the caller. - */ - template - friend Service& use_service(io_service& ios); - - /// Add a service object to the io_service. - /** - * This function is used to add a service to the io_service. - * - * @param ios The io_service object that owns the service. - * - * @param svc The service object. On success, ownership of the service object - * is transferred to the io_service. When the io_service object is destroyed, - * it will destroy the service object by performing: - * @code delete static_cast(svc) @endcode - * - * @throws boost::asio::service_already_exists Thrown if a service of the - * given type is already present in the io_service. - * - * @throws boost::asio::invalid_service_owner Thrown if the service's owning - * io_service is not the io_service object specified by the ios parameter. - */ - template - friend void add_service(io_service& ios, Service* svc); - - /// Determine if an io_service contains a specified service type. - /** - * This function is used to determine whether the io_service contains a - * service object corresponding to the given service type. - * - * @param ios The io_service object that owns the service. - * - * @return A boolean indicating whether the io_service contains the service. - */ - template - friend bool has_service(io_service& ios); - -private: -#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) - detail::winsock_init<> init_; -#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ - || defined(__osf__) - detail::signal_init<> init_; -#endif - - // The service registry. - boost::asio::detail::service_registry* service_registry_; - - // The implementation. - impl_type& impl_; -}; - -/// Class to inform the io_service when it has work to do. -/** - * The work class is used to inform the io_service when work starts and - * finishes. This ensures that the io_service object's run() function will not - * exit while work is underway, and that it does exit when there is no - * unfinished work remaining. - * - * The work class is copy-constructible so that it may be used as a data member - * in a handler class. It is not assignable. - */ -class io_service::work -{ -public: - /// Constructor notifies the io_service that work is starting. - /** - * The constructor is used to inform the io_service that some work has begun. - * This ensures that the io_service object's run() function will not exit - * while the work is underway. - */ - explicit work(boost::asio::io_service& io_service); - - /// Copy constructor notifies the io_service that work is starting. - /** - * The constructor is used to inform the io_service that some work has begun. - * This ensures that the io_service object's run() function will not exit - * while the work is underway. - */ - work(const work& other); - - /// Destructor notifies the io_service that the work is complete. - /** - * The destructor is used to inform the io_service that some work has - * finished. Once the count of unfinished work reaches zero, the io_service - * object's run() function is permitted to exit. - */ - ~work(); - - /// Get the io_service associated with the work. - boost::asio::io_service& get_io_service(); - -private: - // Prevent assignment. - void operator=(const work& other); - - // The io_service implementation. - detail::io_service_impl& io_service_impl_; -}; - -/// Class used to uniquely identify a service. -class io_service::id - : private noncopyable -{ -public: - /// Constructor. - id() {} -}; - -/// Base class for all io_service services. -class io_service::service - : private noncopyable -{ -public: - /// Get the io_service object that owns the service. - boost::asio::io_service& get_io_service(); - -protected: - /// Constructor. - /** - * @param owner The io_service object that owns the service. - */ - BOOST_ASIO_DECL service(boost::asio::io_service& owner); - - /// Destructor. - BOOST_ASIO_DECL virtual ~service(); - -private: - /// Destroy all user-defined handler objects owned by the service. - virtual void shutdown_service() = 0; - - /// Handle notification of a fork-related event to perform any necessary - /// housekeeping. - /** - * This function is not a pure virtual so that services only have to - * implement it if necessary. The default implementation does nothing. - */ - BOOST_ASIO_DECL virtual void fork_service( - boost::asio::io_service::fork_event event); - - friend class boost::asio::detail::service_registry; - struct key - { - key() : type_info_(0), id_(0) {} - const std::type_info* type_info_; - const boost::asio::io_service::id* id_; - } key_; - - boost::asio::io_service& owner_; - service* next_; -}; - -/// Exception thrown when trying to add a duplicate service to an io_service. -class service_already_exists - : public std::logic_error -{ -public: - BOOST_ASIO_DECL service_already_exists(); -}; - -/// Exception thrown when trying to add a service object to an io_service where -/// the service has a different owner. -class invalid_service_owner - : public std::logic_error -{ -public: - BOOST_ASIO_DECL invalid_service_owner(); -}; - -namespace detail { - -// Special derived service id type to keep classes header-file only. -template -class service_id - : public boost::asio::io_service::id -{ -}; - -// Special service base class to keep classes header-file only. -template -class service_base - : public boost::asio::io_service::service -{ -public: - static boost::asio::detail::service_id id; - - // Constructor. - service_base(boost::asio::io_service& io_service) - : boost::asio::io_service::service(io_service) - { - } -}; - -template -boost::asio::detail::service_id service_base::id; - -} // namespace detail -} // namespace asio -} // namespace boost - -#include - -#include -#if defined(BOOST_ASIO_HEADER_ONLY) -# include -#endif // defined(BOOST_ASIO_HEADER_ONLY) - -#endif // BOOST_ASIO_IO_SERVICE_HPP +// +// io_service.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IO_SERVICE_HPP +#define BOOST_ASIO_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# include +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) +# include +#endif + +#include + +namespace boost { +namespace asio { + +class io_service; +template Service& use_service(io_service& ios); +template void add_service(io_service& ios, Service* svc); +template bool has_service(io_service& ios); + +namespace detail { +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_service io_service_impl; + class win_iocp_overlapped_ptr; +#else + typedef class task_io_service io_service_impl; +#endif + class service_registry; +} // namespace detail + +/// Provides core I/O functionality. +/** + * The io_service class provides the core I/O functionality for users of the + * asynchronous I/O objects, including: + * + * @li boost::asio::ip::tcp::socket + * @li boost::asio::ip::tcp::acceptor + * @li boost::asio::ip::udp::socket + * @li boost::asio::deadline_timer. + * + * The io_service class also includes facilities intended for developers of + * custom asynchronous services. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe, with the specific exceptions of the reset() and + * notify_fork() functions. Calling reset() while there are unfinished run(), + * run_one(), poll() or poll_one() calls results in undefined behaviour. The + * notify_fork() function should not be called while any io_service function, + * or any function on an I/O object that is associated with the io_service, is + * being called in another thread. + * + * @par Concepts: + * Dispatcher. + * + * @par Synchronous and asynchronous operations + * + * Synchronous operations on I/O objects implicitly run the io_service object + * for an individual operation. The io_service functions run(), run_one(), + * poll() or poll_one() must be called for the io_service to perform + * asynchronous operations on behalf of a C++ program. Notification that an + * asynchronous operation has completed is delivered by invocation of the + * associated handler. Handlers are invoked only by a thread that is currently + * calling any overload of run(), run_one(), poll() or poll_one() for the + * io_service. + * + * @par Effect of exceptions thrown from handlers + * + * If an exception is thrown from a handler, the exception is allowed to + * propagate through the throwing thread's invocation of run(), run_one(), + * poll() or poll_one(). No other threads that are calling any of these + * functions are affected. It is then the responsibility of the application to + * catch the exception. + * + * After the exception has been caught, the run(), run_one(), poll() or + * poll_one() call may be restarted @em without the need for an intervening + * call to reset(). This allows the thread to rejoin the io_service object's + * thread pool without impacting any other threads in the pool. + * + * For example: + * + * @code + * boost::asio::io_service io_service; + * ... + * for (;;) + * { + * try + * { + * io_service.run(); + * break; // run() exited normally + * } + * catch (my_exception& e) + * { + * // Deal with exception as appropriate. + * } + * } + * @endcode + * + * @par Stopping the io_service from running out of work + * + * Some applications may need to prevent an io_service object's run() call from + * returning when there is no more work to do. For example, the io_service may + * be being run in a background thread that is launched prior to the + * application's asynchronous operations. The run() call may be kept running by + * creating an object of type boost::asio::io_service::work: + * + * @code boost::asio::io_service io_service; + * boost::asio::io_service::work work(io_service); + * ... @endcode + * + * To effect a shutdown, the application will then need to call the io_service + * object's stop() member function. This will cause the io_service run() call + * to return as soon as possible, abandoning unfinished operations and without + * permitting ready handlers to be dispatched. + * + * Alternatively, if the application requires that all operations and handlers + * be allowed to finish normally, the work object may be explicitly destroyed. + * + * @code boost::asio::io_service io_service; + * unique_ptr work( + * new boost::asio::io_service::work(io_service)); + * ... + * work.reset(); // Allow run() to exit. @endcode + * + * @par The io_service class and I/O services + * + * Class io_service implements an extensible, type-safe, polymorphic set of I/O + * services, indexed by service type. An object of class io_service must be + * initialised before I/O objects such as sockets, resolvers and timers can be + * used. These I/O objects are distinguished by having constructors that accept + * an @c io_service& parameter. + * + * I/O services exist to manage the logical interface to the operating system on + * behalf of the I/O objects. In particular, there are resources that are shared + * across a class of I/O objects. For example, timers may be implemented in + * terms of a single timer queue. The I/O services manage these shared + * resources. + * + * Access to the services of an io_service is via three function templates, + * use_service(), add_service() and has_service(). + * + * In a call to @c use_service(), the type argument chooses a service, + * making available all members of the named type. If @c Service is not present + * in an io_service, an object of type @c Service is created and added to the + * io_service. A C++ program can check if an io_service implements a + * particular service with the function template @c has_service(). + * + * Service objects may be explicitly added to an io_service using the function + * template @c add_service(). If the @c Service is already present, the + * service_already_exists exception is thrown. If the owner of the service is + * not the same object as the io_service parameter, the invalid_service_owner + * exception is thrown. + * + * Once a service reference is obtained from an io_service object by calling + * use_service(), that reference remains usable as long as the owning io_service + * object exists. + * + * All I/O service implementations have io_service::service as a public base + * class. Custom I/O services may be implemented by deriving from this class and + * then added to an io_service using the facilities described above. + */ +class io_service + : private noncopyable +{ +private: + typedef detail::io_service_impl impl_type; +#if defined(BOOST_ASIO_HAS_IOCP) + friend class detail::win_iocp_overlapped_ptr; +#endif + +public: + class work; + friend class work; + + class id; + + class service; + + class strand; + + /// Constructor. + BOOST_ASIO_DECL io_service(); + + /// Constructor. + /** + * Construct with a hint about the required level of concurrency. + * + * @param concurrency_hint A suggestion to the implementation on how many + * threads it should allow to run simultaneously. + */ + BOOST_ASIO_DECL explicit io_service(std::size_t concurrency_hint); + + /// Destructor. + /** + * On destruction, the io_service performs the following sequence of + * operations: + * + * @li For each service object @c svc in the io_service set, in reverse order + * of the beginning of service object lifetime, performs + * @c svc->shutdown_service(). + * + * @li Uninvoked handler objects that were scheduled for deferred invocation + * on the io_service, or any associated strand, are destroyed. + * + * @li For each service object @c svc in the io_service set, in reverse order + * of the beginning of service object lifetime, performs + * delete static_cast(svc). + * + * @note The destruction sequence described above permits programs to + * simplify their resource management by using @c shared_ptr<>. Where an + * object's lifetime is tied to the lifetime of a connection (or some other + * sequence of asynchronous operations), a @c shared_ptr to the object would + * be bound into the handlers for all asynchronous operations associated with + * it. This works as follows: + * + * @li When a single connection ends, all associated asynchronous operations + * complete. The corresponding handler objects are destroyed, and all + * @c shared_ptr references to the objects are destroyed. + * + * @li To shut down the whole program, the io_service function stop() is + * called to terminate any run() calls as soon as possible. The io_service + * destructor defined above destroys all handlers, causing all @c shared_ptr + * references to all connection objects to be destroyed. + */ + BOOST_ASIO_DECL ~io_service(); + + /// Run the io_service object's event processing loop. + /** + * The run() function blocks until all work has finished and there are no + * more handlers to be dispatched, or until the io_service has been stopped. + * + * Multiple threads may call the run() function to set up a pool of threads + * from which the io_service may execute handlers. All threads that are + * waiting in the pool are equivalent and the io_service may choose any one + * of them to invoke a handler. + * + * A normal exit from the run() function implies that the io_service object + * is stopped (the stopped() function returns @c true). Subsequent calls to + * run(), run_one(), poll() or poll_one() will return immediately unless there + * is a prior call to reset(). + * + * @return The number of handlers that were executed. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The run() function must not be called from a thread that is currently + * calling one of run(), run_one(), poll() or poll_one() on the same + * io_service object. + * + * The poll() function may also be used to dispatch ready handlers, but + * without blocking. + */ + BOOST_ASIO_DECL std::size_t run(); + + /// Run the io_service object's event processing loop. + /** + * The run() function blocks until all work has finished and there are no + * more handlers to be dispatched, or until the io_service has been stopped. + * + * Multiple threads may call the run() function to set up a pool of threads + * from which the io_service may execute handlers. All threads that are + * waiting in the pool are equivalent and the io_service may choose any one + * of them to invoke a handler. + * + * A normal exit from the run() function implies that the io_service object + * is stopped (the stopped() function returns @c true). Subsequent calls to + * run(), run_one(), poll() or poll_one() will return immediately unless there + * is a prior call to reset(). + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + * + * @note The run() function must not be called from a thread that is currently + * calling one of run(), run_one(), poll() or poll_one() on the same + * io_service object. + * + * The poll() function may also be used to dispatch ready handlers, but + * without blocking. + */ + BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); + + /// Run the io_service object's event processing loop to execute at most one + /// handler. + /** + * The run_one() function blocks until one handler has been dispatched, or + * until the io_service has been stopped. + * + * @return The number of handlers that were executed. A zero return value + * implies that the io_service object is stopped (the stopped() function + * returns @c true). Subsequent calls to run(), run_one(), poll() or + * poll_one() will return immediately unless there is a prior call to + * reset(). + * + * @throws boost::system::system_error Thrown on failure. + */ + BOOST_ASIO_DECL std::size_t run_one(); + + /// Run the io_service object's event processing loop to execute at most one + /// handler. + /** + * The run_one() function blocks until one handler has been dispatched, or + * until the io_service has been stopped. + * + * @return The number of handlers that were executed. A zero return value + * implies that the io_service object is stopped (the stopped() function + * returns @c true). Subsequent calls to run(), run_one(), poll() or + * poll_one() will return immediately unless there is a prior call to + * reset(). + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); + + /// Run the io_service object's event processing loop to execute ready + /// handlers. + /** + * The poll() function runs handlers that are ready to run, without blocking, + * until the io_service has been stopped or there are no more ready handlers. + * + * @return The number of handlers that were executed. + * + * @throws boost::system::system_error Thrown on failure. + */ + BOOST_ASIO_DECL std::size_t poll(); + + /// Run the io_service object's event processing loop to execute ready + /// handlers. + /** + * The poll() function runs handlers that are ready to run, without blocking, + * until the io_service has been stopped or there are no more ready handlers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); + + /// Run the io_service object's event processing loop to execute one ready + /// handler. + /** + * The poll_one() function runs at most one handler that is ready to run, + * without blocking. + * + * @return The number of handlers that were executed. + * + * @throws boost::system::system_error Thrown on failure. + */ + BOOST_ASIO_DECL std::size_t poll_one(); + + /// Run the io_service object's event processing loop to execute one ready + /// handler. + /** + * The poll_one() function runs at most one handler that is ready to run, + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); + + /// Stop the io_service object's event processing loop. + /** + * This function does not block, but instead simply signals the io_service to + * stop. All invocations of its run() or run_one() member functions should + * return as soon as possible. Subsequent calls to run(), run_one(), poll() + * or poll_one() will return immediately until reset() is called. + */ + BOOST_ASIO_DECL void stop(); + + /// Determine whether the io_service object has been stopped. + /** + * This function is used to determine whether an io_service object has been + * stopped, either through an explicit call to stop(), or due to running out + * of work. When an io_service object is stopped, calls to run(), run_one(), + * poll() or poll_one() will return immediately without invoking any + * handlers. + * + * @return @c true if the io_service object is stopped, otherwise @c false. + */ + BOOST_ASIO_DECL bool stopped() const; + + /// Reset the io_service in preparation for a subsequent run() invocation. + /** + * This function must be called prior to any second or later set of + * invocations of the run(), run_one(), poll() or poll_one() functions when a + * previous invocation of these functions returned due to the io_service + * being stopped or running out of work. After a call to reset(), the + * io_service object's stopped() function will return @c false. + * + * This function must not be called while there are any unfinished calls to + * the run(), run_one(), poll() or poll_one() functions. + */ + BOOST_ASIO_DECL void reset(); + + /// Request the io_service to invoke the given handler. + /** + * This function is used to ask the io_service to execute the given handler. + * + * The io_service guarantees that the handler will only be called in a thread + * in which the run(), run_one(), poll() or poll_one() member functions is + * currently being invoked. The handler may be executed inside this function + * if the guarantee can be met. + * + * @param handler The handler to be called. The io_service will make + * a copy of the handler object as required. The function signature of the + * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) + dispatch(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); + + /// Request the io_service to invoke the given handler and return immediately. + /** + * This function is used to ask the io_service to execute the given handler, + * but without allowing the io_service to call the handler from inside this + * function. + * + * The io_service guarantees that the handler will only be called in a thread + * in which the run(), run_one(), poll() or poll_one() member functions is + * currently being invoked. + * + * @param handler The handler to be called. The io_service will make + * a copy of the handler object as required. The function signature of the + * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionHandler, void ()) + post(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler); + + /// Create a new handler that automatically dispatches the wrapped handler + /// on the io_service. + /** + * This function is used to create a new handler function object that, when + * invoked, will automatically pass the wrapped handler to the io_service + * object's dispatch function. + * + * @param handler The handler to be wrapped. The io_service will make a copy + * of the handler object as required. The function signature of the handler + * must be: @code void handler(A1 a1, ... An an); @endcode + * + * @return A function object that, when invoked, passes the wrapped handler to + * the io_service object's dispatch function. Given a function object with the + * signature: + * @code R f(A1 a1, ... An an); @endcode + * If this function object is passed to the wrap function like so: + * @code io_service.wrap(f); @endcode + * then the return value is a function object with the signature + * @code void g(A1 a1, ... An an); @endcode + * that, when invoked, executes code equivalent to: + * @code io_service.dispatch(boost::bind(f, a1, ... an)); @endcode + */ + template +#if defined(GENERATING_DOCUMENTATION) + unspecified +#else + detail::wrapped_handler +#endif + wrap(Handler handler); + + /// Fork-related event notifications. + enum fork_event + { + /// Notify the io_service that the process is about to fork. + fork_prepare, + + /// Notify the io_service that the process has forked and is the parent. + fork_parent, + + /// Notify the io_service that the process has forked and is the child. + fork_child + }; + + /// Notify the io_service of a fork-related event. + /** + * This function is used to inform the io_service that the process is about + * to fork, or has just forked. This allows the io_service, and the services + * it contains, to perform any necessary housekeeping to ensure correct + * operation following a fork. + * + * This function must not be called while any other io_service function, or + * any function on an I/O object associated with the io_service, is being + * called in another thread. It is, however, safe to call this function from + * within a completion handler, provided no other thread is accessing the + * io_service. + * + * @param event A fork-related event. + * + * @throws boost::system::system_error Thrown on failure. If the notification + * fails the io_service object should no longer be used and should be + * destroyed. + * + * @par Example + * The following code illustrates how to incorporate the notify_fork() + * function: + * @code my_io_service.notify_fork(boost::asio::io_service::fork_prepare); + * if (fork() == 0) + * { + * // This is the child process. + * my_io_service.notify_fork(boost::asio::io_service::fork_child); + * } + * else + * { + * // This is the parent process. + * my_io_service.notify_fork(boost::asio::io_service::fork_parent); + * } @endcode + * + * @note For each service object @c svc in the io_service set, performs + * svc->fork_service();. When processing the fork_prepare event, + * services are visited in reverse order of the beginning of service object + * lifetime. Otherwise, services are visited in order of the beginning of + * service object lifetime. + */ + BOOST_ASIO_DECL void notify_fork(boost::asio::io_service::fork_event event); + + /// Obtain the service object corresponding to the given type. + /** + * This function is used to locate a service object that corresponds to + * the given service type. If there is no existing implementation of the + * service, then the io_service will create a new instance of the service. + * + * @param ios The io_service object that owns the service. + * + * @return The service interface implementing the specified service type. + * Ownership of the service interface is not transferred to the caller. + */ + template + friend Service& use_service(io_service& ios); + + /// Add a service object to the io_service. + /** + * This function is used to add a service to the io_service. + * + * @param ios The io_service object that owns the service. + * + * @param svc The service object. On success, ownership of the service object + * is transferred to the io_service. When the io_service object is destroyed, + * it will destroy the service object by performing: + * @code delete static_cast(svc) @endcode + * + * @throws boost::asio::service_already_exists Thrown if a service of the + * given type is already present in the io_service. + * + * @throws boost::asio::invalid_service_owner Thrown if the service's owning + * io_service is not the io_service object specified by the ios parameter. + */ + template + friend void add_service(io_service& ios, Service* svc); + + /// Determine if an io_service contains a specified service type. + /** + * This function is used to determine whether the io_service contains a + * service object corresponding to the given service type. + * + * @param ios The io_service object that owns the service. + * + * @return A boolean indicating whether the io_service contains the service. + */ + template + friend bool has_service(io_service& ios); + +private: +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + detail::winsock_init<> init_; +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) + detail::signal_init<> init_; +#endif + + // The service registry. + boost::asio::detail::service_registry* service_registry_; + + // The implementation. + impl_type& impl_; +}; + +/// Class to inform the io_service when it has work to do. +/** + * The work class is used to inform the io_service when work starts and + * finishes. This ensures that the io_service object's run() function will not + * exit while work is underway, and that it does exit when there is no + * unfinished work remaining. + * + * The work class is copy-constructible so that it may be used as a data member + * in a handler class. It is not assignable. + */ +class io_service::work +{ +public: + /// Constructor notifies the io_service that work is starting. + /** + * The constructor is used to inform the io_service that some work has begun. + * This ensures that the io_service object's run() function will not exit + * while the work is underway. + */ + explicit work(boost::asio::io_service& io_service); + + /// Copy constructor notifies the io_service that work is starting. + /** + * The constructor is used to inform the io_service that some work has begun. + * This ensures that the io_service object's run() function will not exit + * while the work is underway. + */ + work(const work& other); + + /// Destructor notifies the io_service that the work is complete. + /** + * The destructor is used to inform the io_service that some work has + * finished. Once the count of unfinished work reaches zero, the io_service + * object's run() function is permitted to exit. + */ + ~work(); + + /// Get the io_service associated with the work. + boost::asio::io_service& get_io_service(); + +private: + // Prevent assignment. + void operator=(const work& other); + + // The io_service implementation. + detail::io_service_impl& io_service_impl_; +}; + +/// Class used to uniquely identify a service. +class io_service::id + : private noncopyable +{ +public: + /// Constructor. + id() {} +}; + +/// Base class for all io_service services. +class io_service::service + : private noncopyable +{ +public: + /// Get the io_service object that owns the service. + boost::asio::io_service& get_io_service(); + +protected: + /// Constructor. + /** + * @param owner The io_service object that owns the service. + */ + BOOST_ASIO_DECL service(boost::asio::io_service& owner); + + /// Destructor. + BOOST_ASIO_DECL virtual ~service(); + +private: + /// Destroy all user-defined handler objects owned by the service. + virtual void shutdown_service() = 0; + + /// Handle notification of a fork-related event to perform any necessary + /// housekeeping. + /** + * This function is not a pure virtual so that services only have to + * implement it if necessary. The default implementation does nothing. + */ + BOOST_ASIO_DECL virtual void fork_service( + boost::asio::io_service::fork_event event); + + friend class boost::asio::detail::service_registry; + struct key + { + key() : type_info_(0), id_(0) {} + const std::type_info* type_info_; + const boost::asio::io_service::id* id_; + } key_; + + boost::asio::io_service& owner_; + service* next_; +}; + +/// Exception thrown when trying to add a duplicate service to an io_service. +class service_already_exists + : public std::logic_error +{ +public: + BOOST_ASIO_DECL service_already_exists(); +}; + +/// Exception thrown when trying to add a service object to an io_service where +/// the service has a different owner. +class invalid_service_owner + : public std::logic_error +{ +public: + BOOST_ASIO_DECL invalid_service_owner(); +}; + +namespace detail { + +// Special derived service id type to keep classes header-file only. +template +class service_id + : public boost::asio::io_service::id +{ +}; + +// Special service base class to keep classes header-file only. +template +class service_base + : public boost::asio::io_service::service +{ +public: + static boost::asio::detail::service_id id; + + // Constructor. + service_base(boost::asio::io_service& io_service) + : boost::asio::io_service::service(io_service) + { + } +}; + +template +boost::asio::detail::service_id service_base::id; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IO_SERVICE_HPP diff --git a/src/external/3rd/library/boost/boost/asio/ssl/old/detail/openssl_stream_service.hpp b/src/external/3rd/library/boost/boost/asio/ssl/old/detail/openssl_stream_service.hpp index b8d997170..09eab7b69 100644 --- a/src/external/3rd/library/boost/boost/asio/ssl/old/detail/openssl_stream_service.hpp +++ b/src/external/3rd/library/boost/boost/asio/ssl/old/detail/openssl_stream_service.hpp @@ -1,573 +1,573 @@ -// -// ssl/old/detail/stream_service.hpp -// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// -// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com -// Copyright (c) 2005-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP -#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace boost { -namespace asio { -namespace ssl { -namespace old { -namespace detail { - -class openssl_stream_service - : public boost::asio::detail::service_base -{ -private: - enum { max_buffer_size = INT_MAX }; - - //Base handler for asyncrhonous operations - template - class base_handler - { - public: - typedef boost::function< - void (const boost::system::error_code&, size_t)> func_t; - - base_handler(boost::asio::io_service& io_service) - : op_(NULL) - , io_service_(io_service) - , work_(io_service) - {} - - void do_func(const boost::system::error_code& error, size_t size) - { - func_(error, size); - } - - void set_operation(openssl_operation* op) { op_ = op; } - void set_func(func_t func) { func_ = func; } - - ~base_handler() - { - delete op_; - } - - private: - func_t func_; - openssl_operation* op_; - boost::asio::io_service& io_service_; - boost::asio::io_service::work work_; - }; // class base_handler - - // Handler for asynchronous IO (write/read) operations - template - class io_handler - : public base_handler - { - public: - io_handler(Handler handler, boost::asio::io_service& io_service) - : base_handler(io_service) - , handler_(handler) - { - this->set_func(boost::bind( - &io_handler::handler_impl, - this, boost::arg<1>(), boost::arg<2>() )); - } - - private: - Handler handler_; - void handler_impl(const boost::system::error_code& error, size_t size) - { - std::unique_ptr > this_ptr(this); - handler_(error, size); - } - }; // class io_handler - - // Handler for asyncrhonous handshake (connect, accept) functions - template - class handshake_handler - : public base_handler - { - public: - handshake_handler(Handler handler, boost::asio::io_service& io_service) - : base_handler(io_service) - , handler_(handler) - { - this->set_func(boost::bind( - &handshake_handler::handler_impl, - this, boost::arg<1>(), boost::arg<2>() )); - } - - private: - Handler handler_; - void handler_impl(const boost::system::error_code& error, size_t) - { - std::unique_ptr > this_ptr(this); - handler_(error); - } - - }; // class handshake_handler - - // Handler for asyncrhonous shutdown - template - class shutdown_handler - : public base_handler - { - public: - shutdown_handler(Handler handler, boost::asio::io_service& io_service) - : base_handler(io_service), - handler_(handler) - { - this->set_func(boost::bind( - &shutdown_handler::handler_impl, - this, boost::arg<1>(), boost::arg<2>() )); - } - - private: - Handler handler_; - void handler_impl(const boost::system::error_code& error, size_t) - { - std::unique_ptr > this_ptr(this); - handler_(error); - } - }; // class shutdown_handler - -public: - // The implementation type. - typedef struct impl_struct - { - ::SSL* ssl; - ::BIO* ext_bio; - net_buffer recv_buf; - } * impl_type; - - // Construct a new stream socket service for the specified io_service. - explicit openssl_stream_service(boost::asio::io_service& io_service) - : boost::asio::detail::service_base(io_service), - strand_(io_service) - { - } - - // Destroy all user-defined handler objects owned by the service. - void shutdown_service() - { - } - - // Return a null stream implementation. - impl_type null() const - { - return 0; - } - - // Create a new stream implementation. - template - void create(impl_type& impl, Stream& /*next_layer*/, - basic_context& context) - { - impl = new impl_struct; - impl->ssl = ::SSL_new(context.impl()); - ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); - ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - ::BIO* int_bio = 0; - impl->ext_bio = 0; - ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192); - ::SSL_set_bio(impl->ssl, int_bio, int_bio); - } - - // Destroy a stream implementation. - template - void destroy(impl_type& impl, Stream& /*next_layer*/) - { - if (impl != 0) - { - ::BIO_free(impl->ext_bio); - ::SSL_free(impl->ssl); - delete impl; - impl = 0; - } - } - - // Perform SSL handshaking. - template - boost::system::error_code handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, boost::system::error_code& ec) - { - try - { - openssl_operation op( - type == stream_base::client ? - &ssl_wrap::SSL_connect: - &ssl_wrap::SSL_accept, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio); - op.start(); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Start an asynchronous SSL handshake. - template - void async_handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, Handler handler) - { - typedef handshake_handler connect_handler; - - connect_handler* local_handler = - new connect_handler(handler, get_io_service()); - - openssl_operation* op = new openssl_operation - ( - type == stream_base::client ? - &ssl_wrap::SSL_connect: - &ssl_wrap::SSL_accept, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation::start, op)); - } - - // Shut down SSL on the stream. - template - boost::system::error_code shutdown(impl_type& impl, Stream& next_layer, - boost::system::error_code& ec) - { - try - { - openssl_operation op( - &ssl_wrap::SSL_shutdown, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio); - op.start(); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return ec; - } - - ec = boost::system::error_code(); - return ec; - } - - // Asynchronously shut down SSL on the stream. - template - void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler) - { - typedef shutdown_handler disconnect_handler; - - disconnect_handler* local_handler = - new disconnect_handler(handler, get_io_service()); - - openssl_operation* op = new openssl_operation - ( - &ssl_wrap::SSL_shutdown, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation::start, op)); - } - - // Write some data to the stream. - template - std::size_t write_some(impl_type& impl, Stream& next_layer, - const Const_Buffers& buffers, boost::system::error_code& ec) - { - size_t bytes_transferred = 0; - try - { - boost::asio::const_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::const_buffer, Const_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - ec = boost::system::error_code(); - return 0; - } - - boost::function send_func = - boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), - boost::asio::buffer_cast(buffer), - static_cast(buffer_size)); - openssl_operation op( - send_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio - ); - bytes_transferred = static_cast(op.start()); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Start an asynchronous write. - template - void async_write_some(impl_type& impl, Stream& next_layer, - const Const_Buffers& buffers, Handler handler) - { - typedef io_handler send_handler; - - boost::asio::const_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::const_buffer, Const_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - get_io_service().post(boost::asio::detail::bind_handler( - handler, boost::system::error_code(), 0)); - return; - } - - send_handler* local_handler = new send_handler(handler, get_io_service()); - - boost::function send_func = - boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), - boost::asio::buffer_cast(buffer), - static_cast(buffer_size)); - - openssl_operation* op = new openssl_operation - ( - send_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation::start, op)); - } - - // Read some data from the stream. - template - std::size_t read_some(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, boost::system::error_code& ec) - { - size_t bytes_transferred = 0; - try - { - boost::asio::mutable_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - ec = boost::system::error_code(); - return 0; - } - - boost::function recv_func = - boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), - boost::asio::buffer_cast(buffer), - static_cast(buffer_size)); - openssl_operation op(recv_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio - ); - - bytes_transferred = static_cast(op.start()); - } - catch (boost::system::system_error& e) - { - ec = e.code(); - return 0; - } - - ec = boost::system::error_code(); - return bytes_transferred; - } - - // Start an asynchronous read. - template - void async_read_some(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, Handler handler) - { - typedef io_handler recv_handler; - - boost::asio::mutable_buffer buffer = - boost::asio::detail::buffer_sequence_adapter< - boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); - - std::size_t buffer_size = boost::asio::buffer_size(buffer); - if (buffer_size > max_buffer_size) - buffer_size = max_buffer_size; - else if (buffer_size == 0) - { - get_io_service().post(boost::asio::detail::bind_handler( - handler, boost::system::error_code(), 0)); - return; - } - - recv_handler* local_handler = new recv_handler(handler, get_io_service()); - - boost::function recv_func = - boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), - boost::asio::buffer_cast(buffer), - static_cast(buffer_size)); - - openssl_operation* op = new openssl_operation - ( - recv_func, - next_layer, - impl->recv_buf, - impl->ssl, - impl->ext_bio, - boost::bind - ( - &base_handler::do_func, - local_handler, - boost::arg<1>(), - boost::arg<2>() - ), - strand_ - ); - local_handler->set_operation(op); - - strand_.post(boost::bind(&openssl_operation::start, op)); - } - - // Peek at the incoming data on the stream. - template - std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/, - const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec) - { - ec = boost::system::error_code(); - return 0; - } - - // Determine the amount of data that may be read without blocking. - template - std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/, - boost::system::error_code& ec) - { - ec = boost::system::error_code(); - return 0; - } - -private: - boost::asio::io_service::strand strand_; - - typedef boost::asio::detail::mutex mutex_type; - - template - struct ssl_wrap - { - static Mutex ssl_mutex_; - - static int SSL_accept(SSL *ssl) - { - typename Mutex::scoped_lock lock(ssl_mutex_); - return ::SSL_accept(ssl); - } - - static int SSL_connect(SSL *ssl) - { - typename Mutex::scoped_lock lock(ssl_mutex_); - return ::SSL_connect(ssl); - } - - static int SSL_shutdown(SSL *ssl) - { - typename Mutex::scoped_lock lock(ssl_mutex_); - return ::SSL_shutdown(ssl); - } - }; -}; - -template -Mutex openssl_stream_service::ssl_wrap::ssl_mutex_; - -} // namespace detail -} // namespace old -} // namespace ssl -} // namespace asio -} // namespace boost - -#include - -#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP +// +// ssl/old/detail/stream_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com +// Copyright (c) 2005-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP +#define BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ssl { +namespace old { +namespace detail { + +class openssl_stream_service + : public boost::asio::detail::service_base +{ +private: + enum { max_buffer_size = INT_MAX }; + + //Base handler for asyncrhonous operations + template + class base_handler + { + public: + typedef boost::function< + void (const boost::system::error_code&, size_t)> func_t; + + base_handler(boost::asio::io_service& io_service) + : op_(NULL) + , io_service_(io_service) + , work_(io_service) + {} + + void do_func(const boost::system::error_code& error, size_t size) + { + func_(error, size); + } + + void set_operation(openssl_operation* op) { op_ = op; } + void set_func(func_t func) { func_ = func; } + + ~base_handler() + { + delete op_; + } + + private: + func_t func_; + openssl_operation* op_; + boost::asio::io_service& io_service_; + boost::asio::io_service::work work_; + }; // class base_handler + + // Handler for asynchronous IO (write/read) operations + template + class io_handler + : public base_handler + { + public: + io_handler(Handler handler, boost::asio::io_service& io_service) + : base_handler(io_service) + , handler_(handler) + { + this->set_func(boost::bind( + &io_handler::handler_impl, + this, boost::arg<1>(), boost::arg<2>() )); + } + + private: + Handler handler_; + void handler_impl(const boost::system::error_code& error, size_t size) + { + std::unique_ptr > this_ptr(this); + handler_(error, size); + } + }; // class io_handler + + // Handler for asyncrhonous handshake (connect, accept) functions + template + class handshake_handler + : public base_handler + { + public: + handshake_handler(Handler handler, boost::asio::io_service& io_service) + : base_handler(io_service) + , handler_(handler) + { + this->set_func(boost::bind( + &handshake_handler::handler_impl, + this, boost::arg<1>(), boost::arg<2>() )); + } + + private: + Handler handler_; + void handler_impl(const boost::system::error_code& error, size_t) + { + std::unique_ptr > this_ptr(this); + handler_(error); + } + + }; // class handshake_handler + + // Handler for asyncrhonous shutdown + template + class shutdown_handler + : public base_handler + { + public: + shutdown_handler(Handler handler, boost::asio::io_service& io_service) + : base_handler(io_service), + handler_(handler) + { + this->set_func(boost::bind( + &shutdown_handler::handler_impl, + this, boost::arg<1>(), boost::arg<2>() )); + } + + private: + Handler handler_; + void handler_impl(const boost::system::error_code& error, size_t) + { + std::unique_ptr > this_ptr(this); + handler_(error); + } + }; // class shutdown_handler + +public: + // The implementation type. + typedef struct impl_struct + { + ::SSL* ssl; + ::BIO* ext_bio; + net_buffer recv_buf; + } * impl_type; + + // Construct a new stream socket service for the specified io_service. + explicit openssl_stream_service(boost::asio::io_service& io_service) + : boost::asio::detail::service_base(io_service), + strand_(io_service) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + // Return a null stream implementation. + impl_type null() const + { + return 0; + } + + // Create a new stream implementation. + template + void create(impl_type& impl, Stream& /*next_layer*/, + basic_context& context) + { + impl = new impl_struct; + impl->ssl = ::SSL_new(context.impl()); + ::SSL_set_mode(impl->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); + ::SSL_set_mode(impl->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + ::BIO* int_bio = 0; + impl->ext_bio = 0; + ::BIO_new_bio_pair(&int_bio, 8192, &impl->ext_bio, 8192); + ::SSL_set_bio(impl->ssl, int_bio, int_bio); + } + + // Destroy a stream implementation. + template + void destroy(impl_type& impl, Stream& /*next_layer*/) + { + if (impl != 0) + { + ::BIO_free(impl->ext_bio); + ::SSL_free(impl->ssl); + delete impl; + impl = 0; + } + } + + // Perform SSL handshaking. + template + boost::system::error_code handshake(impl_type& impl, Stream& next_layer, + stream_base::handshake_type type, boost::system::error_code& ec) + { + try + { + openssl_operation op( + type == stream_base::client ? + &ssl_wrap::SSL_connect: + &ssl_wrap::SSL_accept, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio); + op.start(); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return ec; + } + + ec = boost::system::error_code(); + return ec; + } + + // Start an asynchronous SSL handshake. + template + void async_handshake(impl_type& impl, Stream& next_layer, + stream_base::handshake_type type, Handler handler) + { + typedef handshake_handler connect_handler; + + connect_handler* local_handler = + new connect_handler(handler, get_io_service()); + + openssl_operation* op = new openssl_operation + ( + type == stream_base::client ? + &ssl_wrap::SSL_connect: + &ssl_wrap::SSL_accept, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation::start, op)); + } + + // Shut down SSL on the stream. + template + boost::system::error_code shutdown(impl_type& impl, Stream& next_layer, + boost::system::error_code& ec) + { + try + { + openssl_operation op( + &ssl_wrap::SSL_shutdown, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio); + op.start(); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return ec; + } + + ec = boost::system::error_code(); + return ec; + } + + // Asynchronously shut down SSL on the stream. + template + void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler) + { + typedef shutdown_handler disconnect_handler; + + disconnect_handler* local_handler = + new disconnect_handler(handler, get_io_service()); + + openssl_operation* op = new openssl_operation + ( + &ssl_wrap::SSL_shutdown, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation::start, op)); + } + + // Write some data to the stream. + template + std::size_t write_some(impl_type& impl, Stream& next_layer, + const Const_Buffers& buffers, boost::system::error_code& ec) + { + size_t bytes_transferred = 0; + try + { + boost::asio::const_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::const_buffer, Const_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + boost::function send_func = + boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), + boost::asio::buffer_cast(buffer), + static_cast(buffer_size)); + openssl_operation op( + send_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio + ); + bytes_transferred = static_cast(op.start()); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; + } + + // Start an asynchronous write. + template + void async_write_some(impl_type& impl, Stream& next_layer, + const Const_Buffers& buffers, Handler handler) + { + typedef io_handler send_handler; + + boost::asio::const_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::const_buffer, Const_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + get_io_service().post(boost::asio::detail::bind_handler( + handler, boost::system::error_code(), 0)); + return; + } + + send_handler* local_handler = new send_handler(handler, get_io_service()); + + boost::function send_func = + boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), + boost::asio::buffer_cast(buffer), + static_cast(buffer_size)); + + openssl_operation* op = new openssl_operation + ( + send_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation::start, op)); + } + + // Read some data from the stream. + template + std::size_t read_some(impl_type& impl, Stream& next_layer, + const Mutable_Buffers& buffers, boost::system::error_code& ec) + { + size_t bytes_transferred = 0; + try + { + boost::asio::mutable_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + ec = boost::system::error_code(); + return 0; + } + + boost::function recv_func = + boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), + boost::asio::buffer_cast(buffer), + static_cast(buffer_size)); + openssl_operation op(recv_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio + ); + + bytes_transferred = static_cast(op.start()); + } + catch (boost::system::system_error& e) + { + ec = e.code(); + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; + } + + // Start an asynchronous read. + template + void async_read_some(impl_type& impl, Stream& next_layer, + const Mutable_Buffers& buffers, Handler handler) + { + typedef io_handler recv_handler; + + boost::asio::mutable_buffer buffer = + boost::asio::detail::buffer_sequence_adapter< + boost::asio::mutable_buffer, Mutable_Buffers>::first(buffers); + + std::size_t buffer_size = boost::asio::buffer_size(buffer); + if (buffer_size > max_buffer_size) + buffer_size = max_buffer_size; + else if (buffer_size == 0) + { + get_io_service().post(boost::asio::detail::bind_handler( + handler, boost::system::error_code(), 0)); + return; + } + + recv_handler* local_handler = new recv_handler(handler, get_io_service()); + + boost::function recv_func = + boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), + boost::asio::buffer_cast(buffer), + static_cast(buffer_size)); + + openssl_operation* op = new openssl_operation + ( + recv_func, + next_layer, + impl->recv_buf, + impl->ssl, + impl->ext_bio, + boost::bind + ( + &base_handler::do_func, + local_handler, + boost::arg<1>(), + boost::arg<2>() + ), + strand_ + ); + local_handler->set_operation(op); + + strand_.post(boost::bind(&openssl_operation::start, op)); + } + + // Peek at the incoming data on the stream. + template + std::size_t peek(impl_type& /*impl*/, Stream& /*next_layer*/, + const Mutable_Buffers& /*buffers*/, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + + // Determine the amount of data that may be read without blocking. + template + std::size_t in_avail(impl_type& /*impl*/, Stream& /*next_layer*/, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return 0; + } + +private: + boost::asio::io_service::strand strand_; + + typedef boost::asio::detail::mutex mutex_type; + + template + struct ssl_wrap + { + static Mutex ssl_mutex_; + + static int SSL_accept(SSL *ssl) + { + typename Mutex::scoped_lock lock(ssl_mutex_); + return ::SSL_accept(ssl); + } + + static int SSL_connect(SSL *ssl) + { + typename Mutex::scoped_lock lock(ssl_mutex_); + return ::SSL_connect(ssl); + } + + static int SSL_shutdown(SSL *ssl) + { + typename Mutex::scoped_lock lock(ssl_mutex_); + return ::SSL_shutdown(ssl); + } + }; +}; + +template +Mutex openssl_stream_service::ssl_wrap::ssl_mutex_; + +} // namespace detail +} // namespace old +} // namespace ssl +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_SSL_OLD_DETAIL_OPENSSL_STREAM_SERVICE_HPP diff --git a/src/external/3rd/library/boost/boost/assign/ptr_list_of.hpp b/src/external/3rd/library/boost/boost/assign/ptr_list_of.hpp index 6d0e1ad62..a312a4e8a 100644 --- a/src/external/3rd/library/boost/boost/assign/ptr_list_of.hpp +++ b/src/external/3rd/library/boost/boost/assign/ptr_list_of.hpp @@ -1,191 +1,191 @@ -// Boost.Assign library -// -// Copyright Thorsten Ottosen 2003-2005. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/assign/ -// - - -#ifndef BOOST_ASSIGN_PTR_LIST_OF_HPP -#define BOOST_ASSIGN_PTR_LIST_OF_HPP - -#if defined(_MSC_VER) -# pragma once -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace boost -{ - -namespace assign_detail -{ - ///////////////////////////////////////////////////////////////////////// - // Part 1: flexible and efficient interface - ///////////////////////////////////////////////////////////////////////// - - template< class T > - class generic_ptr_list : - public converter< generic_ptr_list, - BOOST_DEDUCED_TYPENAME boost::ptr_vector::iterator > - { - protected: - typedef boost::ptr_vector impl_type; - typedef std::unique_ptr release_type; - mutable impl_type values_; - - public: - typedef BOOST_DEDUCED_TYPENAME impl_type::iterator iterator; - typedef iterator const_iterator; - typedef BOOST_DEDUCED_TYPENAME impl_type::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME impl_type::size_type size_type; - typedef BOOST_DEDUCED_TYPENAME impl_type::difference_type difference_type; - public: - generic_ptr_list() : values_( 32u ) - { } - - generic_ptr_list( release_type r ) : values_(r) - { } - - release_type release() - { - return values_.release(); - } - - public: - iterator begin() const { return values_.begin(); } - iterator end() const { return values_.end(); } - bool empty() const { return values_.empty(); } - size_type size() const { return values_.size(); } - - public: - - operator impl_type() const - { - return values_; - } - - template< template class Seq, class U, - class CA, class A > - operator Seq() const - { - Seq result; - result.transfer( result.end(), values_ ); - BOOST_ASSERT( empty() ); - return result; - } - - template< class PtrContainer > - std::unique_ptr convert( const PtrContainer* c ) const - { - std::unique_ptr res( new PtrContainer() ); - while( !empty() ) - res->insert( res->end(), - values_.pop_back().release() ); - return res; - } - - template< class PtrContainer > - std::unique_ptr to_container( const PtrContainer& c ) const - { - return convert( &c ); - } - - protected: - void push_back( T* r ) { values_.push_back( r ); } - - public: - generic_ptr_list& operator()() - { - this->push_back( new T() ); - return *this; - } - - template< class U > - generic_ptr_list& operator()( const U& u ) - { - this->push_back( new T(u) ); - return *this; - } - - -#ifndef BOOST_ASSIGN_MAX_PARAMS // use user's value -#define BOOST_ASSIGN_MAX_PARAMS 5 -#endif -#define BOOST_ASSIGN_MAX_PARAMETERS (BOOST_ASSIGN_MAX_PARAMS - 1) -#define BOOST_ASSIGN_PARAMS1(n) BOOST_PP_ENUM_PARAMS(n, class U) -#define BOOST_ASSIGN_PARAMS2(n) BOOST_PP_ENUM_BINARY_PARAMS(n, U, const& u) -#define BOOST_ASSIGN_PARAMS3(n) BOOST_PP_ENUM_PARAMS(n, u) - -#define BOOST_PP_LOCAL_LIMITS (1, BOOST_ASSIGN_MAX_PARAMETERS) -#define BOOST_PP_LOCAL_MACRO(n) \ - template< class U, BOOST_ASSIGN_PARAMS1(n) > \ - generic_ptr_list& operator()(U const& u, BOOST_ASSIGN_PARAMS2(n) ) \ - { \ - this->push_back( new T(u, BOOST_ASSIGN_PARAMS3(n))); \ - return *this; \ - } \ - /**/ - -#include BOOST_PP_LOCAL_ITERATE() - - }; // class 'generic_ptr_list' - -} // namespace 'assign_detail' - -namespace assign -{ - template< class T > - inline assign_detail::generic_ptr_list - ptr_list_of() - { - return assign_detail::generic_ptr_list()(); - } - - template< class T, class U > - inline assign_detail::generic_ptr_list - ptr_list_of( const U& t ) - { - return assign_detail::generic_ptr_list()( t ); - } - - -#define BOOST_PP_LOCAL_LIMITS (1, BOOST_ASSIGN_MAX_PARAMETERS) -#define BOOST_PP_LOCAL_MACRO(n) \ - template< class T, class U, BOOST_ASSIGN_PARAMS1(n) > \ - inline assign_detail::generic_ptr_list \ - ptr_list_of(U const& u, BOOST_ASSIGN_PARAMS2(n) ) \ - { \ - return assign_detail::generic_ptr_list()(u, BOOST_ASSIGN_PARAMS3(n)); \ - } \ - /**/ - -#include BOOST_PP_LOCAL_ITERATE() - - -} // namespace 'assign' -} // namespace 'boost' - - -#undef BOOST_ASSIGN_PARAMS1 -#undef BOOST_ASSIGN_PARAMS2 -#undef BOOST_ASSIGN_PARAMS3 -#undef BOOST_ASSIGN_MAX_PARAMETERS - -#endif +// Boost.Assign library +// +// Copyright Thorsten Ottosen 2003-2005. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/assign/ +// + + +#ifndef BOOST_ASSIGN_PTR_LIST_OF_HPP +#define BOOST_ASSIGN_PTR_LIST_OF_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace boost +{ + +namespace assign_detail +{ + ///////////////////////////////////////////////////////////////////////// + // Part 1: flexible and efficient interface + ///////////////////////////////////////////////////////////////////////// + + template< class T > + class generic_ptr_list : + public converter< generic_ptr_list, + BOOST_DEDUCED_TYPENAME boost::ptr_vector::iterator > + { + protected: + typedef boost::ptr_vector impl_type; + typedef std::unique_ptr release_type; + mutable impl_type values_; + + public: + typedef BOOST_DEDUCED_TYPENAME impl_type::iterator iterator; + typedef iterator const_iterator; + typedef BOOST_DEDUCED_TYPENAME impl_type::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME impl_type::size_type size_type; + typedef BOOST_DEDUCED_TYPENAME impl_type::difference_type difference_type; + public: + generic_ptr_list() : values_( 32u ) + { } + + generic_ptr_list( release_type r ) : values_(r) + { } + + release_type release() + { + return values_.release(); + } + + public: + iterator begin() const { return values_.begin(); } + iterator end() const { return values_.end(); } + bool empty() const { return values_.empty(); } + size_type size() const { return values_.size(); } + + public: + + operator impl_type() const + { + return values_; + } + + template< template class Seq, class U, + class CA, class A > + operator Seq() const + { + Seq result; + result.transfer( result.end(), values_ ); + BOOST_ASSERT( empty() ); + return result; + } + + template< class PtrContainer > + std::unique_ptr convert( const PtrContainer* c ) const + { + std::unique_ptr res( new PtrContainer() ); + while( !empty() ) + res->insert( res->end(), + values_.pop_back().release() ); + return res; + } + + template< class PtrContainer > + std::unique_ptr to_container( const PtrContainer& c ) const + { + return convert( &c ); + } + + protected: + void push_back( T* r ) { values_.push_back( r ); } + + public: + generic_ptr_list& operator()() + { + this->push_back( new T() ); + return *this; + } + + template< class U > + generic_ptr_list& operator()( const U& u ) + { + this->push_back( new T(u) ); + return *this; + } + + +#ifndef BOOST_ASSIGN_MAX_PARAMS // use user's value +#define BOOST_ASSIGN_MAX_PARAMS 5 +#endif +#define BOOST_ASSIGN_MAX_PARAMETERS (BOOST_ASSIGN_MAX_PARAMS - 1) +#define BOOST_ASSIGN_PARAMS1(n) BOOST_PP_ENUM_PARAMS(n, class U) +#define BOOST_ASSIGN_PARAMS2(n) BOOST_PP_ENUM_BINARY_PARAMS(n, U, const& u) +#define BOOST_ASSIGN_PARAMS3(n) BOOST_PP_ENUM_PARAMS(n, u) + +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_ASSIGN_MAX_PARAMETERS) +#define BOOST_PP_LOCAL_MACRO(n) \ + template< class U, BOOST_ASSIGN_PARAMS1(n) > \ + generic_ptr_list& operator()(U const& u, BOOST_ASSIGN_PARAMS2(n) ) \ + { \ + this->push_back( new T(u, BOOST_ASSIGN_PARAMS3(n))); \ + return *this; \ + } \ + /**/ + +#include BOOST_PP_LOCAL_ITERATE() + + }; // class 'generic_ptr_list' + +} // namespace 'assign_detail' + +namespace assign +{ + template< class T > + inline assign_detail::generic_ptr_list + ptr_list_of() + { + return assign_detail::generic_ptr_list()(); + } + + template< class T, class U > + inline assign_detail::generic_ptr_list + ptr_list_of( const U& t ) + { + return assign_detail::generic_ptr_list()( t ); + } + + +#define BOOST_PP_LOCAL_LIMITS (1, BOOST_ASSIGN_MAX_PARAMETERS) +#define BOOST_PP_LOCAL_MACRO(n) \ + template< class T, class U, BOOST_ASSIGN_PARAMS1(n) > \ + inline assign_detail::generic_ptr_list \ + ptr_list_of(U const& u, BOOST_ASSIGN_PARAMS2(n) ) \ + { \ + return assign_detail::generic_ptr_list()(u, BOOST_ASSIGN_PARAMS3(n)); \ + } \ + /**/ + +#include BOOST_PP_LOCAL_ITERATE() + + +} // namespace 'assign' +} // namespace 'boost' + + +#undef BOOST_ASSIGN_PARAMS1 +#undef BOOST_ASSIGN_PARAMS2 +#undef BOOST_ASSIGN_PARAMS3 +#undef BOOST_ASSIGN_MAX_PARAMETERS + +#endif diff --git a/src/external/3rd/library/boost/boost/config/stdlib/roguewave.hpp b/src/external/3rd/library/boost/boost/config/stdlib/roguewave.hpp index 0258c34e7..fdb9ef2d7 100644 --- a/src/external/3rd/library/boost/boost/config/stdlib/roguewave.hpp +++ b/src/external/3rd/library/boost/boost/config/stdlib/roguewave.hpp @@ -1,189 +1,189 @@ -// (C) Copyright John Maddock 2001 - 2003. -// (C) Copyright Jens Maurer 2001. -// (C) Copyright David Abrahams 2003. -// (C) Copyright Boris Gubenko 2007. -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org for most recent version. - -// Rogue Wave std lib: - -#define BOOST_RW_STDLIB 1 - -#if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER) -# include -# if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER) -# error This is not the Rogue Wave standard library -# endif -#endif -// -// figure out a consistent version number: -// -#ifndef _RWSTD_VER -# define BOOST_RWSTD_VER 0x010000 -#elif _RWSTD_VER < 0x010000 -# define BOOST_RWSTD_VER (_RWSTD_VER << 8) -#else -# define BOOST_RWSTD_VER _RWSTD_VER -#endif - -#ifndef _RWSTD_VER -# define BOOST_STDLIB "Rogue Wave standard library version (Unknown version)" -#elif _RWSTD_VER < 0x04010200 - # define BOOST_STDLIB "Rogue Wave standard library version " BOOST_STRINGIZE(_RWSTD_VER) -#else -# ifdef _RWSTD_VER_STR -# define BOOST_STDLIB "Apache STDCXX standard library version " _RWSTD_VER_STR -# else -# define BOOST_STDLIB "Apache STDCXX standard library version " BOOST_STRINGIZE(_RWSTD_VER) -# endif -#endif - -// -// Prior to version 2.2.0 the primary template for std::numeric_limits -// does not have compile time constants, even though specializations of that -// template do: -// -#if BOOST_RWSTD_VER < 0x020200 -# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS -#endif - -// Sun CC 5.5 patch 113817-07 adds long long specialization, but does not change the -// library version number (http://sunsolve6.sun.com/search/document.do?assetkey=1-21-113817): -#if BOOST_RWSTD_VER <= 0x020101 && (!defined(__SUNPRO_CC) || (__SUNPRO_CC < 0x550)) -# define BOOST_NO_LONG_LONG_NUMERIC_LIMITS -# endif - -// -// Borland version of numeric_limits lacks __int64 specialisation: -// -#ifdef __BORLANDC__ -# define BOOST_NO_MS_INT64_NUMERIC_LIMITS -#endif - -// -// No std::iterator if it can't figure out default template args: -// -#if defined(_RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || defined(RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || (BOOST_RWSTD_VER < 0x020000) -# define BOOST_NO_STD_ITERATOR -#endif - -// -// No iterator traits without partial specialization: -// -#if defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) || defined(RWSTD_NO_CLASS_PARTIAL_SPEC) -# define BOOST_NO_STD_ITERATOR_TRAITS -#endif - -// -// Prior to version 2.0, std::unique_ptr was buggy, and there were no -// new-style iostreams, and no conformant std::allocator: -// -#if (BOOST_RWSTD_VER < 0x020000) -# define BOOST_NO_AUTO_PTR -# define BOOST_NO_STRINGSTREAM -# define BOOST_NO_STD_ALLOCATOR -# define BOOST_NO_STD_LOCALE -#endif - -// -// No template iterator constructors without member template support: -// -#if defined(RWSTD_NO_MEMBER_TEMPLATES) || defined(_RWSTD_NO_MEMBER_TEMPLATES) -# define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS -#endif - -// -// RW defines _RWSTD_ALLOCATOR if the allocator is conformant and in use -// (the or _HPACC_ part is a hack - the library seems to define _RWSTD_ALLOCATOR -// on HP aCC systems even though the allocator is in fact broken): -// -#if !defined(_RWSTD_ALLOCATOR) || (defined(__HP_aCC) && __HP_aCC <= 33100) -# define BOOST_NO_STD_ALLOCATOR -#endif - -// -// If we have a std::locale, we still may not have std::use_facet: -// -#if defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE) && !defined(BOOST_NO_STD_LOCALE) -# define BOOST_NO_STD_USE_FACET -# define BOOST_HAS_TWO_ARG_USE_FACET -#endif - -// -// There's no std::distance prior to version 2, or without -// partial specialization support: -// -#if (BOOST_RWSTD_VER < 0x020000) || defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) - #define BOOST_NO_STD_DISTANCE -#endif - -// -// Some versions of the rogue wave library don't have assignable -// OutputIterators: -// -#if BOOST_RWSTD_VER < 0x020100 -# define BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN -#endif - -// -// Disable BOOST_HAS_LONG_LONG when the library has no support for it. -// -#if !defined(_RWSTD_LONG_LONG) && defined(BOOST_HAS_LONG_LONG) -# undef BOOST_HAS_LONG_LONG -#endif - -// -// check that on HP-UX, the proper RW library is used -// -#if defined(__HP_aCC) && !defined(_HP_NAMESPACE_STD) -# error "Boost requires Standard RW library. Please compile and link with -AA" -#endif - -// -// Define macros specific to RW V2.2 on HP-UX -// -#if defined(__HP_aCC) && (BOOST_RWSTD_VER == 0x02020100) -# ifndef __HP_TC1_MAKE_PAIR -# define __HP_TC1_MAKE_PAIR -# endif -# ifndef _HP_INSTANTIATE_STD2_VL -# define _HP_INSTANTIATE_STD2_VL -# endif -#endif - -#if _RWSTD_VER < 0x05000000 -# define BOOST_NO_CXX11_HDR_ARRAY -#endif -// type_traits header is incomplete: -# define BOOST_NO_CXX11_HDR_TYPE_TRAITS -// -// C++0x headers not yet implemented -// -# define BOOST_NO_CXX11_HDR_CHRONO -# define BOOST_NO_CXX11_HDR_CODECVT -# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE -# define BOOST_NO_CXX11_HDR_FORWARD_LIST -# define BOOST_NO_CXX11_HDR_FUTURE -# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST -# define BOOST_NO_CXX11_HDR_MUTEX -# define BOOST_NO_CXX11_HDR_RANDOM -# define BOOST_NO_CXX11_HDR_RATIO -# define BOOST_NO_CXX11_HDR_REGEX -# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR -# define BOOST_NO_CXX11_HDR_THREAD -# define BOOST_NO_CXX11_HDR_TUPLE -# define BOOST_NO_CXX11_HDR_TYPEINDEX -# define BOOST_NO_CXX11_HDR_UNORDERED_MAP -# define BOOST_NO_CXX11_HDR_UNORDERED_SET -# define BOOST_NO_CXX11_NUMERIC_LIMITS -# define BOOST_NO_CXX11_ALLOCATOR -# define BOOST_NO_CXX11_ATOMIC_SMART_PTR -# define BOOST_NO_CXX11_SMART_PTR -# define BOOST_NO_CXX11_HDR_FUNCTIONAL -# define BOOST_NO_CXX11_HDR_ATOMIC -# define BOOST_NO_CXX11_STD_ALIGN -# define BOOST_NO_CXX11_ADDRESSOF - +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001. +// (C) Copyright David Abrahams 2003. +// (C) Copyright Boris Gubenko 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Rogue Wave std lib: + +#define BOOST_RW_STDLIB 1 + +#if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER) +# include +# if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER) +# error This is not the Rogue Wave standard library +# endif +#endif +// +// figure out a consistent version number: +// +#ifndef _RWSTD_VER +# define BOOST_RWSTD_VER 0x010000 +#elif _RWSTD_VER < 0x010000 +# define BOOST_RWSTD_VER (_RWSTD_VER << 8) +#else +# define BOOST_RWSTD_VER _RWSTD_VER +#endif + +#ifndef _RWSTD_VER +# define BOOST_STDLIB "Rogue Wave standard library version (Unknown version)" +#elif _RWSTD_VER < 0x04010200 + # define BOOST_STDLIB "Rogue Wave standard library version " BOOST_STRINGIZE(_RWSTD_VER) +#else +# ifdef _RWSTD_VER_STR +# define BOOST_STDLIB "Apache STDCXX standard library version " _RWSTD_VER_STR +# else +# define BOOST_STDLIB "Apache STDCXX standard library version " BOOST_STRINGIZE(_RWSTD_VER) +# endif +#endif + +// +// Prior to version 2.2.0 the primary template for std::numeric_limits +// does not have compile time constants, even though specializations of that +// template do: +// +#if BOOST_RWSTD_VER < 0x020200 +# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +#endif + +// Sun CC 5.5 patch 113817-07 adds long long specialization, but does not change the +// library version number (http://sunsolve6.sun.com/search/document.do?assetkey=1-21-113817): +#if BOOST_RWSTD_VER <= 0x020101 && (!defined(__SUNPRO_CC) || (__SUNPRO_CC < 0x550)) +# define BOOST_NO_LONG_LONG_NUMERIC_LIMITS +# endif + +// +// Borland version of numeric_limits lacks __int64 specialisation: +// +#ifdef __BORLANDC__ +# define BOOST_NO_MS_INT64_NUMERIC_LIMITS +#endif + +// +// No std::iterator if it can't figure out default template args: +// +#if defined(_RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || defined(RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || (BOOST_RWSTD_VER < 0x020000) +# define BOOST_NO_STD_ITERATOR +#endif + +// +// No iterator traits without partial specialization: +// +#if defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) || defined(RWSTD_NO_CLASS_PARTIAL_SPEC) +# define BOOST_NO_STD_ITERATOR_TRAITS +#endif + +// +// Prior to version 2.0, std::unique_ptr was buggy, and there were no +// new-style iostreams, and no conformant std::allocator: +// +#if (BOOST_RWSTD_VER < 0x020000) +# define BOOST_NO_AUTO_PTR +# define BOOST_NO_STRINGSTREAM +# define BOOST_NO_STD_ALLOCATOR +# define BOOST_NO_STD_LOCALE +#endif + +// +// No template iterator constructors without member template support: +// +#if defined(RWSTD_NO_MEMBER_TEMPLATES) || defined(_RWSTD_NO_MEMBER_TEMPLATES) +# define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS +#endif + +// +// RW defines _RWSTD_ALLOCATOR if the allocator is conformant and in use +// (the or _HPACC_ part is a hack - the library seems to define _RWSTD_ALLOCATOR +// on HP aCC systems even though the allocator is in fact broken): +// +#if !defined(_RWSTD_ALLOCATOR) || (defined(__HP_aCC) && __HP_aCC <= 33100) +# define BOOST_NO_STD_ALLOCATOR +#endif + +// +// If we have a std::locale, we still may not have std::use_facet: +// +#if defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE) && !defined(BOOST_NO_STD_LOCALE) +# define BOOST_NO_STD_USE_FACET +# define BOOST_HAS_TWO_ARG_USE_FACET +#endif + +// +// There's no std::distance prior to version 2, or without +// partial specialization support: +// +#if (BOOST_RWSTD_VER < 0x020000) || defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + #define BOOST_NO_STD_DISTANCE +#endif + +// +// Some versions of the rogue wave library don't have assignable +// OutputIterators: +// +#if BOOST_RWSTD_VER < 0x020100 +# define BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN +#endif + +// +// Disable BOOST_HAS_LONG_LONG when the library has no support for it. +// +#if !defined(_RWSTD_LONG_LONG) && defined(BOOST_HAS_LONG_LONG) +# undef BOOST_HAS_LONG_LONG +#endif + +// +// check that on HP-UX, the proper RW library is used +// +#if defined(__HP_aCC) && !defined(_HP_NAMESPACE_STD) +# error "Boost requires Standard RW library. Please compile and link with -AA" +#endif + +// +// Define macros specific to RW V2.2 on HP-UX +// +#if defined(__HP_aCC) && (BOOST_RWSTD_VER == 0x02020100) +# ifndef __HP_TC1_MAKE_PAIR +# define __HP_TC1_MAKE_PAIR +# endif +# ifndef _HP_INSTANTIATE_STD2_VL +# define _HP_INSTANTIATE_STD2_VL +# endif +#endif + +#if _RWSTD_VER < 0x05000000 +# define BOOST_NO_CXX11_HDR_ARRAY +#endif +// type_traits header is incomplete: +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +// +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + diff --git a/src/external/3rd/library/boost/boost/date_time/gregorian/greg_facet.hpp b/src/external/3rd/library/boost/boost/date_time/gregorian/greg_facet.hpp index 47c62763d..d0da42d34 100644 --- a/src/external/3rd/library/boost/boost/date_time/gregorian/greg_facet.hpp +++ b/src/external/3rd/library/boost/boost/date_time/gregorian/greg_facet.hpp @@ -1,352 +1,352 @@ -#ifndef GREGORIAN_FACET_HPP___ -#define GREGORIAN_FACET_HPP___ - -/* Copyright (c) 2002,2003 CrystalClear Software, Inc. - * Use, modification and distribution is subject to the - * Boost Software License, Version 1.0. (See accompanying - * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) - * Author: Jeff Garland, Bart Garst - * $Date$ - */ - -#include "boost/date_time/gregorian/gregorian_types.hpp" -#include "boost/date_time/date_formatting_locales.hpp" // sets BOOST_DATE_TIME_NO_LOCALE -#include "boost/date_time/gregorian/parsers.hpp" - -//This file is basically commented out if locales are not supported -#ifndef BOOST_DATE_TIME_NO_LOCALE - -#include -#include -#include -#include -#include - -namespace boost { -namespace gregorian { - - //! Configuration of the output facet template - struct greg_facet_config - { - typedef boost::gregorian::greg_month month_type; - typedef boost::date_time::special_values special_value_enum; - typedef boost::gregorian::months_of_year month_enum; - typedef boost::date_time::weekdays weekday_enum; - }; - -#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO) - //! Create the base facet type for gregorian::date - typedef boost::date_time::date_names_put greg_base_facet; - - //! ostream operator for gregorian::date - /*! Uses the date facet to determine various output parameters including: - * - string values for the month (eg: Jan, Feb, Mar) (default: English) - * - string values for special values (eg: not-a-date-time) (default: English) - * - selection of long, short strings, or numerical month representation (default: short string) - * - month day year order (default yyyy-mmm-dd) - */ - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, const date& d) - { - typedef boost::date_time::date_names_put facet_def; - typedef boost::date_time::ostream_date_formatter greg_ostream_formatter; - greg_ostream_formatter::date_put(d, os); - return os; - } - - //! operator<< for gregorian::greg_month typically streaming: Jan, Feb, Mar... - /*! Uses the date facet to determine output string as well as selection of long or short strings. - * Default if no facet is installed is to output a 2 wide numeric value for the month - * eg: 01 == Jan, 02 == Feb, ... 12 == Dec. - */ - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, const greg_month& m) - { - typedef boost::date_time::date_names_put facet_def; - typedef boost::date_time::ostream_month_formatter greg_month_formatter; - std::locale locale = os.getloc(); - if (std::has_facet(locale)) { - const facet_def& f = std::use_facet(locale); - greg_month_formatter::format_month(m, os, f); - - } - else { //default to numeric - charT fill_char = '0'; - os << std::setw(2) << std::setfill(fill_char) << m.as_number(); - } - - return os; - } - - //! operator<< for gregorian::greg_weekday typically streaming: Sun, Mon, Tue, ... - /*! Uses the date facet to determine output string as well as selection of long or short string. - * Default if no facet is installed is to output a 3 char english string for the - * day of the week. - */ - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, const greg_weekday& wd) - { - typedef boost::date_time::date_names_put facet_def; - typedef boost::date_time::ostream_weekday_formatter greg_weekday_formatter; - std::locale locale = os.getloc(); - if (std::has_facet(locale)) { - const facet_def& f = std::use_facet(locale); - greg_weekday_formatter::format_weekday(wd, os, f, true); - } - else { //default to short English string eg: Sun, Mon, Tue, Wed... - os << wd.as_short_string(); - } - - return os; - } - - //! operator<< for gregorian::date_period typical output: [2002-Jan-01/2002-Jan-31] - /*! Uses the date facet to determine output string as well as selection of long - * or short string fr dates. - * Default if no facet is installed is to output a 3 char english string for the - * day of the week. - */ - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, const date_period& dp) - { - os << '['; //TODO: facet or manipulator for periods? - os << dp.begin(); - os << '/'; //TODO: facet or manipulator for periods? - os << dp.last(); - os << ']'; - return os; - } - - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, const date_duration& dd) - { - //os << dd.days(); - os << dd.get_rep(); - return os; - } - - //! operator<< for gregorian::partial_date. Output: "Jan 1" - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, const partial_date& pd) - { - os << std::setw(2) << std::setfill('0') << pd.day() << ' ' - << pd.month().as_short_string() ; - return os; - } - - //! operator<< for gregorian::nth_kday_of_month. Output: "first Mon of Jun" - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, - const nth_kday_of_month& nkd) - { - os << nkd.nth_week_as_str() << ' ' - << nkd.day_of_week() << " of " - << nkd.month().as_short_string() ; - return os; - } - - //! operator<< for gregorian::first_kday_of_month. Output: "first Mon of Jun" - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, - const first_kday_of_month& fkd) - { - os << "first " << fkd.day_of_week() << " of " - << fkd.month().as_short_string() ; - return os; - } - - //! operator<< for gregorian::last_kday_of_month. Output: "last Mon of Jun" - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, - const last_kday_of_month& lkd) - { - os << "last " << lkd.day_of_week() << " of " - << lkd.month().as_short_string() ; - return os; - } - - //! operator<< for gregorian::first_kday_after. Output: "first Mon after" - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, - const first_kday_after& fka) - { - os << fka.day_of_week() << " after"; - return os; - } - - //! operator<< for gregorian::first_kday_before. Output: "first Mon before" - template - inline - std::basic_ostream& - operator<<(std::basic_ostream& os, - const first_kday_before& fkb) - { - os << fkb.day_of_week() << " before"; - return os; - } -#endif // USE_DATE_TIME_PRE_1_33_FACET_IO - /**************** Input Streaming ******************/ - -#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) - //! operator>> for gregorian::date - template - inline - std::basic_istream& operator>>(std::basic_istream& is, date& d) - { - std::istream_iterator, charT> beg(is), eos; - d = from_stream(beg, eos); - return is; - } -#endif // BOOST_NO_STD_ITERATOR_TRAITS - - //! operator>> for gregorian::date_duration - template - inline - std::basic_istream& operator>>(std::basic_istream& is, - date_duration& dd) - { - long v; - is >> v; - dd = date_duration(v); - return is; - } - - //! operator>> for gregorian::date_period - template - inline - std::basic_istream& operator>>(std::basic_istream& is, - date_period& dp) - { - std::basic_string s; - is >> s; - dp = date_time::from_simple_string_type(s); - return is; - } - - //! generates a locale with the set of gregorian name-strings of type char* - BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, char type); - - //! Returns a pointer to a facet with a default set of names (English) - /* Necessary in the event an exception is thrown from op>> for - * weekday or month. See comments in those functions for more info */ - BOOST_DATE_TIME_DECL boost::date_time::all_date_names_put* create_facet_def(char type); - -#ifndef BOOST_NO_STD_WSTRING - //! generates a locale with the set of gregorian name-strings of type wchar_t* - BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, wchar_t type); - //! Returns a pointer to a facet with a default set of names (English) - /* Necessary in the event an exception is thrown from op>> for - * weekday or month. See comments in those functions for more info */ - BOOST_DATE_TIME_DECL boost::date_time::all_date_names_put* create_facet_def(wchar_t type); -#endif // BOOST_NO_STD_WSTRING - - //! operator>> for gregorian::greg_month - throws exception if invalid month given - template - inline - std::basic_istream& operator>>(std::basic_istream& is,greg_month& m) - { - typedef boost::date_time::all_date_names_put facet_def; - - std::basic_string s; - is >> s; - - if(!std::has_facet(is.getloc())) { - std::locale loc = is.getloc(); - charT a = '\0'; - is.imbue(generate_locale(loc, a)); - } - - short num = 0; - - try{ - const facet_def& f = std::use_facet(is.getloc()); - num = date_time::find_match(f.get_short_month_names(), - f.get_long_month_names(), - (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size, - // which is needed by find_match - } - /* bad_cast will be thrown if the desired facet is not accessible - * so we can generate the facet. This has the drawback of using english - * names as a default. */ - catch(std::bad_cast&){ - charT a = '\0'; - std::unique_ptr< const facet_def > f(create_facet_def(a)); - num = date_time::find_match(f->get_short_month_names(), - f->get_long_month_names(), - (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size, - // which is needed by find_match - } - - ++num; // months numbered 1-12 - m = greg_month(num); - - return is; - } - - //! operator>> for gregorian::greg_weekday - throws exception if invalid weekday given - template - inline - std::basic_istream& operator>>(std::basic_istream& is,greg_weekday& wd) - { - typedef boost::date_time::all_date_names_put facet_def; - - std::basic_string s; - is >> s; - - if(!std::has_facet(is.getloc())) { - std::locale loc = is.getloc(); - charT a = '\0'; - is.imbue(generate_locale(loc, a)); - } - - short num = 0; - try{ - const facet_def& f = std::use_facet(is.getloc()); - num = date_time::find_match(f.get_short_weekday_names(), - f.get_long_weekday_names(), - (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed - // to form the array size which is needed by find_match - } - /* bad_cast will be thrown if the desired facet is not accessible - * so we can generate the facet. This has the drawback of using english - * names as a default. */ - catch(std::bad_cast&){ - charT a = '\0'; - std::unique_ptr< const facet_def > f(create_facet_def(a)); - num = date_time::find_match(f->get_short_weekday_names(), - f->get_long_weekday_names(), - (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed - // to form the array size which is needed by find_match - } - - wd = greg_weekday(num); // weekdays numbered 0-6 - return is; - } - -} } //namespace gregorian - -#endif - - -#endif - +#ifndef GREGORIAN_FACET_HPP___ +#define GREGORIAN_FACET_HPP___ + +/* Copyright (c) 2002,2003 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date$ + */ + +#include "boost/date_time/gregorian/gregorian_types.hpp" +#include "boost/date_time/date_formatting_locales.hpp" // sets BOOST_DATE_TIME_NO_LOCALE +#include "boost/date_time/gregorian/parsers.hpp" + +//This file is basically commented out if locales are not supported +#ifndef BOOST_DATE_TIME_NO_LOCALE + +#include +#include +#include +#include +#include + +namespace boost { +namespace gregorian { + + //! Configuration of the output facet template + struct greg_facet_config + { + typedef boost::gregorian::greg_month month_type; + typedef boost::date_time::special_values special_value_enum; + typedef boost::gregorian::months_of_year month_enum; + typedef boost::date_time::weekdays weekday_enum; + }; + +#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO) + //! Create the base facet type for gregorian::date + typedef boost::date_time::date_names_put greg_base_facet; + + //! ostream operator for gregorian::date + /*! Uses the date facet to determine various output parameters including: + * - string values for the month (eg: Jan, Feb, Mar) (default: English) + * - string values for special values (eg: not-a-date-time) (default: English) + * - selection of long, short strings, or numerical month representation (default: short string) + * - month day year order (default yyyy-mmm-dd) + */ + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, const date& d) + { + typedef boost::date_time::date_names_put facet_def; + typedef boost::date_time::ostream_date_formatter greg_ostream_formatter; + greg_ostream_formatter::date_put(d, os); + return os; + } + + //! operator<< for gregorian::greg_month typically streaming: Jan, Feb, Mar... + /*! Uses the date facet to determine output string as well as selection of long or short strings. + * Default if no facet is installed is to output a 2 wide numeric value for the month + * eg: 01 == Jan, 02 == Feb, ... 12 == Dec. + */ + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, const greg_month& m) + { + typedef boost::date_time::date_names_put facet_def; + typedef boost::date_time::ostream_month_formatter greg_month_formatter; + std::locale locale = os.getloc(); + if (std::has_facet(locale)) { + const facet_def& f = std::use_facet(locale); + greg_month_formatter::format_month(m, os, f); + + } + else { //default to numeric + charT fill_char = '0'; + os << std::setw(2) << std::setfill(fill_char) << m.as_number(); + } + + return os; + } + + //! operator<< for gregorian::greg_weekday typically streaming: Sun, Mon, Tue, ... + /*! Uses the date facet to determine output string as well as selection of long or short string. + * Default if no facet is installed is to output a 3 char english string for the + * day of the week. + */ + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, const greg_weekday& wd) + { + typedef boost::date_time::date_names_put facet_def; + typedef boost::date_time::ostream_weekday_formatter greg_weekday_formatter; + std::locale locale = os.getloc(); + if (std::has_facet(locale)) { + const facet_def& f = std::use_facet(locale); + greg_weekday_formatter::format_weekday(wd, os, f, true); + } + else { //default to short English string eg: Sun, Mon, Tue, Wed... + os << wd.as_short_string(); + } + + return os; + } + + //! operator<< for gregorian::date_period typical output: [2002-Jan-01/2002-Jan-31] + /*! Uses the date facet to determine output string as well as selection of long + * or short string fr dates. + * Default if no facet is installed is to output a 3 char english string for the + * day of the week. + */ + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, const date_period& dp) + { + os << '['; //TODO: facet or manipulator for periods? + os << dp.begin(); + os << '/'; //TODO: facet or manipulator for periods? + os << dp.last(); + os << ']'; + return os; + } + + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, const date_duration& dd) + { + //os << dd.days(); + os << dd.get_rep(); + return os; + } + + //! operator<< for gregorian::partial_date. Output: "Jan 1" + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, const partial_date& pd) + { + os << std::setw(2) << std::setfill('0') << pd.day() << ' ' + << pd.month().as_short_string() ; + return os; + } + + //! operator<< for gregorian::nth_kday_of_month. Output: "first Mon of Jun" + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, + const nth_kday_of_month& nkd) + { + os << nkd.nth_week_as_str() << ' ' + << nkd.day_of_week() << " of " + << nkd.month().as_short_string() ; + return os; + } + + //! operator<< for gregorian::first_kday_of_month. Output: "first Mon of Jun" + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, + const first_kday_of_month& fkd) + { + os << "first " << fkd.day_of_week() << " of " + << fkd.month().as_short_string() ; + return os; + } + + //! operator<< for gregorian::last_kday_of_month. Output: "last Mon of Jun" + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, + const last_kday_of_month& lkd) + { + os << "last " << lkd.day_of_week() << " of " + << lkd.month().as_short_string() ; + return os; + } + + //! operator<< for gregorian::first_kday_after. Output: "first Mon after" + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, + const first_kday_after& fka) + { + os << fka.day_of_week() << " after"; + return os; + } + + //! operator<< for gregorian::first_kday_before. Output: "first Mon before" + template + inline + std::basic_ostream& + operator<<(std::basic_ostream& os, + const first_kday_before& fkb) + { + os << fkb.day_of_week() << " before"; + return os; + } +#endif // USE_DATE_TIME_PRE_1_33_FACET_IO + /**************** Input Streaming ******************/ + +#if !defined(BOOST_NO_STD_ITERATOR_TRAITS) + //! operator>> for gregorian::date + template + inline + std::basic_istream& operator>>(std::basic_istream& is, date& d) + { + std::istream_iterator, charT> beg(is), eos; + d = from_stream(beg, eos); + return is; + } +#endif // BOOST_NO_STD_ITERATOR_TRAITS + + //! operator>> for gregorian::date_duration + template + inline + std::basic_istream& operator>>(std::basic_istream& is, + date_duration& dd) + { + long v; + is >> v; + dd = date_duration(v); + return is; + } + + //! operator>> for gregorian::date_period + template + inline + std::basic_istream& operator>>(std::basic_istream& is, + date_period& dp) + { + std::basic_string s; + is >> s; + dp = date_time::from_simple_string_type(s); + return is; + } + + //! generates a locale with the set of gregorian name-strings of type char* + BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, char type); + + //! Returns a pointer to a facet with a default set of names (English) + /* Necessary in the event an exception is thrown from op>> for + * weekday or month. See comments in those functions for more info */ + BOOST_DATE_TIME_DECL boost::date_time::all_date_names_put* create_facet_def(char type); + +#ifndef BOOST_NO_STD_WSTRING + //! generates a locale with the set of gregorian name-strings of type wchar_t* + BOOST_DATE_TIME_DECL std::locale generate_locale(std::locale& loc, wchar_t type); + //! Returns a pointer to a facet with a default set of names (English) + /* Necessary in the event an exception is thrown from op>> for + * weekday or month. See comments in those functions for more info */ + BOOST_DATE_TIME_DECL boost::date_time::all_date_names_put* create_facet_def(wchar_t type); +#endif // BOOST_NO_STD_WSTRING + + //! operator>> for gregorian::greg_month - throws exception if invalid month given + template + inline + std::basic_istream& operator>>(std::basic_istream& is,greg_month& m) + { + typedef boost::date_time::all_date_names_put facet_def; + + std::basic_string s; + is >> s; + + if(!std::has_facet(is.getloc())) { + std::locale loc = is.getloc(); + charT a = '\0'; + is.imbue(generate_locale(loc, a)); + } + + short num = 0; + + try{ + const facet_def& f = std::use_facet(is.getloc()); + num = date_time::find_match(f.get_short_month_names(), + f.get_long_month_names(), + (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size, + // which is needed by find_match + } + /* bad_cast will be thrown if the desired facet is not accessible + * so we can generate the facet. This has the drawback of using english + * names as a default. */ + catch(std::bad_cast&){ + charT a = '\0'; + std::unique_ptr< const facet_def > f(create_facet_def(a)); + num = date_time::find_match(f->get_short_month_names(), + f->get_long_month_names(), + (greg_month::max)(), s); // greg_month spans 1..12, so max returns the array size, + // which is needed by find_match + } + + ++num; // months numbered 1-12 + m = greg_month(num); + + return is; + } + + //! operator>> for gregorian::greg_weekday - throws exception if invalid weekday given + template + inline + std::basic_istream& operator>>(std::basic_istream& is,greg_weekday& wd) + { + typedef boost::date_time::all_date_names_put facet_def; + + std::basic_string s; + is >> s; + + if(!std::has_facet(is.getloc())) { + std::locale loc = is.getloc(); + charT a = '\0'; + is.imbue(generate_locale(loc, a)); + } + + short num = 0; + try{ + const facet_def& f = std::use_facet(is.getloc()); + num = date_time::find_match(f.get_short_weekday_names(), + f.get_long_weekday_names(), + (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed + // to form the array size which is needed by find_match + } + /* bad_cast will be thrown if the desired facet is not accessible + * so we can generate the facet. This has the drawback of using english + * names as a default. */ + catch(std::bad_cast&){ + charT a = '\0'; + std::unique_ptr< const facet_def > f(create_facet_def(a)); + num = date_time::find_match(f->get_short_weekday_names(), + f->get_long_weekday_names(), + (greg_weekday::max)() + 1, s); // greg_weekday spans 0..6, so increment is needed + // to form the array size which is needed by find_match + } + + wd = greg_weekday(num); // weekdays numbered 0-6 + return is; + } + +} } //namespace gregorian + +#endif + + +#endif + diff --git a/src/external/3rd/library/boost/boost/detail/lightweight_thread.hpp b/src/external/3rd/library/boost/boost/detail/lightweight_thread.hpp index e51d13e1b..07eed91e3 100644 --- a/src/external/3rd/library/boost/boost/detail/lightweight_thread.hpp +++ b/src/external/3rd/library/boost/boost/detail/lightweight_thread.hpp @@ -1,135 +1,135 @@ -#ifndef BOOST_DETAIL_LIGHTWEIGHT_THREAD_HPP_INCLUDED -#define BOOST_DETAIL_LIGHTWEIGHT_THREAD_HPP_INCLUDED - -// MS compatible compilers support #pragma once - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -// boost/detail/lightweight_thread.hpp -// -// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. -// Copyright (c) 2008 Peter Dimov -// -// Distributed under the Boost Software License, Version 1.0. -// See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt - -#include -#include -#include - -// pthread_create, pthread_join - -#if defined( BOOST_HAS_PTHREADS ) - -#include - -#else - -#include -#include - -typedef HANDLE pthread_t; - -int pthread_create( pthread_t * thread, void const *, unsigned (__stdcall * start_routine) (void*), void* arg ) -{ - HANDLE h = (HANDLE)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); - - if( h != 0 ) - { - *thread = h; - return 0; - } - else - { - return EAGAIN; - } -} - -int pthread_join( pthread_t thread, void ** /*value_ptr*/ ) -{ - ::WaitForSingleObject( thread, INFINITE ); - ::CloseHandle( thread ); - return 0; -} - -#endif - -// template int lw_thread_create( pthread_t & pt, F f ); - -namespace boost -{ - -namespace detail -{ - -class lw_abstract_thread -{ -public: - - virtual ~lw_abstract_thread() {} - virtual void run() = 0; -}; - -#if defined( BOOST_HAS_PTHREADS ) - -extern "C" void * lw_thread_routine( void * pv ) -{ - std::unique_ptr pt( static_cast( pv ) ); - - pt->run(); - - return 0; -} - -#else - -unsigned __stdcall lw_thread_routine( void * pv ) -{ - std::unique_ptr pt( static_cast( pv ) ); - - pt->run(); - - return 0; -} - -#endif - -template class lw_thread_impl: public lw_abstract_thread -{ -public: - - explicit lw_thread_impl( F f ): f_( f ) - { - } - - void run() - { - f_(); - } - -private: - - F f_; -}; - -template int lw_thread_create( pthread_t & pt, F f ) -{ - std::unique_ptr p( new lw_thread_impl( f ) ); - - int r = pthread_create( &pt, 0, lw_thread_routine, p.get() ); - - if( r == 0 ) - { - p.release(); - } - - return r; -} - -} // namespace detail -} // namespace boost - -#endif // #ifndef BOOST_DETAIL_LIGHTWEIGHT_THREAD_HPP_INCLUDED +#ifndef BOOST_DETAIL_LIGHTWEIGHT_THREAD_HPP_INCLUDED +#define BOOST_DETAIL_LIGHTWEIGHT_THREAD_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/detail/lightweight_thread.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include + +// pthread_create, pthread_join + +#if defined( BOOST_HAS_PTHREADS ) + +#include + +#else + +#include +#include + +typedef HANDLE pthread_t; + +int pthread_create( pthread_t * thread, void const *, unsigned (__stdcall * start_routine) (void*), void* arg ) +{ + HANDLE h = (HANDLE)_beginthreadex( 0, 0, start_routine, arg, 0, 0 ); + + if( h != 0 ) + { + *thread = h; + return 0; + } + else + { + return EAGAIN; + } +} + +int pthread_join( pthread_t thread, void ** /*value_ptr*/ ) +{ + ::WaitForSingleObject( thread, INFINITE ); + ::CloseHandle( thread ); + return 0; +} + +#endif + +// template int lw_thread_create( pthread_t & pt, F f ); + +namespace boost +{ + +namespace detail +{ + +class lw_abstract_thread +{ +public: + + virtual ~lw_abstract_thread() {} + virtual void run() = 0; +}; + +#if defined( BOOST_HAS_PTHREADS ) + +extern "C" void * lw_thread_routine( void * pv ) +{ + std::unique_ptr pt( static_cast( pv ) ); + + pt->run(); + + return 0; +} + +#else + +unsigned __stdcall lw_thread_routine( void * pv ) +{ + std::unique_ptr pt( static_cast( pv ) ); + + pt->run(); + + return 0; +} + +#endif + +template class lw_thread_impl: public lw_abstract_thread +{ +public: + + explicit lw_thread_impl( F f ): f_( f ) + { + } + + void run() + { + f_(); + } + +private: + + F f_; +}; + +template int lw_thread_create( pthread_t & pt, F f ) +{ + std::unique_ptr p( new lw_thread_impl( f ) ); + + int r = pthread_create( &pt, 0, lw_thread_routine, p.get() ); + + if( r == 0 ) + { + p.release(); + } + + return r; +} + +} // namespace detail +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_LIGHTWEIGHT_THREAD_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/get_pointer.hpp b/src/external/3rd/library/boost/boost/get_pointer.hpp index 0bf9275a5..d2f9efdb8 100644 --- a/src/external/3rd/library/boost/boost/get_pointer.hpp +++ b/src/external/3rd/library/boost/boost/get_pointer.hpp @@ -1,48 +1,48 @@ -// Copyright Peter Dimov and David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef GET_POINTER_DWA20021219_HPP -#define GET_POINTER_DWA20021219_HPP - -#include - -// In order to avoid circular dependencies with Boost.TR1 -// we make sure that our include of doesn't try to -// pull in the TR1 headers: that's why we use this header -// rather than including directly: -#include // std::unique_ptr - -namespace boost { - -// get_pointer(p) extracts a ->* capable pointer from p - -template T * get_pointer(T * p) -{ - return p; -} - -// get_pointer(shared_ptr const & p) has been moved to shared_ptr.hpp - -template T * get_pointer(std::unique_ptr const& p) -{ - return p.get(); -} - -#if !defined( BOOST_NO_CXX11_SMART_PTR ) - -template T * get_pointer( std::unique_ptr const& p ) -{ - return p.get(); -} - -template T * get_pointer( std::shared_ptr const& p ) -{ - return p.get(); -} - -#endif - -} // namespace boost - -#endif // GET_POINTER_DWA20021219_HPP +// Copyright Peter Dimov and David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef GET_POINTER_DWA20021219_HPP +#define GET_POINTER_DWA20021219_HPP + +#include + +// In order to avoid circular dependencies with Boost.TR1 +// we make sure that our include of doesn't try to +// pull in the TR1 headers: that's why we use this header +// rather than including directly: +#include // std::unique_ptr + +namespace boost { + +// get_pointer(p) extracts a ->* capable pointer from p + +template T * get_pointer(T * p) +{ + return p; +} + +// get_pointer(shared_ptr const & p) has been moved to shared_ptr.hpp + +template T * get_pointer(std::unique_ptr const& p) +{ + return p.get(); +} + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + +template T * get_pointer( std::unique_ptr const& p ) +{ + return p.get(); +} + +template T * get_pointer( std::shared_ptr const& p ) +{ + return p.get(); +} + +#endif + +} // namespace boost + +#endif // GET_POINTER_DWA20021219_HPP diff --git a/src/external/3rd/library/boost/boost/graph/detail/adjacency_list.hpp b/src/external/3rd/library/boost/boost/graph/detail/adjacency_list.hpp index 05de943f7..6d54357eb 100644 --- a/src/external/3rd/library/boost/boost/graph/detail/adjacency_list.hpp +++ b/src/external/3rd/library/boost/boost/graph/detail/adjacency_list.hpp @@ -1,2827 +1,2827 @@ -// -*- c++ -*- -//======================================================================= -// Copyright 1997, 1998, 1999, 2000 University of Notre Dame. -// Copyright 2010 Thomas Claveirole -// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Thomas Claveirole -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -//======================================================================= - -#ifndef BOOST_GRAPH_DETAIL_ADJACENCY_LIST_HPP -#define BOOST_GRAPH_DETAIL_ADJACENCY_LIST_HPP - -#include // for vertex_map in copy_impl -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES -#define BOOST_GRAPH_MOVE_IF_POSSIBLE(x) (x) -#else -#include -#define BOOST_GRAPH_MOVE_IF_POSSIBLE(x) (std::move((x))) -#endif - -/* - Outline for this file: - - out_edge_iterator and in_edge_iterator implementation - edge_iterator for undirected graph - stored edge types (these object live in the out-edge/in-edge lists) - directed edges helper class - directed graph helper class - undirected graph helper class - bidirectional graph helper class - bidirectional graph helper class (without edge properties) - bidirectional graph helper class (with edge properties) - adjacency_list helper class - adj_list_impl class - vec_adj_list_impl class - adj_list_gen class - vertex property map - edge property map - - - Note: it would be nice to merge some of the undirected and - bidirectional code... it is awful similar. - */ - - -namespace boost { - - namespace detail { - - template - struct directed_category_traits { - typedef directed_tag directed_category; - }; - - template <> - struct directed_category_traits { - typedef directed_tag directed_category; - }; - template <> - struct directed_category_traits { - typedef undirected_tag directed_category; - }; - template <> - struct directed_category_traits { - typedef bidirectional_tag directed_category; - }; - - template - struct target_is { - target_is(const Vertex& v) : m_target(v) { } - template - bool operator()(const StoredEdge& e) const { - return e.get_target() == m_target; - } - Vertex m_target; - }; - - // O(E/V) - template - void erase_from_incidence_list(EdgeList& el, vertex_descriptor v, - allow_parallel_edge_tag) - { - boost::graph_detail::erase_if(el, detail::target_is(v)); - } - // O(log(E/V)) - template - void erase_from_incidence_list(EdgeList& el, vertex_descriptor v, - disallow_parallel_edge_tag) - { - typedef typename EdgeList::value_type StoredEdge; - el.erase(StoredEdge(v)); - } - - //========================================================================= - // Out-Edge and In-Edge Iterator Implementation - - template - struct out_edge_iter - : iterator_adaptor< - out_edge_iter - , BaseIter - , EdgeDescriptor - , use_default - , EdgeDescriptor - , Difference - > - { - typedef iterator_adaptor< - out_edge_iter - , BaseIter - , EdgeDescriptor - , use_default - , EdgeDescriptor - , Difference - > super_t; - - inline out_edge_iter() { } - inline out_edge_iter(const BaseIter& i, const VertexDescriptor& src) - : super_t(i), m_src(src) { } - - inline EdgeDescriptor - dereference() const - { - return EdgeDescriptor(m_src, (*this->base()).get_target(), - &(*this->base()).get_property()); - } - VertexDescriptor m_src; - }; - - template - struct in_edge_iter - : iterator_adaptor< - in_edge_iter - , BaseIter - , EdgeDescriptor - , use_default - , EdgeDescriptor - , Difference - > - { - typedef iterator_adaptor< - in_edge_iter - , BaseIter - , EdgeDescriptor - , use_default - , EdgeDescriptor - , Difference - > super_t; - - inline in_edge_iter() { } - inline in_edge_iter(const BaseIter& i, const VertexDescriptor& src) - : super_t(i), m_src(src) { } - - inline EdgeDescriptor - dereference() const - { - return EdgeDescriptor((*this->base()).get_target(), m_src, - &this->base()->get_property()); - } - VertexDescriptor m_src; - }; - - //========================================================================= - // Undirected Edge Iterator Implementation - - template - struct undirected_edge_iter - : iterator_adaptor< - undirected_edge_iter - , EdgeIter - , EdgeDescriptor - , use_default - , EdgeDescriptor - , Difference - > - { - typedef iterator_adaptor< - undirected_edge_iter - , EdgeIter - , EdgeDescriptor - , use_default - , EdgeDescriptor - , Difference - > super_t; - - undirected_edge_iter() {} - - explicit undirected_edge_iter(EdgeIter i) - : super_t(i) {} - - inline EdgeDescriptor - dereference() const { - return EdgeDescriptor( - (*this->base()).m_source - , (*this->base()).m_target - , &this->base()->get_property()); - } - }; - - //========================================================================= - // Edge Storage Types (stored in the out-edge/in-edge lists) - - template - class stored_edge - : public boost::equality_comparable1< stored_edge, - boost::less_than_comparable1< stored_edge > > - { - public: - typedef no_property property_type; - inline stored_edge() { } - inline stored_edge(Vertex target, const no_property& = no_property()) - : m_target(target) { } - // Need to write this explicitly so stored_edge_property can - // invoke Base::operator= (at least, for SGI MIPSPro compiler) - inline stored_edge& operator=(const stored_edge& x) { - m_target = x.m_target; - return *this; - } - inline Vertex& get_target() const { return m_target; } - inline const no_property& get_property() const { return s_prop; } - inline bool operator==(const stored_edge& x) const - { return m_target == x.get_target(); } - inline bool operator<(const stored_edge& x) const - { return m_target < x.get_target(); } - //protected: need to add hash<> as a friend - static no_property s_prop; - // Sometimes target not used as key in the set, and in that case - // it is ok to change the target. - mutable Vertex m_target; - }; - template - no_property stored_edge::s_prop; - -#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) - template - class stored_edge_property : public stored_edge { - typedef stored_edge_property self; - typedef stored_edge Base; - public: - typedef Property property_type; - inline stored_edge_property() { } - inline stored_edge_property(Vertex target, - const Property& p = Property()) - : stored_edge(target), m_property(new Property(p)) { } - stored_edge_property(const self& x) - : Base(x), m_property(const_cast(x).m_property) { } - self& operator=(const self& x) { - Base::operator=(x); - m_property = const_cast(x).m_property; - return *this; - } - inline Property& get_property() { return *m_property; } - inline const Property& get_property() const { return *m_property; } - protected: - // Holding the property by-value causes edge-descriptor - // invalidation for add_edge() with EdgeList=vecS. Instead we - // hold a pointer to the property. std::unique_ptr is not - // a perfect fit for the job, but it is darn close. - std::unique_ptr m_property; - }; -#else - template - class stored_edge_property : public stored_edge { - typedef stored_edge_property self; - typedef stored_edge Base; - public: - typedef Property property_type; - inline stored_edge_property() { } - inline stored_edge_property(Vertex target, - const Property& p = Property()) - : stored_edge(target), m_property(new Property(p)) { } -#if defined(BOOST_MSVC) || (defined(BOOST_GCC) && (BOOST_GCC / 100) < 406) - stored_edge_property(self&& x) : Base(static_cast< Base const& >(x)) { - m_property.swap(x.m_property); - } - stored_edge_property(self const& x) : Base(static_cast< Base const& >(x)) { - m_property.swap(const_cast(x).m_property); - } - self& operator=(self&& x) { - Base::operator=(static_cast< Base const& >(x)); - m_property = std::move(x.m_property); - return *this; - } - self& operator=(self const& x) { - Base::operator=(static_cast< Base const& >(x)); - m_property = std::move(const_cast(x).m_property); - return *this; - } -#else - stored_edge_property(self&& x) = default; - self& operator=(self&& x) = default; -#endif - inline Property& get_property() { return *m_property; } - inline const Property& get_property() const { return *m_property; } - protected: - std::unique_ptr m_property; - }; -#endif - - - template - class stored_edge_iter - : public stored_edge - { - public: - typedef Property property_type; - inline stored_edge_iter() { } - inline stored_edge_iter(Vertex v) - : stored_edge(v) { } - inline stored_edge_iter(Vertex v, Iter i, void* = 0) - : stored_edge(v), m_iter(i) { } - inline Property& get_property() { return m_iter->get_property(); } - inline const Property& get_property() const { - return m_iter->get_property(); - } - inline Iter get_iter() const { return m_iter; } - protected: - Iter m_iter; - }; - - // For when the EdgeList is a std::vector. - // Want to make the iterator stable, so use an offset - // instead of an iterator into a std::vector - template - class stored_ra_edge_iter - : public stored_edge - { - typedef typename EdgeVec::iterator Iter; - public: - typedef Property property_type; - inline stored_ra_edge_iter() { } - inline explicit stored_ra_edge_iter(Vertex v) // Only used for comparisons - : stored_edge(v), m_i(0), m_vec(0){ } - inline stored_ra_edge_iter(Vertex v, Iter i, EdgeVec* edge_vec) - : stored_edge(v), m_i(i - edge_vec->begin()), m_vec(edge_vec){ } - inline Property& get_property() { BOOST_ASSERT ((m_vec != 0)); return (*m_vec)[m_i].get_property(); } - inline const Property& get_property() const { - BOOST_ASSERT ((m_vec != 0)); - return (*m_vec)[m_i].get_property(); - } - inline Iter get_iter() const { BOOST_ASSERT ((m_vec != 0)); return m_vec->begin() + m_i; } - protected: - std::size_t m_i; - EdgeVec* m_vec; - }; - - } // namespace detail - - template - const typename property_value::type& - get(Tag property_tag, - const detail::stored_edge_property& e) - { - return get_property_value(e.get_property(), property_tag); - } - - template - const typename property_value::type& - get(Tag property_tag, - const detail::stored_edge_iter& e) - { - return get_property_value(e.get_property(), property_tag); - } - - template - const typename property_value::type& - get(Tag property_tag, - const detail::stored_ra_edge_iter& e) - { - return get_property_value(e.get_property(), property_tag); - } - - //========================================================================= - // Directed Edges Helper Class - - namespace detail { - - // O(E/V) - template - inline void - remove_directed_edge_dispatch(edge_descriptor, EdgeList& el, - StoredProperty& p) - { - for (typename EdgeList::iterator i = el.begin(); - i != el.end(); ++i) - if (&(*i).get_property() == &p) { - el.erase(i); - return; - } - } - - template - inline void - remove_directed_edge_if_dispatch(incidence_iterator first, - incidence_iterator last, - EdgeList& el, Predicate pred, - boost::allow_parallel_edge_tag) - { - // remove_if - while (first != last && !pred(*first)) - ++first; - incidence_iterator i = first; - if (first != last) - for (++i; i != last; ++i) - if (!pred(*i)) { - *first.base() = BOOST_GRAPH_MOVE_IF_POSSIBLE(*i.base()); - ++first; - } - el.erase(first.base(), el.end()); - } - template - inline void - remove_directed_edge_if_dispatch(incidence_iterator first, - incidence_iterator last, - EdgeList& el, - Predicate pred, - boost::disallow_parallel_edge_tag) - { - for (incidence_iterator next = first; - first != last; first = next) { - ++next; - if (pred(*first)) - el.erase( first.base() ); - } - } - - template - inline void - undirected_remove_out_edge_if_dispatch(Graph& g, - incidence_iterator first, - incidence_iterator last, - EdgeList& el, Predicate pred, - boost::allow_parallel_edge_tag) - { - typedef typename Graph::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - // remove_if - while (first != last && !pred(*first)) - ++first; - incidence_iterator i = first; - bool self_loop_removed = false; - if (first != last) - for (; i != last; ++i) { - if (self_loop_removed) { - /* With self loops, the descriptor will show up - * twice. The first time it will be removed, and now it - * will be skipped. - */ - self_loop_removed = false; - } - else if (!pred(*i)) { - *first.base() = BOOST_GRAPH_MOVE_IF_POSSIBLE(*i.base()); - ++first; - } else { - if (source(*i, g) == target(*i, g)) self_loop_removed = true; - else { - // Remove the edge from the target - detail::remove_directed_edge_dispatch - (*i, - g.out_edge_list(target(*i, g)), - *(PropT*)(*i).get_property()); - } - - // Erase the edge property - g.m_edges.erase( (*i.base()).get_iter() ); - } - } - el.erase(first.base(), el.end()); - } - template - inline void - undirected_remove_out_edge_if_dispatch(Graph& g, - incidence_iterator first, - incidence_iterator last, - EdgeList& el, - Predicate pred, - boost::disallow_parallel_edge_tag) - { - typedef typename Graph::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - for (incidence_iterator next = first; - first != last; first = next) { - ++next; - if (pred(*first)) { - if (source(*first, g) != target(*first, g)) { - // Remove the edge from the target - detail::remove_directed_edge_dispatch - (*first, - g.out_edge_list(target(*first, g)), - *(PropT*)(*first).get_property()); - } - - // Erase the edge property - g.m_edges.erase( (*first.base()).get_iter() ); - - // Erase the edge in the source - el.erase( first.base() ); - } - } - } - - // O(E/V) - template - inline void - remove_directed_edge_dispatch(edge_descriptor e, EdgeList& el, - no_property&) - { - for (typename EdgeList::iterator i = el.begin(); - i != el.end(); ++i) - if ((*i).get_target() == e.m_target) { - el.erase(i); - return; - } - } - - } // namespace detail - - template - struct directed_edges_helper { - - // Placement of these overloaded remove_edge() functions - // inside the class avoids a VC++ bug. - - // O(E/V) - inline void - remove_edge(typename Config::edge_descriptor e) - { - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(*this); - typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); - typedef typename Config::OutEdgeList::value_type::property_type PType; - detail::remove_directed_edge_dispatch(e, el, - *(PType*)e.get_property()); - } - - // O(1) - inline void - remove_edge(typename Config::out_edge_iterator iter) - { - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(*this); - typename Config::edge_descriptor e = *iter; - typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); - el.erase(iter.base()); - } - - }; - - // O(1) - template - inline std::pair - edges(const directed_edges_helper& g_) - { - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_iterator edge_iterator; - const graph_type& cg = static_cast(g_); - graph_type& g = const_cast(cg); - return std::make_pair( edge_iterator(g.vertex_set().begin(), - g.vertex_set().begin(), - g.vertex_set().end(), g), - edge_iterator(g.vertex_set().begin(), - g.vertex_set().end(), - g.vertex_set().end(), g) ); - } - - //========================================================================= - // Directed Graph Helper Class - - struct adj_list_dir_traversal_tag : - public virtual vertex_list_graph_tag, - public virtual incidence_graph_tag, - public virtual adjacency_graph_tag, - public virtual edge_list_graph_tag { }; - - template - struct directed_graph_helper - : public directed_edges_helper { - typedef typename Config::edge_descriptor edge_descriptor; - typedef adj_list_dir_traversal_tag traversal_category; - }; - - // O(E/V) - template - inline void - remove_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - directed_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_parallel_category Cat; - graph_type& g = static_cast(g_); - detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat()); - } - - template - inline void - remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, - directed_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - typename Config::out_edge_iterator first, last; - boost::tie(first, last) = out_edges(u, g); - typedef typename Config::edge_parallel_category edge_parallel_category; - detail::remove_directed_edge_if_dispatch - (first, last, g.out_edge_list(u), pred, edge_parallel_category()); - } - - template - inline void - remove_edge_if(Predicate pred, directed_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - - typename Config::vertex_iterator vi, vi_end; - for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) - remove_out_edge_if(*vi, pred, g); - } - - template - inline void - remove_edge(EdgeOrIter e_or_iter, directed_graph_helper& g_) - { - g_.remove_edge(e_or_iter); - } - - // O(V + E) for allow_parallel_edges - // O(V * log(E/V)) for disallow_parallel_edges - template - inline void - clear_vertex(typename Config::vertex_descriptor u, - directed_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_parallel_category Cat; - graph_type& g = static_cast(g_); - typename Config::vertex_iterator vi, viend; - for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) - detail::erase_from_incidence_list(g.out_edge_list(*vi), u, Cat()); - g.out_edge_list(u).clear(); - // clear() should be a req of Sequence and AssociativeContainer, - // or maybe just Container - } - - template - inline void - clear_out_edges(typename Config::vertex_descriptor u, - directed_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - g.out_edge_list(u).clear(); - // clear() should be a req of Sequence and AssociativeContainer, - // or maybe just Container - } - - // O(V), could do better... - template - inline typename Config::edges_size_type - num_edges(const directed_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - const graph_type& g = static_cast(g_); - typename Config::edges_size_type num_e = 0; - typename Config::vertex_iterator vi, vi_end; - for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) - num_e += out_degree(*vi, g); - return num_e; - } - // O(1) for allow_parallel_edge_tag - // O(log(E/V)) for disallow_parallel_edge_tag - template - inline std::pair::edge_descriptor, bool> - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - const typename Config::edge_property_type& p, - directed_graph_helper& g_) - { - typedef typename Config::edge_descriptor edge_descriptor; - typedef typename Config::graph_type graph_type; - typedef typename Config::StoredEdge StoredEdge; - graph_type& g = static_cast(g_); - typename Config::OutEdgeList::iterator i; - bool inserted; - boost::tie(i, inserted) = boost::graph_detail::push(g.out_edge_list(u), - StoredEdge(v, p)); - return std::make_pair(edge_descriptor(u, v, &(*i).get_property()), - inserted); - } - // Did not use default argument here because that - // causes Visual C++ to get confused. - template - inline std::pair - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - directed_graph_helper& g_) - { - typename Config::edge_property_type p; - return add_edge(u, v, p, g_); - } - //========================================================================= - // Undirected Graph Helper Class - - template - struct undirected_graph_helper; - - struct undir_adj_list_traversal_tag : - public virtual vertex_list_graph_tag, - public virtual incidence_graph_tag, - public virtual adjacency_graph_tag, - public virtual edge_list_graph_tag, - public virtual bidirectional_graph_tag { }; - - namespace detail { - - // using class with specialization for dispatch is a VC++ workaround. - template - struct remove_undirected_edge_dispatch { - - // O(E/V) - template - static void - apply(edge_descriptor e, - undirected_graph_helper& g_, - StoredProperty& p) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - - typename Config::OutEdgeList& out_el = g.out_edge_list(source(e, g)); - typename Config::OutEdgeList::iterator out_i = out_el.begin(); - typename Config::EdgeIter edge_iter_to_erase; - for (; out_i != out_el.end(); ++out_i) - if (&(*out_i).get_property() == &p) { - edge_iter_to_erase = (*out_i).get_iter(); - out_el.erase(out_i); - break; - } - typename Config::OutEdgeList& in_el = g.out_edge_list(target(e, g)); - typename Config::OutEdgeList::iterator in_i = in_el.begin(); - for (; in_i != in_el.end(); ++in_i) - if (&(*in_i).get_property() == &p) { - in_el.erase(in_i); - break; - } - g.m_edges.erase(edge_iter_to_erase); - } - }; - - template <> - struct remove_undirected_edge_dispatch { - // O(E/V) - template - static void - apply(edge_descriptor e, - undirected_graph_helper& g_, - no_property&) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - no_property* p = (no_property*)e.get_property(); - typename Config::OutEdgeList& out_el = g.out_edge_list(source(e, g)); - typename Config::OutEdgeList::iterator out_i = out_el.begin(); - typename Config::EdgeIter edge_iter_to_erase; - for (; out_i != out_el.end(); ++out_i) - if (&(*out_i).get_property() == p) { - edge_iter_to_erase = (*out_i).get_iter(); - out_el.erase(out_i); - break; - } - typename Config::OutEdgeList& in_el = g.out_edge_list(target(e, g)); - typename Config::OutEdgeList::iterator in_i = in_el.begin(); - for (; in_i != in_el.end(); ++in_i) - if (&(*in_i).get_property() == p) { - in_el.erase(in_i); - break; - } - g.m_edges.erase(edge_iter_to_erase); - } - }; - - // O(E/V) - template - inline void - remove_edge_and_property(Graph& g, EdgeList& el, Vertex v, - boost::allow_parallel_edge_tag cat) - { - typedef typename Graph::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typename EdgeList::iterator i = el.begin(), end = el.end(); - for (; i != end; ++i) { - if ((*i).get_target() == v) { - // NOTE: Wihtout this skip, this loop will double-delete properties - // of loop edges. This solution is based on the observation that - // the incidence edges of a vertex with a loop are adjacent in the - // out edge list. This *may* actually hold for multisets also. - bool skip = (boost::next(i) != end && i->get_iter() == boost::next(i)->get_iter()); - g.m_edges.erase((*i).get_iter()); - if (skip) ++i; - } - } - detail::erase_from_incidence_list(el, v, cat); - } - // O(log(E/V)) - template - inline void - remove_edge_and_property(Graph& g, EdgeList& el, Vertex v, - boost::disallow_parallel_edge_tag) - { - typedef typename Graph::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename EdgeList::value_type StoredEdge; - typename EdgeList::iterator i = el.find(StoredEdge(v)), end = el.end(); - if (i != end) { - g.m_edges.erase((*i).get_iter()); - el.erase(i); - } - } - - } // namespace detail - - template - struct list_edge // short name due to VC++ truncation and linker problems - : public boost::detail::edge_base - { - typedef EdgeProperty property_type; - typedef boost::detail::edge_base Base; - list_edge(Vertex u, Vertex v, const EdgeProperty& p = EdgeProperty()) - : Base(u, v), m_property(p) { } - EdgeProperty& get_property() { return m_property; } - const EdgeProperty& get_property() const { return m_property; } - // the following methods should never be used, but are needed - // to make SGI MIPSpro C++ happy - list_edge() { } - bool operator==(const list_edge&) const { return false; } - bool operator<(const list_edge&) const { return false; } - EdgeProperty m_property; - }; - - template - struct undirected_graph_helper { - - typedef undir_adj_list_traversal_tag traversal_category; - - // Placement of these overloaded remove_edge() functions - // inside the class avoids a VC++ bug. - - // O(E/V) - inline void - remove_edge(typename Config::edge_descriptor e) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::OutEdgeList::value_type::property_type PType; - detail::remove_undirected_edge_dispatch::apply - (e, *this, *(PType*)e.get_property()); - } - // O(E/V) - inline void - remove_edge(typename Config::out_edge_iterator iter) - { - this->remove_edge(*iter); - } - }; - - // Had to make these non-members to avoid accidental instantiation - // on SGI MIPSpro C++ - template - inline typename C::InEdgeList& - in_edge_list(undirected_graph_helper&, - typename C::vertex_descriptor v) - { - typename C::stored_vertex* sv = (typename C::stored_vertex*)v; - return sv->m_out_edges; - } - template - inline const typename C::InEdgeList& - in_edge_list(const undirected_graph_helper&, - typename C::vertex_descriptor v) { - typename C::stored_vertex* sv = (typename C::stored_vertex*)v; - return sv->m_out_edges; - } - - // O(E/V) - template - inline void - remove_edge(EdgeOrIter e, undirected_graph_helper& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - g_.remove_edge(e); - } - - // O(E/V) or O(log(E/V)) - template - void - remove_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - undirected_graph_helper& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - typedef typename Config::edge_parallel_category Cat; - detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); - detail::erase_from_incidence_list(g.out_edge_list(v), u, Cat()); - } - - template - void - remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, - undirected_graph_helper& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - typedef typename Config::OutEdgeList::value_type::property_type PropT; - graph_type& g = static_cast(g_); - typename Config::out_edge_iterator first, last; - boost::tie(first, last) = out_edges(u, g); - typedef typename Config::edge_parallel_category Cat; - detail::undirected_remove_out_edge_if_dispatch - (g, first, last, g.out_edge_list(u), pred, Cat()); - } - template - void - remove_in_edge_if(typename Config::vertex_descriptor u, Predicate pred, - undirected_graph_helper& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - remove_out_edge_if(u, pred, g_); - } - - // O(E/V * E) or O(log(E/V) * E) - template - void - remove_edge_if(Predicate pred, undirected_graph_helper& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - typename Config::edge_iterator ei, ei_end, next; - boost::tie(ei, ei_end) = edges(g); - for (next = ei; ei != ei_end; ei = next) { - ++next; - if (pred(*ei)) - remove_edge(*ei, g); - } - } - - // O(1) - template - inline std::pair - edges(const undirected_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_iterator edge_iterator; - const graph_type& cg = static_cast(g_); - graph_type& g = const_cast(cg); - return std::make_pair( edge_iterator(g.m_edges.begin()), - edge_iterator(g.m_edges.end()) ); - } - // O(1) - template - inline typename Config::edges_size_type - num_edges(const undirected_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - const graph_type& g = static_cast(g_); - return g.m_edges.size(); - } - // O(E/V * E/V) - template - inline void - clear_vertex(typename Config::vertex_descriptor u, - undirected_graph_helper& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - while (true) { - typename Config::out_edge_iterator ei, ei_end; - boost::tie(ei, ei_end) = out_edges(u, g); - if (ei == ei_end) break; - remove_edge(*ei, g); - } - } - // O(1) for allow_parallel_edge_tag - // O(log(E/V)) for disallow_parallel_edge_tag - template - inline std::pair - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - const typename Config::edge_property_type& p, - undirected_graph_helper& g_) - { - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::edge_descriptor edge_descriptor; - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - - bool inserted; - typename Config::EdgeContainer::value_type e(u, v, p); - typename Config::EdgeContainer::iterator p_iter - = graph_detail::push(g.m_edges, e).first; - - typename Config::OutEdgeList::iterator i; - boost::tie(i, inserted) = boost::graph_detail::push(g.out_edge_list(u), - StoredEdge(v, p_iter, &g.m_edges)); - if (inserted) { - boost::graph_detail::push(g.out_edge_list(v), StoredEdge(u, p_iter, &g.m_edges)); - return std::make_pair(edge_descriptor(u, v, &p_iter->get_property()), - true); - } else { - g.m_edges.erase(p_iter); - return std::make_pair - (edge_descriptor(u, v, &i->get_iter()->get_property()), false); - } - } - template - inline std::pair - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - undirected_graph_helper& g_) - { - typename Config::edge_property_type p; - return add_edge(u, v, p, g_); - } - - // O(1) - template - inline typename Config::degree_size_type - degree(typename Config::vertex_descriptor u, - const undirected_graph_helper& g_) - { - typedef typename Config::graph_type Graph; - const Graph& g = static_cast(g_); - return out_degree(u, g); - } - - template - inline std::pair - in_edges(typename Config::vertex_descriptor u, - const undirected_graph_helper& g_) - { - typedef typename Config::graph_type Graph; - const Graph& cg = static_cast(g_); - Graph& g = const_cast(cg); - typedef typename Config::in_edge_iterator in_edge_iterator; - return - std::make_pair(in_edge_iterator(g.out_edge_list(u).begin(), u), - in_edge_iterator(g.out_edge_list(u).end(), u)); - } - - template - inline typename Config::degree_size_type - in_degree(typename Config::vertex_descriptor u, - const undirected_graph_helper& g_) - { return degree(u, g_); } - - //========================================================================= - // Bidirectional Graph Helper Class - - struct bidir_adj_list_traversal_tag : - public virtual vertex_list_graph_tag, - public virtual incidence_graph_tag, - public virtual adjacency_graph_tag, - public virtual edge_list_graph_tag, - public virtual bidirectional_graph_tag { }; - - template - struct bidirectional_graph_helper - : public directed_edges_helper { - typedef bidir_adj_list_traversal_tag traversal_category; - }; - - // Had to make these non-members to avoid accidental instantiation - // on SGI MIPSpro C++ - template - inline typename C::InEdgeList& - in_edge_list(bidirectional_graph_helper&, - typename C::vertex_descriptor v) - { - typename C::stored_vertex* sv = (typename C::stored_vertex*)v; - return sv->m_in_edges; - } - template - inline const typename C::InEdgeList& - in_edge_list(const bidirectional_graph_helper&, - typename C::vertex_descriptor v) { - typename C::stored_vertex* sv = (typename C::stored_vertex*)v; - return sv->m_in_edges; - } - - template - inline void - remove_edge_if(Predicate pred, bidirectional_graph_helper& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - typename Config::edge_iterator ei, ei_end, next; - boost::tie(ei, ei_end) = edges(g); - for (next = ei; ei != ei_end; ei = next) { - ++next; - if (pred(*ei)) - remove_edge(*ei, g); - } - } - - template - inline std::pair - in_edges(typename Config::vertex_descriptor u, - const bidirectional_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - const graph_type& cg = static_cast(g_); - graph_type& g = const_cast(cg); - typedef typename Config::in_edge_iterator in_edge_iterator; - return - std::make_pair(in_edge_iterator(in_edge_list(g, u).begin(), u), - in_edge_iterator(in_edge_list(g, u).end(), u)); - } - - // O(1) - template - inline std::pair - edges(const bidirectional_graph_helper& g_) - { - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_iterator edge_iterator; - const graph_type& cg = static_cast(g_); - graph_type& g = const_cast(cg); - return std::make_pair( edge_iterator(g.m_edges.begin()), - edge_iterator(g.m_edges.end()) ); - } - - //========================================================================= - // Bidirectional Graph Helper Class (with edge properties) - - - template - struct bidirectional_graph_helper_with_property - : public bidirectional_graph_helper - { - typedef typename Config::graph_type graph_type; - typedef typename Config::out_edge_iterator out_edge_iterator; - - std::pair - get_parallel_edge_sublist(typename Config::edge_descriptor e, - const graph_type& g, - void*) - { return out_edges(source(e, g), g); } - - std::pair - get_parallel_edge_sublist(typename Config::edge_descriptor e, - const graph_type& g, - setS*) - { return edge_range(source(e, g), target(e, g), g); } - - std::pair - get_parallel_edge_sublist(typename Config::edge_descriptor e, - const graph_type& g, - multisetS*) - { return edge_range(source(e, g), target(e, g), g); } - - std::pair - get_parallel_edge_sublist(typename Config::edge_descriptor e, - const graph_type& g, - hash_setS*) - { return edge_range(source(e, g), target(e, g), g); } - - // Placement of these overloaded remove_edge() functions - // inside the class avoids a VC++ bug. - - // O(E/V) or O(log(E/V)) - void - remove_edge(typename Config::edge_descriptor e) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - graph_type& g = static_cast(*this); - - typedef typename Config::edgelist_selector OutEdgeListS; - - std::pair rng = - get_parallel_edge_sublist(e, g, (OutEdgeListS*)(0)); - rng.first = std::find(rng.first, rng.second, e); - BOOST_ASSERT(rng.first != rng.second); - remove_edge(rng.first); - } - - inline void - remove_edge(typename Config::out_edge_iterator iter) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(*this); - typename Config::edge_descriptor e = *iter; - typename Config::OutEdgeList& oel = g.out_edge_list(source(e, g)); - typename Config::InEdgeList& iel = in_edge_list(g, target(e, g)); - typedef typename Config::OutEdgeList::value_type::property_type PType; - PType& p = *(PType*)e.get_property(); - detail::remove_directed_edge_dispatch(*iter, iel, p); - g.m_edges.erase(iter.base()->get_iter()); - oel.erase(iter.base()); - } - }; - - // O(E/V) for allow_parallel_edge_tag - // O(log(E/V)) for disallow_parallel_edge_tag - template - inline void - remove_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - typedef typename Config::edge_parallel_category Cat; - detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); - detail::erase_from_incidence_list(in_edge_list(g, v), u, Cat()); - } - - // O(E/V) or O(log(E/V)) - template - inline void - remove_edge(EdgeOrIter e, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - g_.remove_edge(e); - } - - template - inline void - remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - typedef typename Config::OutEdgeList::value_type::property_type PropT; - graph_type& g = static_cast(g_); - - typedef typename Config::EdgeIter EdgeIter; - typedef std::vector Garbage; - Garbage garbage; - - // First remove the edges from the targets' in-edge lists and - // from the graph's edge set list. - typename Config::out_edge_iterator out_i, out_end; - for (boost::tie(out_i, out_end) = out_edges(u, g); out_i != out_end; ++out_i) - if (pred(*out_i)) { - detail::remove_directed_edge_dispatch - (*out_i, in_edge_list(g, target(*out_i, g)), - *(PropT*)(*out_i).get_property()); - // Put in garbage to delete later. Will need the properties - // for the remove_if of the out-edges. - garbage.push_back((*out_i.base()).get_iter()); - } - - // Now remove the edges from this out-edge list. - typename Config::out_edge_iterator first, last; - boost::tie(first, last) = out_edges(u, g); - typedef typename Config::edge_parallel_category Cat; - detail::remove_directed_edge_if_dispatch - (first, last, g.out_edge_list(u), pred, Cat()); - - // Now delete the edge properties from the g.m_edges list - for (typename Garbage::iterator i = garbage.begin(); - i != garbage.end(); ++i) - g.m_edges.erase(*i); - } - template - inline void - remove_in_edge_if(typename Config::vertex_descriptor v, Predicate pred, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - typedef typename Config::OutEdgeList::value_type::property_type PropT; - graph_type& g = static_cast(g_); - - typedef typename Config::EdgeIter EdgeIter; - typedef std::vector Garbage; - Garbage garbage; - - // First remove the edges from the sources' out-edge lists and - // from the graph's edge set list. - typename Config::in_edge_iterator in_i, in_end; - for (boost::tie(in_i, in_end) = in_edges(v, g); in_i != in_end; ++in_i) - if (pred(*in_i)) { - typename Config::vertex_descriptor u = source(*in_i, g); - detail::remove_directed_edge_dispatch - (*in_i, g.out_edge_list(u), *(PropT*)(*in_i).get_property()); - // Put in garbage to delete later. Will need the properties - // for the remove_if of the out-edges. - garbage.push_back((*in_i.base()).get_iter()); - } - // Now remove the edges from this in-edge list. - typename Config::in_edge_iterator first, last; - boost::tie(first, last) = in_edges(v, g); - typedef typename Config::edge_parallel_category Cat; - detail::remove_directed_edge_if_dispatch - (first, last, in_edge_list(g, v), pred, Cat()); - - // Now delete the edge properties from the g.m_edges list - for (typename Garbage::iterator i = garbage.begin(); - i != garbage.end(); ++i) - g.m_edges.erase(*i); - } - - // O(1) - template - inline typename Config::edges_size_type - num_edges(const bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::graph_type graph_type; - const graph_type& g = static_cast(g_); - return g.m_edges.size(); - } - // O(E/V * E/V) for allow_parallel_edge_tag - // O(E/V * log(E/V)) for disallow_parallel_edge_tag - template - inline void - clear_vertex(typename Config::vertex_descriptor u, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_parallel_category Cat; - graph_type& g = static_cast(g_); - typename Config::OutEdgeList& el = g.out_edge_list(u); - typename Config::OutEdgeList::iterator - ei = el.begin(), ei_end = el.end(); - for (; ei != ei_end; ++ei) { - detail::erase_from_incidence_list - (in_edge_list(g, (*ei).get_target()), u, Cat()); - g.m_edges.erase((*ei).get_iter()); - } - typename Config::InEdgeList& in_el = in_edge_list(g, u); - typename Config::InEdgeList::iterator - in_ei = in_el.begin(), in_ei_end = in_el.end(); - for (; in_ei != in_ei_end; ++in_ei) { - detail::erase_from_incidence_list - (g.out_edge_list((*in_ei).get_target()), u, Cat()); - g.m_edges.erase((*in_ei).get_iter()); - } - g.out_edge_list(u).clear(); - in_edge_list(g, u).clear(); - } - - template - inline void - clear_out_edges(typename Config::vertex_descriptor u, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_parallel_category Cat; - graph_type& g = static_cast(g_); - typename Config::OutEdgeList& el = g.out_edge_list(u); - typename Config::OutEdgeList::iterator - ei = el.begin(), ei_end = el.end(); - for (; ei != ei_end; ++ei) { - detail::erase_from_incidence_list - (in_edge_list(g, (*ei).get_target()), u, Cat()); - g.m_edges.erase((*ei).get_iter()); - } - g.out_edge_list(u).clear(); - } - - template - inline void - clear_in_edges(typename Config::vertex_descriptor u, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Config::graph_type graph_type; - typedef typename Config::edge_parallel_category Cat; - graph_type& g = static_cast(g_); - typename Config::InEdgeList& in_el = in_edge_list(g, u); - typename Config::InEdgeList::iterator - in_ei = in_el.begin(), in_ei_end = in_el.end(); - for (; in_ei != in_ei_end; ++in_ei) { - detail::erase_from_incidence_list - (g.out_edge_list((*in_ei).get_target()), u, Cat()); - g.m_edges.erase((*in_ei).get_iter()); - } - in_edge_list(g, u).clear(); - } - - // O(1) for allow_parallel_edge_tag - // O(log(E/V)) for disallow_parallel_edge_tag - template - inline std::pair - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - const typename Config::edge_property_type& p, - bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::graph_type graph_type; - graph_type& g = static_cast(g_); - typedef typename Config::edge_descriptor edge_descriptor; - typedef typename Config::StoredEdge StoredEdge; - bool inserted; - typename Config::EdgeContainer::value_type e(u, v, p); - typename Config::EdgeContainer::iterator p_iter - = graph_detail::push(g.m_edges, e).first; - typename Config::OutEdgeList::iterator i; - boost::tie(i, inserted) = boost::graph_detail::push(g.out_edge_list(u), - StoredEdge(v, p_iter, &g.m_edges)); - if (inserted) { - boost::graph_detail::push(in_edge_list(g, v), StoredEdge(u, p_iter, &g.m_edges)); - return std::make_pair(edge_descriptor(u, v, &p_iter->m_property), - true); - } else { - g.m_edges.erase(p_iter); - return std::make_pair(edge_descriptor(u, v, - &i->get_iter()->get_property()), - false); - } - } - - template - inline std::pair - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - bidirectional_graph_helper_with_property& g_) - { - typename Config::edge_property_type p; - return add_edge(u, v, p, g_); - } - // O(1) - template - inline typename Config::degree_size_type - degree(typename Config::vertex_descriptor u, - const bidirectional_graph_helper_with_property& g_) - { - typedef typename Config::graph_type graph_type; - const graph_type& g = static_cast(g_); - return in_degree(u, g) + out_degree(u, g); - } - - //========================================================================= - // Adjacency List Helper Class - - template - struct adj_list_helper : public Base - { - typedef typename Config::graph_type AdjList; - typedef typename Config::vertex_descriptor vertex_descriptor; - typedef typename Config::edge_descriptor edge_descriptor; - typedef typename Config::out_edge_iterator out_edge_iterator; - typedef typename Config::in_edge_iterator in_edge_iterator; - typedef typename Config::adjacency_iterator adjacency_iterator; - typedef typename Config::inv_adjacency_iterator inv_adjacency_iterator; - typedef typename Config::vertex_iterator vertex_iterator; - typedef typename Config::edge_iterator edge_iterator; - typedef typename Config::directed_category directed_category; - typedef typename Config::edge_parallel_category edge_parallel_category; - typedef typename Config::vertices_size_type vertices_size_type; - typedef typename Config::edges_size_type edges_size_type; - typedef typename Config::degree_size_type degree_size_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::vertex_property_type vertex_property_type; - typedef typename Config::edge_property_type edge_property_type; - typedef typename Config::graph_property_type graph_property_type; - - typedef typename Config::global_edgelist_selector - global_edgelist_selector; - - typedef typename lookup_one_property::type vertex_bundled; - typedef typename lookup_one_property::type edge_bundled; - typedef typename lookup_one_property::type graph_bundled; - }; - - template - inline std::pair - adjacent_vertices(typename Config::vertex_descriptor u, - const adj_list_helper& g_) - { - typedef typename Config::graph_type AdjList; - const AdjList& cg = static_cast(g_); - AdjList& g = const_cast(cg); - typedef typename Config::adjacency_iterator adjacency_iterator; - typename Config::out_edge_iterator first, last; - boost::tie(first, last) = out_edges(u, g); - return std::make_pair(adjacency_iterator(first, &g), - adjacency_iterator(last, &g)); - } - template - inline std::pair - inv_adjacent_vertices(typename Config::vertex_descriptor u, - const adj_list_helper& g_) - { - typedef typename Config::graph_type AdjList; - const AdjList& cg = static_cast(g_); - AdjList& g = const_cast(cg); - typedef typename Config::inv_adjacency_iterator inv_adjacency_iterator; - typename Config::in_edge_iterator first, last; - boost::tie(first, last) = in_edges(u, g); - return std::make_pair(inv_adjacency_iterator(first, &g), - inv_adjacency_iterator(last, &g)); - } - template - inline std::pair - out_edges(typename Config::vertex_descriptor u, - const adj_list_helper& g_) - { - typedef typename Config::graph_type AdjList; - typedef typename Config::out_edge_iterator out_edge_iterator; - const AdjList& cg = static_cast(g_); - AdjList& g = const_cast(cg); - return - std::make_pair(out_edge_iterator(g.out_edge_list(u).begin(), u), - out_edge_iterator(g.out_edge_list(u).end(), u)); - } - template - inline std::pair - vertices(const adj_list_helper& g_) - { - typedef typename Config::graph_type AdjList; - const AdjList& cg = static_cast(g_); - AdjList& g = const_cast(cg); - return std::make_pair( g.vertex_set().begin(), g.vertex_set().end() ); - } - template - inline typename Config::vertices_size_type - num_vertices(const adj_list_helper& g_) - { - typedef typename Config::graph_type AdjList; - const AdjList& g = static_cast(g_); - return g.vertex_set().size(); - } - template - inline typename Config::degree_size_type - out_degree(typename Config::vertex_descriptor u, - const adj_list_helper& g_) - { - typedef typename Config::graph_type AdjList; - const AdjList& g = static_cast(g_); - return g.out_edge_list(u).size(); - } - template - inline std::pair - edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - const adj_list_helper& g_) - { - typedef typename Config::graph_type Graph; - typedef typename Config::StoredEdge StoredEdge; - const Graph& cg = static_cast(g_); - const typename Config::OutEdgeList& el = cg.out_edge_list(u); - typename Config::OutEdgeList::const_iterator it = graph_detail:: - find(el, StoredEdge(v)); - return std::make_pair( - typename Config::edge_descriptor - (u, v, (it == el.end() ? 0 : &(*it).get_property())), - (it != el.end())); - } - - template - inline std::pair - edge_range(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - const adj_list_helper& g_) - { - typedef typename Config::graph_type Graph; - typedef typename Config::StoredEdge StoredEdge; - const Graph& cg = static_cast(g_); - Graph& g = const_cast(cg); - typedef typename Config::out_edge_iterator out_edge_iterator; - typename Config::OutEdgeList& el = g.out_edge_list(u); - typename Config::OutEdgeList::iterator first, last; - typename Config::EdgeContainer fake_edge_container; - boost::tie(first, last) = graph_detail:: - equal_range(el, StoredEdge(v)); - return std::make_pair(out_edge_iterator(first, u), - out_edge_iterator(last, u)); - } - - template - inline typename Config::degree_size_type - in_degree(typename Config::vertex_descriptor u, - const directed_edges_helper& g_) - { - typedef typename Config::graph_type Graph; - const Graph& cg = static_cast(g_); - Graph& g = const_cast(cg); - return in_edge_list(g, u).size(); - } - - namespace detail { - template - inline - typename boost::property_map::type - get_dispatch(adj_list_helper&, Property p, - boost::edge_property_tag) { - typedef typename Config::graph_type Graph; - typedef typename boost::property_map::type PA; - return PA(p); - } - template - inline - typename boost::property_map::const_type - get_dispatch(const adj_list_helper&, Property p, - boost::edge_property_tag) { - typedef typename Config::graph_type Graph; - typedef typename boost::property_map::const_type PA; - return PA(p); - } - - template - inline - typename boost::property_map::type - get_dispatch(adj_list_helper& g, Property p, - boost::vertex_property_tag) { - typedef typename Config::graph_type Graph; - typedef typename boost::property_map::type PA; - return PA(&static_cast(g), p); - } - template - inline - typename boost::property_map::const_type - get_dispatch(const adj_list_helper& g, Property p, - boost::vertex_property_tag) { - typedef typename Config::graph_type Graph; - typedef typename boost::property_map::const_type PA; - const Graph& cg = static_cast(g); - return PA(&cg, p); - } - - } // namespace detail - - // Implementation of the PropertyGraph interface - template - inline - typename boost::property_map::type - get(Property p, adj_list_helper& g) { - typedef typename detail::property_kind_from_graph, Property>::type Kind; - return detail::get_dispatch(g, p, Kind()); - } - template - inline - typename boost::property_map::const_type - get(Property p, const adj_list_helper& g) { - typedef typename detail::property_kind_from_graph, Property>::type Kind; - return detail::get_dispatch(g, p, Kind()); - } - - template - inline - typename boost::property_traits< - typename boost::property_map::type - >::reference - get(Property p, adj_list_helper& g, const Key& key) { - return get(get(p, g), key); - } - - template - inline - typename boost::property_traits< - typename boost::property_map::const_type - >::reference - get(Property p, const adj_list_helper& g, const Key& key) { - return get(get(p, g), key); - } - - template - inline void - put(Property p, adj_list_helper& g, - const Key& key, const Value& value) - { - typedef typename Config::graph_type Graph; - typedef typename boost::property_map::type Map; - Map pmap = get(p, static_cast(g)); - put(pmap, key, value); - } - - - //========================================================================= - // Generalize Adjacency List Implementation - - struct adj_list_tag { }; - - template - class adj_list_impl - : public adj_list_helper - { - typedef typename Config::OutEdgeList OutEdgeList; - typedef typename Config::InEdgeList InEdgeList; - typedef typename Config::StoredVertexList StoredVertexList; - public: - typedef typename Config::stored_vertex stored_vertex; - typedef typename Config::EdgeContainer EdgeContainer; - typedef typename Config::vertex_descriptor vertex_descriptor; - typedef typename Config::edge_descriptor edge_descriptor; - typedef typename Config::vertex_iterator vertex_iterator; - typedef typename Config::edge_iterator edge_iterator; - typedef typename Config::edge_parallel_category edge_parallel_category; - typedef typename Config::vertices_size_type vertices_size_type; - typedef typename Config::edges_size_type edges_size_type; - typedef typename Config::degree_size_type degree_size_type; - typedef typename Config::edge_property_type edge_property_type; - typedef adj_list_tag graph_tag; - - static vertex_descriptor null_vertex() - { - return 0; - } - - inline adj_list_impl() { } - - inline adj_list_impl(const adj_list_impl& x) { - copy_impl(x); - } - inline adj_list_impl& operator=(const adj_list_impl& x) { - this->clear(); - copy_impl(x); - return *this; - } - inline void clear() { - for (typename StoredVertexList::iterator i = m_vertices.begin(); - i != m_vertices.end(); ++i) - delete (stored_vertex*)*i; - m_vertices.clear(); - m_edges.clear(); - } - inline adj_list_impl(vertices_size_type num_vertices) { - for (vertices_size_type i = 0; i < num_vertices; ++i) - add_vertex(static_cast(*this)); - } - template - inline adj_list_impl(vertices_size_type num_vertices, - EdgeIterator first, EdgeIterator last) - { - vertex_descriptor* v = new vertex_descriptor[num_vertices]; - for (vertices_size_type i = 0; i < num_vertices; ++i) - v[i] = add_vertex(static_cast(*this)); - - while (first != last) { - add_edge(v[(*first).first], v[(*first).second], *this); - ++first; - } - delete [] v; - } - template - inline adj_list_impl(vertices_size_type num_vertices, - EdgeIterator first, EdgeIterator last, - EdgePropertyIterator ep_iter) - { - vertex_descriptor* v = new vertex_descriptor[num_vertices]; - for (vertices_size_type i = 0; i < num_vertices; ++i) - v[i] = add_vertex(static_cast(*this)); - - while (first != last) { - add_edge(v[(*first).first], v[(*first).second], *ep_iter, *this); - ++first; - ++ep_iter; - } - delete [] v; - } - ~adj_list_impl() { - for (typename StoredVertexList::iterator i = m_vertices.begin(); - i != m_vertices.end(); ++i) - delete (stored_vertex*)*i; - } - // protected: - inline OutEdgeList& out_edge_list(vertex_descriptor v) { - stored_vertex* sv = (stored_vertex*)v; - return sv->m_out_edges; - } - inline const OutEdgeList& out_edge_list(vertex_descriptor v) const { - stored_vertex* sv = (stored_vertex*)v; - return sv->m_out_edges; - } - inline StoredVertexList& vertex_set() { return m_vertices; } - inline const StoredVertexList& vertex_set() const { return m_vertices; } - - inline void copy_impl(const adj_list_impl& x_) - { - const Derived& x = static_cast(x_); - - // Would be better to have a constant time way to get from - // vertices in x to the corresponding vertices in *this. - std::map vertex_map; - - // Copy the stored vertex objects by adding each vertex - // and copying its property object. - vertex_iterator vi, vi_end; - for (boost::tie(vi, vi_end) = vertices(x); vi != vi_end; ++vi) { - stored_vertex* v = (stored_vertex*)add_vertex(*this); - v->m_property = ((stored_vertex*)*vi)->m_property; - vertex_map[(stored_vertex*)*vi] = v; - } - // Copy the edges by adding each edge and copying its - // property object. - edge_iterator ei, ei_end; - for (boost::tie(ei, ei_end) = edges(x); ei != ei_end; ++ei) { - edge_descriptor e; - bool inserted; - vertex_descriptor s = source(*ei,x), t = target(*ei,x); - boost::tie(e, inserted) = add_edge(vertex_map[(stored_vertex*)s], - vertex_map[(stored_vertex*)t], *this); - *((edge_property_type*)e.m_eproperty) - = *((edge_property_type*)(*ei).m_eproperty); - } - } - - - typename Config::EdgeContainer m_edges; - StoredVertexList m_vertices; - }; - - // O(1) - template - inline typename Config::vertex_descriptor - add_vertex(adj_list_impl& g_) - { - Derived& g = static_cast(g_); - typedef typename Config::stored_vertex stored_vertex; - stored_vertex* v = new stored_vertex; - typename Config::StoredVertexList::iterator pos; - bool inserted; - boost::tie(pos,inserted) = boost::graph_detail::push(g.m_vertices, v); - v->m_position = pos; - g.added_vertex(v); - return v; - } - // O(1) - template - inline typename Config::vertex_descriptor - add_vertex(const typename Config::vertex_property_type& p, - adj_list_impl& g_) - { - typedef typename Config::vertex_descriptor vertex_descriptor; - Derived& g = static_cast(g_); - if (optional v - = g.vertex_by_property(get_property_value(p, vertex_bundle))) - return *v; - - typedef typename Config::stored_vertex stored_vertex; - stored_vertex* v = new stored_vertex(p); - typename Config::StoredVertexList::iterator pos; - bool inserted; - boost::tie(pos,inserted) = boost::graph_detail::push(g.m_vertices, v); - v->m_position = pos; - g.added_vertex(v); - return v; - } - // O(1) - template - inline void remove_vertex(typename Config::vertex_descriptor u, - adj_list_impl& g_) - { - typedef typename Config::stored_vertex stored_vertex; - Derived& g = static_cast(g_); - g.removing_vertex(u, boost::graph_detail::iterator_stability(g_.m_vertices)); - stored_vertex* su = (stored_vertex*)u; - g.m_vertices.erase(su->m_position); - delete su; - } - // O(V) - template - inline typename Config::vertex_descriptor - vertex(typename Config::vertices_size_type n, - const adj_list_impl& g_) - { - const Derived& g = static_cast(g_); - typename Config::vertex_iterator i = vertices(g).first; - while (n--) ++i; // std::advance(i, n); (not VC++ portable) - return *i; - } - - //========================================================================= - // Vector-Backbone Adjacency List Implementation - - namespace detail { - - template - inline void - remove_vertex_dispatch(Graph& g, vertex_descriptor u, - boost::directed_tag) - { - typedef typename Graph::edge_parallel_category edge_parallel_category; - g.m_vertices.erase(g.m_vertices.begin() + u); - vertex_descriptor V = num_vertices(g); - if (u != V) { - for (vertex_descriptor v = 0; v < V; ++v) - reindex_edge_list(g.out_edge_list(v), u, edge_parallel_category()); - } - } - - template - inline void - remove_vertex_dispatch(Graph& g, vertex_descriptor u, - boost::undirected_tag) - { - typedef typename Graph::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Graph::edge_parallel_category edge_parallel_category; - g.m_vertices.erase(g.m_vertices.begin() + u); - vertex_descriptor V = num_vertices(g); - for (vertex_descriptor v = 0; v < V; ++v) - reindex_edge_list(g.out_edge_list(v), u, - edge_parallel_category()); - typedef typename Graph::EdgeContainer Container; - typedef typename Container::iterator Iter; - Iter ei = g.m_edges.begin(), ei_end = g.m_edges.end(); - for (; ei != ei_end; ++ei) { - if (ei->m_source > u) - --ei->m_source; - if (ei->m_target > u) - --ei->m_target; - } - } - template - inline void - remove_vertex_dispatch(Graph& g, vertex_descriptor u, - boost::bidirectional_tag) - { - typedef typename Graph::global_edgelist_selector EdgeListS; - BOOST_STATIC_ASSERT((!is_same::value)); - - typedef typename Graph::edge_parallel_category edge_parallel_category; - g.m_vertices.erase(g.m_vertices.begin() + u); - vertex_descriptor V = num_vertices(g); - vertex_descriptor v; - if (u != V) { - for (v = 0; v < V; ++v) - reindex_edge_list(g.out_edge_list(v), u, - edge_parallel_category()); - for (v = 0; v < V; ++v) - reindex_edge_list(in_edge_list(g, v), u, - edge_parallel_category()); - - typedef typename Graph::EdgeContainer Container; - typedef typename Container::iterator Iter; - Iter ei = g.m_edges.begin(), ei_end = g.m_edges.end(); - for (; ei != ei_end; ++ei) { - if (ei->m_source > u) - --ei->m_source; - if (ei->m_target > u) - --ei->m_target; - } - } - } - - template - inline void - reindex_edge_list(EdgeList& el, vertex_descriptor u, - boost::allow_parallel_edge_tag) - { - typename EdgeList::iterator ei = el.begin(), e_end = el.end(); - for (; ei != e_end; ++ei) - if ((*ei).get_target() > u) - --(*ei).get_target(); - } - template - inline void - reindex_edge_list(EdgeList& el, vertex_descriptor u, - boost::disallow_parallel_edge_tag) - { - typename EdgeList::iterator ei = el.begin(), e_end = el.end(); - while (ei != e_end) { - typename EdgeList::value_type ce = *ei; - ++ei; - if (ce.get_target() > u) { - el.erase(ce); - --ce.get_target(); - el.insert(ce); - } - } - } - } // namespace detail - - struct vec_adj_list_tag { }; - - template - class vec_adj_list_impl - : public adj_list_helper - { - typedef typename Config::OutEdgeList OutEdgeList; - typedef typename Config::InEdgeList InEdgeList; - typedef typename Config::StoredVertexList StoredVertexList; - public: - typedef typename Config::vertex_descriptor vertex_descriptor; - typedef typename Config::edge_descriptor edge_descriptor; - typedef typename Config::out_edge_iterator out_edge_iterator; - typedef typename Config::edge_iterator edge_iterator; - typedef typename Config::directed_category directed_category; - typedef typename Config::vertices_size_type vertices_size_type; - typedef typename Config::edges_size_type edges_size_type; - typedef typename Config::degree_size_type degree_size_type; - typedef typename Config::StoredEdge StoredEdge; - typedef typename Config::stored_vertex stored_vertex; - typedef typename Config::EdgeContainer EdgeContainer; - typedef typename Config::edge_property_type edge_property_type; - typedef vec_adj_list_tag graph_tag; - - static vertex_descriptor null_vertex() - { - return (std::numeric_limits::max)(); - } - - inline vec_adj_list_impl() { } - - inline vec_adj_list_impl(const vec_adj_list_impl& x) { - copy_impl(x); - } - inline vec_adj_list_impl& operator=(const vec_adj_list_impl& x) { - this->clear(); - copy_impl(x); - return *this; - } - inline void clear() { - m_vertices.clear(); - m_edges.clear(); - } - - inline vec_adj_list_impl(vertices_size_type _num_vertices) - : m_vertices(_num_vertices) { } - - template - inline vec_adj_list_impl(vertices_size_type num_vertices, - EdgeIterator first, EdgeIterator last) - : m_vertices(num_vertices) - { - while (first != last) { - add_edge((*first).first, (*first).second, - static_cast(*this)); - ++first; - } - } - template - inline vec_adj_list_impl(vertices_size_type num_vertices, - EdgeIterator first, EdgeIterator last, - EdgePropertyIterator ep_iter) - : m_vertices(num_vertices) - { - while (first != last) { - add_edge((*first).first, (*first).second, *ep_iter, - static_cast(*this)); - ++first; - ++ep_iter; - } - } - - // protected: - inline boost::integer_range vertex_set() const { - return boost::integer_range(0, m_vertices.size()); - } - inline OutEdgeList& out_edge_list(vertex_descriptor v) { - return m_vertices[v].m_out_edges; - } - inline const OutEdgeList& out_edge_list(vertex_descriptor v) const { - return m_vertices[v].m_out_edges; - } - inline void copy_impl(const vec_adj_list_impl& x_) - { - const Graph& x = static_cast(x_); - // Copy the stored vertex objects by adding each vertex - // and copying its property object. - for (vertices_size_type i = 0; i < num_vertices(x); ++i) { - vertex_descriptor v = add_vertex(*this); - m_vertices[v].m_property = x.m_vertices[i].m_property; - } - // Copy the edges by adding each edge and copying its - // property object. - edge_iterator ei, ei_end; - for (boost::tie(ei, ei_end) = edges(x); ei != ei_end; ++ei) { - edge_descriptor e; - bool inserted; - boost::tie(e, inserted) = add_edge(source(*ei,x), target(*ei,x) , *this); - *((edge_property_type*)e.m_eproperty) - = *((edge_property_type*)(*ei).m_eproperty); - } - } - typename Config::EdgeContainer m_edges; - StoredVertexList m_vertices; - }; - // Had to make these non-members to avoid accidental instantiation - // on SGI MIPSpro C++ - template - inline typename C::InEdgeList& - in_edge_list(vec_adj_list_impl& g, - typename C::vertex_descriptor v) { - return g.m_vertices[v].m_in_edges; - } - template - inline const typename C::InEdgeList& - in_edge_list(const vec_adj_list_impl& g, - typename C::vertex_descriptor v) { - return g.m_vertices[v].m_in_edges; - } - - // O(1) - template - inline typename Config::vertex_descriptor - add_vertex(vec_adj_list_impl& g_) { - Graph& g = static_cast(g_); - g.m_vertices.resize(g.m_vertices.size() + 1); - g.added_vertex(g.m_vertices.size() - 1); - return g.m_vertices.size() - 1; - } - - template - inline typename Config::vertex_descriptor - add_vertex(const typename Config::vertex_property_type& p, - vec_adj_list_impl& g_) { - typedef typename Config::vertex_descriptor vertex_descriptor; - Graph& g = static_cast(g_); - if (optional v - = g.vertex_by_property(get_property_value(p, vertex_bundle))) - return *v; - typedef typename Config::stored_vertex stored_vertex; - g.m_vertices.push_back(stored_vertex(p)); - g.added_vertex(g.m_vertices.size() - 1); - return g.m_vertices.size() - 1; - } - - // Here we override the directed_graph_helper add_edge() function - // so that the number of vertices is automatically changed if - // either u or v is greater than the number of vertices. - template - inline std::pair - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - const typename Config::edge_property_type& p, - vec_adj_list_impl& g_) - { - BOOST_USING_STD_MAX(); - typename Config::vertex_descriptor x = max BOOST_PREVENT_MACRO_SUBSTITUTION(u, v); - if (x >= num_vertices(g_)) - g_.m_vertices.resize(x + 1); - adj_list_helper& g = g_; - return add_edge(u, v, p, g); - } - template - inline std::pair - add_edge(typename Config::vertex_descriptor u, - typename Config::vertex_descriptor v, - vec_adj_list_impl& g_) - { - typename Config::edge_property_type p; - return add_edge(u, v, p, g_); - } - - - // O(V + E) - template - inline void remove_vertex(typename Config::vertex_descriptor v, - vec_adj_list_impl& g_) - { - typedef typename Config::directed_category Cat; - Graph& g = static_cast(g_); - g.removing_vertex(v, boost::graph_detail::iterator_stability(g_.m_vertices)); - detail::remove_vertex_dispatch(g, v, Cat()); - } - // O(1) - template - inline typename Config::vertex_descriptor - vertex(typename Config::vertices_size_type n, - const vec_adj_list_impl&) - { - return n; - } - - - namespace detail { - - //========================================================================= - // Adjacency List Generator - - template - struct adj_list_gen - { - typedef typename detail::is_random_access::type - is_rand_access; - typedef typename has_property::type has_edge_property; - typedef typename DirectedS::is_directed_t DirectedT; - typedef typename DirectedS::is_bidir_t BidirectionalT; - - struct config - { - typedef OutEdgeListS edgelist_selector; - typedef EdgeListS global_edgelist_selector; - - typedef Graph graph_type; - typedef EdgeProperty edge_property_type; - typedef VertexProperty vertex_property_type; - typedef GraphProperty graph_property_type; - typedef std::size_t vertices_size_type; - - typedef adjacency_list_traits - Traits; - - typedef typename Traits::directed_category directed_category; - typedef typename Traits::edge_parallel_category edge_parallel_category; - typedef typename Traits::vertex_descriptor vertex_descriptor; - typedef typename Traits::edge_descriptor edge_descriptor; - - typedef void* vertex_ptr; - - // need to reorganize this to avoid instantiating stuff - // that doesn't get used -JGS - - // VertexList and vertex_iterator - typedef typename container_gen::type SeqVertexList; - typedef boost::integer_range RandVertexList; - typedef typename mpl::if_::type VertexList; - - typedef typename VertexList::iterator vertex_iterator; - - // EdgeContainer and StoredEdge - - typedef typename container_gen >::type EdgeContainer; - - typedef typename mpl::and_::type >::type on_edge_storage; - - typedef typename mpl::if_::type edges_size_type; - - typedef typename EdgeContainer::iterator EdgeIter; - - typedef typename detail::is_random_access::type is_edge_ra; - - typedef typename mpl::if_, - typename mpl::if_, - stored_edge_iter - >::type - >::type StoredEdge; - - // Adjacency Types - - typedef typename container_gen::type - OutEdgeList; - typedef typename OutEdgeList::size_type degree_size_type; - typedef typename OutEdgeList::iterator OutEdgeIter; - - typedef boost::detail::iterator_traits OutEdgeIterTraits; - typedef typename OutEdgeIterTraits::iterator_category OutEdgeIterCat; - typedef typename OutEdgeIterTraits::difference_type OutEdgeIterDiff; - - typedef out_edge_iter< - OutEdgeIter, vertex_descriptor, edge_descriptor, OutEdgeIterDiff - > out_edge_iterator; - - typedef typename adjacency_iterator_generator::type adjacency_iterator; - - typedef OutEdgeList InEdgeList; - typedef OutEdgeIter InEdgeIter; - typedef OutEdgeIterCat InEdgeIterCat; - typedef OutEdgeIterDiff InEdgeIterDiff; - - typedef in_edge_iter< - InEdgeIter, vertex_descriptor, edge_descriptor, InEdgeIterDiff - > in_edge_iterator; - - typedef typename inv_adjacency_iterator_generator::type inv_adjacency_iterator; - - // Edge Iterator - - typedef boost::detail::iterator_traits EdgeIterTraits; - typedef typename EdgeIterTraits::iterator_category EdgeIterCat; - typedef typename EdgeIterTraits::difference_type EdgeIterDiff; - - typedef undirected_edge_iter< - EdgeIter - , edge_descriptor - , EdgeIterDiff - > UndirectedEdgeIter; // also used for bidirectional - - typedef adj_list_edge_iterator DirectedEdgeIter; - - typedef typename mpl::if_::type edge_iterator; - - // stored_vertex and StoredVertexList - typedef typename container_gen::type - SeqStoredVertexList; - struct seq_stored_vertex { - seq_stored_vertex() { } - seq_stored_vertex(const VertexProperty& p) : m_property(p) { } - OutEdgeList m_out_edges; - VertexProperty m_property; - typename SeqStoredVertexList::iterator m_position; - }; - struct bidir_seq_stored_vertex { - bidir_seq_stored_vertex() { } - bidir_seq_stored_vertex(const VertexProperty& p) : m_property(p) { } - OutEdgeList m_out_edges; - InEdgeList m_in_edges; - VertexProperty m_property; - typename SeqStoredVertexList::iterator m_position; - }; - struct rand_stored_vertex { - rand_stored_vertex() { } - rand_stored_vertex(const VertexProperty& p) : m_property(p) { } - OutEdgeList m_out_edges; - VertexProperty m_property; - }; - struct bidir_rand_stored_vertex { - bidir_rand_stored_vertex() { } - bidir_rand_stored_vertex(const VertexProperty& p) : m_property(p) { } - OutEdgeList m_out_edges; - InEdgeList m_in_edges; - VertexProperty m_property; - }; - typedef typename mpl::if_::type, - typename mpl::if_::type - >::type StoredVertex; - struct stored_vertex : public StoredVertex { - stored_vertex() { } - stored_vertex(const VertexProperty& p) : StoredVertex(p) { } - }; - - typedef typename container_gen::type - RandStoredVertexList; - typedef typename mpl::if_< is_rand_access, - RandStoredVertexList, SeqStoredVertexList>::type StoredVertexList; - }; // end of config - - - typedef typename mpl::if_, - typename mpl::if_, - undirected_graph_helper - >::type - >::type DirectedHelper; - - typedef typename mpl::if_, - adj_list_impl - >::type type; - - }; - - } // namespace detail - - //========================================================================= - // Vertex Property Maps - - template - struct adj_list_vertex_property_map - : public boost::put_get_helper< - Reference, - adj_list_vertex_property_map - > - { - typedef typename Graph::stored_vertex StoredVertex; - typedef ValueType value_type; - typedef Reference reference; - typedef typename Graph::vertex_descriptor key_type; - typedef boost::lvalue_property_map_tag category; - inline adj_list_vertex_property_map(const Graph* = 0, Tag tag = Tag()): m_tag(tag) { } - inline Reference operator[](key_type v) const { - StoredVertex* sv = (StoredVertex*)v; - return get_property_value(sv->m_property, m_tag); - } - inline Reference operator()(key_type v) const { - return this->operator[](v); - } - Tag m_tag; - }; - - template - struct adj_list_vertex_all_properties_map - : public boost::put_get_helper - > - { - typedef typename Graph::stored_vertex StoredVertex; - typedef Property value_type; - typedef PropRef reference; - typedef typename Graph::vertex_descriptor key_type; - typedef boost::lvalue_property_map_tag category; - inline adj_list_vertex_all_properties_map(const Graph* = 0, vertex_all_t = vertex_all_t()) { } - inline PropRef operator[](key_type v) const { - StoredVertex* sv = (StoredVertex*)v; - return sv->m_property; - } - inline PropRef operator()(key_type v) const { - return this->operator[](v); - } - }; - - template - struct vec_adj_list_vertex_property_map - : public boost::put_get_helper< - Reference, - vec_adj_list_vertex_property_map - > - { - typedef ValueType value_type; - typedef Reference reference; - typedef typename boost::graph_traits::vertex_descriptor key_type; - typedef boost::lvalue_property_map_tag category; - vec_adj_list_vertex_property_map(GraphPtr g = 0, Tag tag = Tag()) : m_g(g), m_tag(tag) { } - inline Reference operator[](key_type v) const { - return get_property_value(m_g->m_vertices[v].m_property, m_tag); - } - inline Reference operator()(key_type v) const { - return this->operator[](v); - } - GraphPtr m_g; - Tag m_tag; - }; - - template - struct vec_adj_list_vertex_all_properties_map - : public boost::put_get_helper - > - { - typedef Property value_type; - typedef PropertyRef reference; - typedef typename boost::graph_traits::vertex_descriptor key_type; - typedef boost::lvalue_property_map_tag category; - vec_adj_list_vertex_all_properties_map(GraphPtr g = 0, vertex_all_t = vertex_all_t()) : m_g(g) { } - inline PropertyRef operator[](key_type v) const { - return m_g->m_vertices[v].m_property; - } - inline PropertyRef operator()(key_type v) const { - return this->operator[](v); - } - GraphPtr m_g; - }; - - struct adj_list_any_vertex_pa { - template - struct bind_ { - typedef typename property_value::type value_type; - typedef value_type& reference; - typedef const value_type& const_reference; - - typedef adj_list_vertex_property_map - type; - typedef adj_list_vertex_property_map - const_type; - }; - }; - struct adj_list_all_vertex_pa { - template - struct bind_ { - typedef typename Graph::vertex_descriptor Vertex; - typedef adj_list_vertex_all_properties_map type; - typedef adj_list_vertex_all_properties_map const_type; - }; - }; - - template - struct vec_adj_list_vertex_id_map - : public boost::put_get_helper< - Vertex, vec_adj_list_vertex_id_map - > - { - typedef Vertex value_type; - typedef Vertex key_type; - typedef Vertex reference; - typedef boost::readable_property_map_tag category; - inline vec_adj_list_vertex_id_map() { } - template - inline vec_adj_list_vertex_id_map(const Graph&, vertex_index_t) { } - inline value_type operator[](key_type v) const { return v; } - inline value_type operator()(key_type v) const { return v; } - }; - - struct vec_adj_list_any_vertex_pa { - template - struct bind_ { - typedef typename property_value::type value_type; - typedef value_type& reference; - typedef const value_type& const_reference; - - typedef vec_adj_list_vertex_property_map - type; - typedef vec_adj_list_vertex_property_map - const_type; - }; - }; - struct vec_adj_list_id_vertex_pa { - template - struct bind_ { - typedef typename Graph::vertex_descriptor Vertex; - typedef vec_adj_list_vertex_id_map type; - typedef vec_adj_list_vertex_id_map const_type; - }; - }; - struct vec_adj_list_all_vertex_pa { - template - struct bind_ { - typedef typename Graph::vertex_descriptor Vertex; - typedef vec_adj_list_vertex_all_properties_map - type; - typedef vec_adj_list_vertex_all_properties_map - const_type; - }; - }; - namespace detail { - template - struct adj_list_choose_vertex_pa - : boost::mpl::if_< - boost::is_same, - adj_list_all_vertex_pa, - adj_list_any_vertex_pa>::type - ::template bind_ - {}; - - - template - struct vec_adj_list_choose_vertex_pa_helper { - typedef vec_adj_list_any_vertex_pa type; - }; - template <> - struct vec_adj_list_choose_vertex_pa_helper { - typedef vec_adj_list_id_vertex_pa type; - }; - template <> - struct vec_adj_list_choose_vertex_pa_helper { - typedef vec_adj_list_all_vertex_pa type; - }; - template - struct vec_adj_list_choose_vertex_pa - : vec_adj_list_choose_vertex_pa_helper::type::template bind_ - {}; - } // namespace detail - - //========================================================================= - // Edge Property Map - - template - struct adj_list_edge_property_map - : public put_get_helper< - Ref, - adj_list_edge_property_map - > - { - Tag tag; - explicit adj_list_edge_property_map(Tag tag = Tag()): tag(tag) {} - - typedef Value value_type; - typedef Ref reference; - typedef detail::edge_desc_impl key_type; - typedef boost::lvalue_property_map_tag category; - inline Ref operator[](key_type e) const { - Property& p = *(Property*)e.get_property(); - return get_property_value(p, tag); - } - inline Ref operator()(key_type e) const { - return this->operator[](e); - } - }; - - template - struct adj_list_edge_all_properties_map - : public put_get_helper - > - { - explicit adj_list_edge_all_properties_map(edge_all_t = edge_all_t()) {} - typedef Property value_type; - typedef PropRef reference; - typedef detail::edge_desc_impl key_type; - typedef boost::lvalue_property_map_tag category; - inline PropRef operator[](key_type e) const { - return *(PropPtr)e.get_property(); - } - inline PropRef operator()(key_type e) const { - return this->operator[](e); - } - }; - - // Edge Property Maps - - namespace detail { - struct adj_list_any_edge_pmap { - template - struct bind_ { - typedef typename property_value::type value_type; - typedef value_type& reference; - typedef const value_type& const_reference; - - typedef adj_list_edge_property_map - type; - typedef adj_list_edge_property_map - const_type; - }; - }; - struct adj_list_all_edge_pmap { - template - struct bind_ { - typedef adj_list_edge_all_properties_map - type; - typedef adj_list_edge_all_properties_map - const_type; - }; - }; - - template - struct adj_list_choose_edge_pmap_helper { - typedef adj_list_any_edge_pmap type; - }; - template <> - struct adj_list_choose_edge_pmap_helper { - typedef adj_list_all_edge_pmap type; - }; - template - struct adj_list_choose_edge_pmap - : adj_list_choose_edge_pmap_helper::type::template bind_ - {}; - struct adj_list_edge_property_selector { - template - struct bind_: adj_list_choose_edge_pmap {}; - }; - } // namespace detail - - template <> - struct edge_property_selector { - typedef detail::adj_list_edge_property_selector type; - }; - template <> - struct edge_property_selector { - typedef detail::adj_list_edge_property_selector type; - }; - - // Vertex Property Maps - - struct adj_list_vertex_property_selector { - template - struct bind_ - : detail::adj_list_choose_vertex_pa - {}; - }; - template <> - struct vertex_property_selector { - typedef adj_list_vertex_property_selector type; - }; - - struct vec_adj_list_vertex_property_selector { - template - struct bind_: detail::vec_adj_list_choose_vertex_pa {}; - }; - template <> - struct vertex_property_selector { - typedef vec_adj_list_vertex_property_selector type; - }; - -} // namespace boost - -namespace boost { - - template - struct hash< boost::detail::stored_edge > - { - std::size_t - operator()(const boost::detail::stored_edge& e) const - { - return hash()(e.m_target); - } - }; - - template - struct hash< boost::detail::stored_edge_property > - { - std::size_t - operator()(const boost::detail::stored_edge_property& e) const - { - return hash()(e.m_target); - } - }; - - template - struct hash< boost::detail::stored_edge_iter > - { - std::size_t - operator()(const boost::detail::stored_edge_iter& e) const - { - return hash()(e.m_target); - } - }; - -} - - -#endif // BOOST_GRAPH_DETAIL_DETAIL_ADJACENCY_LIST_CCT - -/* - Implementation Notes: - - Many of the public interface functions in this file would have been - more conveniently implemented as inline friend functions. - However there are a few compiler bugs that make that approach - non-portable. - - 1. g++ inline friend in namespace bug - 2. g++ using clause doesn't work with inline friends - 3. VC++ doesn't have Koenig lookup - - For these reasons, the functions were all written as non-inline free - functions, and static cast was used to convert from the helper - class to the adjacency_list derived class. - - Looking back, it might have been better to write out all functions - in terms of the adjacency_list, and then use a tag to dispatch - to the various helpers instead of using inheritance. - - */ +// -*- c++ -*- +//======================================================================= +// Copyright 1997, 1998, 1999, 2000 University of Notre Dame. +// Copyright 2010 Thomas Claveirole +// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Thomas Claveirole +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= + +#ifndef BOOST_GRAPH_DETAIL_ADJACENCY_LIST_HPP +#define BOOST_GRAPH_DETAIL_ADJACENCY_LIST_HPP + +#include // for vertex_map in copy_impl +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_GRAPH_MOVE_IF_POSSIBLE(x) (x) +#else +#include +#define BOOST_GRAPH_MOVE_IF_POSSIBLE(x) (std::move((x))) +#endif + +/* + Outline for this file: + + out_edge_iterator and in_edge_iterator implementation + edge_iterator for undirected graph + stored edge types (these object live in the out-edge/in-edge lists) + directed edges helper class + directed graph helper class + undirected graph helper class + bidirectional graph helper class + bidirectional graph helper class (without edge properties) + bidirectional graph helper class (with edge properties) + adjacency_list helper class + adj_list_impl class + vec_adj_list_impl class + adj_list_gen class + vertex property map + edge property map + + + Note: it would be nice to merge some of the undirected and + bidirectional code... it is awful similar. + */ + + +namespace boost { + + namespace detail { + + template + struct directed_category_traits { + typedef directed_tag directed_category; + }; + + template <> + struct directed_category_traits { + typedef directed_tag directed_category; + }; + template <> + struct directed_category_traits { + typedef undirected_tag directed_category; + }; + template <> + struct directed_category_traits { + typedef bidirectional_tag directed_category; + }; + + template + struct target_is { + target_is(const Vertex& v) : m_target(v) { } + template + bool operator()(const StoredEdge& e) const { + return e.get_target() == m_target; + } + Vertex m_target; + }; + + // O(E/V) + template + void erase_from_incidence_list(EdgeList& el, vertex_descriptor v, + allow_parallel_edge_tag) + { + boost::graph_detail::erase_if(el, detail::target_is(v)); + } + // O(log(E/V)) + template + void erase_from_incidence_list(EdgeList& el, vertex_descriptor v, + disallow_parallel_edge_tag) + { + typedef typename EdgeList::value_type StoredEdge; + el.erase(StoredEdge(v)); + } + + //========================================================================= + // Out-Edge and In-Edge Iterator Implementation + + template + struct out_edge_iter + : iterator_adaptor< + out_edge_iter + , BaseIter + , EdgeDescriptor + , use_default + , EdgeDescriptor + , Difference + > + { + typedef iterator_adaptor< + out_edge_iter + , BaseIter + , EdgeDescriptor + , use_default + , EdgeDescriptor + , Difference + > super_t; + + inline out_edge_iter() { } + inline out_edge_iter(const BaseIter& i, const VertexDescriptor& src) + : super_t(i), m_src(src) { } + + inline EdgeDescriptor + dereference() const + { + return EdgeDescriptor(m_src, (*this->base()).get_target(), + &(*this->base()).get_property()); + } + VertexDescriptor m_src; + }; + + template + struct in_edge_iter + : iterator_adaptor< + in_edge_iter + , BaseIter + , EdgeDescriptor + , use_default + , EdgeDescriptor + , Difference + > + { + typedef iterator_adaptor< + in_edge_iter + , BaseIter + , EdgeDescriptor + , use_default + , EdgeDescriptor + , Difference + > super_t; + + inline in_edge_iter() { } + inline in_edge_iter(const BaseIter& i, const VertexDescriptor& src) + : super_t(i), m_src(src) { } + + inline EdgeDescriptor + dereference() const + { + return EdgeDescriptor((*this->base()).get_target(), m_src, + &this->base()->get_property()); + } + VertexDescriptor m_src; + }; + + //========================================================================= + // Undirected Edge Iterator Implementation + + template + struct undirected_edge_iter + : iterator_adaptor< + undirected_edge_iter + , EdgeIter + , EdgeDescriptor + , use_default + , EdgeDescriptor + , Difference + > + { + typedef iterator_adaptor< + undirected_edge_iter + , EdgeIter + , EdgeDescriptor + , use_default + , EdgeDescriptor + , Difference + > super_t; + + undirected_edge_iter() {} + + explicit undirected_edge_iter(EdgeIter i) + : super_t(i) {} + + inline EdgeDescriptor + dereference() const { + return EdgeDescriptor( + (*this->base()).m_source + , (*this->base()).m_target + , &this->base()->get_property()); + } + }; + + //========================================================================= + // Edge Storage Types (stored in the out-edge/in-edge lists) + + template + class stored_edge + : public boost::equality_comparable1< stored_edge, + boost::less_than_comparable1< stored_edge > > + { + public: + typedef no_property property_type; + inline stored_edge() { } + inline stored_edge(Vertex target, const no_property& = no_property()) + : m_target(target) { } + // Need to write this explicitly so stored_edge_property can + // invoke Base::operator= (at least, for SGI MIPSPro compiler) + inline stored_edge& operator=(const stored_edge& x) { + m_target = x.m_target; + return *this; + } + inline Vertex& get_target() const { return m_target; } + inline const no_property& get_property() const { return s_prop; } + inline bool operator==(const stored_edge& x) const + { return m_target == x.get_target(); } + inline bool operator<(const stored_edge& x) const + { return m_target < x.get_target(); } + //protected: need to add hash<> as a friend + static no_property s_prop; + // Sometimes target not used as key in the set, and in that case + // it is ok to change the target. + mutable Vertex m_target; + }; + template + no_property stored_edge::s_prop; + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) || defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) + template + class stored_edge_property : public stored_edge { + typedef stored_edge_property self; + typedef stored_edge Base; + public: + typedef Property property_type; + inline stored_edge_property() { } + inline stored_edge_property(Vertex target, + const Property& p = Property()) + : stored_edge(target), m_property(new Property(p)) { } + stored_edge_property(const self& x) + : Base(x), m_property(const_cast(x).m_property) { } + self& operator=(const self& x) { + Base::operator=(x); + m_property = const_cast(x).m_property; + return *this; + } + inline Property& get_property() { return *m_property; } + inline const Property& get_property() const { return *m_property; } + protected: + // Holding the property by-value causes edge-descriptor + // invalidation for add_edge() with EdgeList=vecS. Instead we + // hold a pointer to the property. std::unique_ptr is not + // a perfect fit for the job, but it is darn close. + std::unique_ptr m_property; + }; +#else + template + class stored_edge_property : public stored_edge { + typedef stored_edge_property self; + typedef stored_edge Base; + public: + typedef Property property_type; + inline stored_edge_property() { } + inline stored_edge_property(Vertex target, + const Property& p = Property()) + : stored_edge(target), m_property(new Property(p)) { } +#if defined(BOOST_MSVC) || (defined(BOOST_GCC) && (BOOST_GCC / 100) < 406) + stored_edge_property(self&& x) : Base(static_cast< Base const& >(x)) { + m_property.swap(x.m_property); + } + stored_edge_property(self const& x) : Base(static_cast< Base const& >(x)) { + m_property.swap(const_cast(x).m_property); + } + self& operator=(self&& x) { + Base::operator=(static_cast< Base const& >(x)); + m_property = std::move(x.m_property); + return *this; + } + self& operator=(self const& x) { + Base::operator=(static_cast< Base const& >(x)); + m_property = std::move(const_cast(x).m_property); + return *this; + } +#else + stored_edge_property(self&& x) = default; + self& operator=(self&& x) = default; +#endif + inline Property& get_property() { return *m_property; } + inline const Property& get_property() const { return *m_property; } + protected: + std::unique_ptr m_property; + }; +#endif + + + template + class stored_edge_iter + : public stored_edge + { + public: + typedef Property property_type; + inline stored_edge_iter() { } + inline stored_edge_iter(Vertex v) + : stored_edge(v) { } + inline stored_edge_iter(Vertex v, Iter i, void* = 0) + : stored_edge(v), m_iter(i) { } + inline Property& get_property() { return m_iter->get_property(); } + inline const Property& get_property() const { + return m_iter->get_property(); + } + inline Iter get_iter() const { return m_iter; } + protected: + Iter m_iter; + }; + + // For when the EdgeList is a std::vector. + // Want to make the iterator stable, so use an offset + // instead of an iterator into a std::vector + template + class stored_ra_edge_iter + : public stored_edge + { + typedef typename EdgeVec::iterator Iter; + public: + typedef Property property_type; + inline stored_ra_edge_iter() { } + inline explicit stored_ra_edge_iter(Vertex v) // Only used for comparisons + : stored_edge(v), m_i(0), m_vec(0){ } + inline stored_ra_edge_iter(Vertex v, Iter i, EdgeVec* edge_vec) + : stored_edge(v), m_i(i - edge_vec->begin()), m_vec(edge_vec){ } + inline Property& get_property() { BOOST_ASSERT ((m_vec != 0)); return (*m_vec)[m_i].get_property(); } + inline const Property& get_property() const { + BOOST_ASSERT ((m_vec != 0)); + return (*m_vec)[m_i].get_property(); + } + inline Iter get_iter() const { BOOST_ASSERT ((m_vec != 0)); return m_vec->begin() + m_i; } + protected: + std::size_t m_i; + EdgeVec* m_vec; + }; + + } // namespace detail + + template + const typename property_value::type& + get(Tag property_tag, + const detail::stored_edge_property& e) + { + return get_property_value(e.get_property(), property_tag); + } + + template + const typename property_value::type& + get(Tag property_tag, + const detail::stored_edge_iter& e) + { + return get_property_value(e.get_property(), property_tag); + } + + template + const typename property_value::type& + get(Tag property_tag, + const detail::stored_ra_edge_iter& e) + { + return get_property_value(e.get_property(), property_tag); + } + + //========================================================================= + // Directed Edges Helper Class + + namespace detail { + + // O(E/V) + template + inline void + remove_directed_edge_dispatch(edge_descriptor, EdgeList& el, + StoredProperty& p) + { + for (typename EdgeList::iterator i = el.begin(); + i != el.end(); ++i) + if (&(*i).get_property() == &p) { + el.erase(i); + return; + } + } + + template + inline void + remove_directed_edge_if_dispatch(incidence_iterator first, + incidence_iterator last, + EdgeList& el, Predicate pred, + boost::allow_parallel_edge_tag) + { + // remove_if + while (first != last && !pred(*first)) + ++first; + incidence_iterator i = first; + if (first != last) + for (++i; i != last; ++i) + if (!pred(*i)) { + *first.base() = BOOST_GRAPH_MOVE_IF_POSSIBLE(*i.base()); + ++first; + } + el.erase(first.base(), el.end()); + } + template + inline void + remove_directed_edge_if_dispatch(incidence_iterator first, + incidence_iterator last, + EdgeList& el, + Predicate pred, + boost::disallow_parallel_edge_tag) + { + for (incidence_iterator next = first; + first != last; first = next) { + ++next; + if (pred(*first)) + el.erase( first.base() ); + } + } + + template + inline void + undirected_remove_out_edge_if_dispatch(Graph& g, + incidence_iterator first, + incidence_iterator last, + EdgeList& el, Predicate pred, + boost::allow_parallel_edge_tag) + { + typedef typename Graph::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + // remove_if + while (first != last && !pred(*first)) + ++first; + incidence_iterator i = first; + bool self_loop_removed = false; + if (first != last) + for (; i != last; ++i) { + if (self_loop_removed) { + /* With self loops, the descriptor will show up + * twice. The first time it will be removed, and now it + * will be skipped. + */ + self_loop_removed = false; + } + else if (!pred(*i)) { + *first.base() = BOOST_GRAPH_MOVE_IF_POSSIBLE(*i.base()); + ++first; + } else { + if (source(*i, g) == target(*i, g)) self_loop_removed = true; + else { + // Remove the edge from the target + detail::remove_directed_edge_dispatch + (*i, + g.out_edge_list(target(*i, g)), + *(PropT*)(*i).get_property()); + } + + // Erase the edge property + g.m_edges.erase( (*i.base()).get_iter() ); + } + } + el.erase(first.base(), el.end()); + } + template + inline void + undirected_remove_out_edge_if_dispatch(Graph& g, + incidence_iterator first, + incidence_iterator last, + EdgeList& el, + Predicate pred, + boost::disallow_parallel_edge_tag) + { + typedef typename Graph::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + for (incidence_iterator next = first; + first != last; first = next) { + ++next; + if (pred(*first)) { + if (source(*first, g) != target(*first, g)) { + // Remove the edge from the target + detail::remove_directed_edge_dispatch + (*first, + g.out_edge_list(target(*first, g)), + *(PropT*)(*first).get_property()); + } + + // Erase the edge property + g.m_edges.erase( (*first.base()).get_iter() ); + + // Erase the edge in the source + el.erase( first.base() ); + } + } + } + + // O(E/V) + template + inline void + remove_directed_edge_dispatch(edge_descriptor e, EdgeList& el, + no_property&) + { + for (typename EdgeList::iterator i = el.begin(); + i != el.end(); ++i) + if ((*i).get_target() == e.m_target) { + el.erase(i); + return; + } + } + + } // namespace detail + + template + struct directed_edges_helper { + + // Placement of these overloaded remove_edge() functions + // inside the class avoids a VC++ bug. + + // O(E/V) + inline void + remove_edge(typename Config::edge_descriptor e) + { + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(*this); + typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); + typedef typename Config::OutEdgeList::value_type::property_type PType; + detail::remove_directed_edge_dispatch(e, el, + *(PType*)e.get_property()); + } + + // O(1) + inline void + remove_edge(typename Config::out_edge_iterator iter) + { + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(*this); + typename Config::edge_descriptor e = *iter; + typename Config::OutEdgeList& el = g.out_edge_list(source(e, g)); + el.erase(iter.base()); + } + + }; + + // O(1) + template + inline std::pair + edges(const directed_edges_helper& g_) + { + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_iterator edge_iterator; + const graph_type& cg = static_cast(g_); + graph_type& g = const_cast(cg); + return std::make_pair( edge_iterator(g.vertex_set().begin(), + g.vertex_set().begin(), + g.vertex_set().end(), g), + edge_iterator(g.vertex_set().begin(), + g.vertex_set().end(), + g.vertex_set().end(), g) ); + } + + //========================================================================= + // Directed Graph Helper Class + + struct adj_list_dir_traversal_tag : + public virtual vertex_list_graph_tag, + public virtual incidence_graph_tag, + public virtual adjacency_graph_tag, + public virtual edge_list_graph_tag { }; + + template + struct directed_graph_helper + : public directed_edges_helper { + typedef typename Config::edge_descriptor edge_descriptor; + typedef adj_list_dir_traversal_tag traversal_category; + }; + + // O(E/V) + template + inline void + remove_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + directed_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_parallel_category Cat; + graph_type& g = static_cast(g_); + detail::erase_from_incidence_list(g.out_edge_list(u), v, Cat()); + } + + template + inline void + remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, + directed_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + typename Config::out_edge_iterator first, last; + boost::tie(first, last) = out_edges(u, g); + typedef typename Config::edge_parallel_category edge_parallel_category; + detail::remove_directed_edge_if_dispatch + (first, last, g.out_edge_list(u), pred, edge_parallel_category()); + } + + template + inline void + remove_edge_if(Predicate pred, directed_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + + typename Config::vertex_iterator vi, vi_end; + for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) + remove_out_edge_if(*vi, pred, g); + } + + template + inline void + remove_edge(EdgeOrIter e_or_iter, directed_graph_helper& g_) + { + g_.remove_edge(e_or_iter); + } + + // O(V + E) for allow_parallel_edges + // O(V * log(E/V)) for disallow_parallel_edges + template + inline void + clear_vertex(typename Config::vertex_descriptor u, + directed_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_parallel_category Cat; + graph_type& g = static_cast(g_); + typename Config::vertex_iterator vi, viend; + for (boost::tie(vi, viend) = vertices(g); vi != viend; ++vi) + detail::erase_from_incidence_list(g.out_edge_list(*vi), u, Cat()); + g.out_edge_list(u).clear(); + // clear() should be a req of Sequence and AssociativeContainer, + // or maybe just Container + } + + template + inline void + clear_out_edges(typename Config::vertex_descriptor u, + directed_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + g.out_edge_list(u).clear(); + // clear() should be a req of Sequence and AssociativeContainer, + // or maybe just Container + } + + // O(V), could do better... + template + inline typename Config::edges_size_type + num_edges(const directed_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + const graph_type& g = static_cast(g_); + typename Config::edges_size_type num_e = 0; + typename Config::vertex_iterator vi, vi_end; + for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) + num_e += out_degree(*vi, g); + return num_e; + } + // O(1) for allow_parallel_edge_tag + // O(log(E/V)) for disallow_parallel_edge_tag + template + inline std::pair::edge_descriptor, bool> + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + const typename Config::edge_property_type& p, + directed_graph_helper& g_) + { + typedef typename Config::edge_descriptor edge_descriptor; + typedef typename Config::graph_type graph_type; + typedef typename Config::StoredEdge StoredEdge; + graph_type& g = static_cast(g_); + typename Config::OutEdgeList::iterator i; + bool inserted; + boost::tie(i, inserted) = boost::graph_detail::push(g.out_edge_list(u), + StoredEdge(v, p)); + return std::make_pair(edge_descriptor(u, v, &(*i).get_property()), + inserted); + } + // Did not use default argument here because that + // causes Visual C++ to get confused. + template + inline std::pair + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + directed_graph_helper& g_) + { + typename Config::edge_property_type p; + return add_edge(u, v, p, g_); + } + //========================================================================= + // Undirected Graph Helper Class + + template + struct undirected_graph_helper; + + struct undir_adj_list_traversal_tag : + public virtual vertex_list_graph_tag, + public virtual incidence_graph_tag, + public virtual adjacency_graph_tag, + public virtual edge_list_graph_tag, + public virtual bidirectional_graph_tag { }; + + namespace detail { + + // using class with specialization for dispatch is a VC++ workaround. + template + struct remove_undirected_edge_dispatch { + + // O(E/V) + template + static void + apply(edge_descriptor e, + undirected_graph_helper& g_, + StoredProperty& p) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + + typename Config::OutEdgeList& out_el = g.out_edge_list(source(e, g)); + typename Config::OutEdgeList::iterator out_i = out_el.begin(); + typename Config::EdgeIter edge_iter_to_erase; + for (; out_i != out_el.end(); ++out_i) + if (&(*out_i).get_property() == &p) { + edge_iter_to_erase = (*out_i).get_iter(); + out_el.erase(out_i); + break; + } + typename Config::OutEdgeList& in_el = g.out_edge_list(target(e, g)); + typename Config::OutEdgeList::iterator in_i = in_el.begin(); + for (; in_i != in_el.end(); ++in_i) + if (&(*in_i).get_property() == &p) { + in_el.erase(in_i); + break; + } + g.m_edges.erase(edge_iter_to_erase); + } + }; + + template <> + struct remove_undirected_edge_dispatch { + // O(E/V) + template + static void + apply(edge_descriptor e, + undirected_graph_helper& g_, + no_property&) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + no_property* p = (no_property*)e.get_property(); + typename Config::OutEdgeList& out_el = g.out_edge_list(source(e, g)); + typename Config::OutEdgeList::iterator out_i = out_el.begin(); + typename Config::EdgeIter edge_iter_to_erase; + for (; out_i != out_el.end(); ++out_i) + if (&(*out_i).get_property() == p) { + edge_iter_to_erase = (*out_i).get_iter(); + out_el.erase(out_i); + break; + } + typename Config::OutEdgeList& in_el = g.out_edge_list(target(e, g)); + typename Config::OutEdgeList::iterator in_i = in_el.begin(); + for (; in_i != in_el.end(); ++in_i) + if (&(*in_i).get_property() == p) { + in_el.erase(in_i); + break; + } + g.m_edges.erase(edge_iter_to_erase); + } + }; + + // O(E/V) + template + inline void + remove_edge_and_property(Graph& g, EdgeList& el, Vertex v, + boost::allow_parallel_edge_tag cat) + { + typedef typename Graph::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typename EdgeList::iterator i = el.begin(), end = el.end(); + for (; i != end; ++i) { + if ((*i).get_target() == v) { + // NOTE: Wihtout this skip, this loop will double-delete properties + // of loop edges. This solution is based on the observation that + // the incidence edges of a vertex with a loop are adjacent in the + // out edge list. This *may* actually hold for multisets also. + bool skip = (boost::next(i) != end && i->get_iter() == boost::next(i)->get_iter()); + g.m_edges.erase((*i).get_iter()); + if (skip) ++i; + } + } + detail::erase_from_incidence_list(el, v, cat); + } + // O(log(E/V)) + template + inline void + remove_edge_and_property(Graph& g, EdgeList& el, Vertex v, + boost::disallow_parallel_edge_tag) + { + typedef typename Graph::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename EdgeList::value_type StoredEdge; + typename EdgeList::iterator i = el.find(StoredEdge(v)), end = el.end(); + if (i != end) { + g.m_edges.erase((*i).get_iter()); + el.erase(i); + } + } + + } // namespace detail + + template + struct list_edge // short name due to VC++ truncation and linker problems + : public boost::detail::edge_base + { + typedef EdgeProperty property_type; + typedef boost::detail::edge_base Base; + list_edge(Vertex u, Vertex v, const EdgeProperty& p = EdgeProperty()) + : Base(u, v), m_property(p) { } + EdgeProperty& get_property() { return m_property; } + const EdgeProperty& get_property() const { return m_property; } + // the following methods should never be used, but are needed + // to make SGI MIPSpro C++ happy + list_edge() { } + bool operator==(const list_edge&) const { return false; } + bool operator<(const list_edge&) const { return false; } + EdgeProperty m_property; + }; + + template + struct undirected_graph_helper { + + typedef undir_adj_list_traversal_tag traversal_category; + + // Placement of these overloaded remove_edge() functions + // inside the class avoids a VC++ bug. + + // O(E/V) + inline void + remove_edge(typename Config::edge_descriptor e) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::OutEdgeList::value_type::property_type PType; + detail::remove_undirected_edge_dispatch::apply + (e, *this, *(PType*)e.get_property()); + } + // O(E/V) + inline void + remove_edge(typename Config::out_edge_iterator iter) + { + this->remove_edge(*iter); + } + }; + + // Had to make these non-members to avoid accidental instantiation + // on SGI MIPSpro C++ + template + inline typename C::InEdgeList& + in_edge_list(undirected_graph_helper&, + typename C::vertex_descriptor v) + { + typename C::stored_vertex* sv = (typename C::stored_vertex*)v; + return sv->m_out_edges; + } + template + inline const typename C::InEdgeList& + in_edge_list(const undirected_graph_helper&, + typename C::vertex_descriptor v) { + typename C::stored_vertex* sv = (typename C::stored_vertex*)v; + return sv->m_out_edges; + } + + // O(E/V) + template + inline void + remove_edge(EdgeOrIter e, undirected_graph_helper& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + g_.remove_edge(e); + } + + // O(E/V) or O(log(E/V)) + template + void + remove_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + undirected_graph_helper& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + typedef typename Config::edge_parallel_category Cat; + detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); + detail::erase_from_incidence_list(g.out_edge_list(v), u, Cat()); + } + + template + void + remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, + undirected_graph_helper& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + typedef typename Config::OutEdgeList::value_type::property_type PropT; + graph_type& g = static_cast(g_); + typename Config::out_edge_iterator first, last; + boost::tie(first, last) = out_edges(u, g); + typedef typename Config::edge_parallel_category Cat; + detail::undirected_remove_out_edge_if_dispatch + (g, first, last, g.out_edge_list(u), pred, Cat()); + } + template + void + remove_in_edge_if(typename Config::vertex_descriptor u, Predicate pred, + undirected_graph_helper& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + remove_out_edge_if(u, pred, g_); + } + + // O(E/V * E) or O(log(E/V) * E) + template + void + remove_edge_if(Predicate pred, undirected_graph_helper& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + typename Config::edge_iterator ei, ei_end, next; + boost::tie(ei, ei_end) = edges(g); + for (next = ei; ei != ei_end; ei = next) { + ++next; + if (pred(*ei)) + remove_edge(*ei, g); + } + } + + // O(1) + template + inline std::pair + edges(const undirected_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_iterator edge_iterator; + const graph_type& cg = static_cast(g_); + graph_type& g = const_cast(cg); + return std::make_pair( edge_iterator(g.m_edges.begin()), + edge_iterator(g.m_edges.end()) ); + } + // O(1) + template + inline typename Config::edges_size_type + num_edges(const undirected_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + const graph_type& g = static_cast(g_); + return g.m_edges.size(); + } + // O(E/V * E/V) + template + inline void + clear_vertex(typename Config::vertex_descriptor u, + undirected_graph_helper& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + while (true) { + typename Config::out_edge_iterator ei, ei_end; + boost::tie(ei, ei_end) = out_edges(u, g); + if (ei == ei_end) break; + remove_edge(*ei, g); + } + } + // O(1) for allow_parallel_edge_tag + // O(log(E/V)) for disallow_parallel_edge_tag + template + inline std::pair + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + const typename Config::edge_property_type& p, + undirected_graph_helper& g_) + { + typedef typename Config::StoredEdge StoredEdge; + typedef typename Config::edge_descriptor edge_descriptor; + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + + bool inserted; + typename Config::EdgeContainer::value_type e(u, v, p); + typename Config::EdgeContainer::iterator p_iter + = graph_detail::push(g.m_edges, e).first; + + typename Config::OutEdgeList::iterator i; + boost::tie(i, inserted) = boost::graph_detail::push(g.out_edge_list(u), + StoredEdge(v, p_iter, &g.m_edges)); + if (inserted) { + boost::graph_detail::push(g.out_edge_list(v), StoredEdge(u, p_iter, &g.m_edges)); + return std::make_pair(edge_descriptor(u, v, &p_iter->get_property()), + true); + } else { + g.m_edges.erase(p_iter); + return std::make_pair + (edge_descriptor(u, v, &i->get_iter()->get_property()), false); + } + } + template + inline std::pair + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + undirected_graph_helper& g_) + { + typename Config::edge_property_type p; + return add_edge(u, v, p, g_); + } + + // O(1) + template + inline typename Config::degree_size_type + degree(typename Config::vertex_descriptor u, + const undirected_graph_helper& g_) + { + typedef typename Config::graph_type Graph; + const Graph& g = static_cast(g_); + return out_degree(u, g); + } + + template + inline std::pair + in_edges(typename Config::vertex_descriptor u, + const undirected_graph_helper& g_) + { + typedef typename Config::graph_type Graph; + const Graph& cg = static_cast(g_); + Graph& g = const_cast(cg); + typedef typename Config::in_edge_iterator in_edge_iterator; + return + std::make_pair(in_edge_iterator(g.out_edge_list(u).begin(), u), + in_edge_iterator(g.out_edge_list(u).end(), u)); + } + + template + inline typename Config::degree_size_type + in_degree(typename Config::vertex_descriptor u, + const undirected_graph_helper& g_) + { return degree(u, g_); } + + //========================================================================= + // Bidirectional Graph Helper Class + + struct bidir_adj_list_traversal_tag : + public virtual vertex_list_graph_tag, + public virtual incidence_graph_tag, + public virtual adjacency_graph_tag, + public virtual edge_list_graph_tag, + public virtual bidirectional_graph_tag { }; + + template + struct bidirectional_graph_helper + : public directed_edges_helper { + typedef bidir_adj_list_traversal_tag traversal_category; + }; + + // Had to make these non-members to avoid accidental instantiation + // on SGI MIPSpro C++ + template + inline typename C::InEdgeList& + in_edge_list(bidirectional_graph_helper&, + typename C::vertex_descriptor v) + { + typename C::stored_vertex* sv = (typename C::stored_vertex*)v; + return sv->m_in_edges; + } + template + inline const typename C::InEdgeList& + in_edge_list(const bidirectional_graph_helper&, + typename C::vertex_descriptor v) { + typename C::stored_vertex* sv = (typename C::stored_vertex*)v; + return sv->m_in_edges; + } + + template + inline void + remove_edge_if(Predicate pred, bidirectional_graph_helper& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + typename Config::edge_iterator ei, ei_end, next; + boost::tie(ei, ei_end) = edges(g); + for (next = ei; ei != ei_end; ei = next) { + ++next; + if (pred(*ei)) + remove_edge(*ei, g); + } + } + + template + inline std::pair + in_edges(typename Config::vertex_descriptor u, + const bidirectional_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + const graph_type& cg = static_cast(g_); + graph_type& g = const_cast(cg); + typedef typename Config::in_edge_iterator in_edge_iterator; + return + std::make_pair(in_edge_iterator(in_edge_list(g, u).begin(), u), + in_edge_iterator(in_edge_list(g, u).end(), u)); + } + + // O(1) + template + inline std::pair + edges(const bidirectional_graph_helper& g_) + { + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_iterator edge_iterator; + const graph_type& cg = static_cast(g_); + graph_type& g = const_cast(cg); + return std::make_pair( edge_iterator(g.m_edges.begin()), + edge_iterator(g.m_edges.end()) ); + } + + //========================================================================= + // Bidirectional Graph Helper Class (with edge properties) + + + template + struct bidirectional_graph_helper_with_property + : public bidirectional_graph_helper + { + typedef typename Config::graph_type graph_type; + typedef typename Config::out_edge_iterator out_edge_iterator; + + std::pair + get_parallel_edge_sublist(typename Config::edge_descriptor e, + const graph_type& g, + void*) + { return out_edges(source(e, g), g); } + + std::pair + get_parallel_edge_sublist(typename Config::edge_descriptor e, + const graph_type& g, + setS*) + { return edge_range(source(e, g), target(e, g), g); } + + std::pair + get_parallel_edge_sublist(typename Config::edge_descriptor e, + const graph_type& g, + multisetS*) + { return edge_range(source(e, g), target(e, g), g); } + + std::pair + get_parallel_edge_sublist(typename Config::edge_descriptor e, + const graph_type& g, + hash_setS*) + { return edge_range(source(e, g), target(e, g), g); } + + // Placement of these overloaded remove_edge() functions + // inside the class avoids a VC++ bug. + + // O(E/V) or O(log(E/V)) + void + remove_edge(typename Config::edge_descriptor e) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + graph_type& g = static_cast(*this); + + typedef typename Config::edgelist_selector OutEdgeListS; + + std::pair rng = + get_parallel_edge_sublist(e, g, (OutEdgeListS*)(0)); + rng.first = std::find(rng.first, rng.second, e); + BOOST_ASSERT(rng.first != rng.second); + remove_edge(rng.first); + } + + inline void + remove_edge(typename Config::out_edge_iterator iter) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(*this); + typename Config::edge_descriptor e = *iter; + typename Config::OutEdgeList& oel = g.out_edge_list(source(e, g)); + typename Config::InEdgeList& iel = in_edge_list(g, target(e, g)); + typedef typename Config::OutEdgeList::value_type::property_type PType; + PType& p = *(PType*)e.get_property(); + detail::remove_directed_edge_dispatch(*iter, iel, p); + g.m_edges.erase(iter.base()->get_iter()); + oel.erase(iter.base()); + } + }; + + // O(E/V) for allow_parallel_edge_tag + // O(log(E/V)) for disallow_parallel_edge_tag + template + inline void + remove_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + typedef typename Config::edge_parallel_category Cat; + detail::remove_edge_and_property(g, g.out_edge_list(u), v, Cat()); + detail::erase_from_incidence_list(in_edge_list(g, v), u, Cat()); + } + + // O(E/V) or O(log(E/V)) + template + inline void + remove_edge(EdgeOrIter e, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + g_.remove_edge(e); + } + + template + inline void + remove_out_edge_if(typename Config::vertex_descriptor u, Predicate pred, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + typedef typename Config::OutEdgeList::value_type::property_type PropT; + graph_type& g = static_cast(g_); + + typedef typename Config::EdgeIter EdgeIter; + typedef std::vector Garbage; + Garbage garbage; + + // First remove the edges from the targets' in-edge lists and + // from the graph's edge set list. + typename Config::out_edge_iterator out_i, out_end; + for (boost::tie(out_i, out_end) = out_edges(u, g); out_i != out_end; ++out_i) + if (pred(*out_i)) { + detail::remove_directed_edge_dispatch + (*out_i, in_edge_list(g, target(*out_i, g)), + *(PropT*)(*out_i).get_property()); + // Put in garbage to delete later. Will need the properties + // for the remove_if of the out-edges. + garbage.push_back((*out_i.base()).get_iter()); + } + + // Now remove the edges from this out-edge list. + typename Config::out_edge_iterator first, last; + boost::tie(first, last) = out_edges(u, g); + typedef typename Config::edge_parallel_category Cat; + detail::remove_directed_edge_if_dispatch + (first, last, g.out_edge_list(u), pred, Cat()); + + // Now delete the edge properties from the g.m_edges list + for (typename Garbage::iterator i = garbage.begin(); + i != garbage.end(); ++i) + g.m_edges.erase(*i); + } + template + inline void + remove_in_edge_if(typename Config::vertex_descriptor v, Predicate pred, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + typedef typename Config::OutEdgeList::value_type::property_type PropT; + graph_type& g = static_cast(g_); + + typedef typename Config::EdgeIter EdgeIter; + typedef std::vector Garbage; + Garbage garbage; + + // First remove the edges from the sources' out-edge lists and + // from the graph's edge set list. + typename Config::in_edge_iterator in_i, in_end; + for (boost::tie(in_i, in_end) = in_edges(v, g); in_i != in_end; ++in_i) + if (pred(*in_i)) { + typename Config::vertex_descriptor u = source(*in_i, g); + detail::remove_directed_edge_dispatch + (*in_i, g.out_edge_list(u), *(PropT*)(*in_i).get_property()); + // Put in garbage to delete later. Will need the properties + // for the remove_if of the out-edges. + garbage.push_back((*in_i.base()).get_iter()); + } + // Now remove the edges from this in-edge list. + typename Config::in_edge_iterator first, last; + boost::tie(first, last) = in_edges(v, g); + typedef typename Config::edge_parallel_category Cat; + detail::remove_directed_edge_if_dispatch + (first, last, in_edge_list(g, v), pred, Cat()); + + // Now delete the edge properties from the g.m_edges list + for (typename Garbage::iterator i = garbage.begin(); + i != garbage.end(); ++i) + g.m_edges.erase(*i); + } + + // O(1) + template + inline typename Config::edges_size_type + num_edges(const bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::graph_type graph_type; + const graph_type& g = static_cast(g_); + return g.m_edges.size(); + } + // O(E/V * E/V) for allow_parallel_edge_tag + // O(E/V * log(E/V)) for disallow_parallel_edge_tag + template + inline void + clear_vertex(typename Config::vertex_descriptor u, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_parallel_category Cat; + graph_type& g = static_cast(g_); + typename Config::OutEdgeList& el = g.out_edge_list(u); + typename Config::OutEdgeList::iterator + ei = el.begin(), ei_end = el.end(); + for (; ei != ei_end; ++ei) { + detail::erase_from_incidence_list + (in_edge_list(g, (*ei).get_target()), u, Cat()); + g.m_edges.erase((*ei).get_iter()); + } + typename Config::InEdgeList& in_el = in_edge_list(g, u); + typename Config::InEdgeList::iterator + in_ei = in_el.begin(), in_ei_end = in_el.end(); + for (; in_ei != in_ei_end; ++in_ei) { + detail::erase_from_incidence_list + (g.out_edge_list((*in_ei).get_target()), u, Cat()); + g.m_edges.erase((*in_ei).get_iter()); + } + g.out_edge_list(u).clear(); + in_edge_list(g, u).clear(); + } + + template + inline void + clear_out_edges(typename Config::vertex_descriptor u, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_parallel_category Cat; + graph_type& g = static_cast(g_); + typename Config::OutEdgeList& el = g.out_edge_list(u); + typename Config::OutEdgeList::iterator + ei = el.begin(), ei_end = el.end(); + for (; ei != ei_end; ++ei) { + detail::erase_from_incidence_list + (in_edge_list(g, (*ei).get_target()), u, Cat()); + g.m_edges.erase((*ei).get_iter()); + } + g.out_edge_list(u).clear(); + } + + template + inline void + clear_in_edges(typename Config::vertex_descriptor u, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Config::graph_type graph_type; + typedef typename Config::edge_parallel_category Cat; + graph_type& g = static_cast(g_); + typename Config::InEdgeList& in_el = in_edge_list(g, u); + typename Config::InEdgeList::iterator + in_ei = in_el.begin(), in_ei_end = in_el.end(); + for (; in_ei != in_ei_end; ++in_ei) { + detail::erase_from_incidence_list + (g.out_edge_list((*in_ei).get_target()), u, Cat()); + g.m_edges.erase((*in_ei).get_iter()); + } + in_edge_list(g, u).clear(); + } + + // O(1) for allow_parallel_edge_tag + // O(log(E/V)) for disallow_parallel_edge_tag + template + inline std::pair + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + const typename Config::edge_property_type& p, + bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::graph_type graph_type; + graph_type& g = static_cast(g_); + typedef typename Config::edge_descriptor edge_descriptor; + typedef typename Config::StoredEdge StoredEdge; + bool inserted; + typename Config::EdgeContainer::value_type e(u, v, p); + typename Config::EdgeContainer::iterator p_iter + = graph_detail::push(g.m_edges, e).first; + typename Config::OutEdgeList::iterator i; + boost::tie(i, inserted) = boost::graph_detail::push(g.out_edge_list(u), + StoredEdge(v, p_iter, &g.m_edges)); + if (inserted) { + boost::graph_detail::push(in_edge_list(g, v), StoredEdge(u, p_iter, &g.m_edges)); + return std::make_pair(edge_descriptor(u, v, &p_iter->m_property), + true); + } else { + g.m_edges.erase(p_iter); + return std::make_pair(edge_descriptor(u, v, + &i->get_iter()->get_property()), + false); + } + } + + template + inline std::pair + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + bidirectional_graph_helper_with_property& g_) + { + typename Config::edge_property_type p; + return add_edge(u, v, p, g_); + } + // O(1) + template + inline typename Config::degree_size_type + degree(typename Config::vertex_descriptor u, + const bidirectional_graph_helper_with_property& g_) + { + typedef typename Config::graph_type graph_type; + const graph_type& g = static_cast(g_); + return in_degree(u, g) + out_degree(u, g); + } + + //========================================================================= + // Adjacency List Helper Class + + template + struct adj_list_helper : public Base + { + typedef typename Config::graph_type AdjList; + typedef typename Config::vertex_descriptor vertex_descriptor; + typedef typename Config::edge_descriptor edge_descriptor; + typedef typename Config::out_edge_iterator out_edge_iterator; + typedef typename Config::in_edge_iterator in_edge_iterator; + typedef typename Config::adjacency_iterator adjacency_iterator; + typedef typename Config::inv_adjacency_iterator inv_adjacency_iterator; + typedef typename Config::vertex_iterator vertex_iterator; + typedef typename Config::edge_iterator edge_iterator; + typedef typename Config::directed_category directed_category; + typedef typename Config::edge_parallel_category edge_parallel_category; + typedef typename Config::vertices_size_type vertices_size_type; + typedef typename Config::edges_size_type edges_size_type; + typedef typename Config::degree_size_type degree_size_type; + typedef typename Config::StoredEdge StoredEdge; + typedef typename Config::vertex_property_type vertex_property_type; + typedef typename Config::edge_property_type edge_property_type; + typedef typename Config::graph_property_type graph_property_type; + + typedef typename Config::global_edgelist_selector + global_edgelist_selector; + + typedef typename lookup_one_property::type vertex_bundled; + typedef typename lookup_one_property::type edge_bundled; + typedef typename lookup_one_property::type graph_bundled; + }; + + template + inline std::pair + adjacent_vertices(typename Config::vertex_descriptor u, + const adj_list_helper& g_) + { + typedef typename Config::graph_type AdjList; + const AdjList& cg = static_cast(g_); + AdjList& g = const_cast(cg); + typedef typename Config::adjacency_iterator adjacency_iterator; + typename Config::out_edge_iterator first, last; + boost::tie(first, last) = out_edges(u, g); + return std::make_pair(adjacency_iterator(first, &g), + adjacency_iterator(last, &g)); + } + template + inline std::pair + inv_adjacent_vertices(typename Config::vertex_descriptor u, + const adj_list_helper& g_) + { + typedef typename Config::graph_type AdjList; + const AdjList& cg = static_cast(g_); + AdjList& g = const_cast(cg); + typedef typename Config::inv_adjacency_iterator inv_adjacency_iterator; + typename Config::in_edge_iterator first, last; + boost::tie(first, last) = in_edges(u, g); + return std::make_pair(inv_adjacency_iterator(first, &g), + inv_adjacency_iterator(last, &g)); + } + template + inline std::pair + out_edges(typename Config::vertex_descriptor u, + const adj_list_helper& g_) + { + typedef typename Config::graph_type AdjList; + typedef typename Config::out_edge_iterator out_edge_iterator; + const AdjList& cg = static_cast(g_); + AdjList& g = const_cast(cg); + return + std::make_pair(out_edge_iterator(g.out_edge_list(u).begin(), u), + out_edge_iterator(g.out_edge_list(u).end(), u)); + } + template + inline std::pair + vertices(const adj_list_helper& g_) + { + typedef typename Config::graph_type AdjList; + const AdjList& cg = static_cast(g_); + AdjList& g = const_cast(cg); + return std::make_pair( g.vertex_set().begin(), g.vertex_set().end() ); + } + template + inline typename Config::vertices_size_type + num_vertices(const adj_list_helper& g_) + { + typedef typename Config::graph_type AdjList; + const AdjList& g = static_cast(g_); + return g.vertex_set().size(); + } + template + inline typename Config::degree_size_type + out_degree(typename Config::vertex_descriptor u, + const adj_list_helper& g_) + { + typedef typename Config::graph_type AdjList; + const AdjList& g = static_cast(g_); + return g.out_edge_list(u).size(); + } + template + inline std::pair + edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + const adj_list_helper& g_) + { + typedef typename Config::graph_type Graph; + typedef typename Config::StoredEdge StoredEdge; + const Graph& cg = static_cast(g_); + const typename Config::OutEdgeList& el = cg.out_edge_list(u); + typename Config::OutEdgeList::const_iterator it = graph_detail:: + find(el, StoredEdge(v)); + return std::make_pair( + typename Config::edge_descriptor + (u, v, (it == el.end() ? 0 : &(*it).get_property())), + (it != el.end())); + } + + template + inline std::pair + edge_range(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + const adj_list_helper& g_) + { + typedef typename Config::graph_type Graph; + typedef typename Config::StoredEdge StoredEdge; + const Graph& cg = static_cast(g_); + Graph& g = const_cast(cg); + typedef typename Config::out_edge_iterator out_edge_iterator; + typename Config::OutEdgeList& el = g.out_edge_list(u); + typename Config::OutEdgeList::iterator first, last; + typename Config::EdgeContainer fake_edge_container; + boost::tie(first, last) = graph_detail:: + equal_range(el, StoredEdge(v)); + return std::make_pair(out_edge_iterator(first, u), + out_edge_iterator(last, u)); + } + + template + inline typename Config::degree_size_type + in_degree(typename Config::vertex_descriptor u, + const directed_edges_helper& g_) + { + typedef typename Config::graph_type Graph; + const Graph& cg = static_cast(g_); + Graph& g = const_cast(cg); + return in_edge_list(g, u).size(); + } + + namespace detail { + template + inline + typename boost::property_map::type + get_dispatch(adj_list_helper&, Property p, + boost::edge_property_tag) { + typedef typename Config::graph_type Graph; + typedef typename boost::property_map::type PA; + return PA(p); + } + template + inline + typename boost::property_map::const_type + get_dispatch(const adj_list_helper&, Property p, + boost::edge_property_tag) { + typedef typename Config::graph_type Graph; + typedef typename boost::property_map::const_type PA; + return PA(p); + } + + template + inline + typename boost::property_map::type + get_dispatch(adj_list_helper& g, Property p, + boost::vertex_property_tag) { + typedef typename Config::graph_type Graph; + typedef typename boost::property_map::type PA; + return PA(&static_cast(g), p); + } + template + inline + typename boost::property_map::const_type + get_dispatch(const adj_list_helper& g, Property p, + boost::vertex_property_tag) { + typedef typename Config::graph_type Graph; + typedef typename boost::property_map::const_type PA; + const Graph& cg = static_cast(g); + return PA(&cg, p); + } + + } // namespace detail + + // Implementation of the PropertyGraph interface + template + inline + typename boost::property_map::type + get(Property p, adj_list_helper& g) { + typedef typename detail::property_kind_from_graph, Property>::type Kind; + return detail::get_dispatch(g, p, Kind()); + } + template + inline + typename boost::property_map::const_type + get(Property p, const adj_list_helper& g) { + typedef typename detail::property_kind_from_graph, Property>::type Kind; + return detail::get_dispatch(g, p, Kind()); + } + + template + inline + typename boost::property_traits< + typename boost::property_map::type + >::reference + get(Property p, adj_list_helper& g, const Key& key) { + return get(get(p, g), key); + } + + template + inline + typename boost::property_traits< + typename boost::property_map::const_type + >::reference + get(Property p, const adj_list_helper& g, const Key& key) { + return get(get(p, g), key); + } + + template + inline void + put(Property p, adj_list_helper& g, + const Key& key, const Value& value) + { + typedef typename Config::graph_type Graph; + typedef typename boost::property_map::type Map; + Map pmap = get(p, static_cast(g)); + put(pmap, key, value); + } + + + //========================================================================= + // Generalize Adjacency List Implementation + + struct adj_list_tag { }; + + template + class adj_list_impl + : public adj_list_helper + { + typedef typename Config::OutEdgeList OutEdgeList; + typedef typename Config::InEdgeList InEdgeList; + typedef typename Config::StoredVertexList StoredVertexList; + public: + typedef typename Config::stored_vertex stored_vertex; + typedef typename Config::EdgeContainer EdgeContainer; + typedef typename Config::vertex_descriptor vertex_descriptor; + typedef typename Config::edge_descriptor edge_descriptor; + typedef typename Config::vertex_iterator vertex_iterator; + typedef typename Config::edge_iterator edge_iterator; + typedef typename Config::edge_parallel_category edge_parallel_category; + typedef typename Config::vertices_size_type vertices_size_type; + typedef typename Config::edges_size_type edges_size_type; + typedef typename Config::degree_size_type degree_size_type; + typedef typename Config::edge_property_type edge_property_type; + typedef adj_list_tag graph_tag; + + static vertex_descriptor null_vertex() + { + return 0; + } + + inline adj_list_impl() { } + + inline adj_list_impl(const adj_list_impl& x) { + copy_impl(x); + } + inline adj_list_impl& operator=(const adj_list_impl& x) { + this->clear(); + copy_impl(x); + return *this; + } + inline void clear() { + for (typename StoredVertexList::iterator i = m_vertices.begin(); + i != m_vertices.end(); ++i) + delete (stored_vertex*)*i; + m_vertices.clear(); + m_edges.clear(); + } + inline adj_list_impl(vertices_size_type num_vertices) { + for (vertices_size_type i = 0; i < num_vertices; ++i) + add_vertex(static_cast(*this)); + } + template + inline adj_list_impl(vertices_size_type num_vertices, + EdgeIterator first, EdgeIterator last) + { + vertex_descriptor* v = new vertex_descriptor[num_vertices]; + for (vertices_size_type i = 0; i < num_vertices; ++i) + v[i] = add_vertex(static_cast(*this)); + + while (first != last) { + add_edge(v[(*first).first], v[(*first).second], *this); + ++first; + } + delete [] v; + } + template + inline adj_list_impl(vertices_size_type num_vertices, + EdgeIterator first, EdgeIterator last, + EdgePropertyIterator ep_iter) + { + vertex_descriptor* v = new vertex_descriptor[num_vertices]; + for (vertices_size_type i = 0; i < num_vertices; ++i) + v[i] = add_vertex(static_cast(*this)); + + while (first != last) { + add_edge(v[(*first).first], v[(*first).second], *ep_iter, *this); + ++first; + ++ep_iter; + } + delete [] v; + } + ~adj_list_impl() { + for (typename StoredVertexList::iterator i = m_vertices.begin(); + i != m_vertices.end(); ++i) + delete (stored_vertex*)*i; + } + // protected: + inline OutEdgeList& out_edge_list(vertex_descriptor v) { + stored_vertex* sv = (stored_vertex*)v; + return sv->m_out_edges; + } + inline const OutEdgeList& out_edge_list(vertex_descriptor v) const { + stored_vertex* sv = (stored_vertex*)v; + return sv->m_out_edges; + } + inline StoredVertexList& vertex_set() { return m_vertices; } + inline const StoredVertexList& vertex_set() const { return m_vertices; } + + inline void copy_impl(const adj_list_impl& x_) + { + const Derived& x = static_cast(x_); + + // Would be better to have a constant time way to get from + // vertices in x to the corresponding vertices in *this. + std::map vertex_map; + + // Copy the stored vertex objects by adding each vertex + // and copying its property object. + vertex_iterator vi, vi_end; + for (boost::tie(vi, vi_end) = vertices(x); vi != vi_end; ++vi) { + stored_vertex* v = (stored_vertex*)add_vertex(*this); + v->m_property = ((stored_vertex*)*vi)->m_property; + vertex_map[(stored_vertex*)*vi] = v; + } + // Copy the edges by adding each edge and copying its + // property object. + edge_iterator ei, ei_end; + for (boost::tie(ei, ei_end) = edges(x); ei != ei_end; ++ei) { + edge_descriptor e; + bool inserted; + vertex_descriptor s = source(*ei,x), t = target(*ei,x); + boost::tie(e, inserted) = add_edge(vertex_map[(stored_vertex*)s], + vertex_map[(stored_vertex*)t], *this); + *((edge_property_type*)e.m_eproperty) + = *((edge_property_type*)(*ei).m_eproperty); + } + } + + + typename Config::EdgeContainer m_edges; + StoredVertexList m_vertices; + }; + + // O(1) + template + inline typename Config::vertex_descriptor + add_vertex(adj_list_impl& g_) + { + Derived& g = static_cast(g_); + typedef typename Config::stored_vertex stored_vertex; + stored_vertex* v = new stored_vertex; + typename Config::StoredVertexList::iterator pos; + bool inserted; + boost::tie(pos,inserted) = boost::graph_detail::push(g.m_vertices, v); + v->m_position = pos; + g.added_vertex(v); + return v; + } + // O(1) + template + inline typename Config::vertex_descriptor + add_vertex(const typename Config::vertex_property_type& p, + adj_list_impl& g_) + { + typedef typename Config::vertex_descriptor vertex_descriptor; + Derived& g = static_cast(g_); + if (optional v + = g.vertex_by_property(get_property_value(p, vertex_bundle))) + return *v; + + typedef typename Config::stored_vertex stored_vertex; + stored_vertex* v = new stored_vertex(p); + typename Config::StoredVertexList::iterator pos; + bool inserted; + boost::tie(pos,inserted) = boost::graph_detail::push(g.m_vertices, v); + v->m_position = pos; + g.added_vertex(v); + return v; + } + // O(1) + template + inline void remove_vertex(typename Config::vertex_descriptor u, + adj_list_impl& g_) + { + typedef typename Config::stored_vertex stored_vertex; + Derived& g = static_cast(g_); + g.removing_vertex(u, boost::graph_detail::iterator_stability(g_.m_vertices)); + stored_vertex* su = (stored_vertex*)u; + g.m_vertices.erase(su->m_position); + delete su; + } + // O(V) + template + inline typename Config::vertex_descriptor + vertex(typename Config::vertices_size_type n, + const adj_list_impl& g_) + { + const Derived& g = static_cast(g_); + typename Config::vertex_iterator i = vertices(g).first; + while (n--) ++i; // std::advance(i, n); (not VC++ portable) + return *i; + } + + //========================================================================= + // Vector-Backbone Adjacency List Implementation + + namespace detail { + + template + inline void + remove_vertex_dispatch(Graph& g, vertex_descriptor u, + boost::directed_tag) + { + typedef typename Graph::edge_parallel_category edge_parallel_category; + g.m_vertices.erase(g.m_vertices.begin() + u); + vertex_descriptor V = num_vertices(g); + if (u != V) { + for (vertex_descriptor v = 0; v < V; ++v) + reindex_edge_list(g.out_edge_list(v), u, edge_parallel_category()); + } + } + + template + inline void + remove_vertex_dispatch(Graph& g, vertex_descriptor u, + boost::undirected_tag) + { + typedef typename Graph::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Graph::edge_parallel_category edge_parallel_category; + g.m_vertices.erase(g.m_vertices.begin() + u); + vertex_descriptor V = num_vertices(g); + for (vertex_descriptor v = 0; v < V; ++v) + reindex_edge_list(g.out_edge_list(v), u, + edge_parallel_category()); + typedef typename Graph::EdgeContainer Container; + typedef typename Container::iterator Iter; + Iter ei = g.m_edges.begin(), ei_end = g.m_edges.end(); + for (; ei != ei_end; ++ei) { + if (ei->m_source > u) + --ei->m_source; + if (ei->m_target > u) + --ei->m_target; + } + } + template + inline void + remove_vertex_dispatch(Graph& g, vertex_descriptor u, + boost::bidirectional_tag) + { + typedef typename Graph::global_edgelist_selector EdgeListS; + BOOST_STATIC_ASSERT((!is_same::value)); + + typedef typename Graph::edge_parallel_category edge_parallel_category; + g.m_vertices.erase(g.m_vertices.begin() + u); + vertex_descriptor V = num_vertices(g); + vertex_descriptor v; + if (u != V) { + for (v = 0; v < V; ++v) + reindex_edge_list(g.out_edge_list(v), u, + edge_parallel_category()); + for (v = 0; v < V; ++v) + reindex_edge_list(in_edge_list(g, v), u, + edge_parallel_category()); + + typedef typename Graph::EdgeContainer Container; + typedef typename Container::iterator Iter; + Iter ei = g.m_edges.begin(), ei_end = g.m_edges.end(); + for (; ei != ei_end; ++ei) { + if (ei->m_source > u) + --ei->m_source; + if (ei->m_target > u) + --ei->m_target; + } + } + } + + template + inline void + reindex_edge_list(EdgeList& el, vertex_descriptor u, + boost::allow_parallel_edge_tag) + { + typename EdgeList::iterator ei = el.begin(), e_end = el.end(); + for (; ei != e_end; ++ei) + if ((*ei).get_target() > u) + --(*ei).get_target(); + } + template + inline void + reindex_edge_list(EdgeList& el, vertex_descriptor u, + boost::disallow_parallel_edge_tag) + { + typename EdgeList::iterator ei = el.begin(), e_end = el.end(); + while (ei != e_end) { + typename EdgeList::value_type ce = *ei; + ++ei; + if (ce.get_target() > u) { + el.erase(ce); + --ce.get_target(); + el.insert(ce); + } + } + } + } // namespace detail + + struct vec_adj_list_tag { }; + + template + class vec_adj_list_impl + : public adj_list_helper + { + typedef typename Config::OutEdgeList OutEdgeList; + typedef typename Config::InEdgeList InEdgeList; + typedef typename Config::StoredVertexList StoredVertexList; + public: + typedef typename Config::vertex_descriptor vertex_descriptor; + typedef typename Config::edge_descriptor edge_descriptor; + typedef typename Config::out_edge_iterator out_edge_iterator; + typedef typename Config::edge_iterator edge_iterator; + typedef typename Config::directed_category directed_category; + typedef typename Config::vertices_size_type vertices_size_type; + typedef typename Config::edges_size_type edges_size_type; + typedef typename Config::degree_size_type degree_size_type; + typedef typename Config::StoredEdge StoredEdge; + typedef typename Config::stored_vertex stored_vertex; + typedef typename Config::EdgeContainer EdgeContainer; + typedef typename Config::edge_property_type edge_property_type; + typedef vec_adj_list_tag graph_tag; + + static vertex_descriptor null_vertex() + { + return (std::numeric_limits::max)(); + } + + inline vec_adj_list_impl() { } + + inline vec_adj_list_impl(const vec_adj_list_impl& x) { + copy_impl(x); + } + inline vec_adj_list_impl& operator=(const vec_adj_list_impl& x) { + this->clear(); + copy_impl(x); + return *this; + } + inline void clear() { + m_vertices.clear(); + m_edges.clear(); + } + + inline vec_adj_list_impl(vertices_size_type _num_vertices) + : m_vertices(_num_vertices) { } + + template + inline vec_adj_list_impl(vertices_size_type num_vertices, + EdgeIterator first, EdgeIterator last) + : m_vertices(num_vertices) + { + while (first != last) { + add_edge((*first).first, (*first).second, + static_cast(*this)); + ++first; + } + } + template + inline vec_adj_list_impl(vertices_size_type num_vertices, + EdgeIterator first, EdgeIterator last, + EdgePropertyIterator ep_iter) + : m_vertices(num_vertices) + { + while (first != last) { + add_edge((*first).first, (*first).second, *ep_iter, + static_cast(*this)); + ++first; + ++ep_iter; + } + } + + // protected: + inline boost::integer_range vertex_set() const { + return boost::integer_range(0, m_vertices.size()); + } + inline OutEdgeList& out_edge_list(vertex_descriptor v) { + return m_vertices[v].m_out_edges; + } + inline const OutEdgeList& out_edge_list(vertex_descriptor v) const { + return m_vertices[v].m_out_edges; + } + inline void copy_impl(const vec_adj_list_impl& x_) + { + const Graph& x = static_cast(x_); + // Copy the stored vertex objects by adding each vertex + // and copying its property object. + for (vertices_size_type i = 0; i < num_vertices(x); ++i) { + vertex_descriptor v = add_vertex(*this); + m_vertices[v].m_property = x.m_vertices[i].m_property; + } + // Copy the edges by adding each edge and copying its + // property object. + edge_iterator ei, ei_end; + for (boost::tie(ei, ei_end) = edges(x); ei != ei_end; ++ei) { + edge_descriptor e; + bool inserted; + boost::tie(e, inserted) = add_edge(source(*ei,x), target(*ei,x) , *this); + *((edge_property_type*)e.m_eproperty) + = *((edge_property_type*)(*ei).m_eproperty); + } + } + typename Config::EdgeContainer m_edges; + StoredVertexList m_vertices; + }; + // Had to make these non-members to avoid accidental instantiation + // on SGI MIPSpro C++ + template + inline typename C::InEdgeList& + in_edge_list(vec_adj_list_impl& g, + typename C::vertex_descriptor v) { + return g.m_vertices[v].m_in_edges; + } + template + inline const typename C::InEdgeList& + in_edge_list(const vec_adj_list_impl& g, + typename C::vertex_descriptor v) { + return g.m_vertices[v].m_in_edges; + } + + // O(1) + template + inline typename Config::vertex_descriptor + add_vertex(vec_adj_list_impl& g_) { + Graph& g = static_cast(g_); + g.m_vertices.resize(g.m_vertices.size() + 1); + g.added_vertex(g.m_vertices.size() - 1); + return g.m_vertices.size() - 1; + } + + template + inline typename Config::vertex_descriptor + add_vertex(const typename Config::vertex_property_type& p, + vec_adj_list_impl& g_) { + typedef typename Config::vertex_descriptor vertex_descriptor; + Graph& g = static_cast(g_); + if (optional v + = g.vertex_by_property(get_property_value(p, vertex_bundle))) + return *v; + typedef typename Config::stored_vertex stored_vertex; + g.m_vertices.push_back(stored_vertex(p)); + g.added_vertex(g.m_vertices.size() - 1); + return g.m_vertices.size() - 1; + } + + // Here we override the directed_graph_helper add_edge() function + // so that the number of vertices is automatically changed if + // either u or v is greater than the number of vertices. + template + inline std::pair + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + const typename Config::edge_property_type& p, + vec_adj_list_impl& g_) + { + BOOST_USING_STD_MAX(); + typename Config::vertex_descriptor x = max BOOST_PREVENT_MACRO_SUBSTITUTION(u, v); + if (x >= num_vertices(g_)) + g_.m_vertices.resize(x + 1); + adj_list_helper& g = g_; + return add_edge(u, v, p, g); + } + template + inline std::pair + add_edge(typename Config::vertex_descriptor u, + typename Config::vertex_descriptor v, + vec_adj_list_impl& g_) + { + typename Config::edge_property_type p; + return add_edge(u, v, p, g_); + } + + + // O(V + E) + template + inline void remove_vertex(typename Config::vertex_descriptor v, + vec_adj_list_impl& g_) + { + typedef typename Config::directed_category Cat; + Graph& g = static_cast(g_); + g.removing_vertex(v, boost::graph_detail::iterator_stability(g_.m_vertices)); + detail::remove_vertex_dispatch(g, v, Cat()); + } + // O(1) + template + inline typename Config::vertex_descriptor + vertex(typename Config::vertices_size_type n, + const vec_adj_list_impl&) + { + return n; + } + + + namespace detail { + + //========================================================================= + // Adjacency List Generator + + template + struct adj_list_gen + { + typedef typename detail::is_random_access::type + is_rand_access; + typedef typename has_property::type has_edge_property; + typedef typename DirectedS::is_directed_t DirectedT; + typedef typename DirectedS::is_bidir_t BidirectionalT; + + struct config + { + typedef OutEdgeListS edgelist_selector; + typedef EdgeListS global_edgelist_selector; + + typedef Graph graph_type; + typedef EdgeProperty edge_property_type; + typedef VertexProperty vertex_property_type; + typedef GraphProperty graph_property_type; + typedef std::size_t vertices_size_type; + + typedef adjacency_list_traits + Traits; + + typedef typename Traits::directed_category directed_category; + typedef typename Traits::edge_parallel_category edge_parallel_category; + typedef typename Traits::vertex_descriptor vertex_descriptor; + typedef typename Traits::edge_descriptor edge_descriptor; + + typedef void* vertex_ptr; + + // need to reorganize this to avoid instantiating stuff + // that doesn't get used -JGS + + // VertexList and vertex_iterator + typedef typename container_gen::type SeqVertexList; + typedef boost::integer_range RandVertexList; + typedef typename mpl::if_::type VertexList; + + typedef typename VertexList::iterator vertex_iterator; + + // EdgeContainer and StoredEdge + + typedef typename container_gen >::type EdgeContainer; + + typedef typename mpl::and_::type >::type on_edge_storage; + + typedef typename mpl::if_::type edges_size_type; + + typedef typename EdgeContainer::iterator EdgeIter; + + typedef typename detail::is_random_access::type is_edge_ra; + + typedef typename mpl::if_, + typename mpl::if_, + stored_edge_iter + >::type + >::type StoredEdge; + + // Adjacency Types + + typedef typename container_gen::type + OutEdgeList; + typedef typename OutEdgeList::size_type degree_size_type; + typedef typename OutEdgeList::iterator OutEdgeIter; + + typedef boost::detail::iterator_traits OutEdgeIterTraits; + typedef typename OutEdgeIterTraits::iterator_category OutEdgeIterCat; + typedef typename OutEdgeIterTraits::difference_type OutEdgeIterDiff; + + typedef out_edge_iter< + OutEdgeIter, vertex_descriptor, edge_descriptor, OutEdgeIterDiff + > out_edge_iterator; + + typedef typename adjacency_iterator_generator::type adjacency_iterator; + + typedef OutEdgeList InEdgeList; + typedef OutEdgeIter InEdgeIter; + typedef OutEdgeIterCat InEdgeIterCat; + typedef OutEdgeIterDiff InEdgeIterDiff; + + typedef in_edge_iter< + InEdgeIter, vertex_descriptor, edge_descriptor, InEdgeIterDiff + > in_edge_iterator; + + typedef typename inv_adjacency_iterator_generator::type inv_adjacency_iterator; + + // Edge Iterator + + typedef boost::detail::iterator_traits EdgeIterTraits; + typedef typename EdgeIterTraits::iterator_category EdgeIterCat; + typedef typename EdgeIterTraits::difference_type EdgeIterDiff; + + typedef undirected_edge_iter< + EdgeIter + , edge_descriptor + , EdgeIterDiff + > UndirectedEdgeIter; // also used for bidirectional + + typedef adj_list_edge_iterator DirectedEdgeIter; + + typedef typename mpl::if_::type edge_iterator; + + // stored_vertex and StoredVertexList + typedef typename container_gen::type + SeqStoredVertexList; + struct seq_stored_vertex { + seq_stored_vertex() { } + seq_stored_vertex(const VertexProperty& p) : m_property(p) { } + OutEdgeList m_out_edges; + VertexProperty m_property; + typename SeqStoredVertexList::iterator m_position; + }; + struct bidir_seq_stored_vertex { + bidir_seq_stored_vertex() { } + bidir_seq_stored_vertex(const VertexProperty& p) : m_property(p) { } + OutEdgeList m_out_edges; + InEdgeList m_in_edges; + VertexProperty m_property; + typename SeqStoredVertexList::iterator m_position; + }; + struct rand_stored_vertex { + rand_stored_vertex() { } + rand_stored_vertex(const VertexProperty& p) : m_property(p) { } + OutEdgeList m_out_edges; + VertexProperty m_property; + }; + struct bidir_rand_stored_vertex { + bidir_rand_stored_vertex() { } + bidir_rand_stored_vertex(const VertexProperty& p) : m_property(p) { } + OutEdgeList m_out_edges; + InEdgeList m_in_edges; + VertexProperty m_property; + }; + typedef typename mpl::if_::type, + typename mpl::if_::type + >::type StoredVertex; + struct stored_vertex : public StoredVertex { + stored_vertex() { } + stored_vertex(const VertexProperty& p) : StoredVertex(p) { } + }; + + typedef typename container_gen::type + RandStoredVertexList; + typedef typename mpl::if_< is_rand_access, + RandStoredVertexList, SeqStoredVertexList>::type StoredVertexList; + }; // end of config + + + typedef typename mpl::if_, + typename mpl::if_, + undirected_graph_helper + >::type + >::type DirectedHelper; + + typedef typename mpl::if_, + adj_list_impl + >::type type; + + }; + + } // namespace detail + + //========================================================================= + // Vertex Property Maps + + template + struct adj_list_vertex_property_map + : public boost::put_get_helper< + Reference, + adj_list_vertex_property_map + > + { + typedef typename Graph::stored_vertex StoredVertex; + typedef ValueType value_type; + typedef Reference reference; + typedef typename Graph::vertex_descriptor key_type; + typedef boost::lvalue_property_map_tag category; + inline adj_list_vertex_property_map(const Graph* = 0, Tag tag = Tag()): m_tag(tag) { } + inline Reference operator[](key_type v) const { + StoredVertex* sv = (StoredVertex*)v; + return get_property_value(sv->m_property, m_tag); + } + inline Reference operator()(key_type v) const { + return this->operator[](v); + } + Tag m_tag; + }; + + template + struct adj_list_vertex_all_properties_map + : public boost::put_get_helper + > + { + typedef typename Graph::stored_vertex StoredVertex; + typedef Property value_type; + typedef PropRef reference; + typedef typename Graph::vertex_descriptor key_type; + typedef boost::lvalue_property_map_tag category; + inline adj_list_vertex_all_properties_map(const Graph* = 0, vertex_all_t = vertex_all_t()) { } + inline PropRef operator[](key_type v) const { + StoredVertex* sv = (StoredVertex*)v; + return sv->m_property; + } + inline PropRef operator()(key_type v) const { + return this->operator[](v); + } + }; + + template + struct vec_adj_list_vertex_property_map + : public boost::put_get_helper< + Reference, + vec_adj_list_vertex_property_map + > + { + typedef ValueType value_type; + typedef Reference reference; + typedef typename boost::graph_traits::vertex_descriptor key_type; + typedef boost::lvalue_property_map_tag category; + vec_adj_list_vertex_property_map(GraphPtr g = 0, Tag tag = Tag()) : m_g(g), m_tag(tag) { } + inline Reference operator[](key_type v) const { + return get_property_value(m_g->m_vertices[v].m_property, m_tag); + } + inline Reference operator()(key_type v) const { + return this->operator[](v); + } + GraphPtr m_g; + Tag m_tag; + }; + + template + struct vec_adj_list_vertex_all_properties_map + : public boost::put_get_helper + > + { + typedef Property value_type; + typedef PropertyRef reference; + typedef typename boost::graph_traits::vertex_descriptor key_type; + typedef boost::lvalue_property_map_tag category; + vec_adj_list_vertex_all_properties_map(GraphPtr g = 0, vertex_all_t = vertex_all_t()) : m_g(g) { } + inline PropertyRef operator[](key_type v) const { + return m_g->m_vertices[v].m_property; + } + inline PropertyRef operator()(key_type v) const { + return this->operator[](v); + } + GraphPtr m_g; + }; + + struct adj_list_any_vertex_pa { + template + struct bind_ { + typedef typename property_value::type value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + + typedef adj_list_vertex_property_map + type; + typedef adj_list_vertex_property_map + const_type; + }; + }; + struct adj_list_all_vertex_pa { + template + struct bind_ { + typedef typename Graph::vertex_descriptor Vertex; + typedef adj_list_vertex_all_properties_map type; + typedef adj_list_vertex_all_properties_map const_type; + }; + }; + + template + struct vec_adj_list_vertex_id_map + : public boost::put_get_helper< + Vertex, vec_adj_list_vertex_id_map + > + { + typedef Vertex value_type; + typedef Vertex key_type; + typedef Vertex reference; + typedef boost::readable_property_map_tag category; + inline vec_adj_list_vertex_id_map() { } + template + inline vec_adj_list_vertex_id_map(const Graph&, vertex_index_t) { } + inline value_type operator[](key_type v) const { return v; } + inline value_type operator()(key_type v) const { return v; } + }; + + struct vec_adj_list_any_vertex_pa { + template + struct bind_ { + typedef typename property_value::type value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + + typedef vec_adj_list_vertex_property_map + type; + typedef vec_adj_list_vertex_property_map + const_type; + }; + }; + struct vec_adj_list_id_vertex_pa { + template + struct bind_ { + typedef typename Graph::vertex_descriptor Vertex; + typedef vec_adj_list_vertex_id_map type; + typedef vec_adj_list_vertex_id_map const_type; + }; + }; + struct vec_adj_list_all_vertex_pa { + template + struct bind_ { + typedef typename Graph::vertex_descriptor Vertex; + typedef vec_adj_list_vertex_all_properties_map + type; + typedef vec_adj_list_vertex_all_properties_map + const_type; + }; + }; + namespace detail { + template + struct adj_list_choose_vertex_pa + : boost::mpl::if_< + boost::is_same, + adj_list_all_vertex_pa, + adj_list_any_vertex_pa>::type + ::template bind_ + {}; + + + template + struct vec_adj_list_choose_vertex_pa_helper { + typedef vec_adj_list_any_vertex_pa type; + }; + template <> + struct vec_adj_list_choose_vertex_pa_helper { + typedef vec_adj_list_id_vertex_pa type; + }; + template <> + struct vec_adj_list_choose_vertex_pa_helper { + typedef vec_adj_list_all_vertex_pa type; + }; + template + struct vec_adj_list_choose_vertex_pa + : vec_adj_list_choose_vertex_pa_helper::type::template bind_ + {}; + } // namespace detail + + //========================================================================= + // Edge Property Map + + template + struct adj_list_edge_property_map + : public put_get_helper< + Ref, + adj_list_edge_property_map + > + { + Tag tag; + explicit adj_list_edge_property_map(Tag tag = Tag()): tag(tag) {} + + typedef Value value_type; + typedef Ref reference; + typedef detail::edge_desc_impl key_type; + typedef boost::lvalue_property_map_tag category; + inline Ref operator[](key_type e) const { + Property& p = *(Property*)e.get_property(); + return get_property_value(p, tag); + } + inline Ref operator()(key_type e) const { + return this->operator[](e); + } + }; + + template + struct adj_list_edge_all_properties_map + : public put_get_helper + > + { + explicit adj_list_edge_all_properties_map(edge_all_t = edge_all_t()) {} + typedef Property value_type; + typedef PropRef reference; + typedef detail::edge_desc_impl key_type; + typedef boost::lvalue_property_map_tag category; + inline PropRef operator[](key_type e) const { + return *(PropPtr)e.get_property(); + } + inline PropRef operator()(key_type e) const { + return this->operator[](e); + } + }; + + // Edge Property Maps + + namespace detail { + struct adj_list_any_edge_pmap { + template + struct bind_ { + typedef typename property_value::type value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + + typedef adj_list_edge_property_map + type; + typedef adj_list_edge_property_map + const_type; + }; + }; + struct adj_list_all_edge_pmap { + template + struct bind_ { + typedef adj_list_edge_all_properties_map + type; + typedef adj_list_edge_all_properties_map + const_type; + }; + }; + + template + struct adj_list_choose_edge_pmap_helper { + typedef adj_list_any_edge_pmap type; + }; + template <> + struct adj_list_choose_edge_pmap_helper { + typedef adj_list_all_edge_pmap type; + }; + template + struct adj_list_choose_edge_pmap + : adj_list_choose_edge_pmap_helper::type::template bind_ + {}; + struct adj_list_edge_property_selector { + template + struct bind_: adj_list_choose_edge_pmap {}; + }; + } // namespace detail + + template <> + struct edge_property_selector { + typedef detail::adj_list_edge_property_selector type; + }; + template <> + struct edge_property_selector { + typedef detail::adj_list_edge_property_selector type; + }; + + // Vertex Property Maps + + struct adj_list_vertex_property_selector { + template + struct bind_ + : detail::adj_list_choose_vertex_pa + {}; + }; + template <> + struct vertex_property_selector { + typedef adj_list_vertex_property_selector type; + }; + + struct vec_adj_list_vertex_property_selector { + template + struct bind_: detail::vec_adj_list_choose_vertex_pa {}; + }; + template <> + struct vertex_property_selector { + typedef vec_adj_list_vertex_property_selector type; + }; + +} // namespace boost + +namespace boost { + + template + struct hash< boost::detail::stored_edge > + { + std::size_t + operator()(const boost::detail::stored_edge& e) const + { + return hash()(e.m_target); + } + }; + + template + struct hash< boost::detail::stored_edge_property > + { + std::size_t + operator()(const boost::detail::stored_edge_property& e) const + { + return hash()(e.m_target); + } + }; + + template + struct hash< boost::detail::stored_edge_iter > + { + std::size_t + operator()(const boost::detail::stored_edge_iter& e) const + { + return hash()(e.m_target); + } + }; + +} + + +#endif // BOOST_GRAPH_DETAIL_DETAIL_ADJACENCY_LIST_CCT + +/* + Implementation Notes: + + Many of the public interface functions in this file would have been + more conveniently implemented as inline friend functions. + However there are a few compiler bugs that make that approach + non-portable. + + 1. g++ inline friend in namespace bug + 2. g++ using clause doesn't work with inline friends + 3. VC++ doesn't have Koenig lookup + + For these reasons, the functions were all written as non-inline free + functions, and static cast was used to convert from the helper + class to the adjacency_list derived class. + + Looking back, it might have been better to write out all functions + in terms of the adjacency_list, and then use a tag to dispatch + to the various helpers instead of using inheritance. + + */ diff --git a/src/external/3rd/library/boost/boost/iostreams/chain.hpp b/src/external/3rd/library/boost/boost/iostreams/chain.hpp index adbd657e2..b78e5d722 100644 --- a/src/external/3rd/library/boost/boost/iostreams/chain.hpp +++ b/src/external/3rd/library/boost/boost/iostreams/chain.hpp @@ -1,598 +1,598 @@ -// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) -// (C) Copyright 2003-2007 Jonathan Turkanis -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) - -// See http://www.boost.org/libs/iostreams for documentation. - -#ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED -#define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include -#include // unary_function. -#include // advance. -#include -#include // allocator, unique_ptr. -#include -#include // logic_error, out_of_range. -#include -#include // BOOST_MSVC, template friends, -#include // BOOST_NESTED_TEMPLATE -#include -#include -#include -#include -#include // pubsync. -#include -#include -#include -#include // is_filter. -#include -#include -#include -#include -#include -#include -#include -#include // VC6.5 requires this -#if BOOST_WORKAROUND(BOOST_MSVC, < 1310) // #include order -# include -#endif - -// Sometimes type_info objects must be compared by name. Borrowed from -// Boost.Python and Boost.Function. -#if (defined(__GNUC__) && __GNUC__ >= 3) || \ - defined(_AIX) || \ - (defined(__sgi) && defined(__host_mips)) || \ - (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \ - /**/ -# include -# define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \ - (std::strcmp((X).name(),(Y).name()) == 0) -#else -# define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) -#endif - -// Deprecated -#define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \ - chain.component_type( index ) \ - /**/ - -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) -# define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \ - chain.component< target >( index ) \ - /**/ -#else -# define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \ - chain.component( index, ::boost::type< target >() ) \ - /**/ -#endif - -namespace boost { namespace iostreams { - -//--------------Definition of chain and wchain--------------------------------// - -namespace detail { - -template class chain_client; - -// -// Concept name: Chain. -// Description: Represents a chain of stream buffers which provides access -// to the first buffer in the chain and sends notifications when the -// streambufs are added to or removed from chain. -// Refines: Closable device with mode equal to typename Chain::mode. -// Models: chain, converting_chain. -// Example: -// -// class chain { -// public: -// typedef xxx chain_type; -// typedef xxx client_type; -// typedef xxx mode; -// bool is_complete() const; // Ready for i/o. -// template -// void push( const T& t, // Adds a stream buffer to -// streamsize, // chain, based on t, with -// streamsize ); // given buffer and putback -// // buffer sizes. Pass -1 to -// // request default size. -// protected: -// void register_client(client_type* client); // Associate client. -// void notify(); // Notify client. -// }; -// - -// -// Description: Represents a chain of filters with an optional device at the -// end. -// Template parameters: -// Self - A class deriving from the current instantiation of this template. -// This is an example of the Curiously Recurring Template Pattern. -// Ch - The character type. -// Tr - The character traits type. -// Alloc - The allocator type. -// Mode - A mode tag. -// -template -class chain_base { -public: - typedef Ch char_type; - BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr) - typedef Alloc allocator_type; - typedef Mode mode; - struct category - : Mode, - device_tag - { }; - typedef chain_client client_type; - friend class chain_client; -private: - typedef linked_streambuf streambuf_type; - typedef std::list list_type; - typedef chain_base my_type; -protected: - chain_base() : pimpl_(new chain_impl) { } - chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { } -public: - - // dual_use is a pseudo-mode to facilitate filter writing, - // not a genuine mode. - BOOST_STATIC_ASSERT((!is_convertible::value)); - - //----------Buffer sizing-------------------------------------------------// - - // Sets the size of the buffer created for the devices to be added to this - // chain. Does not affect the size of the buffer for devices already - // added. - void set_device_buffer_size(std::streamsize n) - { pimpl_->device_buffer_size_ = n; } - - // Sets the size of the buffer created for the filters to be added - // to this chain. Does not affect the size of the buffer for filters already - // added. - void set_filter_buffer_size(std::streamsize n) - { pimpl_->filter_buffer_size_ = n; } - - // Sets the size of the putback buffer for filters and devices to be added - // to this chain. Does not affect the size of the buffer for filters or - // devices already added. - void set_pback_size(std::streamsize n) - { pimpl_->pback_size_ = n; } - - //----------Device interface----------------------------------------------// - - std::streamsize read(char_type* s, std::streamsize n); - std::streamsize write(const char_type* s, std::streamsize n); - std::streampos seek(stream_offset off, BOOST_IOS::seekdir way); - - //----------Direct component access---------------------------------------// - - const std::type_info& component_type(int n) const - { - if (static_cast(n) >= size()) - boost::throw_exception(std::out_of_range("bad chain offset")); - return (*boost::next(list().begin(), n))->component_type(); - } - -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) - // Deprecated. - template - const std::type_info& component_type() const { return component_type(N); } - - template - T* component(int n) const { return component(n, boost::type()); } - - // Deprecated. - template - T* component() const { return component(N); } -#endif - -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) - private: -#endif - template - T* component(int n, boost::type) const - { - if (static_cast(n) >= size()) - boost::throw_exception(std::out_of_range("bad chain offset")); - streambuf_type* link = *boost::next(list().begin(), n); - if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T))) - return static_cast(link->component_impl()); - else - return 0; - } -public: - - //----------Container-like interface--------------------------------------// - - typedef typename list_type::size_type size_type; - streambuf_type& front() { return *list().front(); } - BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl) - void pop(); - bool empty() const { return list().empty(); } - size_type size() const { return list().size(); } - void reset(); - - //----------Additional i/o functions--------------------------------------// - - // Returns true if this chain is non-empty and its final link - // is a source or sink, i.e., if it is ready to perform i/o. - bool is_complete() const; - bool auto_close() const; - void set_auto_close(bool close); - bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; } - bool strict_sync(); -private: - template - void push_impl(const T& t, std::streamsize buffer_size = -1, - std::streamsize pback_size = -1) - { - typedef typename iostreams::category_of::type category; - typedef typename unwrap_ios::type component_type; - typedef stream_buffer< - component_type, - BOOST_IOSTREAMS_CHAR_TRAITS(char_type), - Alloc, Mode - > streambuf_t; - typedef typename list_type::iterator iterator; - BOOST_STATIC_ASSERT((is_convertible::value)); - if (is_complete()) - boost::throw_exception(std::logic_error("chain complete")); - streambuf_type* prev = !empty() ? list().back() : 0; - buffer_size = - buffer_size != -1 ? - buffer_size : - iostreams::optimal_buffer_size(t); - pback_size = - pback_size != -1 ? - pback_size : - pimpl_->pback_size_; - std::unique_ptr - buf(new streambuf_t(t, buffer_size, pback_size)); - list().push_back(buf.get()); - buf.release(); - if (is_device::value) { - pimpl_->flags_ |= f_complete | f_open; - for ( iterator first = list().begin(), - last = list().end(); - first != last; - ++first ) - { - (*first)->set_needs_close(); - } - } - if (prev) prev->set_next(list().back()); - notify(); - } - - list_type& list() { return pimpl_->links_; } - const list_type& list() const { return pimpl_->links_; } - void register_client(client_type* client) { pimpl_->client_ = client; } - void notify() { if (pimpl_->client_) pimpl_->client_->notify(); } - - //----------Nested classes------------------------------------------------// - - static void close(streambuf_type* b, BOOST_IOS::openmode m) - { - if (m == BOOST_IOS::out && is_convertible::value) - b->BOOST_IOSTREAMS_PUBSYNC(); - b->close(m); - } - - static void set_next(streambuf_type* b, streambuf_type* next) - { b->set_next(next); } - - static void set_auto_close(streambuf_type* b, bool close) - { b->set_auto_close(close); } - - struct closer : public std::unary_function { - closer(BOOST_IOS::openmode m) : mode_(m) { } - void operator() (streambuf_type* b) - { - close(b, mode_); - } - BOOST_IOS::openmode mode_; - }; - friend struct closer; - - enum flags { - f_complete = 1, - f_open = 2, - f_auto_close = 4 - }; - - struct chain_impl { - chain_impl() - : client_(0), device_buffer_size_(default_device_buffer_size), - filter_buffer_size_(default_filter_buffer_size), - pback_size_(default_pback_buffer_size), - flags_(f_auto_close) - { } - ~chain_impl() - { - try { close(); } catch (...) { } - try { reset(); } catch (...) { } - } - void close() - { - if ((flags_ & f_open) != 0) { - flags_ &= ~f_open; - stream_buffer< basic_null_device > null; - if ((flags_ & f_complete) == 0) { - null.open(basic_null_device()); - set_next(links_.back(), &null); - } - links_.front()->BOOST_IOSTREAMS_PUBSYNC(); - try { - boost::iostreams::detail::execute_foreach( - links_.rbegin(), links_.rend(), - closer(BOOST_IOS::in) - ); - } catch (...) { - try { - boost::iostreams::detail::execute_foreach( - links_.begin(), links_.end(), - closer(BOOST_IOS::out) - ); - } catch (...) { } - throw; - } - boost::iostreams::detail::execute_foreach( - links_.begin(), links_.end(), - closer(BOOST_IOS::out) - ); - } - } - void reset() - { - typedef typename list_type::iterator iterator; - for ( iterator first = links_.begin(), - last = links_.end(); - first != last; - ++first ) - { - if ( (flags_ & f_complete) == 0 || - (flags_ & f_auto_close) == 0 ) - { - set_auto_close(*first, false); - } - streambuf_type* buf = 0; - std::swap(buf, *first); - delete buf; - } - links_.clear(); - flags_ &= ~f_complete; - flags_ &= ~f_open; - } - list_type links_; - client_type* client_; - std::streamsize device_buffer_size_, - filter_buffer_size_, - pback_size_; - int flags_; - }; - friend struct chain_impl; - - //----------Member data---------------------------------------------------// - -private: - shared_ptr pimpl_; -}; - -} // End namespace detail. - -// -// Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category) -// Description: Defines a template derived from chain_base appropriate for a -// particular i/o category. The template has the following parameters: -// Ch - The character type. -// Tr - The character traits type. -// Alloc - The allocator type. -// Macro parameters: -// name_ - The name of the template to be defined. -// category_ - The i/o category of the template to be defined. -// -#define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \ - template< typename Mode, typename Ch = default_char_, \ - typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \ - typename Alloc = std::allocator > \ - class name_ : public boost::iostreams::detail::chain_base< \ - name_, \ - Ch, Tr, Alloc, Mode \ - > \ - { \ - public: \ - struct category : device_tag, Mode { }; \ - typedef Mode mode; \ - private: \ - typedef boost::iostreams::detail::chain_base< \ - name_, \ - Ch, Tr, Alloc, Mode \ - > base_type; \ - public: \ - typedef Ch char_type; \ - typedef Tr traits_type; \ - typedef typename traits_type::int_type int_type; \ - typedef typename traits_type::off_type off_type; \ - name_() { } \ - name_(const name_& rhs) : base_type(rhs) { } \ - name_& operator=(const name_& rhs) \ - { base_type::operator=(rhs); return *this; } \ - }; \ - /**/ -BOOST_IOSTREAMS_DECL_CHAIN(chain, char) -BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t) -#undef BOOST_IOSTREAMS_DECL_CHAIN - -//--------------Definition of chain_client------------------------------------// - -namespace detail { - -// -// Template name: chain_client -// Description: Class whose instances provide access to an underlying chain -// using an interface similar to the chains. -// Subclasses: the various stream and stream buffer templates. -// -template -class chain_client { -public: - typedef Chain chain_type; - typedef typename chain_type::char_type char_type; - typedef typename chain_type::traits_type traits_type; - typedef typename chain_type::size_type size_type; - typedef typename chain_type::mode mode; - - chain_client(chain_type* chn = 0) : chain_(chn ) { } - chain_client(chain_client* client) : chain_(client->chain_) { } - virtual ~chain_client() { } - - const std::type_info& component_type(int n) const - { return chain_->component_type(n); } - -#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) - // Deprecated. - template - const std::type_info& component_type() const - { return chain_->BOOST_NESTED_TEMPLATE component_type(); } - - template - T* component(int n) const - { return chain_->BOOST_NESTED_TEMPLATE component(n); } - - // Deprecated. - template - T* component() const - { return chain_->BOOST_NESTED_TEMPLATE component(); } -#else - template - T* component(int n, boost::type t) const - { return chain_->component(n, t); } -#endif - - bool is_complete() const { return chain_->is_complete(); } - bool auto_close() const { return chain_->auto_close(); } - void set_auto_close(bool close) { chain_->set_auto_close(close); } - bool strict_sync() { return chain_->strict_sync(); } - void set_device_buffer_size(std::streamsize n) - { chain_->set_device_buffer_size(n); } - void set_filter_buffer_size(std::streamsize n) - { chain_->set_filter_buffer_size(n); } - void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); } - BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl) - void pop() { chain_->pop(); } - bool empty() const { return chain_->empty(); } - size_type size() { return chain_->size(); } - void reset() { chain_->reset(); } - - // Returns a copy of the underlying chain. - chain_type filters() { return *chain_; } - chain_type filters() const { return *chain_; } -protected: - template - void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS()) - { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); } - chain_type& ref() { return *chain_; } - void set_chain(chain_type* c) - { chain_ = c; chain_->register_client(this); } -#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \ - (!BOOST_WORKAROUND(__BORLANDC__, < 0x600)) - template - friend class chain_base; -#else - public: -#endif - virtual void notify() { } -private: - chain_type* chain_; -}; - -//--------------Implementation of chain_base----------------------------------// - -template -inline std::streamsize chain_base::read - (char_type* s, std::streamsize n) -{ return iostreams::read(*list().front(), s, n); } - -template -inline std::streamsize chain_base::write - (const char_type* s, std::streamsize n) -{ return iostreams::write(*list().front(), s, n); } - -template -inline std::streampos chain_base::seek - (stream_offset off, BOOST_IOS::seekdir way) -{ return iostreams::seek(*list().front(), off, way); } - -template -void chain_base::reset() -{ - using namespace std; - pimpl_->close(); - pimpl_->reset(); -} - -template -bool chain_base::is_complete() const -{ - return (pimpl_->flags_ & f_complete) != 0; -} - -template -bool chain_base::auto_close() const -{ - return (pimpl_->flags_ & f_auto_close) != 0; -} - -template -void chain_base::set_auto_close(bool close) -{ - pimpl_->flags_ = - (pimpl_->flags_ & ~f_auto_close) | - (close ? f_auto_close : 0); -} - -template -bool chain_base::strict_sync() -{ - typedef typename list_type::iterator iterator; - bool result = true; - for ( iterator first = list().begin(), - last = list().end(); - first != last; - ++first ) - { - bool s = (*first)->strict_sync(); - result = result && s; - } - return result; -} - -template -void chain_base::pop() -{ - BOOST_ASSERT(!empty()); - if (auto_close()) - pimpl_->close(); - streambuf_type* buf = 0; - std::swap(buf, list().back()); - buf->set_auto_close(false); - buf->set_next(0); - delete buf; - list().pop_back(); - pimpl_->flags_ &= ~f_complete; - if (auto_close() || list().empty()) - pimpl_->flags_ &= ~f_open; -} - -} // End namespace detail. - -} } // End namespaces iostreams, boost. - -#endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2003-2007 Jonathan Turkanis +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) + +// See http://www.boost.org/libs/iostreams for documentation. + +#ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED +#define BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include +#include // unary_function. +#include // advance. +#include +#include // allocator, unique_ptr. +#include +#include // logic_error, out_of_range. +#include +#include // BOOST_MSVC, template friends, +#include // BOOST_NESTED_TEMPLATE +#include +#include +#include +#include +#include // pubsync. +#include +#include +#include +#include // is_filter. +#include +#include +#include +#include +#include +#include +#include +#include // VC6.5 requires this +#if BOOST_WORKAROUND(BOOST_MSVC, < 1310) // #include order +# include +#endif + +// Sometimes type_info objects must be compared by name. Borrowed from +// Boost.Python and Boost.Function. +#if (defined(__GNUC__) && __GNUC__ >= 3) || \ + defined(_AIX) || \ + (defined(__sgi) && defined(__host_mips)) || \ + (defined(linux) && defined(__INTEL_COMPILER) && defined(__ICC)) \ + /**/ +# include +# define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) \ + (std::strcmp((X).name(),(Y).name()) == 0) +#else +# define BOOST_IOSTREAMS_COMPARE_TYPE_ID(X,Y) ((X)==(Y)) +#endif + +// Deprecated +#define BOOST_IOSTREAMS_COMPONENT_TYPE(chain, index) \ + chain.component_type( index ) \ + /**/ + +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) +# define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \ + chain.component< target >( index ) \ + /**/ +#else +# define BOOST_IOSTREAMS_COMPONENT(chain, index, target) \ + chain.component( index, ::boost::type< target >() ) \ + /**/ +#endif + +namespace boost { namespace iostreams { + +//--------------Definition of chain and wchain--------------------------------// + +namespace detail { + +template class chain_client; + +// +// Concept name: Chain. +// Description: Represents a chain of stream buffers which provides access +// to the first buffer in the chain and sends notifications when the +// streambufs are added to or removed from chain. +// Refines: Closable device with mode equal to typename Chain::mode. +// Models: chain, converting_chain. +// Example: +// +// class chain { +// public: +// typedef xxx chain_type; +// typedef xxx client_type; +// typedef xxx mode; +// bool is_complete() const; // Ready for i/o. +// template +// void push( const T& t, // Adds a stream buffer to +// streamsize, // chain, based on t, with +// streamsize ); // given buffer and putback +// // buffer sizes. Pass -1 to +// // request default size. +// protected: +// void register_client(client_type* client); // Associate client. +// void notify(); // Notify client. +// }; +// + +// +// Description: Represents a chain of filters with an optional device at the +// end. +// Template parameters: +// Self - A class deriving from the current instantiation of this template. +// This is an example of the Curiously Recurring Template Pattern. +// Ch - The character type. +// Tr - The character traits type. +// Alloc - The allocator type. +// Mode - A mode tag. +// +template +class chain_base { +public: + typedef Ch char_type; + BOOST_IOSTREAMS_STREAMBUF_TYPEDEFS(Tr) + typedef Alloc allocator_type; + typedef Mode mode; + struct category + : Mode, + device_tag + { }; + typedef chain_client client_type; + friend class chain_client; +private: + typedef linked_streambuf streambuf_type; + typedef std::list list_type; + typedef chain_base my_type; +protected: + chain_base() : pimpl_(new chain_impl) { } + chain_base(const chain_base& rhs): pimpl_(rhs.pimpl_) { } +public: + + // dual_use is a pseudo-mode to facilitate filter writing, + // not a genuine mode. + BOOST_STATIC_ASSERT((!is_convertible::value)); + + //----------Buffer sizing-------------------------------------------------// + + // Sets the size of the buffer created for the devices to be added to this + // chain. Does not affect the size of the buffer for devices already + // added. + void set_device_buffer_size(std::streamsize n) + { pimpl_->device_buffer_size_ = n; } + + // Sets the size of the buffer created for the filters to be added + // to this chain. Does not affect the size of the buffer for filters already + // added. + void set_filter_buffer_size(std::streamsize n) + { pimpl_->filter_buffer_size_ = n; } + + // Sets the size of the putback buffer for filters and devices to be added + // to this chain. Does not affect the size of the buffer for filters or + // devices already added. + void set_pback_size(std::streamsize n) + { pimpl_->pback_size_ = n; } + + //----------Device interface----------------------------------------------// + + std::streamsize read(char_type* s, std::streamsize n); + std::streamsize write(const char_type* s, std::streamsize n); + std::streampos seek(stream_offset off, BOOST_IOS::seekdir way); + + //----------Direct component access---------------------------------------// + + const std::type_info& component_type(int n) const + { + if (static_cast(n) >= size()) + boost::throw_exception(std::out_of_range("bad chain offset")); + return (*boost::next(list().begin(), n))->component_type(); + } + +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) + // Deprecated. + template + const std::type_info& component_type() const { return component_type(N); } + + template + T* component(int n) const { return component(n, boost::type()); } + + // Deprecated. + template + T* component() const { return component(N); } +#endif + +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) + private: +#endif + template + T* component(int n, boost::type) const + { + if (static_cast(n) >= size()) + boost::throw_exception(std::out_of_range("bad chain offset")); + streambuf_type* link = *boost::next(list().begin(), n); + if (BOOST_IOSTREAMS_COMPARE_TYPE_ID(link->component_type(), typeid(T))) + return static_cast(link->component_impl()); + else + return 0; + } +public: + + //----------Container-like interface--------------------------------------// + + typedef typename list_type::size_type size_type; + streambuf_type& front() { return *list().front(); } + BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl) + void pop(); + bool empty() const { return list().empty(); } + size_type size() const { return list().size(); } + void reset(); + + //----------Additional i/o functions--------------------------------------// + + // Returns true if this chain is non-empty and its final link + // is a source or sink, i.e., if it is ready to perform i/o. + bool is_complete() const; + bool auto_close() const; + void set_auto_close(bool close); + bool sync() { return front().BOOST_IOSTREAMS_PUBSYNC() != -1; } + bool strict_sync(); +private: + template + void push_impl(const T& t, std::streamsize buffer_size = -1, + std::streamsize pback_size = -1) + { + typedef typename iostreams::category_of::type category; + typedef typename unwrap_ios::type component_type; + typedef stream_buffer< + component_type, + BOOST_IOSTREAMS_CHAR_TRAITS(char_type), + Alloc, Mode + > streambuf_t; + typedef typename list_type::iterator iterator; + BOOST_STATIC_ASSERT((is_convertible::value)); + if (is_complete()) + boost::throw_exception(std::logic_error("chain complete")); + streambuf_type* prev = !empty() ? list().back() : 0; + buffer_size = + buffer_size != -1 ? + buffer_size : + iostreams::optimal_buffer_size(t); + pback_size = + pback_size != -1 ? + pback_size : + pimpl_->pback_size_; + std::unique_ptr + buf(new streambuf_t(t, buffer_size, pback_size)); + list().push_back(buf.get()); + buf.release(); + if (is_device::value) { + pimpl_->flags_ |= f_complete | f_open; + for ( iterator first = list().begin(), + last = list().end(); + first != last; + ++first ) + { + (*first)->set_needs_close(); + } + } + if (prev) prev->set_next(list().back()); + notify(); + } + + list_type& list() { return pimpl_->links_; } + const list_type& list() const { return pimpl_->links_; } + void register_client(client_type* client) { pimpl_->client_ = client; } + void notify() { if (pimpl_->client_) pimpl_->client_->notify(); } + + //----------Nested classes------------------------------------------------// + + static void close(streambuf_type* b, BOOST_IOS::openmode m) + { + if (m == BOOST_IOS::out && is_convertible::value) + b->BOOST_IOSTREAMS_PUBSYNC(); + b->close(m); + } + + static void set_next(streambuf_type* b, streambuf_type* next) + { b->set_next(next); } + + static void set_auto_close(streambuf_type* b, bool close) + { b->set_auto_close(close); } + + struct closer : public std::unary_function { + closer(BOOST_IOS::openmode m) : mode_(m) { } + void operator() (streambuf_type* b) + { + close(b, mode_); + } + BOOST_IOS::openmode mode_; + }; + friend struct closer; + + enum flags { + f_complete = 1, + f_open = 2, + f_auto_close = 4 + }; + + struct chain_impl { + chain_impl() + : client_(0), device_buffer_size_(default_device_buffer_size), + filter_buffer_size_(default_filter_buffer_size), + pback_size_(default_pback_buffer_size), + flags_(f_auto_close) + { } + ~chain_impl() + { + try { close(); } catch (...) { } + try { reset(); } catch (...) { } + } + void close() + { + if ((flags_ & f_open) != 0) { + flags_ &= ~f_open; + stream_buffer< basic_null_device > null; + if ((flags_ & f_complete) == 0) { + null.open(basic_null_device()); + set_next(links_.back(), &null); + } + links_.front()->BOOST_IOSTREAMS_PUBSYNC(); + try { + boost::iostreams::detail::execute_foreach( + links_.rbegin(), links_.rend(), + closer(BOOST_IOS::in) + ); + } catch (...) { + try { + boost::iostreams::detail::execute_foreach( + links_.begin(), links_.end(), + closer(BOOST_IOS::out) + ); + } catch (...) { } + throw; + } + boost::iostreams::detail::execute_foreach( + links_.begin(), links_.end(), + closer(BOOST_IOS::out) + ); + } + } + void reset() + { + typedef typename list_type::iterator iterator; + for ( iterator first = links_.begin(), + last = links_.end(); + first != last; + ++first ) + { + if ( (flags_ & f_complete) == 0 || + (flags_ & f_auto_close) == 0 ) + { + set_auto_close(*first, false); + } + streambuf_type* buf = 0; + std::swap(buf, *first); + delete buf; + } + links_.clear(); + flags_ &= ~f_complete; + flags_ &= ~f_open; + } + list_type links_; + client_type* client_; + std::streamsize device_buffer_size_, + filter_buffer_size_, + pback_size_; + int flags_; + }; + friend struct chain_impl; + + //----------Member data---------------------------------------------------// + +private: + shared_ptr pimpl_; +}; + +} // End namespace detail. + +// +// Macro: BOOST_IOSTREAMS_DECL_CHAIN(name, category) +// Description: Defines a template derived from chain_base appropriate for a +// particular i/o category. The template has the following parameters: +// Ch - The character type. +// Tr - The character traits type. +// Alloc - The allocator type. +// Macro parameters: +// name_ - The name of the template to be defined. +// category_ - The i/o category of the template to be defined. +// +#define BOOST_IOSTREAMS_DECL_CHAIN(name_, default_char_) \ + template< typename Mode, typename Ch = default_char_, \ + typename Tr = BOOST_IOSTREAMS_CHAR_TRAITS(Ch), \ + typename Alloc = std::allocator > \ + class name_ : public boost::iostreams::detail::chain_base< \ + name_, \ + Ch, Tr, Alloc, Mode \ + > \ + { \ + public: \ + struct category : device_tag, Mode { }; \ + typedef Mode mode; \ + private: \ + typedef boost::iostreams::detail::chain_base< \ + name_, \ + Ch, Tr, Alloc, Mode \ + > base_type; \ + public: \ + typedef Ch char_type; \ + typedef Tr traits_type; \ + typedef typename traits_type::int_type int_type; \ + typedef typename traits_type::off_type off_type; \ + name_() { } \ + name_(const name_& rhs) : base_type(rhs) { } \ + name_& operator=(const name_& rhs) \ + { base_type::operator=(rhs); return *this; } \ + }; \ + /**/ +BOOST_IOSTREAMS_DECL_CHAIN(chain, char) +BOOST_IOSTREAMS_DECL_CHAIN(wchain, wchar_t) +#undef BOOST_IOSTREAMS_DECL_CHAIN + +//--------------Definition of chain_client------------------------------------// + +namespace detail { + +// +// Template name: chain_client +// Description: Class whose instances provide access to an underlying chain +// using an interface similar to the chains. +// Subclasses: the various stream and stream buffer templates. +// +template +class chain_client { +public: + typedef Chain chain_type; + typedef typename chain_type::char_type char_type; + typedef typename chain_type::traits_type traits_type; + typedef typename chain_type::size_type size_type; + typedef typename chain_type::mode mode; + + chain_client(chain_type* chn = 0) : chain_(chn ) { } + chain_client(chain_client* client) : chain_(client->chain_) { } + virtual ~chain_client() { } + + const std::type_info& component_type(int n) const + { return chain_->component_type(n); } + +#if !BOOST_WORKAROUND(BOOST_MSVC, < 1310) + // Deprecated. + template + const std::type_info& component_type() const + { return chain_->BOOST_NESTED_TEMPLATE component_type(); } + + template + T* component(int n) const + { return chain_->BOOST_NESTED_TEMPLATE component(n); } + + // Deprecated. + template + T* component() const + { return chain_->BOOST_NESTED_TEMPLATE component(); } +#else + template + T* component(int n, boost::type t) const + { return chain_->component(n, t); } +#endif + + bool is_complete() const { return chain_->is_complete(); } + bool auto_close() const { return chain_->auto_close(); } + void set_auto_close(bool close) { chain_->set_auto_close(close); } + bool strict_sync() { return chain_->strict_sync(); } + void set_device_buffer_size(std::streamsize n) + { chain_->set_device_buffer_size(n); } + void set_filter_buffer_size(std::streamsize n) + { chain_->set_filter_buffer_size(n); } + void set_pback_size(std::streamsize n) { chain_->set_pback_size(n); } + BOOST_IOSTREAMS_DEFINE_PUSH(push, mode, char_type, push_impl) + void pop() { chain_->pop(); } + bool empty() const { return chain_->empty(); } + size_type size() { return chain_->size(); } + void reset() { chain_->reset(); } + + // Returns a copy of the underlying chain. + chain_type filters() { return *chain_; } + chain_type filters() const { return *chain_; } +protected: + template + void push_impl(const T& t BOOST_IOSTREAMS_PUSH_PARAMS()) + { chain_->push(t BOOST_IOSTREAMS_PUSH_ARGS()); } + chain_type& ref() { return *chain_; } + void set_chain(chain_type* c) + { chain_ = c; chain_->register_client(this); } +#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) && \ + (!BOOST_WORKAROUND(__BORLANDC__, < 0x600)) + template + friend class chain_base; +#else + public: +#endif + virtual void notify() { } +private: + chain_type* chain_; +}; + +//--------------Implementation of chain_base----------------------------------// + +template +inline std::streamsize chain_base::read + (char_type* s, std::streamsize n) +{ return iostreams::read(*list().front(), s, n); } + +template +inline std::streamsize chain_base::write + (const char_type* s, std::streamsize n) +{ return iostreams::write(*list().front(), s, n); } + +template +inline std::streampos chain_base::seek + (stream_offset off, BOOST_IOS::seekdir way) +{ return iostreams::seek(*list().front(), off, way); } + +template +void chain_base::reset() +{ + using namespace std; + pimpl_->close(); + pimpl_->reset(); +} + +template +bool chain_base::is_complete() const +{ + return (pimpl_->flags_ & f_complete) != 0; +} + +template +bool chain_base::auto_close() const +{ + return (pimpl_->flags_ & f_auto_close) != 0; +} + +template +void chain_base::set_auto_close(bool close) +{ + pimpl_->flags_ = + (pimpl_->flags_ & ~f_auto_close) | + (close ? f_auto_close : 0); +} + +template +bool chain_base::strict_sync() +{ + typedef typename list_type::iterator iterator; + bool result = true; + for ( iterator first = list().begin(), + last = list().end(); + first != last; + ++first ) + { + bool s = (*first)->strict_sync(); + result = result && s; + } + return result; +} + +template +void chain_base::pop() +{ + BOOST_ASSERT(!empty()); + if (auto_close()) + pimpl_->close(); + streambuf_type* buf = 0; + std::swap(buf, list().back()); + buf->set_auto_close(false); + buf->set_next(0); + delete buf; + list().pop_back(); + pimpl_->flags_ &= ~f_complete; + if (auto_close() || list().empty()) + pimpl_->flags_ &= ~f_open; +} + +} // End namespace detail. + +} } // End namespaces iostreams, boost. + +#endif // #ifndef BOOST_IOSTREAMS_DETAIL_CHAIN_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/iostreams/filter/symmetric.hpp b/src/external/3rd/library/boost/boost/iostreams/filter/symmetric.hpp index 698c3b8ea..ba88a7c52 100644 --- a/src/external/3rd/library/boost/boost/iostreams/filter/symmetric.hpp +++ b/src/external/3rd/library/boost/boost/iostreams/filter/symmetric.hpp @@ -1,310 +1,310 @@ -// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) -// (C) Copyright 2003-2007 Jonathan Turkanis -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) - -// See http://www.boost.org/libs/iostreams for documentation. - -// Contains the definitions of the class templates symmetric_filter, -// which models DualUseFilter based on a model of the Symmetric Filter. - -// -// Roughly, a Symmetric Filter is a class type with the following interface: -// -// struct symmetric_filter { -// typedef xxx char_type; -// -// bool filter( const char*& begin_in, const char* end_in, -// char*& begin_out, char* end_out, bool flush ) -// { -// // Consume as many characters as possible from the interval -// // [begin_in, end_in), without exhausting the output range -// // [begin_out, end_out). If flush is true, write as mush output -// // as possible. -// // A return value of true indicates that filter should be called -// // again. More precisely, if flush is false, a return value of -// // false indicates that the natural end of stream has been reached -// // and that all filtered data has been forwarded; if flush is -// // true, a return value of false indicates that all filtered data -// // has been forwarded. -// } -// void close() { /* Reset filter's state. */ } -// }; -// -// Symmetric Filter filters need not be CopyConstructable. -// - -#ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED -#define BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -#include -#include // allocator, unique_ptr. -#include // BOOST_DEDUCED_TYPENAME. -#include -#include // buffer size. -#include -#include -#include -#include -#include -#include // read, write. -#include -#include -#include -#include -#include -#include - -// Must come last. -#include // MSVC. - -namespace boost { namespace iostreams { - -template< typename SymmetricFilter, - typename Alloc = - std::allocator< - BOOST_DEDUCED_TYPENAME char_type_of::type - > > -class symmetric_filter { -public: - typedef typename char_type_of::type char_type; - typedef BOOST_IOSTREAMS_CHAR_TRAITS(char_type) traits_type; - typedef std::basic_string string_type; - struct category - : dual_use, - filter_tag, - multichar_tag, - closable_tag - { }; - - // Expands to a sequence of ctors which forward to impl. - #define BOOST_PP_LOCAL_MACRO(n) \ - BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \ - explicit symmetric_filter( \ - int buffer_size BOOST_PP_COMMA_IF(n) \ - BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \ - : pimpl_(new impl(buffer_size BOOST_PP_COMMA_IF(n) \ - BOOST_PP_ENUM_PARAMS(n, t))) \ - { BOOST_ASSERT(buffer_size > 0); } \ - /**/ - #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY) - #include BOOST_PP_LOCAL_ITERATE() - #undef BOOST_PP_LOCAL_MACRO - - template - std::streamsize read(Source& src, char_type* s, std::streamsize n) - { - using namespace std; - if (!(state() & f_read)) - begin_read(); - - buffer_type& buf = pimpl_->buf_; - int status = (state() & f_eof) != 0 ? f_eof : f_good; - char_type *next_s = s, - *end_s = s + n; - while (true) - { - // Invoke filter if there are unconsumed characters in buffer or if - // filter must be flushed. - bool flush = status == f_eof; - if (buf.ptr() != buf.eptr() || flush) { - const char_type* next = buf.ptr(); - bool done = - !filter().filter(next, buf.eptr(), next_s, end_s, flush); - buf.ptr() = buf.data() + (next - buf.data()); - if (done) - return detail::check_eof( - static_cast(next_s - s) - ); - } - - // If no more characters are available without blocking, or - // if read request has been satisfied, return. - if ( (status == f_would_block && buf.ptr() == buf.eptr()) || - next_s == end_s ) - { - return static_cast(next_s - s); - } - - // Fill buffer. - if (status == f_good) - status = fill(src); - } - } - - template - std::streamsize write(Sink& snk, const char_type* s, std::streamsize n) - { - if (!(state() & f_write)) - begin_write(); - - buffer_type& buf = pimpl_->buf_; - const char_type *next_s, *end_s; - for (next_s = s, end_s = s + n; next_s != end_s; ) { - if (buf.ptr() == buf.eptr() && !flush(snk)) - break; - if(!filter().filter(next_s, end_s, buf.ptr(), buf.eptr(), false)) { - flush(snk); - break; - } - } - return static_cast(next_s - s); - } - - template - void close(Sink& snk, BOOST_IOS::openmode mode) - { - if (mode == BOOST_IOS::out) { - - if (!(state() & f_write)) - begin_write(); - - // Repeatedly invoke filter() with no input. - try { - buffer_type& buf = pimpl_->buf_; - char_type dummy; - const char_type* end = &dummy; - bool again = true; - while (again) { - if (buf.ptr() != buf.eptr()) - again = filter().filter( end, end, buf.ptr(), - buf.eptr(), true ); - flush(snk); - } - } catch (...) { - try { close_impl(); } catch (...) { } - throw; - } - close_impl(); - } else { - close_impl(); - } - } - SymmetricFilter& filter() { return *pimpl_; } - string_type unconsumed_input() const; - -// Give impl access to buffer_type on Tru64 -#if !BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) - private: -#endif - typedef detail::buffer buffer_type; -private: - buffer_type& buf() { return pimpl_->buf_; } - const buffer_type& buf() const { return pimpl_->buf_; } - int& state() { return pimpl_->state_; } - void begin_read(); - void begin_write(); - - template - int fill(Source& src) - { - std::streamsize amt = iostreams::read(src, buf().data(), buf().size()); - if (amt == -1) { - state() |= f_eof; - return f_eof; - } - buf().set(0, amt); - return amt != 0 ? f_good : f_would_block; - } - - // Attempts to write the contents of the buffer the given Sink. - // Returns true if at least on character was written. - template - bool flush(Sink& snk) - { - typedef typename iostreams::category_of::type category; - typedef is_convertible can_write; - return flush(snk, can_write()); - } - - template - bool flush(Sink& snk, mpl::true_) - { - std::streamsize amt = - static_cast(buf().ptr() - buf().data()); - std::streamsize result = - boost::iostreams::write(snk, buf().data(), amt); - if (result < amt && result > 0) - traits_type::move(buf().data(), buf().data() + result, amt - result); - buf().set(amt - result, buf().size()); - return result != 0; - } - - template - bool flush(Sink&, mpl::false_) { return true;} - - void close_impl(); - - enum flag_type { - f_read = 1, - f_write = f_read << 1, - f_eof = f_write << 1, - f_good, - f_would_block - }; - - struct impl : SymmetricFilter { - - // Expands to a sequence of ctors which forward to SymmetricFilter. - #define BOOST_PP_LOCAL_MACRO(n) \ - BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \ - impl( int buffer_size BOOST_PP_COMMA_IF(n) \ - BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \ - : SymmetricFilter(BOOST_PP_ENUM_PARAMS(n, t)), \ - buf_(buffer_size), state_(0) \ - { } \ - /**/ - #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY) - #include BOOST_PP_LOCAL_ITERATE() - #undef BOOST_PP_LOCAL_MACRO - - buffer_type buf_; - int state_; - }; - - shared_ptr pimpl_; -}; -BOOST_IOSTREAMS_PIPABLE(symmetric_filter, 2) - -//------------------Implementation of symmetric_filter----------------// - -template -void symmetric_filter::begin_read() -{ - BOOST_ASSERT(!(state() & f_write)); - state() |= f_read; - buf().set(0, 0); -} - -template -void symmetric_filter::begin_write() -{ - BOOST_ASSERT(!(state() & f_read)); - state() |= f_write; - buf().set(0, buf().size()); -} - -template -void symmetric_filter::close_impl() -{ - state() = 0; - buf().set(0, 0); - filter().close(); -} - -template -typename symmetric_filter::string_type -symmetric_filter::unconsumed_input() const -{ return string_type(buf().ptr(), buf().eptr()); } - -//----------------------------------------------------------------------------// - -} } // End namespaces iostreams, boost. - -#include // MSVC. - -#endif // #ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED +// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com) +// (C) Copyright 2003-2007 Jonathan Turkanis +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.) + +// See http://www.boost.org/libs/iostreams for documentation. + +// Contains the definitions of the class templates symmetric_filter, +// which models DualUseFilter based on a model of the Symmetric Filter. + +// +// Roughly, a Symmetric Filter is a class type with the following interface: +// +// struct symmetric_filter { +// typedef xxx char_type; +// +// bool filter( const char*& begin_in, const char* end_in, +// char*& begin_out, char* end_out, bool flush ) +// { +// // Consume as many characters as possible from the interval +// // [begin_in, end_in), without exhausting the output range +// // [begin_out, end_out). If flush is true, write as mush output +// // as possible. +// // A return value of true indicates that filter should be called +// // again. More precisely, if flush is false, a return value of +// // false indicates that the natural end of stream has been reached +// // and that all filtered data has been forwarded; if flush is +// // true, a return value of false indicates that all filtered data +// // has been forwarded. +// } +// void close() { /* Reset filter's state. */ } +// }; +// +// Symmetric Filter filters need not be CopyConstructable. +// + +#ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED +#define BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +#include +#include // allocator, unique_ptr. +#include // BOOST_DEDUCED_TYPENAME. +#include +#include // buffer size. +#include +#include +#include +#include +#include +#include // read, write. +#include +#include +#include +#include +#include +#include + +// Must come last. +#include // MSVC. + +namespace boost { namespace iostreams { + +template< typename SymmetricFilter, + typename Alloc = + std::allocator< + BOOST_DEDUCED_TYPENAME char_type_of::type + > > +class symmetric_filter { +public: + typedef typename char_type_of::type char_type; + typedef BOOST_IOSTREAMS_CHAR_TRAITS(char_type) traits_type; + typedef std::basic_string string_type; + struct category + : dual_use, + filter_tag, + multichar_tag, + closable_tag + { }; + + // Expands to a sequence of ctors which forward to impl. + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \ + explicit symmetric_filter( \ + int buffer_size BOOST_PP_COMMA_IF(n) \ + BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \ + : pimpl_(new impl(buffer_size BOOST_PP_COMMA_IF(n) \ + BOOST_PP_ENUM_PARAMS(n, t))) \ + { BOOST_ASSERT(buffer_size > 0); } \ + /**/ + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY) + #include BOOST_PP_LOCAL_ITERATE() + #undef BOOST_PP_LOCAL_MACRO + + template + std::streamsize read(Source& src, char_type* s, std::streamsize n) + { + using namespace std; + if (!(state() & f_read)) + begin_read(); + + buffer_type& buf = pimpl_->buf_; + int status = (state() & f_eof) != 0 ? f_eof : f_good; + char_type *next_s = s, + *end_s = s + n; + while (true) + { + // Invoke filter if there are unconsumed characters in buffer or if + // filter must be flushed. + bool flush = status == f_eof; + if (buf.ptr() != buf.eptr() || flush) { + const char_type* next = buf.ptr(); + bool done = + !filter().filter(next, buf.eptr(), next_s, end_s, flush); + buf.ptr() = buf.data() + (next - buf.data()); + if (done) + return detail::check_eof( + static_cast(next_s - s) + ); + } + + // If no more characters are available without blocking, or + // if read request has been satisfied, return. + if ( (status == f_would_block && buf.ptr() == buf.eptr()) || + next_s == end_s ) + { + return static_cast(next_s - s); + } + + // Fill buffer. + if (status == f_good) + status = fill(src); + } + } + + template + std::streamsize write(Sink& snk, const char_type* s, std::streamsize n) + { + if (!(state() & f_write)) + begin_write(); + + buffer_type& buf = pimpl_->buf_; + const char_type *next_s, *end_s; + for (next_s = s, end_s = s + n; next_s != end_s; ) { + if (buf.ptr() == buf.eptr() && !flush(snk)) + break; + if(!filter().filter(next_s, end_s, buf.ptr(), buf.eptr(), false)) { + flush(snk); + break; + } + } + return static_cast(next_s - s); + } + + template + void close(Sink& snk, BOOST_IOS::openmode mode) + { + if (mode == BOOST_IOS::out) { + + if (!(state() & f_write)) + begin_write(); + + // Repeatedly invoke filter() with no input. + try { + buffer_type& buf = pimpl_->buf_; + char_type dummy; + const char_type* end = &dummy; + bool again = true; + while (again) { + if (buf.ptr() != buf.eptr()) + again = filter().filter( end, end, buf.ptr(), + buf.eptr(), true ); + flush(snk); + } + } catch (...) { + try { close_impl(); } catch (...) { } + throw; + } + close_impl(); + } else { + close_impl(); + } + } + SymmetricFilter& filter() { return *pimpl_; } + string_type unconsumed_input() const; + +// Give impl access to buffer_type on Tru64 +#if !BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042)) + private: +#endif + typedef detail::buffer buffer_type; +private: + buffer_type& buf() { return pimpl_->buf_; } + const buffer_type& buf() const { return pimpl_->buf_; } + int& state() { return pimpl_->state_; } + void begin_read(); + void begin_write(); + + template + int fill(Source& src) + { + std::streamsize amt = iostreams::read(src, buf().data(), buf().size()); + if (amt == -1) { + state() |= f_eof; + return f_eof; + } + buf().set(0, amt); + return amt != 0 ? f_good : f_would_block; + } + + // Attempts to write the contents of the buffer the given Sink. + // Returns true if at least on character was written. + template + bool flush(Sink& snk) + { + typedef typename iostreams::category_of::type category; + typedef is_convertible can_write; + return flush(snk, can_write()); + } + + template + bool flush(Sink& snk, mpl::true_) + { + std::streamsize amt = + static_cast(buf().ptr() - buf().data()); + std::streamsize result = + boost::iostreams::write(snk, buf().data(), amt); + if (result < amt && result > 0) + traits_type::move(buf().data(), buf().data() + result, amt - result); + buf().set(amt - result, buf().size()); + return result != 0; + } + + template + bool flush(Sink&, mpl::false_) { return true;} + + void close_impl(); + + enum flag_type { + f_read = 1, + f_write = f_read << 1, + f_eof = f_write << 1, + f_good, + f_would_block + }; + + struct impl : SymmetricFilter { + + // Expands to a sequence of ctors which forward to SymmetricFilter. + #define BOOST_PP_LOCAL_MACRO(n) \ + BOOST_IOSTREAMS_TEMPLATE_PARAMS(n, T) \ + impl( int buffer_size BOOST_PP_COMMA_IF(n) \ + BOOST_PP_ENUM_BINARY_PARAMS(n, const T, &t) ) \ + : SymmetricFilter(BOOST_PP_ENUM_PARAMS(n, t)), \ + buf_(buffer_size), state_(0) \ + { } \ + /**/ + #define BOOST_PP_LOCAL_LIMITS (0, BOOST_IOSTREAMS_MAX_FORWARDING_ARITY) + #include BOOST_PP_LOCAL_ITERATE() + #undef BOOST_PP_LOCAL_MACRO + + buffer_type buf_; + int state_; + }; + + shared_ptr pimpl_; +}; +BOOST_IOSTREAMS_PIPABLE(symmetric_filter, 2) + +//------------------Implementation of symmetric_filter----------------// + +template +void symmetric_filter::begin_read() +{ + BOOST_ASSERT(!(state() & f_write)); + state() |= f_read; + buf().set(0, 0); +} + +template +void symmetric_filter::begin_write() +{ + BOOST_ASSERT(!(state() & f_read)); + state() |= f_write; + buf().set(0, buf().size()); +} + +template +void symmetric_filter::close_impl() +{ + state() = 0; + buf().set(0, 0); + filter().close(); +} + +template +typename symmetric_filter::string_type +symmetric_filter::unconsumed_input() const +{ return string_type(buf().ptr(), buf().eptr()); } + +//----------------------------------------------------------------------------// + +} } // End namespaces iostreams, boost. + +#include // MSVC. + +#endif // #ifndef BOOST_IOSTREAMS_SYMMETRIC_FILTER_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/locale/format.hpp b/src/external/3rd/library/boost/boost/locale/format.hpp index be12a5fed..33336dbe1 100644 --- a/src/external/3rd/library/boost/boost/locale/format.hpp +++ b/src/external/3rd/library/boost/boost/locale/format.hpp @@ -1,515 +1,515 @@ -// -// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -#ifndef BOOST_LOCALE_FORMAT_HPP_INCLUDED -#define BOOST_LOCALE_FORMAT_HPP_INCLUDED - -#include -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable : 4275 4251 4231 4660) -#endif -#include -#include - -#include - - -namespace boost { - namespace locale { - - /// - /// \defgroup format Format - /// - /// This module provides printf like functionality integrated into iostreams and suitable for localization - /// - /// @{ - /// - - /// \cond INTERNAL - namespace details { - - template - struct formattible { - typedef std::basic_ostream stream_type; - typedef void (*writer_type)(stream_type &output,void const *ptr); - - formattible() : - pointer_(0), - writer_(&formattible::void_write) - { - } - - formattible(formattible const &other) : - pointer_(other.pointer_), - writer_(other.writer_) - { - } - - formattible const &operator=(formattible const &other) - { - if(this != &other) { - pointer_=other.pointer_; - writer_=other.writer_; - } - return *this; - } - - template - formattible(Type const &value) - { - pointer_ = static_cast(&value); - writer_ = &write; - } - - template - formattible const &operator=(Type const &other) - { - *this = formattible(other); - return *this; - } - - friend stream_type &operator<<(stream_type &out,formattible const &fmt) - { - fmt.writer_(out,fmt.pointer_); - return out; - } - - private: - static void void_write(stream_type &output,void const * /*ptr*/) - { - CharType empty_string[1]={0}; - output< - static void write(stream_type &output,void const *ptr) - { - output << *static_cast(ptr); - } - - void const *pointer_; - writer_type writer_; - }; // formattible - - class BOOST_LOCALE_DECL format_parser { - public: - format_parser(std::ios_base &ios,void *,void (*imbuer)(void *,std::locale const &)); - ~format_parser(); - - unsigned get_position(); - - void set_one_flag(std::string const &key,std::string const &value); - - template - void set_flag_with_str(std::string const &key,std::basic_string const &value) - { - if(key=="ftime" || key=="strftime") { - as::strftime(ios_); - ios_info::get(ios_).date_time_pattern(value); - } - } - void restore(); - private: - void imbue(std::locale const &); - format_parser(format_parser const &); - void operator=(format_parser const &); - - std::ios_base &ios_; - struct data; - std::unique_ptr d; - }; - - } - - /// \endcond - - /// - /// \brief a printf like class that allows type-safe and locale aware message formatting - /// - /// This class creates a formatted message similar to printf or boost::format and receives - /// formatted entries via operator %. - /// - /// For example - /// \code - /// cout << format("Hello {1}, you are {2} years old") % name % age << endl; - /// \endcode - /// - /// Formatting is enclosed between curly brackets \c { \c } and defined by a comma separated list of flags in the format key[=value] - /// value may also be text included between single quotes \c ' that is used for special purposes where inclusion of non-ASCII - /// text is allowed - /// - /// Including of literal \c { and \c } is possible by specifying double brackets \c {{ and \c }} accordingly. - /// - /// - /// For example: - /// - /// \code - /// cout << format("The height of water at {1,time} is {2,num=fixed,precision=3}") % time % height; - /// \endcode - /// - /// The special key -- a number without a value defines the position of an input parameter. - /// List of keys: - /// - \c [0-9]+ -- digits, the index of a formatted parameter -- mandatory key. - /// - \c num or \c number -- format a number. Optional values are: - /// - \c hex -- display hexadecimal number - /// - \c oct -- display in octal format - /// - \c sci or \c scientific -- display in scientific format - /// - \c fix or \c fixed -- display in fixed format - /// . - /// For example \c number=sci - /// - \c cur or \c currency -- format currency. Optional values are: - /// - /// - \c iso -- display using ISO currency symbol. - /// - \c nat or \c national -- display using national currency symbol. - /// . - /// - \c per or \c percent -- format percent value. - /// - \c date, \c time , \c datetime or \c dt -- format date, time or date and time. Optional values are: - /// - \c s or \c short -- display in short format - /// - \c m or \c medium -- display in medium format. - /// - \c l or \c long -- display in long format. - /// - \c f or \c full -- display in full format. - /// . - /// - \c ftime with string (quoted) parameter -- display as with \c strftime see, \c as::ftime manipulator - /// - \c spell or \c spellout -- spell the number. - /// - \c ord or \c ordinal -- format ordinal number (1st, 2nd... etc) - /// - \c left or \c < -- align to left. - /// - \c right or \c > -- align to right. - /// - \c width or \c w -- set field width (requires parameter). - /// - \c precision or \c p -- set precision (requires parameter). - /// - \c locale -- with parameter -- switch locale for current operation. This command generates locale - /// with formatting facets giving more fine grained control of formatting. For example: - /// \code - /// cout << format("Today {1,date} ({1,date,locale=he_IL.UTF-8@calendar=hebrew,date} Hebrew Date)") % date; - /// \endcode - /// - \c timezone or \c tz -- the name of the timezone to display the time in. For example:\n - /// \code - /// cout << format("Time is: Local {1,time}, ({1,time,tz=EET} Eastern European Time)") % date; - /// \endcode - /// - \c local - display the time in local time - /// - \c gmt - display the time in UTC time scale - /// \code - /// cout << format("Local time is: {1,time,local}, universal time is {1,time,gmt}") % time; - /// \endcode - /// - /// - /// Invalid formatting strings are slightly ignored. This would prevent from translator - /// to crash the program in unexpected location. - /// - template - class basic_format { - public: - typedef CharType char_type; ///< Underlying character type - typedef basic_message message_type; ///< The translation message type - /// \cond INTERNAL - typedef details::formattible formattible_type; - /// \endcond - - typedef std::basic_string string_type; ///< string type for this type of character - typedef std::basic_ostream stream_type; ///< output stream type for this type of character - - - /// - /// Create a format class for \a format_string - /// - basic_format(string_type format_string) : - format_(format_string), - translate_(false), - parameters_count_(0) - { - } - /// - /// Create a format class using message \a trans. The message if translated first according - /// to the rules of target locale and then interpreted as format string - /// - basic_format(message_type const &trans) : - message_(trans), - translate_(true), - parameters_count_(0) - { - } - - /// - /// Add new parameter to format list. The object should be a type - /// with defined expression out << object where \c out is \c std::basic_ostream. - /// - template - basic_format &operator % (Formattible const &object) - { - add(formattible_type(object)); - return *this; - } - - /// - /// Format a string using a locale \a loc - /// - string_type str(std::locale const &loc = std::locale()) const - { - std::basic_ostringstream buffer; - buffer.imbue(loc); - write(buffer); - return buffer.str(); - } - - /// - /// write a formatted string to output stream \a out using out's locale - /// - void write(stream_type &out) const - { - string_type format; - if(translate_) - format = message_.str(out.getloc(),ios_info::get(out).domain_id()); - else - format = format_; - - format_output(out,format); - - } - - - private: - - class format_guard { - public: - format_guard(details::format_parser &fmt) : - fmt_(&fmt), - restored_(false) - { - } - void restore() - { - if(restored_) - return; - fmt_->restore(); - restored_ = true; - } - ~format_guard() - { - try { - restore(); - } - catch(...) { - } - } - private: - details::format_parser *fmt_; - bool restored_; - }; - - void format_output(stream_type &out,string_type const &sformat) const - { - char_type obrk='{'; - char_type cbrk='}'; - char_type eq='='; - char_type comma=','; - char_type quote='\''; - - size_t pos = 0; - size_t size=sformat.size(); - CharType const *format=sformat.c_str(); - while(format[pos]!=0) { - if(format[pos] != obrk) { - if(format[pos]==cbrk && format[pos+1]==cbrk) { - out << cbrk; - pos+=2; - } - else { - out<(&out),&basic_format::imbue_locale); - - format_guard guard(fmt); - - while(pos < size) { - std::string key; - std::string svalue; - string_type value; - bool use_svalue = true; - for(;format[pos];pos++) { - char_type c=format[pos]; - if(c==comma || c==eq || c==cbrk) - break; - else { - key+=static_cast(c); - } - } - - if(format[pos]==eq) { - pos++; - if(format[pos]==quote) { - pos++; - use_svalue = false; - while(format[pos]) { - if(format[pos]==quote) { - if(format[pos+1]==quote) { - value+=quote; - pos+=2; - } - else { - pos++; - break; - } - } - else { - value+=format[pos]; - pos++; - } - } - } - else { - char_type c; - while((c=format[pos])!=0 && c!=comma && c!=cbrk) { - svalue+=static_cast(c); - pos++; - } - } - } - - if(use_svalue) { - fmt.set_one_flag(key,svalue); - } - else - fmt.set_flag_with_str(key,value); - - if(format[pos]==comma) { - pos++; - continue; - } - else if(format[pos]==cbrk) { - unsigned position = fmt.get_position(); - out << get(position); - guard.restore(); - pos++; - break; - } - else { - guard.restore(); - break; - } - } - } - } - - - // - // Non-copyable - // - basic_format(basic_format const &other); - void operator=(basic_format const &other); - - void add(formattible_type const ¶m) - { - if(parameters_count_ >= base_params_) - ext_params_.push_back(param); - else - parameters_[parameters_count_] = param; - parameters_count_++; - } - - formattible_type get(unsigned id) const - { - if(id >= parameters_count_) - return formattible_type(); - else if(id >= base_params_) - return ext_params_[id - base_params_]; - else - return parameters_[id]; - } - - static void imbue_locale(void *ptr,std::locale const &l) - { - reinterpret_cast(ptr)->imbue(l); - } - - - - static unsigned const base_params_ = 8; - - message_type message_; - string_type format_; - bool translate_; - - - formattible_type parameters_[base_params_]; - unsigned parameters_count_; - std::vector ext_params_; - }; - - /// - /// Write formatted message to stream. - /// - /// This operator actually causes actual text formatting. It uses the locale of \a out stream - /// - template - std::basic_ostream &operator<<(std::basic_ostream &out,basic_format const &fmt) - { - fmt.write(out); - return out; - } - - - /// - /// Definition of char based format - /// - typedef basic_format format; - - /// - /// Definition of wchar_t based format - /// - typedef basic_format wformat; - - #ifdef BOOST_HAS_CHAR16_T - /// - /// Definition of char16_t based format - /// - typedef basic_format u16format; - #endif - - #ifdef BOOST_HAS_CHAR32_T - /// - /// Definition of char32_t based format - /// - typedef basic_format u32format; - #endif - - /// - /// @} - /// - - } -} - -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - -#endif - -/// -/// \example hello.cpp -/// -/// Basic example of using various functions provided by this library -/// -/// \example whello.cpp -/// -/// Basic example of using various functions with wide strings provided by this library -/// -/// - -// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 - +// +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_LOCALE_FORMAT_HPP_INCLUDED +#define BOOST_LOCALE_FORMAT_HPP_INCLUDED + +#include +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable : 4275 4251 4231 4660) +#endif +#include +#include + +#include + + +namespace boost { + namespace locale { + + /// + /// \defgroup format Format + /// + /// This module provides printf like functionality integrated into iostreams and suitable for localization + /// + /// @{ + /// + + /// \cond INTERNAL + namespace details { + + template + struct formattible { + typedef std::basic_ostream stream_type; + typedef void (*writer_type)(stream_type &output,void const *ptr); + + formattible() : + pointer_(0), + writer_(&formattible::void_write) + { + } + + formattible(formattible const &other) : + pointer_(other.pointer_), + writer_(other.writer_) + { + } + + formattible const &operator=(formattible const &other) + { + if(this != &other) { + pointer_=other.pointer_; + writer_=other.writer_; + } + return *this; + } + + template + formattible(Type const &value) + { + pointer_ = static_cast(&value); + writer_ = &write; + } + + template + formattible const &operator=(Type const &other) + { + *this = formattible(other); + return *this; + } + + friend stream_type &operator<<(stream_type &out,formattible const &fmt) + { + fmt.writer_(out,fmt.pointer_); + return out; + } + + private: + static void void_write(stream_type &output,void const * /*ptr*/) + { + CharType empty_string[1]={0}; + output< + static void write(stream_type &output,void const *ptr) + { + output << *static_cast(ptr); + } + + void const *pointer_; + writer_type writer_; + }; // formattible + + class BOOST_LOCALE_DECL format_parser { + public: + format_parser(std::ios_base &ios,void *,void (*imbuer)(void *,std::locale const &)); + ~format_parser(); + + unsigned get_position(); + + void set_one_flag(std::string const &key,std::string const &value); + + template + void set_flag_with_str(std::string const &key,std::basic_string const &value) + { + if(key=="ftime" || key=="strftime") { + as::strftime(ios_); + ios_info::get(ios_).date_time_pattern(value); + } + } + void restore(); + private: + void imbue(std::locale const &); + format_parser(format_parser const &); + void operator=(format_parser const &); + + std::ios_base &ios_; + struct data; + std::unique_ptr d; + }; + + } + + /// \endcond + + /// + /// \brief a printf like class that allows type-safe and locale aware message formatting + /// + /// This class creates a formatted message similar to printf or boost::format and receives + /// formatted entries via operator %. + /// + /// For example + /// \code + /// cout << format("Hello {1}, you are {2} years old") % name % age << endl; + /// \endcode + /// + /// Formatting is enclosed between curly brackets \c { \c } and defined by a comma separated list of flags in the format key[=value] + /// value may also be text included between single quotes \c ' that is used for special purposes where inclusion of non-ASCII + /// text is allowed + /// + /// Including of literal \c { and \c } is possible by specifying double brackets \c {{ and \c }} accordingly. + /// + /// + /// For example: + /// + /// \code + /// cout << format("The height of water at {1,time} is {2,num=fixed,precision=3}") % time % height; + /// \endcode + /// + /// The special key -- a number without a value defines the position of an input parameter. + /// List of keys: + /// - \c [0-9]+ -- digits, the index of a formatted parameter -- mandatory key. + /// - \c num or \c number -- format a number. Optional values are: + /// - \c hex -- display hexadecimal number + /// - \c oct -- display in octal format + /// - \c sci or \c scientific -- display in scientific format + /// - \c fix or \c fixed -- display in fixed format + /// . + /// For example \c number=sci + /// - \c cur or \c currency -- format currency. Optional values are: + /// + /// - \c iso -- display using ISO currency symbol. + /// - \c nat or \c national -- display using national currency symbol. + /// . + /// - \c per or \c percent -- format percent value. + /// - \c date, \c time , \c datetime or \c dt -- format date, time or date and time. Optional values are: + /// - \c s or \c short -- display in short format + /// - \c m or \c medium -- display in medium format. + /// - \c l or \c long -- display in long format. + /// - \c f or \c full -- display in full format. + /// . + /// - \c ftime with string (quoted) parameter -- display as with \c strftime see, \c as::ftime manipulator + /// - \c spell or \c spellout -- spell the number. + /// - \c ord or \c ordinal -- format ordinal number (1st, 2nd... etc) + /// - \c left or \c < -- align to left. + /// - \c right or \c > -- align to right. + /// - \c width or \c w -- set field width (requires parameter). + /// - \c precision or \c p -- set precision (requires parameter). + /// - \c locale -- with parameter -- switch locale for current operation. This command generates locale + /// with formatting facets giving more fine grained control of formatting. For example: + /// \code + /// cout << format("Today {1,date} ({1,date,locale=he_IL.UTF-8@calendar=hebrew,date} Hebrew Date)") % date; + /// \endcode + /// - \c timezone or \c tz -- the name of the timezone to display the time in. For example:\n + /// \code + /// cout << format("Time is: Local {1,time}, ({1,time,tz=EET} Eastern European Time)") % date; + /// \endcode + /// - \c local - display the time in local time + /// - \c gmt - display the time in UTC time scale + /// \code + /// cout << format("Local time is: {1,time,local}, universal time is {1,time,gmt}") % time; + /// \endcode + /// + /// + /// Invalid formatting strings are slightly ignored. This would prevent from translator + /// to crash the program in unexpected location. + /// + template + class basic_format { + public: + typedef CharType char_type; ///< Underlying character type + typedef basic_message message_type; ///< The translation message type + /// \cond INTERNAL + typedef details::formattible formattible_type; + /// \endcond + + typedef std::basic_string string_type; ///< string type for this type of character + typedef std::basic_ostream stream_type; ///< output stream type for this type of character + + + /// + /// Create a format class for \a format_string + /// + basic_format(string_type format_string) : + format_(format_string), + translate_(false), + parameters_count_(0) + { + } + /// + /// Create a format class using message \a trans. The message if translated first according + /// to the rules of target locale and then interpreted as format string + /// + basic_format(message_type const &trans) : + message_(trans), + translate_(true), + parameters_count_(0) + { + } + + /// + /// Add new parameter to format list. The object should be a type + /// with defined expression out << object where \c out is \c std::basic_ostream. + /// + template + basic_format &operator % (Formattible const &object) + { + add(formattible_type(object)); + return *this; + } + + /// + /// Format a string using a locale \a loc + /// + string_type str(std::locale const &loc = std::locale()) const + { + std::basic_ostringstream buffer; + buffer.imbue(loc); + write(buffer); + return buffer.str(); + } + + /// + /// write a formatted string to output stream \a out using out's locale + /// + void write(stream_type &out) const + { + string_type format; + if(translate_) + format = message_.str(out.getloc(),ios_info::get(out).domain_id()); + else + format = format_; + + format_output(out,format); + + } + + + private: + + class format_guard { + public: + format_guard(details::format_parser &fmt) : + fmt_(&fmt), + restored_(false) + { + } + void restore() + { + if(restored_) + return; + fmt_->restore(); + restored_ = true; + } + ~format_guard() + { + try { + restore(); + } + catch(...) { + } + } + private: + details::format_parser *fmt_; + bool restored_; + }; + + void format_output(stream_type &out,string_type const &sformat) const + { + char_type obrk='{'; + char_type cbrk='}'; + char_type eq='='; + char_type comma=','; + char_type quote='\''; + + size_t pos = 0; + size_t size=sformat.size(); + CharType const *format=sformat.c_str(); + while(format[pos]!=0) { + if(format[pos] != obrk) { + if(format[pos]==cbrk && format[pos+1]==cbrk) { + out << cbrk; + pos+=2; + } + else { + out<(&out),&basic_format::imbue_locale); + + format_guard guard(fmt); + + while(pos < size) { + std::string key; + std::string svalue; + string_type value; + bool use_svalue = true; + for(;format[pos];pos++) { + char_type c=format[pos]; + if(c==comma || c==eq || c==cbrk) + break; + else { + key+=static_cast(c); + } + } + + if(format[pos]==eq) { + pos++; + if(format[pos]==quote) { + pos++; + use_svalue = false; + while(format[pos]) { + if(format[pos]==quote) { + if(format[pos+1]==quote) { + value+=quote; + pos+=2; + } + else { + pos++; + break; + } + } + else { + value+=format[pos]; + pos++; + } + } + } + else { + char_type c; + while((c=format[pos])!=0 && c!=comma && c!=cbrk) { + svalue+=static_cast(c); + pos++; + } + } + } + + if(use_svalue) { + fmt.set_one_flag(key,svalue); + } + else + fmt.set_flag_with_str(key,value); + + if(format[pos]==comma) { + pos++; + continue; + } + else if(format[pos]==cbrk) { + unsigned position = fmt.get_position(); + out << get(position); + guard.restore(); + pos++; + break; + } + else { + guard.restore(); + break; + } + } + } + } + + + // + // Non-copyable + // + basic_format(basic_format const &other); + void operator=(basic_format const &other); + + void add(formattible_type const ¶m) + { + if(parameters_count_ >= base_params_) + ext_params_.push_back(param); + else + parameters_[parameters_count_] = param; + parameters_count_++; + } + + formattible_type get(unsigned id) const + { + if(id >= parameters_count_) + return formattible_type(); + else if(id >= base_params_) + return ext_params_[id - base_params_]; + else + return parameters_[id]; + } + + static void imbue_locale(void *ptr,std::locale const &l) + { + reinterpret_cast(ptr)->imbue(l); + } + + + + static unsigned const base_params_ = 8; + + message_type message_; + string_type format_; + bool translate_; + + + formattible_type parameters_[base_params_]; + unsigned parameters_count_; + std::vector ext_params_; + }; + + /// + /// Write formatted message to stream. + /// + /// This operator actually causes actual text formatting. It uses the locale of \a out stream + /// + template + std::basic_ostream &operator<<(std::basic_ostream &out,basic_format const &fmt) + { + fmt.write(out); + return out; + } + + + /// + /// Definition of char based format + /// + typedef basic_format format; + + /// + /// Definition of wchar_t based format + /// + typedef basic_format wformat; + + #ifdef BOOST_HAS_CHAR16_T + /// + /// Definition of char16_t based format + /// + typedef basic_format u16format; + #endif + + #ifdef BOOST_HAS_CHAR32_T + /// + /// Definition of char32_t based format + /// + typedef basic_format u32format; + #endif + + /// + /// @} + /// + + } +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif + +/// +/// \example hello.cpp +/// +/// Basic example of using various functions provided by this library +/// +/// \example whello.cpp +/// +/// Basic example of using various functions with wide strings provided by this library +/// +/// + +// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 + diff --git a/src/external/3rd/library/boost/boost/locale/generator.hpp b/src/external/3rd/library/boost/boost/locale/generator.hpp index 7b3aa868c..ae7fe7f05 100644 --- a/src/external/3rd/library/boost/boost/locale/generator.hpp +++ b/src/external/3rd/library/boost/boost/locale/generator.hpp @@ -1,235 +1,235 @@ -// -// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -#ifndef BOOST_LOCALE_GENERATOR_HPP -#define BOOST_LOCALE_GENERATOR_HPP -#include -#include -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable : 4275 4251 4231 4660) -#endif -#include -#include -#include - -namespace boost { - - template - class shared_ptr; - - /// - /// \brief This is the main namespace that encloses all localization classes - /// - namespace locale { - - class localization_backend; - class localization_backend_manager; - - static const uint32_t nochar_facet = 0; ///< Unspecified character category for character independent facets - static const uint32_t char_facet = 1 << 0; ///< 8-bit character facets - static const uint32_t wchar_t_facet = 1 << 1; ///< wide character facets - static const uint32_t char16_t_facet = 1 << 2; ///< C++0x char16_t facets - static const uint32_t char32_t_facet = 1 << 3; ///< C++0x char32_t facets - - static const uint32_t character_first_facet = char_facet; ///< First facet specific for character type - static const uint32_t character_last_facet = char32_t_facet; ///< Last facet specific for character type - static const uint32_t all_characters = 0xFFFF; ///< Special mask -- generate all - - typedef uint32_t character_facet_type; /// backend,std::string const &id) const; - - generator(generator const &); - void operator=(generator const &); - - struct data; - std::unique_ptr d; - }; - - } -} -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - - -#endif -// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 - +// +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_LOCALE_GENERATOR_HPP +#define BOOST_LOCALE_GENERATOR_HPP +#include +#include +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable : 4275 4251 4231 4660) +#endif +#include +#include +#include + +namespace boost { + + template + class shared_ptr; + + /// + /// \brief This is the main namespace that encloses all localization classes + /// + namespace locale { + + class localization_backend; + class localization_backend_manager; + + static const uint32_t nochar_facet = 0; ///< Unspecified character category for character independent facets + static const uint32_t char_facet = 1 << 0; ///< 8-bit character facets + static const uint32_t wchar_t_facet = 1 << 1; ///< wide character facets + static const uint32_t char16_t_facet = 1 << 2; ///< C++0x char16_t facets + static const uint32_t char32_t_facet = 1 << 3; ///< C++0x char32_t facets + + static const uint32_t character_first_facet = char_facet; ///< First facet specific for character type + static const uint32_t character_last_facet = char32_t_facet; ///< Last facet specific for character type + static const uint32_t all_characters = 0xFFFF; ///< Special mask -- generate all + + typedef uint32_t character_facet_type; /// backend,std::string const &id) const; + + generator(generator const &); + void operator=(generator const &); + + struct data; + std::unique_ptr d; + }; + + } +} +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + + +#endif +// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 + diff --git a/src/external/3rd/library/boost/boost/locale/hold_ptr.hpp b/src/external/3rd/library/boost/boost/locale/hold_ptr.hpp index a2a56b200..e450905ab 100644 --- a/src/external/3rd/library/boost/boost/locale/hold_ptr.hpp +++ b/src/external/3rd/library/boost/boost/locale/hold_ptr.hpp @@ -1,93 +1,93 @@ -// -// Copyright (c) 2010 Artyom Beilis (Tonkikh) -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -#ifndef BOOST_LOCALE_HOLD_PTR_H -#define BOOST_LOCALE_HOLD_PTR_H - -namespace boost { -namespace locale { - /// - /// \brief a smart pointer similar to std::unique_ptr but it is non-copyable and the - /// underlying object has the same constness as the pointer itself (unlike an ordinary pointer). - /// - template - class hold_ptr { - hold_ptr(hold_ptr const &other); // non copyable - hold_ptr const &operator=(hold_ptr const &other); // non assignable - public: - /// - /// Create new empty pointer - /// - hold_ptr() : ptr_(0) {} - /// - /// Create a pointer that holds \a v, ownership is transferred to smart pointer - /// - explicit hold_ptr(T *v) : ptr_(v) {} - - /// - /// Destroy smart pointer and the object it owns. - /// - ~hold_ptr() - { - delete ptr_; - } - - /// - /// Get a const pointer to the object - /// - T const *get() const { return ptr_; } - /// - /// Get a mutable pointer to the object - /// - T *get() { return ptr_; } - - /// - /// Get a const reference to the object - /// - T const &operator *() const { return *ptr_; } - /// - /// Get a mutable reference to the object - /// - T &operator *() { return *ptr_; } - /// - /// Get a const pointer to the object - /// - T const *operator->() const { return ptr_; } - /// - /// Get a mutable pointer to the object - /// - T *operator->() { return ptr_; } - - /// - /// Transfer an ownership on the pointer to user - /// - T *release() { T *tmp=ptr_; ptr_=0; return tmp; } - - /// - /// Set new value to pointer, previous object is destroyed, ownership on new object is transferred - /// - void reset(T *p=0) - { - if(ptr_) delete ptr_; - ptr_=p; - } - /// Swap two pointers - void swap(hold_ptr &other) - { - T *tmp=other.ptr_; - other.ptr_=ptr_; - ptr_=tmp; - } - private: - T *ptr_; - }; - -} // locale -} // boost - -#endif -// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 +// +// Copyright (c) 2010 Artyom Beilis (Tonkikh) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_LOCALE_HOLD_PTR_H +#define BOOST_LOCALE_HOLD_PTR_H + +namespace boost { +namespace locale { + /// + /// \brief a smart pointer similar to std::unique_ptr but it is non-copyable and the + /// underlying object has the same constness as the pointer itself (unlike an ordinary pointer). + /// + template + class hold_ptr { + hold_ptr(hold_ptr const &other); // non copyable + hold_ptr const &operator=(hold_ptr const &other); // non assignable + public: + /// + /// Create new empty pointer + /// + hold_ptr() : ptr_(0) {} + /// + /// Create a pointer that holds \a v, ownership is transferred to smart pointer + /// + explicit hold_ptr(T *v) : ptr_(v) {} + + /// + /// Destroy smart pointer and the object it owns. + /// + ~hold_ptr() + { + delete ptr_; + } + + /// + /// Get a const pointer to the object + /// + T const *get() const { return ptr_; } + /// + /// Get a mutable pointer to the object + /// + T *get() { return ptr_; } + + /// + /// Get a const reference to the object + /// + T const &operator *() const { return *ptr_; } + /// + /// Get a mutable reference to the object + /// + T &operator *() { return *ptr_; } + /// + /// Get a const pointer to the object + /// + T const *operator->() const { return ptr_; } + /// + /// Get a mutable pointer to the object + /// + T *operator->() { return ptr_; } + + /// + /// Transfer an ownership on the pointer to user + /// + T *release() { T *tmp=ptr_; ptr_=0; return tmp; } + + /// + /// Set new value to pointer, previous object is destroyed, ownership on new object is transferred + /// + void reset(T *p=0) + { + if(ptr_) delete ptr_; + ptr_=p; + } + /// Swap two pointers + void swap(hold_ptr &other) + { + T *tmp=other.ptr_; + other.ptr_=ptr_; + ptr_=tmp; + } + private: + T *ptr_; + }; + +} // locale +} // boost + +#endif +// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/src/external/3rd/library/boost/boost/locale/localization_backend.hpp b/src/external/3rd/library/boost/boost/locale/localization_backend.hpp index d1cc9de58..355a7db5b 100644 --- a/src/external/3rd/library/boost/boost/locale/localization_backend.hpp +++ b/src/external/3rd/library/boost/boost/locale/localization_backend.hpp @@ -1,159 +1,159 @@ -// -// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -#ifndef BOOST_LOCALE_LOCALIZATION_BACKEND_HPP -#define BOOST_LOCALE_LOCALIZATION_BACKEND_HPP -#include -#include -#ifdef BOOST_MSVC -# pragma warning(push) -# pragma warning(disable : 4275 4251 4231 4660) -#endif -#include -#include -#include -#include - -namespace boost { - namespace locale { - - /// - /// \brief this class represents a localization backend that can be used for localizing your application. - /// - /// Backends are usually registered inside the localization backends manager and allow transparent support - /// of different backends, so a user can switch the backend by simply linking the application to the correct one. - /// - /// Backends may support different tuning options, but these are the default options available to the user - /// for all of them - /// - /// -# \c locale - the name of the locale in POSIX format like en_US.UTF-8 - /// -# \c use_ansi_encoding - select system locale using ANSI codepages rather then UTF-8 under Windows - /// by default - /// -# \c message_path - path to the location of message catalogs (vector of strings) - /// -# \c message_application - the name of applications that use message catalogs (vector of strings) - /// - /// Each backend can be installed with a different default priotiry so when you work with two different backends, you - /// can specify priotiry so this backend will be chosen according to their priority. - /// - - class localization_backend { - localization_backend(localization_backend const &); - void operator=(localization_backend const &); - public: - - localization_backend() - { - } - - virtual ~localization_backend() - { - } - - /// - /// Make a polymorphic copy of the backend - /// - virtual localization_backend *clone() const = 0; - - /// - /// Set option for backend, for example "locale" or "encoding" - /// - virtual void set_option(std::string const &name,std::string const &value) = 0; - - /// - /// Clear all options - /// - virtual void clear_options() = 0; - - /// - /// Create a facet for category \a category and character type \a type - /// - virtual std::locale install(std::locale const &base,locale_category_type category,character_facet_type type = nochar_facet) = 0; - - }; // localization_backend - - - /// - /// \brief Localization backend manager is a class that holds various backend and allows creation - /// of their combination or selection - /// - - class BOOST_LOCALE_DECL localization_backend_manager { - public: - /// - /// New empty localization_backend_manager - /// - localization_backend_manager(); - /// - /// Copy localization_backend_manager - /// - localization_backend_manager(localization_backend_manager const &); - /// - /// Assign localization_backend_manager - /// - localization_backend_manager const &operator=(localization_backend_manager const &); - - /// - /// Destructor - /// - ~localization_backend_manager(); - - /// - /// Create new localization backend according to current settings. - /// - std::unique_ptr get() const; - - /// - /// Add new backend to the manager, each backend should be uniquely defined by its name. - /// - /// This library provides: "icu", "posix", "winapi" and "std" backends. - /// - void add_backend(std::string const &name,std::unique_ptr backend); - - /// - /// Clear backend - /// - void remove_all_backends(); - - /// - /// Get list of all available backends - /// - std::vector get_all_backends() const; - - /// - /// Select specific backend by name for a category \a category. It allows combining different - /// backends for user preferences. - /// - void select(std::string const &backend_name,locale_category_type category = all_categories); - - /// - /// Set new global backend manager, the old one is returned. - /// - /// This function is thread safe - /// - static localization_backend_manager global(localization_backend_manager const &); - /// - /// Get global backend manager - /// - /// This function is thread safe - /// - static localization_backend_manager global(); - private: - class impl; - std::unique_ptr pimpl_; - }; - - } // locale -} // boost - - -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - -#endif -// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 - +// +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_LOCALE_LOCALIZATION_BACKEND_HPP +#define BOOST_LOCALE_LOCALIZATION_BACKEND_HPP +#include +#include +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable : 4275 4251 4231 4660) +#endif +#include +#include +#include +#include + +namespace boost { + namespace locale { + + /// + /// \brief this class represents a localization backend that can be used for localizing your application. + /// + /// Backends are usually registered inside the localization backends manager and allow transparent support + /// of different backends, so a user can switch the backend by simply linking the application to the correct one. + /// + /// Backends may support different tuning options, but these are the default options available to the user + /// for all of them + /// + /// -# \c locale - the name of the locale in POSIX format like en_US.UTF-8 + /// -# \c use_ansi_encoding - select system locale using ANSI codepages rather then UTF-8 under Windows + /// by default + /// -# \c message_path - path to the location of message catalogs (vector of strings) + /// -# \c message_application - the name of applications that use message catalogs (vector of strings) + /// + /// Each backend can be installed with a different default priotiry so when you work with two different backends, you + /// can specify priotiry so this backend will be chosen according to their priority. + /// + + class localization_backend { + localization_backend(localization_backend const &); + void operator=(localization_backend const &); + public: + + localization_backend() + { + } + + virtual ~localization_backend() + { + } + + /// + /// Make a polymorphic copy of the backend + /// + virtual localization_backend *clone() const = 0; + + /// + /// Set option for backend, for example "locale" or "encoding" + /// + virtual void set_option(std::string const &name,std::string const &value) = 0; + + /// + /// Clear all options + /// + virtual void clear_options() = 0; + + /// + /// Create a facet for category \a category and character type \a type + /// + virtual std::locale install(std::locale const &base,locale_category_type category,character_facet_type type = nochar_facet) = 0; + + }; // localization_backend + + + /// + /// \brief Localization backend manager is a class that holds various backend and allows creation + /// of their combination or selection + /// + + class BOOST_LOCALE_DECL localization_backend_manager { + public: + /// + /// New empty localization_backend_manager + /// + localization_backend_manager(); + /// + /// Copy localization_backend_manager + /// + localization_backend_manager(localization_backend_manager const &); + /// + /// Assign localization_backend_manager + /// + localization_backend_manager const &operator=(localization_backend_manager const &); + + /// + /// Destructor + /// + ~localization_backend_manager(); + + /// + /// Create new localization backend according to current settings. + /// + std::unique_ptr get() const; + + /// + /// Add new backend to the manager, each backend should be uniquely defined by its name. + /// + /// This library provides: "icu", "posix", "winapi" and "std" backends. + /// + void add_backend(std::string const &name,std::unique_ptr backend); + + /// + /// Clear backend + /// + void remove_all_backends(); + + /// + /// Get list of all available backends + /// + std::vector get_all_backends() const; + + /// + /// Select specific backend by name for a category \a category. It allows combining different + /// backends for user preferences. + /// + void select(std::string const &backend_name,locale_category_type category = all_categories); + + /// + /// Set new global backend manager, the old one is returned. + /// + /// This function is thread safe + /// + static localization_backend_manager global(localization_backend_manager const &); + /// + /// Get global backend manager + /// + /// This function is thread safe + /// + static localization_backend_manager global(); + private: + class impl; + std::unique_ptr pimpl_; + }; + + } // locale +} // boost + + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#endif +// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 + diff --git a/src/external/3rd/library/boost/boost/locale/util.hpp b/src/external/3rd/library/boost/boost/locale/util.hpp index 47e6b331c..bfe26e839 100644 --- a/src/external/3rd/library/boost/boost/locale/util.hpp +++ b/src/external/3rd/library/boost/boost/locale/util.hpp @@ -1,209 +1,209 @@ -// -// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -#ifndef BOOST_LOCALE_UTIL_HPP -#define BOOST_LOCALE_UTIL_HPP -#include -#include -#include -#include -#include -#include - -#include -namespace boost { -namespace locale { -/// -/// \brief This namespace provides various utility function useful for Boost.Locale backends -/// implementations -/// -namespace util { - - /// - /// \brief Return default system locale name in POSIX format. - /// - /// This function tries to detect the locale using, LC_CTYPE, LC_ALL and LANG environment - /// variables in this order and if all of them unset, in POSIX platforms it returns "C" - /// - /// On Windows additionally to check the above environment variables, this function - /// tries to creates locale name from ISO-339 and ISO-3199 country codes defined - /// for user default locale. - /// If \a use_utf8_on_windows is true it sets the encoding to UTF-8, otherwise, if system - /// locale supports ANSI code-page it defines the ANSI encoding like windows-1252, otherwise it fall-backs - /// to UTF-8 encoding if ANSI code-page is not available. - /// - BOOST_LOCALE_DECL - std::string get_system_locale(bool use_utf8_on_windows = false); - - /// - /// \brief Installs information facet to locale in based on locale name \a name - /// - /// This function installs boost::locale::info facet into the locale \a in and returns - /// newly created locale. - /// - /// Note: all information is based only on parsing of string \a name; - /// - /// The name has following format: language[_COUNTRY][.encoding][\@variant] - /// Where language is ISO-639 language code like "en" or "ru", COUNTRY is ISO-3166 - /// country identifier like "US" or "RU". the Encoding is a charracter set name - /// like UTF-8 or ISO-8859-1. Variant is backend specific variant like \c euro or - /// calendar=hebrew. - /// - /// If some parameters are missing they are specified as blanks, default encoding - /// is assumed to be US-ASCII and missing language is assumed to be "C" - /// - BOOST_LOCALE_DECL - std::locale create_info(std::locale const &in,std::string const &name); - - - /// - /// \brief This class represent a simple stateless converter from UCS-4 and to UCS-4 for - /// each single code point - /// - /// This class is used for creation of std::codecvt facet for converting utf-16/utf-32 encoding - /// to encoding supported by this converter - /// - /// Please note, this converter should be fully stateless. Fully stateless means it should - /// never assume that it is called in any specific order on the text. Even if the - /// encoding itself seems to be stateless like windows-1255 or shift-jis, some - /// encoders (most notably iconv) can actually compose several code-point into one or - /// decompose them in case composite characters are found. So be very careful when implementing - /// these converters for certain character set. - /// - class base_converter { - public: - - /// - /// This value should be returned when an illegal input sequence or code-point is observed: - /// For example if a UCS-32 code-point is in the range reserved for UTF-16 surrogates - /// or an invalid UTF-8 sequence is found - /// - static const uint32_t illegal=utf::illegal; - - /// - /// This value is returned in following cases: The of incomplete input sequence was found or - /// insufficient output buffer was provided so complete output could not be written. - /// - static const uint32_t incomplete=utf::incomplete; - - virtual ~base_converter() - { - } - /// - /// Return the maximal length that one Unicode code-point can be converted to, for example - /// for UTF-8 it is 4, for Shift-JIS it is 2 and ISO-8859-1 is 1 - /// - virtual int max_len() const - { - return 1; - } - /// - /// Returns true if calling the functions from_unicode, to_unicode, and max_len is thread safe. - /// - /// Rule of thumb: if this class' implementation uses simple tables that are unchanged - /// or is purely algorithmic like UTF-8 - so it does not share any mutable bit for - /// independent to_unicode, from_unicode calls, you may set it to true, otherwise, - /// for example if you use iconv_t descriptor or UConverter as conversion object return false, - /// and this object will be cloned for each use. - /// - virtual bool is_thread_safe() const - { - return false; - } - /// - /// Create a polymorphic copy of this object, usually called only if is_thread_safe() return false - /// - virtual base_converter *clone() const - { - BOOST_ASSERT(typeid(*this)==typeid(base_converter)); - return new base_converter(); - } - - /// - /// Convert a single character starting at begin and ending at most at end to Unicode code-point. - /// - /// if valid input sequence found in [\a begin,\a code_point_end) such as \a begin < \a code_point_end && \a code_point_end <= \a end - /// it is converted to its Unicode code point equivalent, \a begin is set to \a code_point_end - /// - /// if incomplete input sequence found in [\a begin,\a end), i.e. there my be such \a code_point_end that \a code_point_end > \a end - /// and [\a begin, \a code_point_end) would be valid input sequence, then \a incomplete is returned begin stays unchanged, for example - /// for UTF-8 conversion a *begin = 0xc2, \a begin +1 = \a end is such situation. - /// - /// if invalid input sequence found, i.e. there is a sequence [\a begin, \a code_point_end) such as \a code_point_end <= \a end - /// that is illegal for this encoding, \a illegal is returned and begin stays unchanged. For example if *begin = 0xFF and begin < end - /// for UTF-8, then \a illegal is returned. - /// - /// - virtual uint32_t to_unicode(char const *&begin,char const *end) - { - if(begin == end) - return incomplete; - unsigned char cp = *begin; - if(cp <= 0x7F) { - begin++; - return cp; - } - return illegal; - } - /// - /// Convert a single code-point \a u into encoding and store it in [begin,end) range. - /// - /// If u is invalid Unicode code-point, or it can not be mapped correctly to represented character set, - /// \a illegal should be returned - /// - /// If u can be converted to a sequence of bytes c1, ... , cN (1<= N <= max_len() ) then - /// - /// -# If end - begin >= N, c1, ... cN are written starting at begin and N is returned - /// -# If end - begin < N, incomplete is returned, it is unspecified what would be - /// stored in bytes in range [begin,end) - - virtual uint32_t from_unicode(uint32_t u,char *begin,char const *end) - { - if(begin==end) - return incomplete; - if(u >= 0x80) - return illegal; - *begin = static_cast(u); - return 1; - } - }; - - /// - /// This function creates a \a base_converter that can be used for conversion between UTF-8 and - /// unicode code points - /// - BOOST_LOCALE_DECL std::unique_ptr create_utf8_converter(); - /// - /// This function creates a \a base_converter that can be used for conversion between single byte - /// character encodings like ISO-8859-1, koi8-r, windows-1255 and Unicode code points, - /// - /// If \a encoding is not supported, empty pointer is returned. You should check if - /// std::unique_ptr::get() != 0 - /// - BOOST_LOCALE_DECL std::unique_ptr create_simple_converter(std::string const &encoding); - - - /// - /// Install codecvt facet into locale \a in and return new locale that is based on \a in and uses new - /// facet. - /// - /// codecvt facet would convert between narrow and wide/char16_t/char32_t encodings using \a cvt converter. - /// If \a cvt is null pointer, always failure conversion would be used that fails on every first input or output. - /// - /// Note: the codecvt facet handles both UTF-16 and UTF-32 wide encodings, it knows to break and join - /// Unicode code-points above 0xFFFF to and from surrogate pairs correctly. \a cvt should be unaware - /// of wide encoding type - /// - BOOST_LOCALE_DECL - std::locale create_codecvt(std::locale const &in,std::unique_ptr cvt,character_facet_type type); - -} // util -} // locale -} // boost - -#endif -// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 +// +// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh) +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#ifndef BOOST_LOCALE_UTIL_HPP +#define BOOST_LOCALE_UTIL_HPP +#include +#include +#include +#include +#include +#include + +#include +namespace boost { +namespace locale { +/// +/// \brief This namespace provides various utility function useful for Boost.Locale backends +/// implementations +/// +namespace util { + + /// + /// \brief Return default system locale name in POSIX format. + /// + /// This function tries to detect the locale using, LC_CTYPE, LC_ALL and LANG environment + /// variables in this order and if all of them unset, in POSIX platforms it returns "C" + /// + /// On Windows additionally to check the above environment variables, this function + /// tries to creates locale name from ISO-339 and ISO-3199 country codes defined + /// for user default locale. + /// If \a use_utf8_on_windows is true it sets the encoding to UTF-8, otherwise, if system + /// locale supports ANSI code-page it defines the ANSI encoding like windows-1252, otherwise it fall-backs + /// to UTF-8 encoding if ANSI code-page is not available. + /// + BOOST_LOCALE_DECL + std::string get_system_locale(bool use_utf8_on_windows = false); + + /// + /// \brief Installs information facet to locale in based on locale name \a name + /// + /// This function installs boost::locale::info facet into the locale \a in and returns + /// newly created locale. + /// + /// Note: all information is based only on parsing of string \a name; + /// + /// The name has following format: language[_COUNTRY][.encoding][\@variant] + /// Where language is ISO-639 language code like "en" or "ru", COUNTRY is ISO-3166 + /// country identifier like "US" or "RU". the Encoding is a charracter set name + /// like UTF-8 or ISO-8859-1. Variant is backend specific variant like \c euro or + /// calendar=hebrew. + /// + /// If some parameters are missing they are specified as blanks, default encoding + /// is assumed to be US-ASCII and missing language is assumed to be "C" + /// + BOOST_LOCALE_DECL + std::locale create_info(std::locale const &in,std::string const &name); + + + /// + /// \brief This class represent a simple stateless converter from UCS-4 and to UCS-4 for + /// each single code point + /// + /// This class is used for creation of std::codecvt facet for converting utf-16/utf-32 encoding + /// to encoding supported by this converter + /// + /// Please note, this converter should be fully stateless. Fully stateless means it should + /// never assume that it is called in any specific order on the text. Even if the + /// encoding itself seems to be stateless like windows-1255 or shift-jis, some + /// encoders (most notably iconv) can actually compose several code-point into one or + /// decompose them in case composite characters are found. So be very careful when implementing + /// these converters for certain character set. + /// + class base_converter { + public: + + /// + /// This value should be returned when an illegal input sequence or code-point is observed: + /// For example if a UCS-32 code-point is in the range reserved for UTF-16 surrogates + /// or an invalid UTF-8 sequence is found + /// + static const uint32_t illegal=utf::illegal; + + /// + /// This value is returned in following cases: The of incomplete input sequence was found or + /// insufficient output buffer was provided so complete output could not be written. + /// + static const uint32_t incomplete=utf::incomplete; + + virtual ~base_converter() + { + } + /// + /// Return the maximal length that one Unicode code-point can be converted to, for example + /// for UTF-8 it is 4, for Shift-JIS it is 2 and ISO-8859-1 is 1 + /// + virtual int max_len() const + { + return 1; + } + /// + /// Returns true if calling the functions from_unicode, to_unicode, and max_len is thread safe. + /// + /// Rule of thumb: if this class' implementation uses simple tables that are unchanged + /// or is purely algorithmic like UTF-8 - so it does not share any mutable bit for + /// independent to_unicode, from_unicode calls, you may set it to true, otherwise, + /// for example if you use iconv_t descriptor or UConverter as conversion object return false, + /// and this object will be cloned for each use. + /// + virtual bool is_thread_safe() const + { + return false; + } + /// + /// Create a polymorphic copy of this object, usually called only if is_thread_safe() return false + /// + virtual base_converter *clone() const + { + BOOST_ASSERT(typeid(*this)==typeid(base_converter)); + return new base_converter(); + } + + /// + /// Convert a single character starting at begin and ending at most at end to Unicode code-point. + /// + /// if valid input sequence found in [\a begin,\a code_point_end) such as \a begin < \a code_point_end && \a code_point_end <= \a end + /// it is converted to its Unicode code point equivalent, \a begin is set to \a code_point_end + /// + /// if incomplete input sequence found in [\a begin,\a end), i.e. there my be such \a code_point_end that \a code_point_end > \a end + /// and [\a begin, \a code_point_end) would be valid input sequence, then \a incomplete is returned begin stays unchanged, for example + /// for UTF-8 conversion a *begin = 0xc2, \a begin +1 = \a end is such situation. + /// + /// if invalid input sequence found, i.e. there is a sequence [\a begin, \a code_point_end) such as \a code_point_end <= \a end + /// that is illegal for this encoding, \a illegal is returned and begin stays unchanged. For example if *begin = 0xFF and begin < end + /// for UTF-8, then \a illegal is returned. + /// + /// + virtual uint32_t to_unicode(char const *&begin,char const *end) + { + if(begin == end) + return incomplete; + unsigned char cp = *begin; + if(cp <= 0x7F) { + begin++; + return cp; + } + return illegal; + } + /// + /// Convert a single code-point \a u into encoding and store it in [begin,end) range. + /// + /// If u is invalid Unicode code-point, or it can not be mapped correctly to represented character set, + /// \a illegal should be returned + /// + /// If u can be converted to a sequence of bytes c1, ... , cN (1<= N <= max_len() ) then + /// + /// -# If end - begin >= N, c1, ... cN are written starting at begin and N is returned + /// -# If end - begin < N, incomplete is returned, it is unspecified what would be + /// stored in bytes in range [begin,end) + + virtual uint32_t from_unicode(uint32_t u,char *begin,char const *end) + { + if(begin==end) + return incomplete; + if(u >= 0x80) + return illegal; + *begin = static_cast(u); + return 1; + } + }; + + /// + /// This function creates a \a base_converter that can be used for conversion between UTF-8 and + /// unicode code points + /// + BOOST_LOCALE_DECL std::unique_ptr create_utf8_converter(); + /// + /// This function creates a \a base_converter that can be used for conversion between single byte + /// character encodings like ISO-8859-1, koi8-r, windows-1255 and Unicode code points, + /// + /// If \a encoding is not supported, empty pointer is returned. You should check if + /// std::unique_ptr::get() != 0 + /// + BOOST_LOCALE_DECL std::unique_ptr create_simple_converter(std::string const &encoding); + + + /// + /// Install codecvt facet into locale \a in and return new locale that is based on \a in and uses new + /// facet. + /// + /// codecvt facet would convert between narrow and wide/char16_t/char32_t encodings using \a cvt converter. + /// If \a cvt is null pointer, always failure conversion would be used that fails on every first input or output. + /// + /// Note: the codecvt facet handles both UTF-16 and UTF-32 wide encodings, it knows to break and join + /// Unicode code-points above 0xFFFF to and from surrogate pairs correctly. \a cvt should be unaware + /// of wide encoding type + /// + BOOST_LOCALE_DECL + std::locale create_codecvt(std::locale const &in,std::unique_ptr cvt,character_facet_type type); + +} // util +} // locale +} // boost + +#endif +// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 diff --git a/src/external/3rd/library/boost/boost/math/distributions/non_central_chi_squared.hpp b/src/external/3rd/library/boost/boost/math/distributions/non_central_chi_squared.hpp index 04f4133c5..88933c195 100644 --- a/src/external/3rd/library/boost/boost/math/distributions/non_central_chi_squared.hpp +++ b/src/external/3rd/library/boost/boost/math/distributions/non_central_chi_squared.hpp @@ -1,996 +1,996 @@ -// boost\math\distributions\non_central_chi_squared.hpp - -// Copyright John Maddock 2008. - -// Use, modification and distribution are subject to the -// Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt -// or copy at http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP -#define BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP - -#include -#include // for incomplete gamma. gamma_q -#include // for cyl_bessel_i -#include // for iround -#include // complements -#include // central distribution -#include // error checks -#include // isnan. -#include // for root finding. -#include -#include - -namespace boost -{ - namespace math - { - - template - class non_central_chi_squared_distribution; - - namespace detail{ - - template - T non_central_chi_square_q(T x, T f, T theta, const Policy& pol, T init_sum = 0) - { - // - // Computes the complement of the Non-Central Chi-Square - // Distribution CDF by summing a weighted sum of complements - // of the central-distributions. The weighting factor is - // a Poisson Distribution. - // - // This is an application of the technique described in: - // - // Computing discrete mixtures of continuous - // distributions: noncentral chisquare, noncentral t - // and the distribution of the square of the sample - // multiple correlation coeficient. - // D. Benton, K. Krishnamoorthy. - // Computational Statistics & Data Analysis 43 (2003) 249 - 267 - // - BOOST_MATH_STD_USING - - // Special case: - if(x == 0) - return 1; - - // - // Initialize the variables we'll be using: - // - T lambda = theta / 2; - T del = f / 2; - T y = x / 2; - boost::uintmax_t max_iter = policies::get_max_series_iterations(); - T errtol = boost::math::policies::get_epsilon(); - T sum = init_sum; - // - // k is the starting location for iteration, we'll - // move both forwards and backwards from this point. - // k is chosen as the peek of the Poisson weights, which - // will occur *before* the largest term. - // - int k = iround(lambda, pol); - // Forwards and backwards Poisson weights: - T poisf = boost::math::gamma_p_derivative(1 + k, lambda, pol); - T poisb = poisf * k / lambda; - // Initial forwards central chi squared term: - T gamf = boost::math::gamma_q(del + k, y, pol); - // Forwards and backwards recursion terms on the central chi squared: - T xtermf = boost::math::gamma_p_derivative(del + 1 + k, y, pol); - T xtermb = xtermf * (del + k) / y; - // Initial backwards central chi squared term: - T gamb = gamf - xtermb; - - // - // Forwards iteration first, this is the - // stable direction for the gamma function - // recurrences: - // - int i; - for(i = k; static_cast(i-k) < max_iter; ++i) - { - T term = poisf * gamf; - sum += term; - poisf *= lambda / (i + 1); - gamf += xtermf; - xtermf *= y / (del + i + 1); - if(((sum == 0) || (fabs(term / sum) < errtol)) && (term >= poisf * gamf)) - break; - } - //Error check: - if(static_cast(i-k) >= max_iter) - return policies::raise_evaluation_error( - "cdf(non_central_chi_squared_distribution<%1%>, %1%)", - "Series did not converge, closest value was %1%", sum, pol); - // - // Now backwards iteration: the gamma - // function recurrences are unstable in this - // direction, we rely on the terms deminishing in size - // faster than we introduce cancellation errors. - // For this reason it's very important that we start - // *before* the largest term so that backwards iteration - // is strictly converging. - // - for(i = k - 1; i >= 0; --i) - { - T term = poisb * gamb; - sum += term; - poisb *= i / lambda; - xtermb *= (del + i) / y; - gamb -= xtermb; - if((sum == 0) || (fabs(term / sum) < errtol)) - break; - } - - return sum; - } - - template - T non_central_chi_square_p_ding(T x, T f, T theta, const Policy& pol, T init_sum = 0) - { - // - // This is an implementation of: - // - // Algorithm AS 275: - // Computing the Non-Central #2 Distribution Function - // Cherng G. Ding - // Applied Statistics, Vol. 41, No. 2. (1992), pp. 478-482. - // - // This uses a stable forward iteration to sum the - // CDF, unfortunately this can not be used for large - // values of the non-centrality parameter because: - // * The first term may underfow to zero. - // * We may need an extra-ordinary number of terms - // before we reach the first *significant* term. - // - BOOST_MATH_STD_USING - // Special case: - if(x == 0) - return 0; - T tk = boost::math::gamma_p_derivative(f/2 + 1, x/2, pol); - T lambda = theta / 2; - T vk = exp(-lambda); - T uk = vk; - T sum = init_sum + tk * vk; - if(sum == 0) - return sum; - - boost::uintmax_t max_iter = policies::get_max_series_iterations(); - T errtol = boost::math::policies::get_epsilon(); - - int i; - T lterm(0), term(0); - for(i = 1; static_cast(i) < max_iter; ++i) - { - tk = tk * x / (f + 2 * i); - uk = uk * lambda / i; - vk = vk + uk; - lterm = term; - term = vk * tk; - sum += term; - if((fabs(term / sum) < errtol) && (term <= lterm)) - break; - } - //Error check: - if(static_cast(i) >= max_iter) - return policies::raise_evaluation_error( - "cdf(non_central_chi_squared_distribution<%1%>, %1%)", - "Series did not converge, closest value was %1%", sum, pol); - return sum; - } - - - template - T non_central_chi_square_p(T y, T n, T lambda, const Policy& pol, T init_sum) - { - // - // This is taken more or less directly from: - // - // Computing discrete mixtures of continuous - // distributions: noncentral chisquare, noncentral t - // and the distribution of the square of the sample - // multiple correlation coeficient. - // D. Benton, K. Krishnamoorthy. - // Computational Statistics & Data Analysis 43 (2003) 249 - 267 - // - // We're summing a Poisson weighting term multiplied by - // a central chi squared distribution. - // - BOOST_MATH_STD_USING - // Special case: - if(y == 0) - return 0; - boost::uintmax_t max_iter = policies::get_max_series_iterations(); - T errtol = boost::math::policies::get_epsilon(); - T errorf(0), errorb(0); - - T x = y / 2; - T del = lambda / 2; - // - // Starting location for the iteration, we'll iterate - // both forwards and backwards from this point. The - // location chosen is the maximum of the Poisson weight - // function, which ocurrs *after* the largest term in the - // sum. - // - int k = iround(del, pol); - T a = n / 2 + k; - // Central chi squared term for forward iteration: - T gamkf = boost::math::gamma_p(a, x, pol); - - if(lambda == 0) - return gamkf; - // Central chi squared term for backward iteration: - T gamkb = gamkf; - // Forwards Poisson weight: - T poiskf = gamma_p_derivative(k+1, del, pol); - // Backwards Poisson weight: - T poiskb = poiskf; - // Forwards gamma function recursion term: - T xtermf = boost::math::gamma_p_derivative(a, x, pol); - // Backwards gamma function recursion term: - T xtermb = xtermf * x / a; - T sum = init_sum + poiskf * gamkf; - if(sum == 0) - return sum; - int i = 1; - // - // Backwards recursion first, this is the stable - // direction for gamma function recurrences: - // - while(i <= k) - { - xtermb *= (a - i + 1) / x; - gamkb += xtermb; - poiskb = poiskb * (k - i + 1) / del; - errorf = errorb; - errorb = gamkb * poiskb; - sum += errorb; - if((fabs(errorb / sum) < errtol) && (errorb <= errorf)) - break; - ++i; - } - i = 1; - // - // Now forwards recursion, the gamma function - // recurrence relation is unstable in this direction, - // so we rely on the magnitude of successive terms - // decreasing faster than we introduce cancellation error. - // For this reason it's vital that k is chosen to be *after* - // the largest term, so that successive forward iterations - // are strictly (and rapidly) converging. - // - do - { - xtermf = xtermf * x / (a + i - 1); - gamkf = gamkf - xtermf; - poiskf = poiskf * del / (k + i); - errorf = poiskf * gamkf; - sum += errorf; - ++i; - }while((fabs(errorf / sum) > errtol) && (static_cast(i) < max_iter)); - - //Error check: - if(static_cast(i) >= max_iter) - return policies::raise_evaluation_error( - "cdf(non_central_chi_squared_distribution<%1%>, %1%)", - "Series did not converge, closest value was %1%", sum, pol); - - return sum; - } - - template - T non_central_chi_square_pdf(T x, T n, T lambda, const Policy& pol) - { - // - // As above but for the PDF: - // - BOOST_MATH_STD_USING - boost::uintmax_t max_iter = policies::get_max_series_iterations(); - T errtol = boost::math::policies::get_epsilon(); - T x2 = x / 2; - T n2 = n / 2; - T l2 = lambda / 2; - T sum = 0; - int k = itrunc(l2); - T pois = gamma_p_derivative(k + 1, l2, pol) * gamma_p_derivative(n2 + k, x2); - if(pois == 0) - return 0; - T poisb = pois; - for(int i = k; ; ++i) - { - sum += pois; - if(pois / sum < errtol) - break; - if(static_cast(i - k) >= max_iter) - return policies::raise_evaluation_error( - "pdf(non_central_chi_squared_distribution<%1%>, %1%)", - "Series did not converge, closest value was %1%", sum, pol); - pois *= l2 * x2 / ((i + 1) * (n2 + i)); - } - for(int i = k - 1; i >= 0; --i) - { - poisb *= (i + 1) * (n2 + i) / (l2 * x2); - sum += poisb; - if(poisb / sum < errtol) - break; - } - return sum / 2; - } - - template - inline RealType non_central_chi_squared_cdf(RealType x, RealType k, RealType l, bool invert, const Policy&) - { - typedef typename policies::evaluation::type value_type; - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - - BOOST_MATH_STD_USING - value_type result; - if(l == 0) - result = cdf(boost::math::chi_squared_distribution(k), x); - else if(x > k + l) - { - // Complement is the smaller of the two: - result = detail::non_central_chi_square_q( - static_cast(x), - static_cast(k), - static_cast(l), - forwarding_policy(), - static_cast(invert ? 0 : -1)); - invert = !invert; - } - else if(l < 200) - { - // For small values of the non-centrality parameter - // we can use Ding's method: - result = detail::non_central_chi_square_p_ding( - static_cast(x), - static_cast(k), - static_cast(l), - forwarding_policy(), - static_cast(invert ? -1 : 0)); - } - else - { - // For largers values of the non-centrality - // parameter Ding's method will consume an - // extra-ordinary number of terms, and worse - // may return zero when the result is in fact - // finite, use Krishnamoorthy's method instead: - result = detail::non_central_chi_square_p( - static_cast(x), - static_cast(k), - static_cast(l), - forwarding_policy(), - static_cast(invert ? -1 : 0)); - } - if(invert) - result = -result; - return policies::checked_narrowing_cast( - result, - "boost::math::non_central_chi_squared_cdf<%1%>(%1%, %1%, %1%)"); - } - - template - struct nccs_quantile_functor - { - nccs_quantile_functor(const non_central_chi_squared_distribution& d, T t, bool c) - : dist(d), target(t), comp(c) {} - - T operator()(const T& x) - { - return comp ? - target - cdf(complement(dist, x)) - : cdf(dist, x) - target; - } - - private: - non_central_chi_squared_distribution dist; - T target; - bool comp; - }; - - template - RealType nccs_quantile(const non_central_chi_squared_distribution& dist, const RealType& p, bool comp) - { - BOOST_MATH_STD_USING - static const char* function = "quantile(non_central_chi_squared_distribution<%1%>, %1%)"; - typedef typename policies::evaluation::type value_type; - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - - value_type k = dist.degrees_of_freedom(); - value_type l = dist.non_centrality(); - value_type r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy()) - || - !detail::check_probability( - function, - static_cast(p), - &r, - Policy())) - return (RealType)r; - // - // Special cases get short-circuited first: - // - if(p == 0) - return comp ? policies::raise_overflow_error(function, 0, Policy()) : 0; - if(p == 1) - return comp ? 0 : policies::raise_overflow_error(function, 0, Policy()); - // - // This is Pearson's approximation to the quantile, see - // Pearson, E. S. (1959) "Note on an approximation to the distribution of - // noncentral chi squared", Biometrika 46: 364. - // See also: - // "A comparison of approximations to percentiles of the noncentral chi2-distribution", - // Hardeo Sahai and Mario Miguel Ojeda, Revista de Matematica: Teoria y Aplicaciones 2003 10(1–2) : 57–76. - // Note that the latter reference refers to an approximation of the CDF, when they really mean the quantile. - // - value_type b = -(l * l) / (k + 3 * l); - value_type c = (k + 3 * l) / (k + 2 * l); - value_type ff = (k + 2 * l) / (c * c); - value_type guess; - if(comp) - { - guess = b + c * quantile(complement(chi_squared_distribution(ff), p)); - } - else - { - guess = b + c * quantile(chi_squared_distribution(ff), p); - } - // - // Sometimes guess goes very small or negative, in that case we have - // to do something else for the initial guess, this approximation - // was provided in a private communication from Thomas Luu, PhD candidate, - // University College London. It's an asymptotic expansion for the - // quantile which usually gets us within an order of magnitude of the - // correct answer. - // - if(guess < 0.005) - { - value_type pp = comp ? 1 - p : p; - //guess = pow(pow(value_type(2), (k / 2 - 1)) * exp(l / 2) * pp * k, 2 / k); - guess = pow(pow(value_type(2), (k / 2 - 1)) * exp(l / 2) * pp * k * boost::math::tgamma(k / 2, forwarding_policy()), (2 / k)); - if(guess == 0) - guess = tools::min_value(); - } - value_type result = detail::generic_quantile( - non_central_chi_squared_distribution(k, l), - p, - guess, - comp, - function); - - return policies::checked_narrowing_cast( - result, - function); - } - - template - RealType nccs_pdf(const non_central_chi_squared_distribution& dist, const RealType& x) - { - BOOST_MATH_STD_USING - static const char* function = "pdf(non_central_chi_squared_distribution<%1%>, %1%)"; - typedef typename policies::evaluation::type value_type; - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - - value_type k = dist.degrees_of_freedom(); - value_type l = dist.non_centrality(); - value_type r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy()) - || - !detail::check_positive_x( - function, - (value_type)x, - &r, - Policy())) - return (RealType)r; - - if(l == 0) - return pdf(boost::math::chi_squared_distribution(dist.degrees_of_freedom()), x); - - // Special case: - if(x == 0) - return 0; - if(l > 50) - { - r = non_central_chi_square_pdf(static_cast(x), k, l, forwarding_policy()); - } - else - { - r = log(x / l) * (k / 4 - 0.5f) - (x + l) / 2; - if(fabs(r) >= tools::log_max_value() / 4) - { - r = non_central_chi_square_pdf(static_cast(x), k, l, forwarding_policy()); - } - else - { - r = exp(r); - r = 0.5f * r - * boost::math::cyl_bessel_i(k/2 - 1, sqrt(l * x), forwarding_policy()); - } - } - return policies::checked_narrowing_cast( - r, - function); - } - - template - struct degrees_of_freedom_finder - { - degrees_of_freedom_finder( - RealType lam_, RealType x_, RealType p_, bool c) - : lam(lam_), x(x_), p(p_), comp(c) {} - - RealType operator()(const RealType& v) - { - non_central_chi_squared_distribution d(v, lam); - return comp ? - RealType(p - cdf(complement(d, x))) - : RealType(cdf(d, x) - p); - } - private: - RealType lam; - RealType x; - RealType p; - bool comp; - }; - - template - inline RealType find_degrees_of_freedom( - RealType lam, RealType x, RealType p, RealType q, const Policy& pol) - { - const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom"; - if((p == 0) || (q == 0)) - { - // - // Can't a thing if one of p and q is zero: - // - return policies::raise_evaluation_error(function, - "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", - RealType(std::numeric_limits::quiet_NaN()), Policy()); - } - degrees_of_freedom_finder f(lam, x, p < q ? p : q, p < q ? false : true); - tools::eps_tolerance tol(policies::digits()); - boost::uintmax_t max_iter = policies::get_max_root_iterations(); - // - // Pick an initial guess that we know will give us a probability - // right around 0.5. - // - RealType guess = x - lam; - if(guess < 1) - guess = 1; - std::pair ir = tools::bracket_and_solve_root( - f, guess, RealType(2), false, tol, max_iter, pol); - RealType result = ir.first + (ir.second - ir.first) / 2; - if(max_iter >= policies::get_max_root_iterations()) - { - return policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" - " or there is no answer to problem. Current best guess is %1%", result, Policy()); - } - return result; - } - - template - struct non_centrality_finder - { - non_centrality_finder( - RealType v_, RealType x_, RealType p_, bool c) - : v(v_), x(x_), p(p_), comp(c) {} - - RealType operator()(const RealType& lam) - { - non_central_chi_squared_distribution d(v, lam); - return comp ? - RealType(p - cdf(complement(d, x))) - : RealType(cdf(d, x) - p); - } - private: - RealType v; - RealType x; - RealType p; - bool comp; - }; - - template - inline RealType find_non_centrality( - RealType v, RealType x, RealType p, RealType q, const Policy& pol) - { - const char* function = "non_central_chi_squared<%1%>::find_non_centrality"; - if((p == 0) || (q == 0)) - { - // - // Can't do a thing if one of p and q is zero: - // - return policies::raise_evaluation_error(function, - "Can't find non centrality parameter when the probability is 0 or 1, only possible answer is %1%", - RealType(std::numeric_limits::quiet_NaN()), Policy()); - } - non_centrality_finder f(v, x, p < q ? p : q, p < q ? false : true); - tools::eps_tolerance tol(policies::digits()); - boost::uintmax_t max_iter = policies::get_max_root_iterations(); - // - // Pick an initial guess that we know will give us a probability - // right around 0.5. - // - RealType guess = x - v; - if(guess < 1) - guess = 1; - std::pair ir = tools::bracket_and_solve_root( - f, guess, RealType(2), false, tol, max_iter, pol); - RealType result = ir.first + (ir.second - ir.first) / 2; - if(max_iter >= policies::get_max_root_iterations()) - { - return policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" - " or there is no answer to problem. Current best guess is %1%", result, Policy()); - } - return result; - } - - } - - template > - class non_central_chi_squared_distribution - { - public: - typedef RealType value_type; - typedef Policy policy_type; - - non_central_chi_squared_distribution(RealType df_, RealType lambda) : df(df_), ncp(lambda) - { - const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::non_central_chi_squared_distribution(%1%,%1%)"; - RealType r; - detail::check_df( - function, - df, &r, Policy()); - detail::check_non_centrality( - function, - ncp, - &r, - Policy()); - } // non_central_chi_squared_distribution constructor. - - RealType degrees_of_freedom() const - { // Private data getter function. - return df; - } - RealType non_centrality() const - { // Private data getter function. - return ncp; - } - static RealType find_degrees_of_freedom(RealType lam, RealType x, RealType p) - { - const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom"; - typedef typename policies::evaluation::type value_type; - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - value_type result = detail::find_degrees_of_freedom( - static_cast(lam), - static_cast(x), - static_cast(p), - static_cast(1-p), - forwarding_policy()); - return policies::checked_narrowing_cast( - result, - function); - } - template - static RealType find_degrees_of_freedom(const complemented3_type& c) - { - const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom"; - typedef typename policies::evaluation::type value_type; - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - value_type result = detail::find_degrees_of_freedom( - static_cast(c.dist), - static_cast(c.param1), - static_cast(1-c.param2), - static_cast(c.param2), - forwarding_policy()); - return policies::checked_narrowing_cast( - result, - function); - } - static RealType find_non_centrality(RealType v, RealType x, RealType p) - { - const char* function = "non_central_chi_squared<%1%>::find_non_centrality"; - typedef typename policies::evaluation::type value_type; - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - value_type result = detail::find_non_centrality( - static_cast(v), - static_cast(x), - static_cast(p), - static_cast(1-p), - forwarding_policy()); - return policies::checked_narrowing_cast( - result, - function); - } - template - static RealType find_non_centrality(const complemented3_type& c) - { - const char* function = "non_central_chi_squared<%1%>::find_non_centrality"; - typedef typename policies::evaluation::type value_type; - typedef typename policies::normalise< - Policy, - policies::promote_float, - policies::promote_double, - policies::discrete_quantile<>, - policies::assert_undefined<> >::type forwarding_policy; - value_type result = detail::find_non_centrality( - static_cast(c.dist), - static_cast(c.param1), - static_cast(1-c.param2), - static_cast(c.param2), - forwarding_policy()); - return policies::checked_narrowing_cast( - result, - function); - } - private: - // Data member, initialized by constructor. - RealType df; // degrees of freedom. - RealType ncp; // non-centrality parameter - }; // template class non_central_chi_squared_distribution - - typedef non_central_chi_squared_distribution non_central_chi_squared; // Reserved name of type double. - - // Non-member functions to give properties of the distribution. - - template - inline const std::pair range(const non_central_chi_squared_distribution& /* dist */) - { // Range of permissible values for random variable k. - using boost::math::tools::max_value; - return std::pair(static_cast(0), max_value()); // Max integer? - } - - template - inline const std::pair support(const non_central_chi_squared_distribution& /* dist */) - { // Range of supported values for random variable k. - // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. - using boost::math::tools::max_value; - return std::pair(static_cast(0), max_value()); - } - - template - inline RealType mean(const non_central_chi_squared_distribution& dist) - { // Mean of poisson distribution = lambda. - const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::mean()"; - RealType k = dist.degrees_of_freedom(); - RealType l = dist.non_centrality(); - RealType r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy())) - return r; - return k + l; - } // mean - - template - inline RealType mode(const non_central_chi_squared_distribution& dist) - { // mode. - static const char* function = "mode(non_central_chi_squared_distribution<%1%> const&)"; - - RealType k = dist.degrees_of_freedom(); - RealType l = dist.non_centrality(); - RealType r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy())) - return (RealType)r; - return detail::generic_find_mode(dist, 1 + k, function); - } - - template - inline RealType variance(const non_central_chi_squared_distribution& dist) - { // variance. - const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::variance()"; - RealType k = dist.degrees_of_freedom(); - RealType l = dist.non_centrality(); - RealType r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy())) - return r; - return 2 * (2 * l + k); - } - - // RealType standard_deviation(const non_central_chi_squared_distribution& dist) - // standard_deviation provided by derived accessors. - - template - inline RealType skewness(const non_central_chi_squared_distribution& dist) - { // skewness = sqrt(l). - const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::skewness()"; - RealType k = dist.degrees_of_freedom(); - RealType l = dist.non_centrality(); - RealType r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy())) - return r; - BOOST_MATH_STD_USING - return pow(2 / (k + 2 * l), RealType(3)/2) * (k + 3 * l); - } - - template - inline RealType kurtosis_excess(const non_central_chi_squared_distribution& dist) - { - const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::kurtosis_excess()"; - RealType k = dist.degrees_of_freedom(); - RealType l = dist.non_centrality(); - RealType r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy())) - return r; - return 12 * (k + 4 * l) / ((k + 2 * l) * (k + 2 * l)); - } // kurtosis_excess - - template - inline RealType kurtosis(const non_central_chi_squared_distribution& dist) - { - return kurtosis_excess(dist) + 3; - } - - template - inline RealType pdf(const non_central_chi_squared_distribution& dist, const RealType& x) - { // Probability Density/Mass Function. - return detail::nccs_pdf(dist, x); - } // pdf - - template - RealType cdf(const non_central_chi_squared_distribution& dist, const RealType& x) - { - const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)"; - RealType k = dist.degrees_of_freedom(); - RealType l = dist.non_centrality(); - RealType r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy()) - || - !detail::check_positive_x( - function, - x, - &r, - Policy())) - return r; - - return detail::non_central_chi_squared_cdf(x, k, l, false, Policy()); - } // cdf - - template - RealType cdf(const complemented2_type, RealType>& c) - { // Complemented Cumulative Distribution Function - const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)"; - non_central_chi_squared_distribution const& dist = c.dist; - RealType x = c.param; - RealType k = dist.degrees_of_freedom(); - RealType l = dist.non_centrality(); - RealType r; - if(!detail::check_df( - function, - k, &r, Policy()) - || - !detail::check_non_centrality( - function, - l, - &r, - Policy()) - || - !detail::check_positive_x( - function, - x, - &r, - Policy())) - return r; - - return detail::non_central_chi_squared_cdf(x, k, l, true, Policy()); - } // ccdf - - template - inline RealType quantile(const non_central_chi_squared_distribution& dist, const RealType& p) - { // Quantile (or Percent Point) function. - return detail::nccs_quantile(dist, p, false); - } // quantile - - template - inline RealType quantile(const complemented2_type, RealType>& c) - { // Quantile (or Percent Point) function. - return detail::nccs_quantile(c.dist, c.param, true); - } // quantile complement. - - } // namespace math -} // namespace boost - -// This include must be at the end, *after* the accessors -// for this distribution have been defined, in order to -// keep compilers that support two-phase lookup happy. -#include - -#endif // BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP - - - +// boost\math\distributions\non_central_chi_squared.hpp + +// Copyright John Maddock 2008. + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP +#define BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP + +#include +#include // for incomplete gamma. gamma_q +#include // for cyl_bessel_i +#include // for iround +#include // complements +#include // central distribution +#include // error checks +#include // isnan. +#include // for root finding. +#include +#include + +namespace boost +{ + namespace math + { + + template + class non_central_chi_squared_distribution; + + namespace detail{ + + template + T non_central_chi_square_q(T x, T f, T theta, const Policy& pol, T init_sum = 0) + { + // + // Computes the complement of the Non-Central Chi-Square + // Distribution CDF by summing a weighted sum of complements + // of the central-distributions. The weighting factor is + // a Poisson Distribution. + // + // This is an application of the technique described in: + // + // Computing discrete mixtures of continuous + // distributions: noncentral chisquare, noncentral t + // and the distribution of the square of the sample + // multiple correlation coeficient. + // D. Benton, K. Krishnamoorthy. + // Computational Statistics & Data Analysis 43 (2003) 249 - 267 + // + BOOST_MATH_STD_USING + + // Special case: + if(x == 0) + return 1; + + // + // Initialize the variables we'll be using: + // + T lambda = theta / 2; + T del = f / 2; + T y = x / 2; + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + T errtol = boost::math::policies::get_epsilon(); + T sum = init_sum; + // + // k is the starting location for iteration, we'll + // move both forwards and backwards from this point. + // k is chosen as the peek of the Poisson weights, which + // will occur *before* the largest term. + // + int k = iround(lambda, pol); + // Forwards and backwards Poisson weights: + T poisf = boost::math::gamma_p_derivative(1 + k, lambda, pol); + T poisb = poisf * k / lambda; + // Initial forwards central chi squared term: + T gamf = boost::math::gamma_q(del + k, y, pol); + // Forwards and backwards recursion terms on the central chi squared: + T xtermf = boost::math::gamma_p_derivative(del + 1 + k, y, pol); + T xtermb = xtermf * (del + k) / y; + // Initial backwards central chi squared term: + T gamb = gamf - xtermb; + + // + // Forwards iteration first, this is the + // stable direction for the gamma function + // recurrences: + // + int i; + for(i = k; static_cast(i-k) < max_iter; ++i) + { + T term = poisf * gamf; + sum += term; + poisf *= lambda / (i + 1); + gamf += xtermf; + xtermf *= y / (del + i + 1); + if(((sum == 0) || (fabs(term / sum) < errtol)) && (term >= poisf * gamf)) + break; + } + //Error check: + if(static_cast(i-k) >= max_iter) + return policies::raise_evaluation_error( + "cdf(non_central_chi_squared_distribution<%1%>, %1%)", + "Series did not converge, closest value was %1%", sum, pol); + // + // Now backwards iteration: the gamma + // function recurrences are unstable in this + // direction, we rely on the terms deminishing in size + // faster than we introduce cancellation errors. + // For this reason it's very important that we start + // *before* the largest term so that backwards iteration + // is strictly converging. + // + for(i = k - 1; i >= 0; --i) + { + T term = poisb * gamb; + sum += term; + poisb *= i / lambda; + xtermb *= (del + i) / y; + gamb -= xtermb; + if((sum == 0) || (fabs(term / sum) < errtol)) + break; + } + + return sum; + } + + template + T non_central_chi_square_p_ding(T x, T f, T theta, const Policy& pol, T init_sum = 0) + { + // + // This is an implementation of: + // + // Algorithm AS 275: + // Computing the Non-Central #2 Distribution Function + // Cherng G. Ding + // Applied Statistics, Vol. 41, No. 2. (1992), pp. 478-482. + // + // This uses a stable forward iteration to sum the + // CDF, unfortunately this can not be used for large + // values of the non-centrality parameter because: + // * The first term may underfow to zero. + // * We may need an extra-ordinary number of terms + // before we reach the first *significant* term. + // + BOOST_MATH_STD_USING + // Special case: + if(x == 0) + return 0; + T tk = boost::math::gamma_p_derivative(f/2 + 1, x/2, pol); + T lambda = theta / 2; + T vk = exp(-lambda); + T uk = vk; + T sum = init_sum + tk * vk; + if(sum == 0) + return sum; + + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + T errtol = boost::math::policies::get_epsilon(); + + int i; + T lterm(0), term(0); + for(i = 1; static_cast(i) < max_iter; ++i) + { + tk = tk * x / (f + 2 * i); + uk = uk * lambda / i; + vk = vk + uk; + lterm = term; + term = vk * tk; + sum += term; + if((fabs(term / sum) < errtol) && (term <= lterm)) + break; + } + //Error check: + if(static_cast(i) >= max_iter) + return policies::raise_evaluation_error( + "cdf(non_central_chi_squared_distribution<%1%>, %1%)", + "Series did not converge, closest value was %1%", sum, pol); + return sum; + } + + + template + T non_central_chi_square_p(T y, T n, T lambda, const Policy& pol, T init_sum) + { + // + // This is taken more or less directly from: + // + // Computing discrete mixtures of continuous + // distributions: noncentral chisquare, noncentral t + // and the distribution of the square of the sample + // multiple correlation coeficient. + // D. Benton, K. Krishnamoorthy. + // Computational Statistics & Data Analysis 43 (2003) 249 - 267 + // + // We're summing a Poisson weighting term multiplied by + // a central chi squared distribution. + // + BOOST_MATH_STD_USING + // Special case: + if(y == 0) + return 0; + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + T errtol = boost::math::policies::get_epsilon(); + T errorf(0), errorb(0); + + T x = y / 2; + T del = lambda / 2; + // + // Starting location for the iteration, we'll iterate + // both forwards and backwards from this point. The + // location chosen is the maximum of the Poisson weight + // function, which ocurrs *after* the largest term in the + // sum. + // + int k = iround(del, pol); + T a = n / 2 + k; + // Central chi squared term for forward iteration: + T gamkf = boost::math::gamma_p(a, x, pol); + + if(lambda == 0) + return gamkf; + // Central chi squared term for backward iteration: + T gamkb = gamkf; + // Forwards Poisson weight: + T poiskf = gamma_p_derivative(k+1, del, pol); + // Backwards Poisson weight: + T poiskb = poiskf; + // Forwards gamma function recursion term: + T xtermf = boost::math::gamma_p_derivative(a, x, pol); + // Backwards gamma function recursion term: + T xtermb = xtermf * x / a; + T sum = init_sum + poiskf * gamkf; + if(sum == 0) + return sum; + int i = 1; + // + // Backwards recursion first, this is the stable + // direction for gamma function recurrences: + // + while(i <= k) + { + xtermb *= (a - i + 1) / x; + gamkb += xtermb; + poiskb = poiskb * (k - i + 1) / del; + errorf = errorb; + errorb = gamkb * poiskb; + sum += errorb; + if((fabs(errorb / sum) < errtol) && (errorb <= errorf)) + break; + ++i; + } + i = 1; + // + // Now forwards recursion, the gamma function + // recurrence relation is unstable in this direction, + // so we rely on the magnitude of successive terms + // decreasing faster than we introduce cancellation error. + // For this reason it's vital that k is chosen to be *after* + // the largest term, so that successive forward iterations + // are strictly (and rapidly) converging. + // + do + { + xtermf = xtermf * x / (a + i - 1); + gamkf = gamkf - xtermf; + poiskf = poiskf * del / (k + i); + errorf = poiskf * gamkf; + sum += errorf; + ++i; + }while((fabs(errorf / sum) > errtol) && (static_cast(i) < max_iter)); + + //Error check: + if(static_cast(i) >= max_iter) + return policies::raise_evaluation_error( + "cdf(non_central_chi_squared_distribution<%1%>, %1%)", + "Series did not converge, closest value was %1%", sum, pol); + + return sum; + } + + template + T non_central_chi_square_pdf(T x, T n, T lambda, const Policy& pol) + { + // + // As above but for the PDF: + // + BOOST_MATH_STD_USING + boost::uintmax_t max_iter = policies::get_max_series_iterations(); + T errtol = boost::math::policies::get_epsilon(); + T x2 = x / 2; + T n2 = n / 2; + T l2 = lambda / 2; + T sum = 0; + int k = itrunc(l2); + T pois = gamma_p_derivative(k + 1, l2, pol) * gamma_p_derivative(n2 + k, x2); + if(pois == 0) + return 0; + T poisb = pois; + for(int i = k; ; ++i) + { + sum += pois; + if(pois / sum < errtol) + break; + if(static_cast(i - k) >= max_iter) + return policies::raise_evaluation_error( + "pdf(non_central_chi_squared_distribution<%1%>, %1%)", + "Series did not converge, closest value was %1%", sum, pol); + pois *= l2 * x2 / ((i + 1) * (n2 + i)); + } + for(int i = k - 1; i >= 0; --i) + { + poisb *= (i + 1) * (n2 + i) / (l2 * x2); + sum += poisb; + if(poisb / sum < errtol) + break; + } + return sum / 2; + } + + template + inline RealType non_central_chi_squared_cdf(RealType x, RealType k, RealType l, bool invert, const Policy&) + { + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + BOOST_MATH_STD_USING + value_type result; + if(l == 0) + result = cdf(boost::math::chi_squared_distribution(k), x); + else if(x > k + l) + { + // Complement is the smaller of the two: + result = detail::non_central_chi_square_q( + static_cast(x), + static_cast(k), + static_cast(l), + forwarding_policy(), + static_cast(invert ? 0 : -1)); + invert = !invert; + } + else if(l < 200) + { + // For small values of the non-centrality parameter + // we can use Ding's method: + result = detail::non_central_chi_square_p_ding( + static_cast(x), + static_cast(k), + static_cast(l), + forwarding_policy(), + static_cast(invert ? -1 : 0)); + } + else + { + // For largers values of the non-centrality + // parameter Ding's method will consume an + // extra-ordinary number of terms, and worse + // may return zero when the result is in fact + // finite, use Krishnamoorthy's method instead: + result = detail::non_central_chi_square_p( + static_cast(x), + static_cast(k), + static_cast(l), + forwarding_policy(), + static_cast(invert ? -1 : 0)); + } + if(invert) + result = -result; + return policies::checked_narrowing_cast( + result, + "boost::math::non_central_chi_squared_cdf<%1%>(%1%, %1%, %1%)"); + } + + template + struct nccs_quantile_functor + { + nccs_quantile_functor(const non_central_chi_squared_distribution& d, T t, bool c) + : dist(d), target(t), comp(c) {} + + T operator()(const T& x) + { + return comp ? + target - cdf(complement(dist, x)) + : cdf(dist, x) - target; + } + + private: + non_central_chi_squared_distribution dist; + T target; + bool comp; + }; + + template + RealType nccs_quantile(const non_central_chi_squared_distribution& dist, const RealType& p, bool comp) + { + BOOST_MATH_STD_USING + static const char* function = "quantile(non_central_chi_squared_distribution<%1%>, %1%)"; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + value_type k = dist.degrees_of_freedom(); + value_type l = dist.non_centrality(); + value_type r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy()) + || + !detail::check_probability( + function, + static_cast(p), + &r, + Policy())) + return (RealType)r; + // + // Special cases get short-circuited first: + // + if(p == 0) + return comp ? policies::raise_overflow_error(function, 0, Policy()) : 0; + if(p == 1) + return comp ? 0 : policies::raise_overflow_error(function, 0, Policy()); + // + // This is Pearson's approximation to the quantile, see + // Pearson, E. S. (1959) "Note on an approximation to the distribution of + // noncentral chi squared", Biometrika 46: 364. + // See also: + // "A comparison of approximations to percentiles of the noncentral chi2-distribution", + // Hardeo Sahai and Mario Miguel Ojeda, Revista de Matematica: Teoria y Aplicaciones 2003 10(1–2) : 57–76. + // Note that the latter reference refers to an approximation of the CDF, when they really mean the quantile. + // + value_type b = -(l * l) / (k + 3 * l); + value_type c = (k + 3 * l) / (k + 2 * l); + value_type ff = (k + 2 * l) / (c * c); + value_type guess; + if(comp) + { + guess = b + c * quantile(complement(chi_squared_distribution(ff), p)); + } + else + { + guess = b + c * quantile(chi_squared_distribution(ff), p); + } + // + // Sometimes guess goes very small or negative, in that case we have + // to do something else for the initial guess, this approximation + // was provided in a private communication from Thomas Luu, PhD candidate, + // University College London. It's an asymptotic expansion for the + // quantile which usually gets us within an order of magnitude of the + // correct answer. + // + if(guess < 0.005) + { + value_type pp = comp ? 1 - p : p; + //guess = pow(pow(value_type(2), (k / 2 - 1)) * exp(l / 2) * pp * k, 2 / k); + guess = pow(pow(value_type(2), (k / 2 - 1)) * exp(l / 2) * pp * k * boost::math::tgamma(k / 2, forwarding_policy()), (2 / k)); + if(guess == 0) + guess = tools::min_value(); + } + value_type result = detail::generic_quantile( + non_central_chi_squared_distribution(k, l), + p, + guess, + comp, + function); + + return policies::checked_narrowing_cast( + result, + function); + } + + template + RealType nccs_pdf(const non_central_chi_squared_distribution& dist, const RealType& x) + { + BOOST_MATH_STD_USING + static const char* function = "pdf(non_central_chi_squared_distribution<%1%>, %1%)"; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + + value_type k = dist.degrees_of_freedom(); + value_type l = dist.non_centrality(); + value_type r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy()) + || + !detail::check_positive_x( + function, + (value_type)x, + &r, + Policy())) + return (RealType)r; + + if(l == 0) + return pdf(boost::math::chi_squared_distribution(dist.degrees_of_freedom()), x); + + // Special case: + if(x == 0) + return 0; + if(l > 50) + { + r = non_central_chi_square_pdf(static_cast(x), k, l, forwarding_policy()); + } + else + { + r = log(x / l) * (k / 4 - 0.5f) - (x + l) / 2; + if(fabs(r) >= tools::log_max_value() / 4) + { + r = non_central_chi_square_pdf(static_cast(x), k, l, forwarding_policy()); + } + else + { + r = exp(r); + r = 0.5f * r + * boost::math::cyl_bessel_i(k/2 - 1, sqrt(l * x), forwarding_policy()); + } + } + return policies::checked_narrowing_cast( + r, + function); + } + + template + struct degrees_of_freedom_finder + { + degrees_of_freedom_finder( + RealType lam_, RealType x_, RealType p_, bool c) + : lam(lam_), x(x_), p(p_), comp(c) {} + + RealType operator()(const RealType& v) + { + non_central_chi_squared_distribution d(v, lam); + return comp ? + RealType(p - cdf(complement(d, x))) + : RealType(cdf(d, x) - p); + } + private: + RealType lam; + RealType x; + RealType p; + bool comp; + }; + + template + inline RealType find_degrees_of_freedom( + RealType lam, RealType x, RealType p, RealType q, const Policy& pol) + { + const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom"; + if((p == 0) || (q == 0)) + { + // + // Can't a thing if one of p and q is zero: + // + return policies::raise_evaluation_error(function, + "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%", + RealType(std::numeric_limits::quiet_NaN()), Policy()); + } + degrees_of_freedom_finder f(lam, x, p < q ? p : q, p < q ? false : true); + tools::eps_tolerance tol(policies::digits()); + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + // + // Pick an initial guess that we know will give us a probability + // right around 0.5. + // + RealType guess = x - lam; + if(guess < 1) + guess = 1; + std::pair ir = tools::bracket_and_solve_root( + f, guess, RealType(2), false, tol, max_iter, pol); + RealType result = ir.first + (ir.second - ir.first) / 2; + if(max_iter >= policies::get_max_root_iterations()) + { + return policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" + " or there is no answer to problem. Current best guess is %1%", result, Policy()); + } + return result; + } + + template + struct non_centrality_finder + { + non_centrality_finder( + RealType v_, RealType x_, RealType p_, bool c) + : v(v_), x(x_), p(p_), comp(c) {} + + RealType operator()(const RealType& lam) + { + non_central_chi_squared_distribution d(v, lam); + return comp ? + RealType(p - cdf(complement(d, x))) + : RealType(cdf(d, x) - p); + } + private: + RealType v; + RealType x; + RealType p; + bool comp; + }; + + template + inline RealType find_non_centrality( + RealType v, RealType x, RealType p, RealType q, const Policy& pol) + { + const char* function = "non_central_chi_squared<%1%>::find_non_centrality"; + if((p == 0) || (q == 0)) + { + // + // Can't do a thing if one of p and q is zero: + // + return policies::raise_evaluation_error(function, + "Can't find non centrality parameter when the probability is 0 or 1, only possible answer is %1%", + RealType(std::numeric_limits::quiet_NaN()), Policy()); + } + non_centrality_finder f(v, x, p < q ? p : q, p < q ? false : true); + tools::eps_tolerance tol(policies::digits()); + boost::uintmax_t max_iter = policies::get_max_root_iterations(); + // + // Pick an initial guess that we know will give us a probability + // right around 0.5. + // + RealType guess = x - v; + if(guess < 1) + guess = 1; + std::pair ir = tools::bracket_and_solve_root( + f, guess, RealType(2), false, tol, max_iter, pol); + RealType result = ir.first + (ir.second - ir.first) / 2; + if(max_iter >= policies::get_max_root_iterations()) + { + return policies::raise_evaluation_error(function, "Unable to locate solution in a reasonable time:" + " or there is no answer to problem. Current best guess is %1%", result, Policy()); + } + return result; + } + + } + + template > + class non_central_chi_squared_distribution + { + public: + typedef RealType value_type; + typedef Policy policy_type; + + non_central_chi_squared_distribution(RealType df_, RealType lambda) : df(df_), ncp(lambda) + { + const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::non_central_chi_squared_distribution(%1%,%1%)"; + RealType r; + detail::check_df( + function, + df, &r, Policy()); + detail::check_non_centrality( + function, + ncp, + &r, + Policy()); + } // non_central_chi_squared_distribution constructor. + + RealType degrees_of_freedom() const + { // Private data getter function. + return df; + } + RealType non_centrality() const + { // Private data getter function. + return ncp; + } + static RealType find_degrees_of_freedom(RealType lam, RealType x, RealType p) + { + const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom"; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + value_type result = detail::find_degrees_of_freedom( + static_cast(lam), + static_cast(x), + static_cast(p), + static_cast(1-p), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } + template + static RealType find_degrees_of_freedom(const complemented3_type& c) + { + const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom"; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + value_type result = detail::find_degrees_of_freedom( + static_cast(c.dist), + static_cast(c.param1), + static_cast(1-c.param2), + static_cast(c.param2), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } + static RealType find_non_centrality(RealType v, RealType x, RealType p) + { + const char* function = "non_central_chi_squared<%1%>::find_non_centrality"; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + value_type result = detail::find_non_centrality( + static_cast(v), + static_cast(x), + static_cast(p), + static_cast(1-p), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } + template + static RealType find_non_centrality(const complemented3_type& c) + { + const char* function = "non_central_chi_squared<%1%>::find_non_centrality"; + typedef typename policies::evaluation::type value_type; + typedef typename policies::normalise< + Policy, + policies::promote_float, + policies::promote_double, + policies::discrete_quantile<>, + policies::assert_undefined<> >::type forwarding_policy; + value_type result = detail::find_non_centrality( + static_cast(c.dist), + static_cast(c.param1), + static_cast(1-c.param2), + static_cast(c.param2), + forwarding_policy()); + return policies::checked_narrowing_cast( + result, + function); + } + private: + // Data member, initialized by constructor. + RealType df; // degrees of freedom. + RealType ncp; // non-centrality parameter + }; // template class non_central_chi_squared_distribution + + typedef non_central_chi_squared_distribution non_central_chi_squared; // Reserved name of type double. + + // Non-member functions to give properties of the distribution. + + template + inline const std::pair range(const non_central_chi_squared_distribution& /* dist */) + { // Range of permissible values for random variable k. + using boost::math::tools::max_value; + return std::pair(static_cast(0), max_value()); // Max integer? + } + + template + inline const std::pair support(const non_central_chi_squared_distribution& /* dist */) + { // Range of supported values for random variable k. + // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero. + using boost::math::tools::max_value; + return std::pair(static_cast(0), max_value()); + } + + template + inline RealType mean(const non_central_chi_squared_distribution& dist) + { // Mean of poisson distribution = lambda. + const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::mean()"; + RealType k = dist.degrees_of_freedom(); + RealType l = dist.non_centrality(); + RealType r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy())) + return r; + return k + l; + } // mean + + template + inline RealType mode(const non_central_chi_squared_distribution& dist) + { // mode. + static const char* function = "mode(non_central_chi_squared_distribution<%1%> const&)"; + + RealType k = dist.degrees_of_freedom(); + RealType l = dist.non_centrality(); + RealType r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy())) + return (RealType)r; + return detail::generic_find_mode(dist, 1 + k, function); + } + + template + inline RealType variance(const non_central_chi_squared_distribution& dist) + { // variance. + const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::variance()"; + RealType k = dist.degrees_of_freedom(); + RealType l = dist.non_centrality(); + RealType r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy())) + return r; + return 2 * (2 * l + k); + } + + // RealType standard_deviation(const non_central_chi_squared_distribution& dist) + // standard_deviation provided by derived accessors. + + template + inline RealType skewness(const non_central_chi_squared_distribution& dist) + { // skewness = sqrt(l). + const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::skewness()"; + RealType k = dist.degrees_of_freedom(); + RealType l = dist.non_centrality(); + RealType r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy())) + return r; + BOOST_MATH_STD_USING + return pow(2 / (k + 2 * l), RealType(3)/2) * (k + 3 * l); + } + + template + inline RealType kurtosis_excess(const non_central_chi_squared_distribution& dist) + { + const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::kurtosis_excess()"; + RealType k = dist.degrees_of_freedom(); + RealType l = dist.non_centrality(); + RealType r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy())) + return r; + return 12 * (k + 4 * l) / ((k + 2 * l) * (k + 2 * l)); + } // kurtosis_excess + + template + inline RealType kurtosis(const non_central_chi_squared_distribution& dist) + { + return kurtosis_excess(dist) + 3; + } + + template + inline RealType pdf(const non_central_chi_squared_distribution& dist, const RealType& x) + { // Probability Density/Mass Function. + return detail::nccs_pdf(dist, x); + } // pdf + + template + RealType cdf(const non_central_chi_squared_distribution& dist, const RealType& x) + { + const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)"; + RealType k = dist.degrees_of_freedom(); + RealType l = dist.non_centrality(); + RealType r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy()) + || + !detail::check_positive_x( + function, + x, + &r, + Policy())) + return r; + + return detail::non_central_chi_squared_cdf(x, k, l, false, Policy()); + } // cdf + + template + RealType cdf(const complemented2_type, RealType>& c) + { // Complemented Cumulative Distribution Function + const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)"; + non_central_chi_squared_distribution const& dist = c.dist; + RealType x = c.param; + RealType k = dist.degrees_of_freedom(); + RealType l = dist.non_centrality(); + RealType r; + if(!detail::check_df( + function, + k, &r, Policy()) + || + !detail::check_non_centrality( + function, + l, + &r, + Policy()) + || + !detail::check_positive_x( + function, + x, + &r, + Policy())) + return r; + + return detail::non_central_chi_squared_cdf(x, k, l, true, Policy()); + } // ccdf + + template + inline RealType quantile(const non_central_chi_squared_distribution& dist, const RealType& p) + { // Quantile (or Percent Point) function. + return detail::nccs_quantile(dist, p, false); + } // quantile + + template + inline RealType quantile(const complemented2_type, RealType>& c) + { // Quantile (or Percent Point) function. + return detail::nccs_quantile(c.dist, c.param, true); + } // quantile complement. + + } // namespace math +} // namespace boost + +// This include must be at the end, *after* the accessors +// for this distribution have been defined, in order to +// keep compilers that support two-phase lookup happy. +#include + +#endif // BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP + + + diff --git a/src/external/3rd/library/boost/boost/mpi/python/serialize.hpp b/src/external/3rd/library/boost/boost/mpi/python/serialize.hpp index badc00cfd..b4ca6323e 100644 --- a/src/external/3rd/library/boost/boost/mpi/python/serialize.hpp +++ b/src/external/3rd/library/boost/boost/mpi/python/serialize.hpp @@ -1,539 +1,539 @@ -// Copyright (C) 2006 Douglas Gregor - -// Use, modification and distribution is subject to the Boost Software -// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -// Authors: Douglas Gregor - -/** @file serialize.hpp - * - * This file provides Boost.Serialization support for Python objects - * within Boost.MPI. Python objects can be serialized in one of two - * ways. The default serialization method involves using the Python - * "pickle" module to pickle the Python objects, transmits the - * pickled representation, and unpickles the result when - * received. For C++ types that have been exposed to Python and - * registered with register_serialized(), objects are directly - * serialized for transmissing, skipping the pickling step. - */ -#ifndef BOOST_MPI_PYTHON_SERIALIZE_HPP -#define BOOST_MPI_PYTHON_SERIALIZE_HPP - -#include - -#include -#include -#include - -#include -#include - -#include - -#include -#include - -#include -#include - -#include - -#include - -#define BOOST_MPI_PYTHON_FORWARD_ONLY -#include - -/************************************************************************ - * Boost.Python Serialization Section * - ************************************************************************/ -#if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE) -/** - * @brief Declare IArchive and OArchive as a Boost.Serialization - * archives that can be used for Python objects. - * - * This macro can only be expanded from the global namespace. It only - * requires that Archiver be forward-declared. IArchiver and OArchiver - * will only support Serialization of Python objects by pickling - * them. If the Archiver type should also support "direct" - * serialization (for C++ types), use - * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE instead. - */ -# define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \ -namespace boost { namespace python { namespace api { \ - template \ - struct enable_binary< IArchiver , R, T> {}; \ - \ - template \ - struct enable_binary< OArchiver , R, T> {}; \ -} } } -# else -# define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) -#endif - -/** - * @brief Declare IArchiver and OArchiver as a Boost.Serialization - * archives that can be used for Python objects and C++ objects - * wrapped in Python. - * - * This macro can only be expanded from the global namespace. It only - * requires that IArchiver and OArchiver be forward-declared. However, - * note that you will also need to write - * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver, - * OArchiver) in one of your translation units. - -DPG PICK UP HERE - */ -#define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \ -BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \ -namespace boost { namespace python { namespace detail { \ -template<> \ -BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >& \ - get_direct_serialization_table< IArchiver , OArchiver >(); \ -} \ - \ -template<> \ -struct has_direct_serialization< IArchiver , OArchiver> : mpl::true_ { }; \ - \ -template<> \ -struct output_archiver< IArchiver > { typedef OArchiver type; }; \ - \ -template<> \ -struct input_archiver< OArchiver > { typedef IArchiver type; }; \ -} } - -/** - * @brief Define the implementation for Boost.Serialization archivers - * that can be used for Python objects and C++ objects wrapped in - * Python. - * - * This macro can only be expanded from the global namespace. It only - * requires that IArchiver and OArchiver be forward-declared. Before - * using this macro, you will need to declare IArchiver and OArchiver - * as direct serialization archives with - * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver). - */ -#define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver, OArchiver) \ -namespace boost { namespace python { namespace detail { \ -template \ - class BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >; \ - \ -template<> \ - BOOST_MPI_PYTHON_DECL \ - direct_serialization_table< IArchiver , OArchiver >& \ - get_direct_serialization_table< IArchiver , OArchiver >( ) \ -{ \ - static direct_serialization_table< IArchiver, OArchiver > table; \ - return table; \ -} \ -} } } - -namespace boost { namespace python { - -/** - * INTERNAL ONLY - * - * Provides access to the Python "pickle" module from within C++. - */ -class BOOST_MPI_PYTHON_DECL pickle { - struct data_t; - -public: - static str dumps(object obj, int protocol = -1); - static object loads(str s); - -private: - static void initialize_data(); - - static data_t* data; -}; - -/** - * @brief Whether the input/output archiver pair has "direct" - * serialization for C++ objects exposed in Python. - * - * Users do not typically need to specialize this trait, as it will be - * specialized as part of the macro - * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE. - */ -template -struct has_direct_serialization : mpl::false_ { }; - -/** - * @brief A metafunction that determines the output archiver for the - * given input archiver. - * - * Users do not typically need to specialize this trait, as it will be - * specialized as part of the macro - * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE. - */ -template struct output_archiver { }; - -/** - * @brief A metafunction that determines the input archiver for the - * given output archiver. - * - * Users do not typically need to specialize this trait, as it will be - * specialized as part of the macro - * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE. - * - */ -template struct input_archiver { }; - -namespace detail { - - /** - * INTERNAL ONLY - * - * This class contains the direct-serialization code for the given - * IArchiver/OArchiver pair. It is intended to be used as a - * singleton class, and will be accessed when (de-)serializing a - * Boost.Python object with an archiver that supports direct - * serializations. Do not create instances of this class directly: - * instead, use get_direct_serialization_table. - */ - template - class BOOST_MPI_PYTHON_DECL direct_serialization_table - { - public: - typedef boost::function3 - saver_t; - typedef boost::function3 - loader_t; - - typedef std::map > savers_t; - typedef std::map loaders_t; - - /** - * Retrieve the saver (serializer) associated with the Python - * object @p obj. - * - * @param obj The object we want to save. Only its (Python) type - * is important. - * - * @param descriptor The value of the descriptor associated to - * the returned saver. Will be set to zero if no saver was found - * for @p obj. - * - * @returns a function object that can be used to serialize this - * object (and other objects of the same type), if possible. If - * no saver can be found, returns an empty function object.. - */ - saver_t saver(const object& obj, int& descriptor) - { - typename savers_t::iterator pos = savers.find(obj.ptr()->ob_type); - if (pos != savers.end()) { - descriptor = pos->second.first; - return pos->second.second; - } - else { - descriptor = 0; - return saver_t(); - } - } - - /** - * Retrieve the loader (deserializer) associated with the given - * descriptor. - * - * @param descriptor The descriptor number provided by saver() - * when determining the saver for this type. - * - * @returns a function object that can be used to deserialize an - * object whose type is the same as that corresponding to the - * descriptor. If the descriptor is unknown, the return value - * will be an empty function object. - */ - loader_t loader(int descriptor) - { - typename loaders_t::iterator pos = loaders.find(descriptor); - if (pos != loaders.end()) - return pos->second; - else - return loader_t(); - } - - /** - * Register the type T for direct serialization. - * - * @param value A sample value of the type @c T. This may be used - * to compute the Python type associated with the C++ type @c T. - * - * @param type The Python type associated with the C++ type @c - * T. If not provided, it will be computed from the same value @p - * value. - */ - template - void register_type(const T& value = T(), PyTypeObject* type = 0) - { - // If the user did not provide us with a Python type, figure it - // out for ourselves. - if (!type) { - object obj(value); - type = obj.ptr()->ob_type; - } - - register_type(default_saver(), default_loader(type), value, type); - } - - /** - * Register the type T for direct serialization. - * - * @param saver A function object that will serialize a - * Boost.Python object (that represents a C++ object of type @c - * T) to an @c OArchive. - * - * @param loader A function object that will deserialize from an - * @c IArchive into a Boost.Python object that represents a C++ - * object of type @c T. - * - * @param value A sample value of the type @c T. This may be used - * to compute the Python type associated with the C++ type @c T. - * - * @param type The Python type associated with the C++ type @c - * T. If not provided, it will be computed from the same value @p - * value. - */ - template - void register_type(const saver_t& saver, const loader_t& loader, - const T& value = T(), PyTypeObject* type = 0) - { - // If the user did not provide us with a Python type, figure it - // out for ourselves. - if (!type) { - object obj(value); - type = obj.ptr()->ob_type; - } - - int descriptor = savers.size() + 1; - if (savers.find(type) != savers.end()) - return; - - savers[type] = std::make_pair(descriptor, saver); - loaders[descriptor] = loader; - } - - protected: - template - struct default_saver { - void operator()(OArchiver& ar, const object& obj, const unsigned int) { - T value = extract(obj)(); - ar << value; - } - }; - - template - struct default_loader { - default_loader(PyTypeObject* type) : type(type) { } - - void operator()(IArchiver& ar, object& obj, const unsigned int) { - // If we can, extract the object in place. - if (!is_fundamental::value && obj && obj.ptr()->ob_type == type) { - ar >> extract(obj)(); - } else { - T value; - ar >> value; - obj = object(value); - } - } - - private: - PyTypeObject* type; - }; - - savers_t savers; - loaders_t loaders; - }; - - /** - * @brief Retrieve the direct-serialization table for an - * IArchiver/OArchiver pair. - * - * This function is responsible for returning a reference to the - * singleton direct-serialization table. Its primary template is - * left undefined, to force the use of an explicit specialization - * with a definition in a single translation unit. Use the macro - * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL to define this - * explicit specialization. - */ - template - direct_serialization_table& - get_direct_serialization_table(); -} // end namespace detail - -/** - * @brief Register the type T for direct serialization. - * - * The @c register_serialized function registers a C++ type for direct - * serialization with the given @c IArchiver/@c OArchiver pair. Direct - * serialization elides the use of the Python @c pickle package when - * serializing Python objects that represent C++ values. Direct - * serialization can be beneficial both to improve serialization - * performance (Python pickling can be very inefficient) and to permit - * serialization for Python-wrapped C++ objects that do not support - * pickling. - * - * @param value A sample value of the type @c T. This may be used - * to compute the Python type associated with the C++ type @c T. - * - * @param type The Python type associated with the C++ type @c - * T. If not provided, it will be computed from the same value @p - * value. - */ -template -void -register_serialized(const T& value = T(), PyTypeObject* type = 0) -{ - detail::direct_serialization_table& table = - detail::get_direct_serialization_table(); - table.register_type(value, type); -} - -namespace detail { - -/// Save a Python object by pickling it. -template -void -save_impl(Archiver& ar, const boost::python::object& obj, - const unsigned int /*version*/, - mpl::false_ /*has_direct_serialization*/) -{ - boost::python::str py_string = boost::python::pickle::dumps(obj); - int len = boost::python::extract(py_string.attr("__len__")()); - const char* string = boost::python::extract(py_string); - ar << len << boost::serialization::make_array(string, len); -} - -/// Try to save a Python object by directly serializing it; fall back -/// on pickling if required. -template -void -save_impl(Archiver& ar, const boost::python::object& obj, - const unsigned int version, - mpl::true_ /*has_direct_serialization*/) -{ - typedef Archiver OArchiver; - typedef typename input_archiver::type IArchiver; - typedef typename direct_serialization_table::saver_t - saver_t; - - direct_serialization_table& table = - get_direct_serialization_table(); - - int descriptor = 0; - if (saver_t saver = table.saver(obj, descriptor)) { - ar << descriptor; - saver(ar, obj, version); - } else { - // Pickle it - ar << descriptor; - detail::save_impl(ar, obj, version, mpl::false_()); - } -} - -/// Load a Python object by unpickling it -template -void -load_impl(Archiver& ar, boost::python::object& obj, - const unsigned int /*version*/, - mpl::false_ /*has_direct_serialization*/) -{ - int len; - ar >> len; - - std::unique_ptr string(new char[len]); - ar >> boost::serialization::make_array(string.get(), len); - boost::python::str py_string(string.get(), len); - obj = boost::python::pickle::loads(py_string); -} - -/// Try to load a Python object by directly deserializing it; fall back -/// on unpickling if required. -template -void -load_impl(Archiver& ar, boost::python::object& obj, - const unsigned int version, - mpl::true_ /*has_direct_serialization*/) -{ - typedef Archiver IArchiver; - typedef typename output_archiver::type OArchiver; - typedef typename direct_serialization_table::loader_t - loader_t; - - direct_serialization_table& table = - get_direct_serialization_table(); - - int descriptor; - ar >> descriptor; - - if (descriptor) { - loader_t loader = table.loader(descriptor); - BOOST_ASSERT(loader); - - loader(ar, obj, version); - } else { - // Unpickle it - detail::load_impl(ar, obj, version, mpl::false_()); - } -} - -} // end namespace detail - -template -void -save(Archiver& ar, const boost::python::object& obj, - const unsigned int version) -{ - typedef Archiver OArchiver; - typedef typename input_archiver::type IArchiver; - - detail::save_impl(ar, obj, version, - has_direct_serialization()); -} - -template -void -load(Archiver& ar, boost::python::object& obj, - const unsigned int version) -{ - typedef Archiver IArchiver; - typedef typename output_archiver::type OArchiver; - - detail::load_impl(ar, obj, version, - has_direct_serialization()); -} - -template -inline void -serialize(Archive& ar, boost::python::object& obj, const unsigned int version) -{ - boost::serialization::split_free(ar, obj, version); -} - -} } // end namespace boost::python - -/************************************************************************ - * Boost.MPI-Specific Section * - ************************************************************************/ -namespace boost { namespace mpi { - class packed_iarchive; - class packed_oarchive; -} } // end namespace boost::mpi - -BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE( - ::boost::mpi::packed_iarchive, - ::boost::mpi::packed_oarchive) - -namespace boost { namespace mpi { namespace python { - -template -void -register_serialized(const T& value, PyTypeObject* type) -{ - using boost::python::register_serialized; - register_serialized(value, type); -} - -} } } // end namespace boost::mpi::python - -#endif // BOOST_MPI_PYTHON_SERIALIZE_HPP +// Copyright (C) 2006 Douglas Gregor + +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Douglas Gregor + +/** @file serialize.hpp + * + * This file provides Boost.Serialization support for Python objects + * within Boost.MPI. Python objects can be serialized in one of two + * ways. The default serialization method involves using the Python + * "pickle" module to pickle the Python objects, transmits the + * pickled representation, and unpickles the result when + * received. For C++ types that have been exposed to Python and + * registered with register_serialized(), objects are directly + * serialized for transmissing, skipping the pickling step. + */ +#ifndef BOOST_MPI_PYTHON_SERIALIZE_HPP +#define BOOST_MPI_PYTHON_SERIALIZE_HPP + +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +#include + +#include + +#define BOOST_MPI_PYTHON_FORWARD_ONLY +#include + +/************************************************************************ + * Boost.Python Serialization Section * + ************************************************************************/ +#if !defined(BOOST_NO_SFINAE) && !defined(BOOST_NO_IS_CONVERTIBLE) +/** + * @brief Declare IArchive and OArchive as a Boost.Serialization + * archives that can be used for Python objects. + * + * This macro can only be expanded from the global namespace. It only + * requires that Archiver be forward-declared. IArchiver and OArchiver + * will only support Serialization of Python objects by pickling + * them. If the Archiver type should also support "direct" + * serialization (for C++ types), use + * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE instead. + */ +# define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \ +namespace boost { namespace python { namespace api { \ + template \ + struct enable_binary< IArchiver , R, T> {}; \ + \ + template \ + struct enable_binary< OArchiver , R, T> {}; \ +} } } +# else +# define BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) +#endif + +/** + * @brief Declare IArchiver and OArchiver as a Boost.Serialization + * archives that can be used for Python objects and C++ objects + * wrapped in Python. + * + * This macro can only be expanded from the global namespace. It only + * requires that IArchiver and OArchiver be forward-declared. However, + * note that you will also need to write + * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver, + * OArchiver) in one of your translation units. + +DPG PICK UP HERE + */ +#define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \ +BOOST_PYTHON_SERIALIZATION_ARCHIVE(IArchiver, OArchiver) \ +namespace boost { namespace python { namespace detail { \ +template<> \ +BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >& \ + get_direct_serialization_table< IArchiver , OArchiver >(); \ +} \ + \ +template<> \ +struct has_direct_serialization< IArchiver , OArchiver> : mpl::true_ { }; \ + \ +template<> \ +struct output_archiver< IArchiver > { typedef OArchiver type; }; \ + \ +template<> \ +struct input_archiver< OArchiver > { typedef IArchiver type; }; \ +} } + +/** + * @brief Define the implementation for Boost.Serialization archivers + * that can be used for Python objects and C++ objects wrapped in + * Python. + * + * This macro can only be expanded from the global namespace. It only + * requires that IArchiver and OArchiver be forward-declared. Before + * using this macro, you will need to declare IArchiver and OArchiver + * as direct serialization archives with + * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE(IArchiver, OArchiver). + */ +#define BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL(IArchiver, OArchiver) \ +namespace boost { namespace python { namespace detail { \ +template \ + class BOOST_MPI_PYTHON_DECL direct_serialization_table< IArchiver , OArchiver >; \ + \ +template<> \ + BOOST_MPI_PYTHON_DECL \ + direct_serialization_table< IArchiver , OArchiver >& \ + get_direct_serialization_table< IArchiver , OArchiver >( ) \ +{ \ + static direct_serialization_table< IArchiver, OArchiver > table; \ + return table; \ +} \ +} } } + +namespace boost { namespace python { + +/** + * INTERNAL ONLY + * + * Provides access to the Python "pickle" module from within C++. + */ +class BOOST_MPI_PYTHON_DECL pickle { + struct data_t; + +public: + static str dumps(object obj, int protocol = -1); + static object loads(str s); + +private: + static void initialize_data(); + + static data_t* data; +}; + +/** + * @brief Whether the input/output archiver pair has "direct" + * serialization for C++ objects exposed in Python. + * + * Users do not typically need to specialize this trait, as it will be + * specialized as part of the macro + * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE. + */ +template +struct has_direct_serialization : mpl::false_ { }; + +/** + * @brief A metafunction that determines the output archiver for the + * given input archiver. + * + * Users do not typically need to specialize this trait, as it will be + * specialized as part of the macro + * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE. + */ +template struct output_archiver { }; + +/** + * @brief A metafunction that determines the input archiver for the + * given output archiver. + * + * Users do not typically need to specialize this trait, as it will be + * specialized as part of the macro + * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE. + * + */ +template struct input_archiver { }; + +namespace detail { + + /** + * INTERNAL ONLY + * + * This class contains the direct-serialization code for the given + * IArchiver/OArchiver pair. It is intended to be used as a + * singleton class, and will be accessed when (de-)serializing a + * Boost.Python object with an archiver that supports direct + * serializations. Do not create instances of this class directly: + * instead, use get_direct_serialization_table. + */ + template + class BOOST_MPI_PYTHON_DECL direct_serialization_table + { + public: + typedef boost::function3 + saver_t; + typedef boost::function3 + loader_t; + + typedef std::map > savers_t; + typedef std::map loaders_t; + + /** + * Retrieve the saver (serializer) associated with the Python + * object @p obj. + * + * @param obj The object we want to save. Only its (Python) type + * is important. + * + * @param descriptor The value of the descriptor associated to + * the returned saver. Will be set to zero if no saver was found + * for @p obj. + * + * @returns a function object that can be used to serialize this + * object (and other objects of the same type), if possible. If + * no saver can be found, returns an empty function object.. + */ + saver_t saver(const object& obj, int& descriptor) + { + typename savers_t::iterator pos = savers.find(obj.ptr()->ob_type); + if (pos != savers.end()) { + descriptor = pos->second.first; + return pos->second.second; + } + else { + descriptor = 0; + return saver_t(); + } + } + + /** + * Retrieve the loader (deserializer) associated with the given + * descriptor. + * + * @param descriptor The descriptor number provided by saver() + * when determining the saver for this type. + * + * @returns a function object that can be used to deserialize an + * object whose type is the same as that corresponding to the + * descriptor. If the descriptor is unknown, the return value + * will be an empty function object. + */ + loader_t loader(int descriptor) + { + typename loaders_t::iterator pos = loaders.find(descriptor); + if (pos != loaders.end()) + return pos->second; + else + return loader_t(); + } + + /** + * Register the type T for direct serialization. + * + * @param value A sample value of the type @c T. This may be used + * to compute the Python type associated with the C++ type @c T. + * + * @param type The Python type associated with the C++ type @c + * T. If not provided, it will be computed from the same value @p + * value. + */ + template + void register_type(const T& value = T(), PyTypeObject* type = 0) + { + // If the user did not provide us with a Python type, figure it + // out for ourselves. + if (!type) { + object obj(value); + type = obj.ptr()->ob_type; + } + + register_type(default_saver(), default_loader(type), value, type); + } + + /** + * Register the type T for direct serialization. + * + * @param saver A function object that will serialize a + * Boost.Python object (that represents a C++ object of type @c + * T) to an @c OArchive. + * + * @param loader A function object that will deserialize from an + * @c IArchive into a Boost.Python object that represents a C++ + * object of type @c T. + * + * @param value A sample value of the type @c T. This may be used + * to compute the Python type associated with the C++ type @c T. + * + * @param type The Python type associated with the C++ type @c + * T. If not provided, it will be computed from the same value @p + * value. + */ + template + void register_type(const saver_t& saver, const loader_t& loader, + const T& value = T(), PyTypeObject* type = 0) + { + // If the user did not provide us with a Python type, figure it + // out for ourselves. + if (!type) { + object obj(value); + type = obj.ptr()->ob_type; + } + + int descriptor = savers.size() + 1; + if (savers.find(type) != savers.end()) + return; + + savers[type] = std::make_pair(descriptor, saver); + loaders[descriptor] = loader; + } + + protected: + template + struct default_saver { + void operator()(OArchiver& ar, const object& obj, const unsigned int) { + T value = extract(obj)(); + ar << value; + } + }; + + template + struct default_loader { + default_loader(PyTypeObject* type) : type(type) { } + + void operator()(IArchiver& ar, object& obj, const unsigned int) { + // If we can, extract the object in place. + if (!is_fundamental::value && obj && obj.ptr()->ob_type == type) { + ar >> extract(obj)(); + } else { + T value; + ar >> value; + obj = object(value); + } + } + + private: + PyTypeObject* type; + }; + + savers_t savers; + loaders_t loaders; + }; + + /** + * @brief Retrieve the direct-serialization table for an + * IArchiver/OArchiver pair. + * + * This function is responsible for returning a reference to the + * singleton direct-serialization table. Its primary template is + * left undefined, to force the use of an explicit specialization + * with a definition in a single translation unit. Use the macro + * BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE_IMPL to define this + * explicit specialization. + */ + template + direct_serialization_table& + get_direct_serialization_table(); +} // end namespace detail + +/** + * @brief Register the type T for direct serialization. + * + * The @c register_serialized function registers a C++ type for direct + * serialization with the given @c IArchiver/@c OArchiver pair. Direct + * serialization elides the use of the Python @c pickle package when + * serializing Python objects that represent C++ values. Direct + * serialization can be beneficial both to improve serialization + * performance (Python pickling can be very inefficient) and to permit + * serialization for Python-wrapped C++ objects that do not support + * pickling. + * + * @param value A sample value of the type @c T. This may be used + * to compute the Python type associated with the C++ type @c T. + * + * @param type The Python type associated with the C++ type @c + * T. If not provided, it will be computed from the same value @p + * value. + */ +template +void +register_serialized(const T& value = T(), PyTypeObject* type = 0) +{ + detail::direct_serialization_table& table = + detail::get_direct_serialization_table(); + table.register_type(value, type); +} + +namespace detail { + +/// Save a Python object by pickling it. +template +void +save_impl(Archiver& ar, const boost::python::object& obj, + const unsigned int /*version*/, + mpl::false_ /*has_direct_serialization*/) +{ + boost::python::str py_string = boost::python::pickle::dumps(obj); + int len = boost::python::extract(py_string.attr("__len__")()); + const char* string = boost::python::extract(py_string); + ar << len << boost::serialization::make_array(string, len); +} + +/// Try to save a Python object by directly serializing it; fall back +/// on pickling if required. +template +void +save_impl(Archiver& ar, const boost::python::object& obj, + const unsigned int version, + mpl::true_ /*has_direct_serialization*/) +{ + typedef Archiver OArchiver; + typedef typename input_archiver::type IArchiver; + typedef typename direct_serialization_table::saver_t + saver_t; + + direct_serialization_table& table = + get_direct_serialization_table(); + + int descriptor = 0; + if (saver_t saver = table.saver(obj, descriptor)) { + ar << descriptor; + saver(ar, obj, version); + } else { + // Pickle it + ar << descriptor; + detail::save_impl(ar, obj, version, mpl::false_()); + } +} + +/// Load a Python object by unpickling it +template +void +load_impl(Archiver& ar, boost::python::object& obj, + const unsigned int /*version*/, + mpl::false_ /*has_direct_serialization*/) +{ + int len; + ar >> len; + + std::unique_ptr string(new char[len]); + ar >> boost::serialization::make_array(string.get(), len); + boost::python::str py_string(string.get(), len); + obj = boost::python::pickle::loads(py_string); +} + +/// Try to load a Python object by directly deserializing it; fall back +/// on unpickling if required. +template +void +load_impl(Archiver& ar, boost::python::object& obj, + const unsigned int version, + mpl::true_ /*has_direct_serialization*/) +{ + typedef Archiver IArchiver; + typedef typename output_archiver::type OArchiver; + typedef typename direct_serialization_table::loader_t + loader_t; + + direct_serialization_table& table = + get_direct_serialization_table(); + + int descriptor; + ar >> descriptor; + + if (descriptor) { + loader_t loader = table.loader(descriptor); + BOOST_ASSERT(loader); + + loader(ar, obj, version); + } else { + // Unpickle it + detail::load_impl(ar, obj, version, mpl::false_()); + } +} + +} // end namespace detail + +template +void +save(Archiver& ar, const boost::python::object& obj, + const unsigned int version) +{ + typedef Archiver OArchiver; + typedef typename input_archiver::type IArchiver; + + detail::save_impl(ar, obj, version, + has_direct_serialization()); +} + +template +void +load(Archiver& ar, boost::python::object& obj, + const unsigned int version) +{ + typedef Archiver IArchiver; + typedef typename output_archiver::type OArchiver; + + detail::load_impl(ar, obj, version, + has_direct_serialization()); +} + +template +inline void +serialize(Archive& ar, boost::python::object& obj, const unsigned int version) +{ + boost::serialization::split_free(ar, obj, version); +} + +} } // end namespace boost::python + +/************************************************************************ + * Boost.MPI-Specific Section * + ************************************************************************/ +namespace boost { namespace mpi { + class packed_iarchive; + class packed_oarchive; +} } // end namespace boost::mpi + +BOOST_PYTHON_DIRECT_SERIALIZATION_ARCHIVE( + ::boost::mpi::packed_iarchive, + ::boost::mpi::packed_oarchive) + +namespace boost { namespace mpi { namespace python { + +template +void +register_serialized(const T& value, PyTypeObject* type) +{ + using boost::python::register_serialized; + register_serialized(value, type); +} + +} } } // end namespace boost::mpi::python + +#endif // BOOST_MPI_PYTHON_SERIALIZE_HPP diff --git a/src/external/3rd/library/boost/boost/multi_index/global_fun.hpp b/src/external/3rd/library/boost/boost/multi_index/global_fun.hpp index 218b92d5c..71f6bb26a 100644 --- a/src/external/3rd/library/boost/boost/multi_index/global_fun.hpp +++ b/src/external/3rd/library/boost/boost/multi_index/global_fun.hpp @@ -1,177 +1,177 @@ -/* Copyright 2003-2013 Joaquin M Lopez Munoz. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * See http://www.boost.org/libs/multi_index for library home page. - */ - -#ifndef BOOST_MULTI_INDEX_GLOBAL_FUN_HPP -#define BOOST_MULTI_INDEX_GLOBAL_FUN_HPP - -#if defined(_MSC_VER) -#pragma once -#endif - -#include /* keep it first to prevent nasty warns in MSVC */ -#include -#include -#include -#include -#include -#include - -#if !defined(BOOST_NO_SFINAE) -#include -#endif - -namespace boost{ - -template class reference_wrapper; /* fwd decl. */ - -namespace multi_index{ - -namespace detail{ - -/* global_fun is a read-only key extractor from Value based on a given global - * (or static member) function with signature: - * - * Type f([const] Value [&]); - * - * Additionally, global_fun and const_global_fun are overloaded to support - * referece_wrappers of Value and "chained pointers" to Value's. By chained - * pointer to T we mean a type P such that, given a p of Type P - * *...n...*x is convertible to T&, for some n>=1. - * Examples of chained pointers are raw and smart pointers, iterators and - * arbitrary combinations of these (vg. T** or unique_ptr.) - */ - -template -struct const_ref_global_fun_base -{ - typedef typename remove_reference::type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type>::type -#else - Type -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type operator()(Value x)const - { - return PtrToFunction(x); - } - - Type operator()( - const reference_wrapper< - typename remove_reference::type>& x)const - { - return operator()(x.get()); - } - - Type operator()( - const reference_wrapper< - typename remove_const< - typename remove_reference::type>::type>& x)const - { - return operator()(x.get()); - } -}; - -template -struct non_const_ref_global_fun_base -{ - typedef typename remove_reference::type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type>::type -#else - Type -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type operator()(Value x)const - { - return PtrToFunction(x); - } - - Type operator()( - const reference_wrapper< - typename remove_reference::type>& x)const - { - return operator()(x.get()); - } -}; - -template -struct non_ref_global_fun_base -{ - typedef typename remove_reference::type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type>::type -#else - Type -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type operator()(const Value& x)const - { - return PtrToFunction(x); - } - - Type operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type operator()( - const reference_wrapper::type>& x)const - { - return operator()(x.get()); - } -}; - -} /* namespace multi_index::detail */ - -template -struct global_fun: - mpl::if_c< - is_reference::value, - typename mpl::if_c< - is_const::type>::value, - detail::const_ref_global_fun_base, - detail::non_const_ref_global_fun_base - >::type, - detail::non_ref_global_fun_base - >::type -{ -}; - -} /* namespace multi_index */ - -} /* namespace boost */ - -#endif +/* Copyright 2003-2013 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org/libs/multi_index for library home page. + */ + +#ifndef BOOST_MULTI_INDEX_GLOBAL_FUN_HPP +#define BOOST_MULTI_INDEX_GLOBAL_FUN_HPP + +#if defined(_MSC_VER) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_NO_SFINAE) +#include +#endif + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +namespace detail{ + +/* global_fun is a read-only key extractor from Value based on a given global + * (or static member) function with signature: + * + * Type f([const] Value [&]); + * + * Additionally, global_fun and const_global_fun are overloaded to support + * referece_wrappers of Value and "chained pointers" to Value's. By chained + * pointer to T we mean a type P such that, given a p of Type P + * *...n...*x is convertible to T&, for some n>=1. + * Examples of chained pointers are raw and smart pointers, iterators and + * arbitrary combinations of these (vg. T** or unique_ptr.) + */ + +template +struct const_ref_global_fun_base +{ + typedef typename remove_reference::type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type>::type +#else + Type +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(Value x)const + { + return PtrToFunction(x); + } + + Type operator()( + const reference_wrapper< + typename remove_reference::type>& x)const + { + return operator()(x.get()); + } + + Type operator()( + const reference_wrapper< + typename remove_const< + typename remove_reference::type>::type>& x)const + { + return operator()(x.get()); + } +}; + +template +struct non_const_ref_global_fun_base +{ + typedef typename remove_reference::type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type>::type +#else + Type +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(Value x)const + { + return PtrToFunction(x); + } + + Type operator()( + const reference_wrapper< + typename remove_reference::type>& x)const + { + return operator()(x.get()); + } +}; + +template +struct non_ref_global_fun_base +{ + typedef typename remove_reference::type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type>::type +#else + Type +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(const Value& x)const + { + return PtrToFunction(x); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type operator()( + const reference_wrapper::type>& x)const + { + return operator()(x.get()); + } +}; + +} /* namespace multi_index::detail */ + +template +struct global_fun: + mpl::if_c< + is_reference::value, + typename mpl::if_c< + is_const::type>::value, + detail::const_ref_global_fun_base, + detail::non_const_ref_global_fun_base + >::type, + detail::non_ref_global_fun_base + >::type +{ +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/src/external/3rd/library/boost/boost/multi_index/identity.hpp b/src/external/3rd/library/boost/boost/multi_index/identity.hpp index be886cf7c..44036b8cd 100644 --- a/src/external/3rd/library/boost/boost/multi_index/identity.hpp +++ b/src/external/3rd/library/boost/boost/multi_index/identity.hpp @@ -1,137 +1,137 @@ -/* Copyright 2003-2013 Joaquin M Lopez Munoz. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * See http://www.boost.org/libs/multi_index for library home page. - */ - -#ifndef BOOST_MULTI_INDEX_IDENTITY_HPP -#define BOOST_MULTI_INDEX_IDENTITY_HPP - -#if defined(_MSC_VER) -#pragma once -#endif - -#include -#include -#include -#include -#include -#include - -#if !defined(BOOST_NO_SFINAE) -#include -#endif - -namespace boost{ - -template class reference_wrapper; /* fwd decl. */ - -namespace multi_index{ - -namespace detail{ - -/* identity is a do-nothing key extractor that returns the [const] Type& - * object passed. - * Additionally, identity is overloaded to support referece_wrappers - * of Type and "chained pointers" to Type's. By chained pointer to Type we - * mean a type P such that, given a p of type P - * *...n...*x is convertible to Type&, for some n>=1. - * Examples of chained pointers are raw and smart pointers, iterators and - * arbitrary combinations of these (vg. Type** or unique_ptr.) - */ - -template -struct const_identity_base -{ - typedef Type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if,Type&>::type -#else - Type& -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type& operator()(Type& x)const - { - return x; - } - - Type& operator()(const reference_wrapper& x)const - { - return x.get(); - } - - Type& operator()( - const reference_wrapper::type>& x)const - { - return x.get(); - } -}; - -template -struct non_const_identity_base -{ - typedef Type result_type; - - /* templatized for pointer-like types */ - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type&>::type -#else - Type& -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - const Type& operator()(const Type& x)const - { - return x; - } - - Type& operator()(Type& x)const - { - return x; - } - - const Type& operator()(const reference_wrapper& x)const - { - return x.get(); - } - - Type& operator()(const reference_wrapper& x)const - { - return x.get(); - } -}; - -} /* namespace multi_index::detail */ - -template -struct identity: - mpl::if_c< - is_const::value, - detail::const_identity_base,detail::non_const_identity_base - >::type -{ -}; - -} /* namespace multi_index */ - -} /* namespace boost */ - -#endif +/* Copyright 2003-2013 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org/libs/multi_index for library home page. + */ + +#ifndef BOOST_MULTI_INDEX_IDENTITY_HPP +#define BOOST_MULTI_INDEX_IDENTITY_HPP + +#if defined(_MSC_VER) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_NO_SFINAE) +#include +#endif + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +namespace detail{ + +/* identity is a do-nothing key extractor that returns the [const] Type& + * object passed. + * Additionally, identity is overloaded to support referece_wrappers + * of Type and "chained pointers" to Type's. By chained pointer to Type we + * mean a type P such that, given a p of type P + * *...n...*x is convertible to Type&, for some n>=1. + * Examples of chained pointers are raw and smart pointers, iterators and + * arbitrary combinations of these (vg. Type** or unique_ptr.) + */ + +template +struct const_identity_base +{ + typedef Type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if,Type&>::type +#else + Type& +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type& operator()(Type& x)const + { + return x; + } + + Type& operator()(const reference_wrapper& x)const + { + return x.get(); + } + + Type& operator()( + const reference_wrapper::type>& x)const + { + return x.get(); + } +}; + +template +struct non_const_identity_base +{ + typedef Type result_type; + + /* templatized for pointer-like types */ + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type&>::type +#else + Type& +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + const Type& operator()(const Type& x)const + { + return x; + } + + Type& operator()(Type& x)const + { + return x; + } + + const Type& operator()(const reference_wrapper& x)const + { + return x.get(); + } + + Type& operator()(const reference_wrapper& x)const + { + return x.get(); + } +}; + +} /* namespace multi_index::detail */ + +template +struct identity: + mpl::if_c< + is_const::value, + detail::const_identity_base,detail::non_const_identity_base + >::type +{ +}; + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/src/external/3rd/library/boost/boost/multi_index/mem_fun.hpp b/src/external/3rd/library/boost/boost/multi_index/mem_fun.hpp index d89aca709..a357724d7 100644 --- a/src/external/3rd/library/boost/boost/multi_index/mem_fun.hpp +++ b/src/external/3rd/library/boost/boost/multi_index/mem_fun.hpp @@ -1,205 +1,205 @@ -/* Copyright 2003-2013 Joaquin M Lopez Munoz. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * See http://www.boost.org/libs/multi_index for library home page. - */ - -#ifndef BOOST_MULTI_INDEX_MEM_FUN_HPP -#define BOOST_MULTI_INDEX_MEM_FUN_HPP - -#if defined(_MSC_VER) -#pragma once -#endif - -#include /* keep it first to prevent nasty warns in MSVC */ -#include -#include -#include - -#if !defined(BOOST_NO_SFINAE) -#include -#endif - -namespace boost{ - -template class reference_wrapper; /* fwd decl. */ - -namespace multi_index{ - -/* mem_fun implements a read-only key extractor based on a given non-const - * member function of a class. - * const_mem_fun does the same for const member functions. - * Additionally, mem_fun and const_mem_fun are overloaded to support - * referece_wrappers of T and "chained pointers" to T's. By chained pointer - * to T we mean a type P such that, given a p of Type P - * *...n...*x is convertible to T&, for some n>=1. - * Examples of chained pointers are raw and smart pointers, iterators and - * arbitrary combinations of these (vg. T** or unique_ptr.) - */ - -template -struct const_mem_fun -{ - typedef typename remove_reference::type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type>::type -#else - Type -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type operator()(const Class& x)const - { - return (x.*PtrToMemberFunction)(); - } - - Type operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -template -struct mem_fun -{ - typedef typename remove_reference::type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type>::type -#else - Type -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type operator()(Class& x)const - { - return (x.*PtrToMemberFunction)(); - } - - Type operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -/* MSVC++ 6.0 has problems with const member functions as non-type template - * parameters, somehow it takes them as non-const. const_mem_fun_explicit - * workarounds this deficiency by accepting an extra type parameter that - * specifies the signature of the member function. The workaround was found at: - * Daniel, C.:"Re: weird typedef problem in VC", - * news:microsoft.public.vc.language, 21st nov 2002, - * http://groups.google.com/groups? - * hl=en&lr=&ie=UTF-8&selm=ukwvg3O0BHA.1512%40tkmsftngp05 - * - * MSVC++ 6.0 support has been dropped and [const_]mem_fun_explicit is - * deprecated. - */ - -template< - class Class,typename Type, - typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction> -struct const_mem_fun_explicit -{ - typedef typename remove_reference::type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type>::type -#else - Type -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type operator()(const Class& x)const - { - return (x.*PtrToMemberFunction)(); - } - - Type operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -template< - class Class,typename Type, - typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction> -struct mem_fun_explicit -{ - typedef typename remove_reference::type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type>::type -#else - Type -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type operator()(Class& x)const - { - return (x.*PtrToMemberFunction)(); - } - - Type operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -/* BOOST_MULTI_INDEX_CONST_MEM_FUN and BOOST_MULTI_INDEX_MEM_FUN used to - * resolve to [const_]mem_fun_explicit for MSVC++ 6.0 and to - * [const_]mem_fun otherwise. Support for this compiler having been dropped, - * they are now just wrappers over [const_]mem_fun kept for backwards- - * compatibility reasons. - */ - -#define BOOST_MULTI_INDEX_CONST_MEM_FUN(Class,Type,MemberFunName) \ -::boost::multi_index::const_mem_fun< Class,Type,&Class::MemberFunName > -#define BOOST_MULTI_INDEX_MEM_FUN(Class,Type,MemberFunName) \ -::boost::multi_index::mem_fun< Class,Type,&Class::MemberFunName > - -} /* namespace multi_index */ - -} /* namespace boost */ - -#endif +/* Copyright 2003-2013 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org/libs/multi_index for library home page. + */ + +#ifndef BOOST_MULTI_INDEX_MEM_FUN_HPP +#define BOOST_MULTI_INDEX_MEM_FUN_HPP + +#if defined(_MSC_VER) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include + +#if !defined(BOOST_NO_SFINAE) +#include +#endif + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +/* mem_fun implements a read-only key extractor based on a given non-const + * member function of a class. + * const_mem_fun does the same for const member functions. + * Additionally, mem_fun and const_mem_fun are overloaded to support + * referece_wrappers of T and "chained pointers" to T's. By chained pointer + * to T we mean a type P such that, given a p of Type P + * *...n...*x is convertible to T&, for some n>=1. + * Examples of chained pointers are raw and smart pointers, iterators and + * arbitrary combinations of these (vg. T** or unique_ptr.) + */ + +template +struct const_mem_fun +{ + typedef typename remove_reference::type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type>::type +#else + Type +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(const Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +template +struct mem_fun +{ + typedef typename remove_reference::type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type>::type +#else + Type +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +/* MSVC++ 6.0 has problems with const member functions as non-type template + * parameters, somehow it takes them as non-const. const_mem_fun_explicit + * workarounds this deficiency by accepting an extra type parameter that + * specifies the signature of the member function. The workaround was found at: + * Daniel, C.:"Re: weird typedef problem in VC", + * news:microsoft.public.vc.language, 21st nov 2002, + * http://groups.google.com/groups? + * hl=en&lr=&ie=UTF-8&selm=ukwvg3O0BHA.1512%40tkmsftngp05 + * + * MSVC++ 6.0 support has been dropped and [const_]mem_fun_explicit is + * deprecated. + */ + +template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction> +struct const_mem_fun_explicit +{ + typedef typename remove_reference::type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type>::type +#else + Type +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(const Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +template< + class Class,typename Type, + typename PtrToMemberFunctionType,PtrToMemberFunctionType PtrToMemberFunction> +struct mem_fun_explicit +{ + typedef typename remove_reference::type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type>::type +#else + Type +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type operator()(Class& x)const + { + return (x.*PtrToMemberFunction)(); + } + + Type operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +/* BOOST_MULTI_INDEX_CONST_MEM_FUN and BOOST_MULTI_INDEX_MEM_FUN used to + * resolve to [const_]mem_fun_explicit for MSVC++ 6.0 and to + * [const_]mem_fun otherwise. Support for this compiler having been dropped, + * they are now just wrappers over [const_]mem_fun kept for backwards- + * compatibility reasons. + */ + +#define BOOST_MULTI_INDEX_CONST_MEM_FUN(Class,Type,MemberFunName) \ +::boost::multi_index::const_mem_fun< Class,Type,&Class::MemberFunName > +#define BOOST_MULTI_INDEX_MEM_FUN(Class,Type,MemberFunName) \ +::boost::multi_index::mem_fun< Class,Type,&Class::MemberFunName > + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/src/external/3rd/library/boost/boost/multi_index/member.hpp b/src/external/3rd/library/boost/boost/multi_index/member.hpp index 5b9d1b1b7..91619cfcf 100644 --- a/src/external/3rd/library/boost/boost/multi_index/member.hpp +++ b/src/external/3rd/library/boost/boost/multi_index/member.hpp @@ -1,262 +1,262 @@ -/* Copyright 2003-2013 Joaquin M Lopez Munoz. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - * See http://www.boost.org/libs/multi_index for library home page. - */ - -#ifndef BOOST_MULTI_INDEX_MEMBER_HPP -#define BOOST_MULTI_INDEX_MEMBER_HPP - -#if defined(_MSC_VER) -#pragma once -#endif - -#include /* keep it first to prevent nasty warns in MSVC */ -#include -#include -#include -#include - -#if !defined(BOOST_NO_SFINAE) -#include -#endif - -namespace boost{ - -template class reference_wrapper; /* fwd decl. */ - -namespace multi_index{ - -namespace detail{ - -/* member is a read/write key extractor for accessing a given - * member of a class. - * Additionally, member is overloaded to support referece_wrappers - * of T and "chained pointers" to T's. By chained pointer to T we mean - * a type P such that, given a p of Type P - * *...n...*x is convertible to T&, for some n>=1. - * Examples of chained pointers are raw and smart pointers, iterators and - * arbitrary combinations of these (vg. T** or unique_ptr.) - */ - -template -struct const_member_base -{ - typedef Type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type&>::type -#else - Type& -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type& operator()(const Class& x)const - { - return x.*PtrToMember; - } - - Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -template -struct non_const_member_base -{ - typedef Type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type&>::type -#else - Type& -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - const Type& operator()(const Class& x)const - { - return x.*PtrToMember; - } - - Type& operator()(Class& x)const - { - return x.*PtrToMember; - } - - const Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -} /* namespace multi_index::detail */ - -template -struct member: - mpl::if_c< - is_const::value, - detail::const_member_base, - detail::non_const_member_base - >::type -{ -}; - -namespace detail{ - -/* MSVC++ 6.0 does not support properly pointers to members as - * non-type template arguments, as reported in - * http://support.microsoft.com/default.aspx?scid=kb;EN-US;249045 - * A similar problem (though not identical) is shown by MSVC++ 7.0. - * We provide an alternative to member<> accepting offsets instead - * of pointers to members. This happens to work even for non-POD - * types (although the standard forbids use of offsetof on these), - * so it serves as a workaround in this compiler for all practical - * purposes. - * Surprisingly enough, other compilers, like Intel C++ 7.0/7.1 and - * Visual Age 6.0, have similar bugs. This replacement of member<> - * can be used for them too. - * - * Support for such old compilers is dropped and - * [non_]const_member_offset_base is deprecated. - */ - -template -struct const_member_offset_base -{ - typedef Type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type&>::type -#else - Type& -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - Type& operator()(const Class& x)const - { - return *static_cast( - static_cast( - static_cast( - static_cast(&x))+OffsetOfMember)); - } - - Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -template -struct non_const_member_offset_base -{ - typedef Type result_type; - - template - -#if !defined(BOOST_NO_SFINAE) - typename disable_if< - is_convertible,Type&>::type -#else - Type& -#endif - - operator()(const ChainedPtr& x)const - { - return operator()(*x); - } - - const Type& operator()(const Class& x)const - { - return *static_cast( - static_cast( - static_cast( - static_cast(&x))+OffsetOfMember)); - } - - Type& operator()(Class& x)const - { - return *static_cast( - static_cast( - static_cast(static_cast(&x))+OffsetOfMember)); - } - - const Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } - - Type& operator()(const reference_wrapper& x)const - { - return operator()(x.get()); - } -}; - -} /* namespace multi_index::detail */ - -template -struct member_offset: - mpl::if_c< - is_const::value, - detail::const_member_offset_base, - detail::non_const_member_offset_base - >::type -{ -}; - -/* BOOST_MULTI_INDEX_MEMBER resolves to member in the normal cases, - * and to member_offset as a workaround in those defective compilers for - * which BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS is defined. - */ - -#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) -#define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ -::boost::multi_index::member_offset< Class,Type,offsetof(Class,MemberName) > -#else -#define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ -::boost::multi_index::member< Class,Type,&Class::MemberName > -#endif - -} /* namespace multi_index */ - -} /* namespace boost */ - -#endif +/* Copyright 2003-2013 Joaquin M Lopez Munoz. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org/libs/multi_index for library home page. + */ + +#ifndef BOOST_MULTI_INDEX_MEMBER_HPP +#define BOOST_MULTI_INDEX_MEMBER_HPP + +#if defined(_MSC_VER) +#pragma once +#endif + +#include /* keep it first to prevent nasty warns in MSVC */ +#include +#include +#include +#include + +#if !defined(BOOST_NO_SFINAE) +#include +#endif + +namespace boost{ + +template class reference_wrapper; /* fwd decl. */ + +namespace multi_index{ + +namespace detail{ + +/* member is a read/write key extractor for accessing a given + * member of a class. + * Additionally, member is overloaded to support referece_wrappers + * of T and "chained pointers" to T's. By chained pointer to T we mean + * a type P such that, given a p of Type P + * *...n...*x is convertible to T&, for some n>=1. + * Examples of chained pointers are raw and smart pointers, iterators and + * arbitrary combinations of these (vg. T** or unique_ptr.) + */ + +template +struct const_member_base +{ + typedef Type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type&>::type +#else + Type& +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type& operator()(const Class& x)const + { + return x.*PtrToMember; + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +template +struct non_const_member_base +{ + typedef Type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type&>::type +#else + Type& +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + const Type& operator()(const Class& x)const + { + return x.*PtrToMember; + } + + Type& operator()(Class& x)const + { + return x.*PtrToMember; + } + + const Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +} /* namespace multi_index::detail */ + +template +struct member: + mpl::if_c< + is_const::value, + detail::const_member_base, + detail::non_const_member_base + >::type +{ +}; + +namespace detail{ + +/* MSVC++ 6.0 does not support properly pointers to members as + * non-type template arguments, as reported in + * http://support.microsoft.com/default.aspx?scid=kb;EN-US;249045 + * A similar problem (though not identical) is shown by MSVC++ 7.0. + * We provide an alternative to member<> accepting offsets instead + * of pointers to members. This happens to work even for non-POD + * types (although the standard forbids use of offsetof on these), + * so it serves as a workaround in this compiler for all practical + * purposes. + * Surprisingly enough, other compilers, like Intel C++ 7.0/7.1 and + * Visual Age 6.0, have similar bugs. This replacement of member<> + * can be used for them too. + * + * Support for such old compilers is dropped and + * [non_]const_member_offset_base is deprecated. + */ + +template +struct const_member_offset_base +{ + typedef Type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type&>::type +#else + Type& +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + Type& operator()(const Class& x)const + { + return *static_cast( + static_cast( + static_cast( + static_cast(&x))+OffsetOfMember)); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +template +struct non_const_member_offset_base +{ + typedef Type result_type; + + template + +#if !defined(BOOST_NO_SFINAE) + typename disable_if< + is_convertible,Type&>::type +#else + Type& +#endif + + operator()(const ChainedPtr& x)const + { + return operator()(*x); + } + + const Type& operator()(const Class& x)const + { + return *static_cast( + static_cast( + static_cast( + static_cast(&x))+OffsetOfMember)); + } + + Type& operator()(Class& x)const + { + return *static_cast( + static_cast( + static_cast(static_cast(&x))+OffsetOfMember)); + } + + const Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } + + Type& operator()(const reference_wrapper& x)const + { + return operator()(x.get()); + } +}; + +} /* namespace multi_index::detail */ + +template +struct member_offset: + mpl::if_c< + is_const::value, + detail::const_member_offset_base, + detail::non_const_member_offset_base + >::type +{ +}; + +/* BOOST_MULTI_INDEX_MEMBER resolves to member in the normal cases, + * and to member_offset as a workaround in those defective compilers for + * which BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS is defined. + */ + +#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) +#define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ +::boost::multi_index::member_offset< Class,Type,offsetof(Class,MemberName) > +#else +#define BOOST_MULTI_INDEX_MEMBER(Class,Type,MemberName) \ +::boost::multi_index::member< Class,Type,&Class::MemberName > +#endif + +} /* namespace multi_index */ + +} /* namespace boost */ + +#endif diff --git a/src/external/3rd/library/boost/boost/program_options/options_description.hpp b/src/external/3rd/library/boost/boost/program_options/options_description.hpp index 11eebb92d..6a975cf40 100644 --- a/src/external/3rd/library/boost/boost/program_options/options_description.hpp +++ b/src/external/3rd/library/boost/boost/program_options/options_description.hpp @@ -1,278 +1,278 @@ -// Copyright Vladimir Prus 2002-2004. -// Copyright Bertolt Mildner 2004. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt -// or copy at http://www.boost.org/LICENSE_1_0.txt) - - -#ifndef BOOST_OPTION_DESCRIPTION_VP_2003_05_19 -#define BOOST_OPTION_DESCRIPTION_VP_2003_05_19 - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#if defined(BOOST_MSVC) -# pragma warning (push) -# pragma warning (disable:4251) // class 'boost::shared_ptr' needs to have dll-interface to be used by clients of class 'boost::program_options::option_description' -#endif - - -/** Boost namespace */ -namespace boost { -/** Namespace for the library. */ -namespace program_options { - - /** Describes one possible command line/config file option. There are two - kinds of properties of an option. First describe it syntactically and - are used only to validate input. Second affect interpretation of the - option, for example default value for it or function that should be - called when the value is finally known. Routines which perform parsing - never use second kind of properties -- they are side effect free. - @sa options_description - */ - class BOOST_PROGRAM_OPTIONS_DECL option_description { - public: - - option_description(); - - /** Initializes the object with the passed data. - - Note: it would be nice to make the second parameter unique_ptr, - to explicitly pass ownership. Unfortunately, it's often needed to - create objects of types derived from 'value_semantic': - options_description d; - d.add_options()("a", parameter("n")->default_value(1)); - Here, the static type returned by 'parameter' should be derived - from value_semantic. - - Alas, derived->base conversion for unique_ptr does not really work, - see - http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf - http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84 - - So, we have to use plain old pointers. Besides, users are not - expected to use the constructor directly. - - - The 'name' parameter is interpreted by the following rules: - - if there's no "," character in 'name', it specifies long name - - otherwise, the part before "," specifies long name and the part - after -- short name. - */ - option_description(const char* name, - const value_semantic* s); - - /** Initializes the class with the passed data. - */ - option_description(const char* name, - const value_semantic* s, - const char* description); - - virtual ~option_description(); - - enum match_result { no_match, full_match, approximate_match }; - - /** Given 'option', specified in the input source, - returns 'true' if 'option' specifies *this. - */ - match_result match(const std::string& option, bool approx, - bool long_ignore_case, bool short_ignore_case) const; - - /** Returns the key that should identify the option, in - particular in the variables_map class. - The 'option' parameter is the option spelling from the - input source. - If option name contains '*', returns 'option'. - If long name was specified, it's the long name, otherwise - it's a short name with prepended '-'. - */ - const std::string& key(const std::string& option) const; - - - /** Returns the canonical name for the option description to enable the user to - recognised a matching option. - 1) For short options ('-', '/'), returns the short name prefixed. - 2) For long options ('--' / '-') returns the long name prefixed - 3) All other cases, returns the long name (if present) or the short name, - unprefixed. - */ - std::string canonical_display_name(int canonical_option_style = 0) const; - - const std::string& long_name() const; - - /// Explanation of this option - const std::string& description() const; - - /// Semantic of option's value - shared_ptr semantic() const; - - /// Returns the option name, formatted suitably for usage message. - std::string format_name() const; - - /** Returns the parameter name and properties, formatted suitably for - usage message. */ - std::string format_parameter() const; - - private: - - option_description& set_name(const char* name); - - std::string m_short_name, m_long_name, m_description; - // shared_ptr is needed to simplify memory management in - // copy ctor and destructor. - shared_ptr m_value_semantic; - }; - - class options_description; - - /** Class which provides convenient creation syntax to option_description. - */ - class BOOST_PROGRAM_OPTIONS_DECL options_description_easy_init { - public: - options_description_easy_init(options_description* owner); - - options_description_easy_init& - operator()(const char* name, - const char* description); - - options_description_easy_init& - operator()(const char* name, - const value_semantic* s); - - options_description_easy_init& - operator()(const char* name, - const value_semantic* s, - const char* description); - - private: - options_description* owner; - }; - - - /** A set of option descriptions. This provides convenient interface for - adding new option (the add_options) method, and facilities to search - for options by name. - - See @ref a_adding_options "here" for option adding interface discussion. - @sa option_description - */ - class BOOST_PROGRAM_OPTIONS_DECL options_description { - public: - static const unsigned m_default_line_length; - - /** Creates the instance. */ - options_description(unsigned line_length = m_default_line_length, - unsigned min_description_length = m_default_line_length / 2); - /** Creates the instance. The 'caption' parameter gives the name of - this 'options_description' instance. Primarily useful for output. - The 'description_length' specifies the number of columns that - should be reserved for the description text; if the option text - encroaches into this, then the description will start on the next - line. - */ - options_description(const std::string& caption, - unsigned line_length = m_default_line_length, - unsigned min_description_length = m_default_line_length / 2); - /** Adds new variable description. Throws duplicate_variable_error if - either short or long name matches that of already present one. - */ - void add(shared_ptr desc); - /** Adds a group of option description. This has the same - effect as adding all option_descriptions in 'desc' - individually, except that output operator will show - a separate group. - Returns *this. - */ - options_description& add(const options_description& desc); - - /** Find the maximum width of the option column, including options - in groups. */ - unsigned get_option_column_width() const; - - public: - /** Returns an object of implementation-defined type suitable for adding - options to options_description. The returned object will - have overloaded operator() with parameter type matching - 'option_description' constructors. Calling the operator will create - new option_description instance and add it. - */ - options_description_easy_init add_options(); - - const option_description& find(const std::string& name, - bool approx, - bool long_ignore_case = false, - bool short_ignore_case = false) const; - - const option_description* find_nothrow(const std::string& name, - bool approx, - bool long_ignore_case = false, - bool short_ignore_case = false) const; - - - const std::vector< shared_ptr >& options() const; - - /** Produces a human readable output of 'desc', listing options, - their descriptions and allowed parameters. Other options_description - instances previously passed to add will be output separately. */ - friend BOOST_PROGRAM_OPTIONS_DECL std::ostream& operator<<(std::ostream& os, - const options_description& desc); - - /** Outputs 'desc' to the specified stream, calling 'f' to output each - option_description element. */ - void print(std::ostream& os, unsigned width = 0) const; - - private: - typedef std::map::const_iterator name2index_iterator; - typedef std::pair - approximation_range; - - //approximation_range find_approximation(const std::string& prefix) const; - - std::string m_caption; - const unsigned m_line_length; - const unsigned m_min_description_length; - - // Data organization is chosen because: - // - there could be two names for one option - // - option_add_proxy needs to know the last added option - std::vector< shared_ptr > m_options; - - // Whether the option comes from one of declared groups. -#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(313)) - // vector is buggy there, see - // http://support.microsoft.com/default.aspx?scid=kb;en-us;837698 - std::vector belong_to_group; -#else - std::vector belong_to_group; -#endif - - std::vector< shared_ptr > groups; - - }; - - /** Class thrown when duplicate option description is found. */ - class BOOST_PROGRAM_OPTIONS_DECL duplicate_option_error : public error { - public: - duplicate_option_error(const std::string& xwhat) : error(xwhat) {} - }; -}} - -#if defined(BOOST_MSVC) -# pragma warning (pop) -#endif - -#endif +// Copyright Vladimir Prus 2002-2004. +// Copyright Bertolt Mildner 2004. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_OPTION_DESCRIPTION_VP_2003_05_19 +#define BOOST_OPTION_DESCRIPTION_VP_2003_05_19 + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#if defined(BOOST_MSVC) +# pragma warning (push) +# pragma warning (disable:4251) // class 'boost::shared_ptr' needs to have dll-interface to be used by clients of class 'boost::program_options::option_description' +#endif + + +/** Boost namespace */ +namespace boost { +/** Namespace for the library. */ +namespace program_options { + + /** Describes one possible command line/config file option. There are two + kinds of properties of an option. First describe it syntactically and + are used only to validate input. Second affect interpretation of the + option, for example default value for it or function that should be + called when the value is finally known. Routines which perform parsing + never use second kind of properties -- they are side effect free. + @sa options_description + */ + class BOOST_PROGRAM_OPTIONS_DECL option_description { + public: + + option_description(); + + /** Initializes the object with the passed data. + + Note: it would be nice to make the second parameter unique_ptr, + to explicitly pass ownership. Unfortunately, it's often needed to + create objects of types derived from 'value_semantic': + options_description d; + d.add_options()("a", parameter("n")->default_value(1)); + Here, the static type returned by 'parameter' should be derived + from value_semantic. + + Alas, derived->base conversion for unique_ptr does not really work, + see + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf + http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84 + + So, we have to use plain old pointers. Besides, users are not + expected to use the constructor directly. + + + The 'name' parameter is interpreted by the following rules: + - if there's no "," character in 'name', it specifies long name + - otherwise, the part before "," specifies long name and the part + after -- short name. + */ + option_description(const char* name, + const value_semantic* s); + + /** Initializes the class with the passed data. + */ + option_description(const char* name, + const value_semantic* s, + const char* description); + + virtual ~option_description(); + + enum match_result { no_match, full_match, approximate_match }; + + /** Given 'option', specified in the input source, + returns 'true' if 'option' specifies *this. + */ + match_result match(const std::string& option, bool approx, + bool long_ignore_case, bool short_ignore_case) const; + + /** Returns the key that should identify the option, in + particular in the variables_map class. + The 'option' parameter is the option spelling from the + input source. + If option name contains '*', returns 'option'. + If long name was specified, it's the long name, otherwise + it's a short name with prepended '-'. + */ + const std::string& key(const std::string& option) const; + + + /** Returns the canonical name for the option description to enable the user to + recognised a matching option. + 1) For short options ('-', '/'), returns the short name prefixed. + 2) For long options ('--' / '-') returns the long name prefixed + 3) All other cases, returns the long name (if present) or the short name, + unprefixed. + */ + std::string canonical_display_name(int canonical_option_style = 0) const; + + const std::string& long_name() const; + + /// Explanation of this option + const std::string& description() const; + + /// Semantic of option's value + shared_ptr semantic() const; + + /// Returns the option name, formatted suitably for usage message. + std::string format_name() const; + + /** Returns the parameter name and properties, formatted suitably for + usage message. */ + std::string format_parameter() const; + + private: + + option_description& set_name(const char* name); + + std::string m_short_name, m_long_name, m_description; + // shared_ptr is needed to simplify memory management in + // copy ctor and destructor. + shared_ptr m_value_semantic; + }; + + class options_description; + + /** Class which provides convenient creation syntax to option_description. + */ + class BOOST_PROGRAM_OPTIONS_DECL options_description_easy_init { + public: + options_description_easy_init(options_description* owner); + + options_description_easy_init& + operator()(const char* name, + const char* description); + + options_description_easy_init& + operator()(const char* name, + const value_semantic* s); + + options_description_easy_init& + operator()(const char* name, + const value_semantic* s, + const char* description); + + private: + options_description* owner; + }; + + + /** A set of option descriptions. This provides convenient interface for + adding new option (the add_options) method, and facilities to search + for options by name. + + See @ref a_adding_options "here" for option adding interface discussion. + @sa option_description + */ + class BOOST_PROGRAM_OPTIONS_DECL options_description { + public: + static const unsigned m_default_line_length; + + /** Creates the instance. */ + options_description(unsigned line_length = m_default_line_length, + unsigned min_description_length = m_default_line_length / 2); + /** Creates the instance. The 'caption' parameter gives the name of + this 'options_description' instance. Primarily useful for output. + The 'description_length' specifies the number of columns that + should be reserved for the description text; if the option text + encroaches into this, then the description will start on the next + line. + */ + options_description(const std::string& caption, + unsigned line_length = m_default_line_length, + unsigned min_description_length = m_default_line_length / 2); + /** Adds new variable description. Throws duplicate_variable_error if + either short or long name matches that of already present one. + */ + void add(shared_ptr desc); + /** Adds a group of option description. This has the same + effect as adding all option_descriptions in 'desc' + individually, except that output operator will show + a separate group. + Returns *this. + */ + options_description& add(const options_description& desc); + + /** Find the maximum width of the option column, including options + in groups. */ + unsigned get_option_column_width() const; + + public: + /** Returns an object of implementation-defined type suitable for adding + options to options_description. The returned object will + have overloaded operator() with parameter type matching + 'option_description' constructors. Calling the operator will create + new option_description instance and add it. + */ + options_description_easy_init add_options(); + + const option_description& find(const std::string& name, + bool approx, + bool long_ignore_case = false, + bool short_ignore_case = false) const; + + const option_description* find_nothrow(const std::string& name, + bool approx, + bool long_ignore_case = false, + bool short_ignore_case = false) const; + + + const std::vector< shared_ptr >& options() const; + + /** Produces a human readable output of 'desc', listing options, + their descriptions and allowed parameters. Other options_description + instances previously passed to add will be output separately. */ + friend BOOST_PROGRAM_OPTIONS_DECL std::ostream& operator<<(std::ostream& os, + const options_description& desc); + + /** Outputs 'desc' to the specified stream, calling 'f' to output each + option_description element. */ + void print(std::ostream& os, unsigned width = 0) const; + + private: + typedef std::map::const_iterator name2index_iterator; + typedef std::pair + approximation_range; + + //approximation_range find_approximation(const std::string& prefix) const; + + std::string m_caption; + const unsigned m_line_length; + const unsigned m_min_description_length; + + // Data organization is chosen because: + // - there could be two names for one option + // - option_add_proxy needs to know the last added option + std::vector< shared_ptr > m_options; + + // Whether the option comes from one of declared groups. +#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(313)) + // vector is buggy there, see + // http://support.microsoft.com/default.aspx?scid=kb;en-us;837698 + std::vector belong_to_group; +#else + std::vector belong_to_group; +#endif + + std::vector< shared_ptr > groups; + + }; + + /** Class thrown when duplicate option description is found. */ + class BOOST_PROGRAM_OPTIONS_DECL duplicate_option_error : public error { + public: + duplicate_option_error(const std::string& xwhat) : error(xwhat) {} + }; +}} + +#if defined(BOOST_MSVC) +# pragma warning (pop) +#endif + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/detail/associative_ptr_container.hpp b/src/external/3rd/library/boost/boost/ptr_container/detail/associative_ptr_container.hpp index d95087121..3ac7dbe5f 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/detail/associative_ptr_container.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/detail/associative_ptr_container.hpp @@ -1,411 +1,411 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2003-2005. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - - -#ifndef BOOST_PTR_CONTAINER_DETAIL_ASSOCIATIVE_PTR_CONTAINER_HPP -#define BOOST_PTR_CONTAINER_DETAIL_ASSOCIATIVE_PTR_CONTAINER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include - -namespace boost -{ - -namespace ptr_container_detail -{ - template - < - class Config, - class CloneAllocator - > - class associative_ptr_container : - public reversible_ptr_container - { - typedef reversible_ptr_container - base_type; - - typedef BOOST_DEDUCED_TYPENAME base_type::scoped_deleter - scoped_deleter; - - typedef BOOST_DEDUCED_TYPENAME Config::container_type - container_type; - public: // typedefs - typedef BOOST_DEDUCED_TYPENAME Config::key_type - key_type; - typedef BOOST_DEDUCED_TYPENAME Config::key_compare - key_compare; - typedef BOOST_DEDUCED_TYPENAME Config::value_compare - value_compare; - typedef BOOST_DEDUCED_TYPENAME Config::hasher - hasher; - typedef BOOST_DEDUCED_TYPENAME Config::key_equal - key_equal; - typedef BOOST_DEDUCED_TYPENAME Config::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME Config::const_iterator - const_iterator; - typedef BOOST_DEDUCED_TYPENAME Config::local_iterator - local_iterator; - typedef BOOST_DEDUCED_TYPENAME Config::const_local_iterator - const_local_iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type - size_type; - typedef BOOST_DEDUCED_TYPENAME base_type::reference - reference; - typedef BOOST_DEDUCED_TYPENAME base_type::const_reference - const_reference; - - public: // foundation - associative_ptr_container() - { } - - template< class SizeType > - associative_ptr_container( SizeType n, unordered_associative_container_tag tag ) - : base_type( n, tag ) - { } - - template< class Compare, class Allocator > - associative_ptr_container( const Compare& comp, - const Allocator& a ) - : base_type( comp, a, container_type() ) - { } - - template< class Hash, class Pred, class Allocator > - associative_ptr_container( const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { } - - template< class InputIterator, class Compare, class Allocator > - associative_ptr_container( InputIterator first, InputIterator last, - const Compare& comp, - const Allocator& a ) - : base_type( first, last, comp, a, container_type() ) - { } - - template< class InputIterator, class Hash, class Pred, class Allocator > - associative_ptr_container( InputIterator first, InputIterator last, - const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( first, last, hash, pred, a ) - { } - - template< class PtrContainer > - explicit associative_ptr_container( std::unique_ptr r ) - : base_type( r ) - { } - - associative_ptr_container( const associative_ptr_container& r ) - : base_type( r.begin(), r.end(), container_type() ) - { } - - template< class C, class V > - associative_ptr_container( const associative_ptr_container& r ) - : base_type( r.begin(), r.end(), container_type() ) - { } - - template< class PtrContainer > - associative_ptr_container& operator=( std::unique_ptr r ) // nothrow - { - base_type::operator=( r ); - return *this; - } - - associative_ptr_container& operator=( associative_ptr_container r ) // strong - { - this->swap( r ); - return *this; - } - - public: // associative container interface - key_compare key_comp() const - { - return this->base().key_comp(); - } - - value_compare value_comp() const - { - return this->base().value_comp(); - } - - iterator erase( iterator before ) // nothrow - { - BOOST_ASSERT( !this->empty() ); - BOOST_ASSERT( before != this->end() ); - - this->remove( before ); // nothrow - iterator res( before ); // nothrow - ++res; // nothrow - this->base().erase( before.base() ); // nothrow - return res; // nothrow - } - - size_type erase( const key_type& x ) // nothrow - { - iterator i( this->base().find( x ) ); - // nothrow - if( i == this->end() ) // nothrow - return 0u; // nothrow - this->remove( i ); // nothrow - return this->base().erase( x ); // nothrow - } - - iterator erase( iterator first, - iterator last ) // nothrow - { - iterator res( last ); // nothrow - if( res != this->end() ) - ++res; // nothrow - - this->remove( first, last ); // nothrow - this->base().erase( first.base(), last.base() ); // nothrow - return res; // nothrow - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - template< class Range > - BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_convertible, - iterator >::type - erase( const Range& r ) - { - return erase( boost::begin(r), boost::end(r) ); - } - -#endif - - protected: - - template< class AssociatePtrCont > - void multi_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator object, - AssociatePtrCont& from ) // strong - { - BOOST_ASSERT( (void*)&from != (void*)this ); - BOOST_ASSERT( !from.empty() && "Cannot transfer from empty container" ); - - this->base().insert( *object.base() ); // strong - from.base().erase( object.base() ); // nothrow - } - - template< class AssociatePtrCont > - size_type multi_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator first, - BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator last, - AssociatePtrCont& from ) // basic - { - BOOST_ASSERT( (void*)&from != (void*)this ); - - size_type res = 0; - for( ; first != last; ) - { - BOOST_ASSERT( first != from.end() ); - this->base().insert( *first.base() ); // strong - BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator - to_delete( first ); - ++first; - from.base().erase( to_delete.base() ); // nothrow - ++res; - } - - return res; - } - - template< class AssociatePtrCont > - bool single_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator object, - AssociatePtrCont& from ) // strong - { - BOOST_ASSERT( (void*)&from != (void*)this ); - BOOST_ASSERT( !from.empty() && "Cannot transfer from empty container" ); - - std::pair p = - this->base().insert( *object.base() ); // strong - if( p.second ) - from.base().erase( object.base() ); // nothrow - - return p.second; - } - - template< class AssociatePtrCont > - size_type single_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator first, - BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator last, - AssociatePtrCont& from ) // basic - { - BOOST_ASSERT( (void*)&from != (void*)this ); - - size_type res = 0; - for( ; first != last; ) - { - BOOST_ASSERT( first != from.end() ); - std::pair p = - this->base().insert( *first.base() ); // strong - BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator - to_delete( first ); - ++first; - if( p.second ) - { - from.base().erase( to_delete.base() ); // nothrow - ++res; - } - } - return res; - } - - reference front() - { - BOOST_ASSERT( !this->empty() ); - BOOST_ASSERT( *this->begin().base() != 0 ); - return *this->begin(); - } - - const_reference front() const - { - return const_cast(this)->front(); - } - - reference back() - { - BOOST_ASSERT( !this->empty() ); - BOOST_ASSERT( *(--this->end()).base() != 0 ); - return *--this->end(); - } - - const_reference back() const - { - return const_cast(this)->back(); - } - - protected: // unordered interface - hasher hash_function() const - { - return this->base().hash_function(); - } - - key_equal key_eq() const - { - return this->base().key_eq(); - } - - size_type bucket_count() const - { - return this->base().bucket_count(); - } - - size_type max_bucket_count() const - { - return this->base().max_bucket_count(); - } - - size_type bucket_size( size_type n ) const - { - return this->base().bucket_size( n ); - } - - float load_factor() const - { - return this->base().load_factor(); - } - - float max_load_factor() const - { - return this->base().max_load_factor(); - } - - void max_load_factor( float factor ) - { - return this->base().max_load_factor( factor ); - } - - void rehash( size_type n ) - { - this->base().rehash( n ); - } - - public: -#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(70190006)) - iterator begin() - { - return base_type::begin(); - } - - const_iterator begin() const - { - return base_type::begin(); - } - - iterator end() - { - return base_type::end(); - } - - const_iterator end() const - { - return base_type::end(); - } - - const_iterator cbegin() const - { - return base_type::cbegin(); - } - - const_iterator cend() const - { - return base_type::cend(); - } -#else - using base_type::begin; - using base_type::end; - using base_type::cbegin; - using base_type::cend; -#endif - - protected: - local_iterator begin( size_type n ) - { - return local_iterator( this->base().begin( n ) ); - } - - const_local_iterator begin( size_type n ) const - { - return const_local_iterator( this->base().begin( n ) ); - } - - local_iterator end( size_type n ) - { - return local_iterator( this->base().end( n ) ); - } - - const_local_iterator end( size_type n ) const - { - return const_local_iterator( this->base().end( n ) ); - } - - const_local_iterator cbegin( size_type n ) const - { - return const_local_iterator( this->base().cbegin( n ) ); - } - - const_local_iterator cend( size_type n ) - { - return const_local_iterator( this->base().cend( n ) ); - } - - }; // class 'associative_ptr_container' - -} // namespace 'ptr_container_detail' - -} // namespace 'boost' - - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2003-2005. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + + +#ifndef BOOST_PTR_CONTAINER_DETAIL_ASSOCIATIVE_PTR_CONTAINER_HPP +#define BOOST_PTR_CONTAINER_DETAIL_ASSOCIATIVE_PTR_CONTAINER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include + +namespace boost +{ + +namespace ptr_container_detail +{ + template + < + class Config, + class CloneAllocator + > + class associative_ptr_container : + public reversible_ptr_container + { + typedef reversible_ptr_container + base_type; + + typedef BOOST_DEDUCED_TYPENAME base_type::scoped_deleter + scoped_deleter; + + typedef BOOST_DEDUCED_TYPENAME Config::container_type + container_type; + public: // typedefs + typedef BOOST_DEDUCED_TYPENAME Config::key_type + key_type; + typedef BOOST_DEDUCED_TYPENAME Config::key_compare + key_compare; + typedef BOOST_DEDUCED_TYPENAME Config::value_compare + value_compare; + typedef BOOST_DEDUCED_TYPENAME Config::hasher + hasher; + typedef BOOST_DEDUCED_TYPENAME Config::key_equal + key_equal; + typedef BOOST_DEDUCED_TYPENAME Config::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME Config::const_iterator + const_iterator; + typedef BOOST_DEDUCED_TYPENAME Config::local_iterator + local_iterator; + typedef BOOST_DEDUCED_TYPENAME Config::const_local_iterator + const_local_iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type + size_type; + typedef BOOST_DEDUCED_TYPENAME base_type::reference + reference; + typedef BOOST_DEDUCED_TYPENAME base_type::const_reference + const_reference; + + public: // foundation + associative_ptr_container() + { } + + template< class SizeType > + associative_ptr_container( SizeType n, unordered_associative_container_tag tag ) + : base_type( n, tag ) + { } + + template< class Compare, class Allocator > + associative_ptr_container( const Compare& comp, + const Allocator& a ) + : base_type( comp, a, container_type() ) + { } + + template< class Hash, class Pred, class Allocator > + associative_ptr_container( const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { } + + template< class InputIterator, class Compare, class Allocator > + associative_ptr_container( InputIterator first, InputIterator last, + const Compare& comp, + const Allocator& a ) + : base_type( first, last, comp, a, container_type() ) + { } + + template< class InputIterator, class Hash, class Pred, class Allocator > + associative_ptr_container( InputIterator first, InputIterator last, + const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( first, last, hash, pred, a ) + { } + + template< class PtrContainer > + explicit associative_ptr_container( std::unique_ptr r ) + : base_type( r ) + { } + + associative_ptr_container( const associative_ptr_container& r ) + : base_type( r.begin(), r.end(), container_type() ) + { } + + template< class C, class V > + associative_ptr_container( const associative_ptr_container& r ) + : base_type( r.begin(), r.end(), container_type() ) + { } + + template< class PtrContainer > + associative_ptr_container& operator=( std::unique_ptr r ) // nothrow + { + base_type::operator=( r ); + return *this; + } + + associative_ptr_container& operator=( associative_ptr_container r ) // strong + { + this->swap( r ); + return *this; + } + + public: // associative container interface + key_compare key_comp() const + { + return this->base().key_comp(); + } + + value_compare value_comp() const + { + return this->base().value_comp(); + } + + iterator erase( iterator before ) // nothrow + { + BOOST_ASSERT( !this->empty() ); + BOOST_ASSERT( before != this->end() ); + + this->remove( before ); // nothrow + iterator res( before ); // nothrow + ++res; // nothrow + this->base().erase( before.base() ); // nothrow + return res; // nothrow + } + + size_type erase( const key_type& x ) // nothrow + { + iterator i( this->base().find( x ) ); + // nothrow + if( i == this->end() ) // nothrow + return 0u; // nothrow + this->remove( i ); // nothrow + return this->base().erase( x ); // nothrow + } + + iterator erase( iterator first, + iterator last ) // nothrow + { + iterator res( last ); // nothrow + if( res != this->end() ) + ++res; // nothrow + + this->remove( first, last ); // nothrow + this->base().erase( first.base(), last.base() ); // nothrow + return res; // nothrow + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + template< class Range > + BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_convertible, + iterator >::type + erase( const Range& r ) + { + return erase( boost::begin(r), boost::end(r) ); + } + +#endif + + protected: + + template< class AssociatePtrCont > + void multi_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator object, + AssociatePtrCont& from ) // strong + { + BOOST_ASSERT( (void*)&from != (void*)this ); + BOOST_ASSERT( !from.empty() && "Cannot transfer from empty container" ); + + this->base().insert( *object.base() ); // strong + from.base().erase( object.base() ); // nothrow + } + + template< class AssociatePtrCont > + size_type multi_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator first, + BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator last, + AssociatePtrCont& from ) // basic + { + BOOST_ASSERT( (void*)&from != (void*)this ); + + size_type res = 0; + for( ; first != last; ) + { + BOOST_ASSERT( first != from.end() ); + this->base().insert( *first.base() ); // strong + BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator + to_delete( first ); + ++first; + from.base().erase( to_delete.base() ); // nothrow + ++res; + } + + return res; + } + + template< class AssociatePtrCont > + bool single_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator object, + AssociatePtrCont& from ) // strong + { + BOOST_ASSERT( (void*)&from != (void*)this ); + BOOST_ASSERT( !from.empty() && "Cannot transfer from empty container" ); + + std::pair p = + this->base().insert( *object.base() ); // strong + if( p.second ) + from.base().erase( object.base() ); // nothrow + + return p.second; + } + + template< class AssociatePtrCont > + size_type single_transfer( BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator first, + BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator last, + AssociatePtrCont& from ) // basic + { + BOOST_ASSERT( (void*)&from != (void*)this ); + + size_type res = 0; + for( ; first != last; ) + { + BOOST_ASSERT( first != from.end() ); + std::pair p = + this->base().insert( *first.base() ); // strong + BOOST_DEDUCED_TYPENAME AssociatePtrCont::iterator + to_delete( first ); + ++first; + if( p.second ) + { + from.base().erase( to_delete.base() ); // nothrow + ++res; + } + } + return res; + } + + reference front() + { + BOOST_ASSERT( !this->empty() ); + BOOST_ASSERT( *this->begin().base() != 0 ); + return *this->begin(); + } + + const_reference front() const + { + return const_cast(this)->front(); + } + + reference back() + { + BOOST_ASSERT( !this->empty() ); + BOOST_ASSERT( *(--this->end()).base() != 0 ); + return *--this->end(); + } + + const_reference back() const + { + return const_cast(this)->back(); + } + + protected: // unordered interface + hasher hash_function() const + { + return this->base().hash_function(); + } + + key_equal key_eq() const + { + return this->base().key_eq(); + } + + size_type bucket_count() const + { + return this->base().bucket_count(); + } + + size_type max_bucket_count() const + { + return this->base().max_bucket_count(); + } + + size_type bucket_size( size_type n ) const + { + return this->base().bucket_size( n ); + } + + float load_factor() const + { + return this->base().load_factor(); + } + + float max_load_factor() const + { + return this->base().max_load_factor(); + } + + void max_load_factor( float factor ) + { + return this->base().max_load_factor( factor ); + } + + void rehash( size_type n ) + { + this->base().rehash( n ); + } + + public: +#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(70190006)) + iterator begin() + { + return base_type::begin(); + } + + const_iterator begin() const + { + return base_type::begin(); + } + + iterator end() + { + return base_type::end(); + } + + const_iterator end() const + { + return base_type::end(); + } + + const_iterator cbegin() const + { + return base_type::cbegin(); + } + + const_iterator cend() const + { + return base_type::cend(); + } +#else + using base_type::begin; + using base_type::end; + using base_type::cbegin; + using base_type::cend; +#endif + + protected: + local_iterator begin( size_type n ) + { + return local_iterator( this->base().begin( n ) ); + } + + const_local_iterator begin( size_type n ) const + { + return const_local_iterator( this->base().begin( n ) ); + } + + local_iterator end( size_type n ) + { + return local_iterator( this->base().end( n ) ); + } + + const_local_iterator end( size_type n ) const + { + return const_local_iterator( this->base().end( n ) ); + } + + const_local_iterator cbegin( size_type n ) const + { + return const_local_iterator( this->base().cbegin( n ) ); + } + + const_local_iterator cend( size_type n ) + { + return const_local_iterator( this->base().cend( n ) ); + } + + }; // class 'associative_ptr_container' + +} // namespace 'ptr_container_detail' + +} // namespace 'boost' + + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/detail/reversible_ptr_container.hpp b/src/external/3rd/library/boost/boost/ptr_container/detail/reversible_ptr_container.hpp index 639cf16b8..505047c51 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/detail/reversible_ptr_container.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/detail/reversible_ptr_container.hpp @@ -1,752 +1,752 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2003-2005. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - - -#ifndef BOOST_PTR_CONTAINER_DETAIL_REVERSIBLE_PTR_CONTAINER_HPP -#define BOOST_PTR_CONTAINER_DETAIL_REVERSIBLE_PTR_CONTAINER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef BOOST_NO_SFINAE -#else -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) -#pragma warning(push) -#pragma warning(disable:4127) -#endif - -namespace boost -{ - -namespace ptr_container_detail -{ - template< class CloneAllocator > - struct clone_deleter - { - template< class T > - void operator()( const T* p ) const - { - CloneAllocator::deallocate_clone( p ); - } - }; - - template< class T > - struct is_pointer_or_integral - { - BOOST_STATIC_CONSTANT(bool, value = is_pointer::value || is_integral::value ); - }; - - struct is_pointer_or_integral_tag {}; - struct is_range_tag {}; - struct sequence_tag {}; - struct fixed_length_sequence_tag : sequence_tag {}; - struct associative_container_tag {}; - struct ordered_associative_container_tag : associative_container_tag {}; - struct unordered_associative_container_tag : associative_container_tag {}; - - - - template - < - class Config, - class CloneAllocator - > - class reversible_ptr_container - { - private: - BOOST_STATIC_CONSTANT( bool, allow_null = Config::allow_null ); - - typedef BOOST_DEDUCED_TYPENAME Config::value_type Ty_; - - template< bool allow_null_values > - struct null_clone_allocator - { - template< class Iter > - static Ty_* allocate_clone_from_iterator( Iter i ) - { - return allocate_clone( Config::get_const_pointer( i ) ); - } - - static Ty_* allocate_clone( const Ty_* x ) - { - if( allow_null_values ) - { - if( x == 0 ) - return 0; - } - else - { - BOOST_ASSERT( x != 0 && "Cannot insert clone of null!" ); - } - - Ty_* res = CloneAllocator::allocate_clone( *x ); - BOOST_ASSERT( typeid(*res) == typeid(*x) && - "CloneAllocator::allocate_clone() does not clone the " - "object properly. Check that new_clone() is implemented" - " correctly" ); - return res; - } - - static void deallocate_clone( const Ty_* x ) - { - if( allow_null_values ) - { - if( x == 0 ) - return; - } - - CloneAllocator::deallocate_clone( x ); - } - }; - - typedef BOOST_DEDUCED_TYPENAME Config::void_container_type Cont; -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) - typedef null_clone_allocator - null_cloner_type; -#else - typedef null_clone_allocator null_cloner_type; -#endif - typedef clone_deleter Deleter; - - Cont c_; - - public: - Cont& base() { return c_; } - protected: // having this public could break encapsulation - const Cont& base() const { return c_; } - - public: // typedefs - typedef Ty_* value_type; - typedef Ty_* pointer; - typedef Ty_& reference; - typedef const Ty_& const_reference; - - typedef BOOST_DEDUCED_TYPENAME Config::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME Config::const_iterator - const_iterator; - typedef boost::reverse_iterator< iterator > - reverse_iterator; - typedef boost::reverse_iterator< const_iterator > - const_reverse_iterator; - typedef BOOST_DEDUCED_TYPENAME Cont::difference_type - difference_type; - typedef BOOST_DEDUCED_TYPENAME Cont::size_type - size_type; - typedef BOOST_DEDUCED_TYPENAME Config::allocator_type - allocator_type; - typedef CloneAllocator clone_allocator_type; - typedef ptr_container_detail::static_move_ptr - auto_type; - - protected: - - typedef ptr_container_detail::scoped_deleter - scoped_deleter; - typedef BOOST_DEDUCED_TYPENAME Cont::iterator - ptr_iterator; - typedef BOOST_DEDUCED_TYPENAME Cont::const_iterator - ptr_const_iterator; - private: - - template< class InputIterator > - void copy( InputIterator first, InputIterator last ) - { - std::copy( first, last, begin() ); - } - - void copy( const reversible_ptr_container& r ) - { - copy( r.begin(), r.end() ); - } - - void copy_clones_and_release( scoped_deleter& sd ) // nothrow - { - BOOST_ASSERT( size_type( std::distance( sd.begin(), sd.end() ) ) == c_.size() ); - std::copy( sd.begin(), sd.end(), c_.begin() ); - sd.release(); - } - - template< class ForwardIterator > - void clone_assign( ForwardIterator first, - ForwardIterator last ) // strong - { - BOOST_ASSERT( first != last ); - scoped_deleter sd( first, last ); // strong - copy_clones_and_release( sd ); // nothrow - } - - template< class ForwardIterator > - void clone_back_insert( ForwardIterator first, - ForwardIterator last ) - { - BOOST_ASSERT( first != last ); - scoped_deleter sd( first, last ); - insert_clones_and_release( sd, end() ); - } - - void remove_all() - { - remove( begin(), end() ); - } - - protected: - - void insert_clones_and_release( scoped_deleter& sd, - iterator where ) // strong - { - // - // 'c_.insert' always provides the strong guarantee for T* elements - // since a copy constructor of a pointer cannot throw - // - c_.insert( where.base(), - sd.begin(), sd.end() ); - sd.release(); - } - - void insert_clones_and_release( scoped_deleter& sd ) // strong - { - c_.insert( sd.begin(), sd.end() ); - sd.release(); - } - - template< class U > - void remove( U* ptr ) - { - null_policy_deallocate_clone( ptr ); - } - - template< class I > - void remove( I i ) - { - null_policy_deallocate_clone( Config::get_const_pointer(i) ); - } - - template< class I > - void remove( I first, I last ) - { - for( ; first != last; ++first ) - remove( first ); - } - - static void enforce_null_policy( const Ty_* x, const char* msg ) - { - if( !allow_null ) - { - BOOST_PTR_CONTAINER_THROW_EXCEPTION( 0 == x && "null not allowed", - bad_pointer, msg ); - } - } - - static Ty_* null_policy_allocate_clone( const Ty_* x ) - { - return null_cloner_type::allocate_clone( x ); - } - - static void null_policy_deallocate_clone( const Ty_* x ) - { - null_cloner_type::deallocate_clone( x ); - } - - private: - template< class ForwardIterator > - ForwardIterator advance( ForwardIterator begin, size_type n ) - { - ForwardIterator iter = begin; - std::advance( iter, n ); - return iter; - } - - template< class I > - void constructor_impl( I first, I last, std::input_iterator_tag ) // basic - { - while( first != last ) - { - insert( end(), null_cloner_type::allocate_clone_from_iterator(first) ); - ++first; - } - } - - template< class I > - void constructor_impl( I first, I last, std::forward_iterator_tag ) // strong - { - if( first == last ) - return; - clone_back_insert( first, last ); - } - - template< class I > - void associative_constructor_impl( I first, I last ) // strong - { - if( first == last ) - return; - - scoped_deleter sd( first, last ); - insert_clones_and_release( sd ); - } - - public: // foundation! should be protected! - reversible_ptr_container() - { } - - template< class SizeType > - reversible_ptr_container( SizeType n, unordered_associative_container_tag ) - : c_( n ) - { } - - template< class SizeType > - reversible_ptr_container( SizeType n, fixed_length_sequence_tag ) - : c_( n ) - { } - - template< class SizeType > - reversible_ptr_container( SizeType n, const allocator_type& a, - fixed_length_sequence_tag ) - : c_( n, a ) - { } - - explicit reversible_ptr_container( const allocator_type& a ) - : c_( a ) - { } - - template< class PtrContainer > - explicit reversible_ptr_container( std::unique_ptr clone ) - { - swap( *clone ); - } - - reversible_ptr_container( const reversible_ptr_container& r ) - { - constructor_impl( r.begin(), r.end(), std::forward_iterator_tag() ); - } - - template< class C, class V > - reversible_ptr_container( const reversible_ptr_container& r ) - { - constructor_impl( r.begin(), r.end(), std::forward_iterator_tag() ); - } - - template< class PtrContainer > - reversible_ptr_container& operator=( std::unique_ptr clone ) // nothrow - { - swap( *clone ); - return *this; - } - - reversible_ptr_container& operator=( reversible_ptr_container r ) // strong - { - swap( r ); - return *this; - } - - // overhead: null-initilization of container pointer (very cheap compared to cloning) - // overhead: 1 heap allocation (very cheap compared to cloning) - template< class InputIterator > - reversible_ptr_container( InputIterator first, - InputIterator last, - const allocator_type& a = allocator_type() ) // basic, strong - : c_( a ) - { - constructor_impl( first, last, -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -#else - BOOST_DEDUCED_TYPENAME -#endif - iterator_category::type() ); - } - - template< class Compare > - reversible_ptr_container( const Compare& comp, - const allocator_type& a ) - : c_( comp, a ) {} - - template< class ForwardIterator > - reversible_ptr_container( ForwardIterator first, - ForwardIterator last, - fixed_length_sequence_tag ) - : c_( std::distance(first,last) ) - { - constructor_impl( first, last, - std::forward_iterator_tag() ); - } - - template< class SizeType, class InputIterator > - reversible_ptr_container( SizeType n, - InputIterator first, - InputIterator last, - fixed_length_sequence_tag ) - : c_( n ) - { - constructor_impl( first, last, -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -#else - BOOST_DEDUCED_TYPENAME -#endif - iterator_category::type() ); - } - - template< class Compare > - reversible_ptr_container( const Compare& comp, - const allocator_type& a, - associative_container_tag ) - : c_( comp, a ) - { } - - template< class InputIterator > - reversible_ptr_container( InputIterator first, - InputIterator last, - associative_container_tag ) - { - associative_constructor_impl( first, last ); - } - - template< class InputIterator, class Compare > - reversible_ptr_container( InputIterator first, - InputIterator last, - const Compare& comp, - const allocator_type& a, - associative_container_tag ) - : c_( comp, a ) - { - associative_constructor_impl( first, last ); - } - - explicit reversible_ptr_container( size_type n ) - : c_( n ) {} - - template< class Hash, class Pred > - reversible_ptr_container( const Hash& h, - const Pred& pred, - const allocator_type& a ) - : c_( h, pred, a ) {} - - template< class InputIterator, class Hash, class Pred > - reversible_ptr_container( InputIterator first, - InputIterator last, - const Hash& h, - const Pred& pred, - const allocator_type& a ) - : c_( h, pred, a ) - { - associative_constructor_impl( first, last ); - } - - public: - ~reversible_ptr_container() - { - remove_all(); - } - - public: - - allocator_type get_allocator() const - { - return c_.get_allocator(); - } - - public: // container requirements - iterator begin() - { return iterator( c_.begin() ); } - const_iterator begin() const - { return const_iterator( c_.begin() ); } - iterator end() - { return iterator( c_.end() ); } - const_iterator end() const - { return const_iterator( c_.end() ); } - - reverse_iterator rbegin() - { return reverse_iterator( this->end() ); } - const_reverse_iterator rbegin() const - { return const_reverse_iterator( this->end() ); } - reverse_iterator rend() - { return reverse_iterator( this->begin() ); } - const_reverse_iterator rend() const - { return const_reverse_iterator( this->begin() ); } - - const_iterator cbegin() const - { return const_iterator( c_.begin() ); } - const_iterator cend() const - { return const_iterator( c_.end() ); } - - const_reverse_iterator crbegin() const - { return const_reverse_iterator( this->end() ); } - const_reverse_iterator crend() const - { return const_reverse_iterator( this->begin() ); } - - void swap( reversible_ptr_container& r ) // nothrow - { - c_.swap( r.c_ ); - } - - size_type size() const // nothrow - { - return c_.size(); - } - - size_type max_size() const // nothrow - { - return c_.max_size(); - } - - bool empty() const // nothrow - { - return c_.empty(); - } - - public: // optional container requirements - - bool operator==( const reversible_ptr_container& r ) const // nothrow - { - if( size() != r.size() ) - return false; - else - return std::equal( begin(), end(), r.begin() ); - } - - bool operator!=( const reversible_ptr_container& r ) const // nothrow - { - return !(*this == r); - } - - bool operator<( const reversible_ptr_container& r ) const // nothrow - { - return std::lexicographical_compare( begin(), end(), r.begin(), r.end() ); - } - - bool operator<=( const reversible_ptr_container& r ) const // nothrow - { - return !(r < *this); - } - - bool operator>( const reversible_ptr_container& r ) const // nothrow - { - return r < *this; - } - - bool operator>=( const reversible_ptr_container& r ) const // nothrow - { - return !(*this < r); - } - - public: // modifiers - - iterator insert( iterator before, Ty_* x ) - { - enforce_null_policy( x, "Null pointer in 'insert()'" ); - - auto_type ptr( x ); // nothrow - iterator res( c_.insert( before.base(), x ) ); // strong, commit - ptr.release(); // nothrow - return res; - } - - template< class U > - iterator insert( iterator before, std::unique_ptr x ) - { - return insert( before, x.release() ); - } - - iterator erase( iterator x ) // nothrow - { - BOOST_ASSERT( !empty() ); - BOOST_ASSERT( x != end() ); - - remove( x ); - return iterator( c_.erase( x.base() ) ); - } - - iterator erase( iterator first, iterator last ) // nothrow - { - remove( first, last ); - return iterator( c_.erase( first.base(), - last.base() ) ); - } - - template< class Range > - iterator erase( const Range& r ) - { - return erase( boost::begin(r), boost::end(r) ); - } - - void clear() - { - remove_all(); - c_.clear(); - } - - public: // access interface - - auto_type release( iterator where ) - { - BOOST_ASSERT( where != end() ); - - BOOST_PTR_CONTAINER_THROW_EXCEPTION( empty(), bad_ptr_container_operation, - "'release()' on empty container" ); - - auto_type ptr( Config::get_pointer( where ) ); // nothrow - c_.erase( where.base() ); // nothrow - return boost::ptr_container_detail::move( ptr ); - } - - auto_type replace( iterator where, Ty_* x ) // strong - { - BOOST_ASSERT( where != end() ); - - enforce_null_policy( x, "Null pointer in 'replace()'" ); - - auto_type ptr( x ); - - BOOST_PTR_CONTAINER_THROW_EXCEPTION( empty(), bad_ptr_container_operation, - "'replace()' on empty container" ); - - auto_type old( Config::get_pointer( where ) ); // nothrow - const_cast(*where.base()) = ptr.release(); - return boost::ptr_container_detail::move( old ); - } - - template< class U > - auto_type replace( iterator where, std::unique_ptr x ) - { - return replace( where, x.release() ); - } - - auto_type replace( size_type idx, Ty_* x ) // strong - { - enforce_null_policy( x, "Null pointer in 'replace()'" ); - - auto_type ptr( x ); - - BOOST_PTR_CONTAINER_THROW_EXCEPTION( idx >= size(), bad_index, - "'replace()' out of bounds" ); - - auto_type old( static_cast( c_[idx] ) ); // nothrow - c_[idx] = ptr.release(); // nothrow, commit - return boost::ptr_container_detail::move( old ); - } - - template< class U > - auto_type replace( size_type idx, std::unique_ptr x ) - { - return replace( idx, x.release() ); - } - - }; // 'reversible_ptr_container' - - -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -#define BOOST_PTR_CONTAINER_DEFINE_RELEASE( base_type ) \ - typename base_type::auto_type \ - release( typename base_type::iterator i ) \ - { \ - return boost::ptr_container_detail::move(base_type::release(i)); \ - } -#else -#define BOOST_PTR_CONTAINER_DEFINE_RELEASE( base_type ) \ - using base_type::release; -#endif - - // - // two-phase lookup of template functions - // is buggy on most compilers, so we use a macro instead - // -#define BOOST_PTR_CONTAINER_DEFINE_RELEASE_AND_CLONE( PC, base_type, this_type ) \ - explicit PC( std::unique_ptr r ) \ - : base_type ( r ) { } \ - \ - PC& operator=( std::unique_ptr r ) \ - { \ - base_type::operator=( r ); \ - return *this; \ - } \ - \ - std::unique_ptr release() \ - { \ - std::unique_ptr ptr( new this_type );\ - this->swap( *ptr ); \ - return ptr; \ - } \ - BOOST_PTR_CONTAINER_DEFINE_RELEASE( base_type ) \ - \ - std::unique_ptr clone() const \ - { \ - return std::unique_ptr( new this_type( this->begin(), this->end() ) ); \ - } - -#define BOOST_PTR_CONTAINER_DEFINE_COPY_CONSTRUCTORS( PC, base_type ) \ - \ - template< class U > \ - PC( const PC& r ) : base_type( r ) { } \ - \ - PC& operator=( PC r ) \ - { \ - this->swap( r ); \ - return *this; \ - } \ - - -#define BOOST_PTR_CONTAINER_DEFINE_CONSTRUCTORS( PC, base_type ) \ - typedef BOOST_DEDUCED_TYPENAME base_type::iterator iterator; \ - typedef BOOST_DEDUCED_TYPENAME base_type::size_type size_type; \ - typedef BOOST_DEDUCED_TYPENAME base_type::const_reference const_reference; \ - typedef BOOST_DEDUCED_TYPENAME base_type::allocator_type allocator_type; \ - PC() {} \ - explicit PC( const allocator_type& a ) : base_type(a) {} \ - template< class InputIterator > \ - PC( InputIterator first, InputIterator last ) : base_type( first, last ) {} \ - template< class InputIterator > \ - PC( InputIterator first, InputIterator last, \ - const allocator_type& a ) : base_type( first, last, a ) {} - -#define BOOST_PTR_CONTAINER_DEFINE_NON_INHERITED_MEMBERS( PC, base_type, this_type ) \ - BOOST_PTR_CONTAINER_DEFINE_CONSTRUCTORS( PC, base_type ) \ - BOOST_PTR_CONTAINER_DEFINE_RELEASE_AND_CLONE( PC, base_type, this_type ) - -#define BOOST_PTR_CONTAINER_DEFINE_SEQEUENCE_MEMBERS( PC, base_type, this_type ) \ - BOOST_PTR_CONTAINER_DEFINE_NON_INHERITED_MEMBERS( PC, base_type, this_type ) \ - BOOST_PTR_CONTAINER_DEFINE_COPY_CONSTRUCTORS( PC, base_type ) - -} // namespace 'ptr_container_detail' - - // - // @remark: expose movability of internal move-pointer - // - namespace ptr_container - { - using ptr_container_detail::move; - } - -} // namespace 'boost' - -#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) -#pragma warning(pop) -#endif - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2003-2005. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + + +#ifndef BOOST_PTR_CONTAINER_DETAIL_REVERSIBLE_PTR_CONTAINER_HPP +#define BOOST_PTR_CONTAINER_DETAIL_REVERSIBLE_PTR_CONTAINER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_NO_SFINAE +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4127) +#endif + +namespace boost +{ + +namespace ptr_container_detail +{ + template< class CloneAllocator > + struct clone_deleter + { + template< class T > + void operator()( const T* p ) const + { + CloneAllocator::deallocate_clone( p ); + } + }; + + template< class T > + struct is_pointer_or_integral + { + BOOST_STATIC_CONSTANT(bool, value = is_pointer::value || is_integral::value ); + }; + + struct is_pointer_or_integral_tag {}; + struct is_range_tag {}; + struct sequence_tag {}; + struct fixed_length_sequence_tag : sequence_tag {}; + struct associative_container_tag {}; + struct ordered_associative_container_tag : associative_container_tag {}; + struct unordered_associative_container_tag : associative_container_tag {}; + + + + template + < + class Config, + class CloneAllocator + > + class reversible_ptr_container + { + private: + BOOST_STATIC_CONSTANT( bool, allow_null = Config::allow_null ); + + typedef BOOST_DEDUCED_TYPENAME Config::value_type Ty_; + + template< bool allow_null_values > + struct null_clone_allocator + { + template< class Iter > + static Ty_* allocate_clone_from_iterator( Iter i ) + { + return allocate_clone( Config::get_const_pointer( i ) ); + } + + static Ty_* allocate_clone( const Ty_* x ) + { + if( allow_null_values ) + { + if( x == 0 ) + return 0; + } + else + { + BOOST_ASSERT( x != 0 && "Cannot insert clone of null!" ); + } + + Ty_* res = CloneAllocator::allocate_clone( *x ); + BOOST_ASSERT( typeid(*res) == typeid(*x) && + "CloneAllocator::allocate_clone() does not clone the " + "object properly. Check that new_clone() is implemented" + " correctly" ); + return res; + } + + static void deallocate_clone( const Ty_* x ) + { + if( allow_null_values ) + { + if( x == 0 ) + return; + } + + CloneAllocator::deallocate_clone( x ); + } + }; + + typedef BOOST_DEDUCED_TYPENAME Config::void_container_type Cont; +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + typedef null_clone_allocator + null_cloner_type; +#else + typedef null_clone_allocator null_cloner_type; +#endif + typedef clone_deleter Deleter; + + Cont c_; + + public: + Cont& base() { return c_; } + protected: // having this public could break encapsulation + const Cont& base() const { return c_; } + + public: // typedefs + typedef Ty_* value_type; + typedef Ty_* pointer; + typedef Ty_& reference; + typedef const Ty_& const_reference; + + typedef BOOST_DEDUCED_TYPENAME Config::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME Config::const_iterator + const_iterator; + typedef boost::reverse_iterator< iterator > + reverse_iterator; + typedef boost::reverse_iterator< const_iterator > + const_reverse_iterator; + typedef BOOST_DEDUCED_TYPENAME Cont::difference_type + difference_type; + typedef BOOST_DEDUCED_TYPENAME Cont::size_type + size_type; + typedef BOOST_DEDUCED_TYPENAME Config::allocator_type + allocator_type; + typedef CloneAllocator clone_allocator_type; + typedef ptr_container_detail::static_move_ptr + auto_type; + + protected: + + typedef ptr_container_detail::scoped_deleter + scoped_deleter; + typedef BOOST_DEDUCED_TYPENAME Cont::iterator + ptr_iterator; + typedef BOOST_DEDUCED_TYPENAME Cont::const_iterator + ptr_const_iterator; + private: + + template< class InputIterator > + void copy( InputIterator first, InputIterator last ) + { + std::copy( first, last, begin() ); + } + + void copy( const reversible_ptr_container& r ) + { + copy( r.begin(), r.end() ); + } + + void copy_clones_and_release( scoped_deleter& sd ) // nothrow + { + BOOST_ASSERT( size_type( std::distance( sd.begin(), sd.end() ) ) == c_.size() ); + std::copy( sd.begin(), sd.end(), c_.begin() ); + sd.release(); + } + + template< class ForwardIterator > + void clone_assign( ForwardIterator first, + ForwardIterator last ) // strong + { + BOOST_ASSERT( first != last ); + scoped_deleter sd( first, last ); // strong + copy_clones_and_release( sd ); // nothrow + } + + template< class ForwardIterator > + void clone_back_insert( ForwardIterator first, + ForwardIterator last ) + { + BOOST_ASSERT( first != last ); + scoped_deleter sd( first, last ); + insert_clones_and_release( sd, end() ); + } + + void remove_all() + { + remove( begin(), end() ); + } + + protected: + + void insert_clones_and_release( scoped_deleter& sd, + iterator where ) // strong + { + // + // 'c_.insert' always provides the strong guarantee for T* elements + // since a copy constructor of a pointer cannot throw + // + c_.insert( where.base(), + sd.begin(), sd.end() ); + sd.release(); + } + + void insert_clones_and_release( scoped_deleter& sd ) // strong + { + c_.insert( sd.begin(), sd.end() ); + sd.release(); + } + + template< class U > + void remove( U* ptr ) + { + null_policy_deallocate_clone( ptr ); + } + + template< class I > + void remove( I i ) + { + null_policy_deallocate_clone( Config::get_const_pointer(i) ); + } + + template< class I > + void remove( I first, I last ) + { + for( ; first != last; ++first ) + remove( first ); + } + + static void enforce_null_policy( const Ty_* x, const char* msg ) + { + if( !allow_null ) + { + BOOST_PTR_CONTAINER_THROW_EXCEPTION( 0 == x && "null not allowed", + bad_pointer, msg ); + } + } + + static Ty_* null_policy_allocate_clone( const Ty_* x ) + { + return null_cloner_type::allocate_clone( x ); + } + + static void null_policy_deallocate_clone( const Ty_* x ) + { + null_cloner_type::deallocate_clone( x ); + } + + private: + template< class ForwardIterator > + ForwardIterator advance( ForwardIterator begin, size_type n ) + { + ForwardIterator iter = begin; + std::advance( iter, n ); + return iter; + } + + template< class I > + void constructor_impl( I first, I last, std::input_iterator_tag ) // basic + { + while( first != last ) + { + insert( end(), null_cloner_type::allocate_clone_from_iterator(first) ); + ++first; + } + } + + template< class I > + void constructor_impl( I first, I last, std::forward_iterator_tag ) // strong + { + if( first == last ) + return; + clone_back_insert( first, last ); + } + + template< class I > + void associative_constructor_impl( I first, I last ) // strong + { + if( first == last ) + return; + + scoped_deleter sd( first, last ); + insert_clones_and_release( sd ); + } + + public: // foundation! should be protected! + reversible_ptr_container() + { } + + template< class SizeType > + reversible_ptr_container( SizeType n, unordered_associative_container_tag ) + : c_( n ) + { } + + template< class SizeType > + reversible_ptr_container( SizeType n, fixed_length_sequence_tag ) + : c_( n ) + { } + + template< class SizeType > + reversible_ptr_container( SizeType n, const allocator_type& a, + fixed_length_sequence_tag ) + : c_( n, a ) + { } + + explicit reversible_ptr_container( const allocator_type& a ) + : c_( a ) + { } + + template< class PtrContainer > + explicit reversible_ptr_container( std::unique_ptr clone ) + { + swap( *clone ); + } + + reversible_ptr_container( const reversible_ptr_container& r ) + { + constructor_impl( r.begin(), r.end(), std::forward_iterator_tag() ); + } + + template< class C, class V > + reversible_ptr_container( const reversible_ptr_container& r ) + { + constructor_impl( r.begin(), r.end(), std::forward_iterator_tag() ); + } + + template< class PtrContainer > + reversible_ptr_container& operator=( std::unique_ptr clone ) // nothrow + { + swap( *clone ); + return *this; + } + + reversible_ptr_container& operator=( reversible_ptr_container r ) // strong + { + swap( r ); + return *this; + } + + // overhead: null-initilization of container pointer (very cheap compared to cloning) + // overhead: 1 heap allocation (very cheap compared to cloning) + template< class InputIterator > + reversible_ptr_container( InputIterator first, + InputIterator last, + const allocator_type& a = allocator_type() ) // basic, strong + : c_( a ) + { + constructor_impl( first, last, +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#else + BOOST_DEDUCED_TYPENAME +#endif + iterator_category::type() ); + } + + template< class Compare > + reversible_ptr_container( const Compare& comp, + const allocator_type& a ) + : c_( comp, a ) {} + + template< class ForwardIterator > + reversible_ptr_container( ForwardIterator first, + ForwardIterator last, + fixed_length_sequence_tag ) + : c_( std::distance(first,last) ) + { + constructor_impl( first, last, + std::forward_iterator_tag() ); + } + + template< class SizeType, class InputIterator > + reversible_ptr_container( SizeType n, + InputIterator first, + InputIterator last, + fixed_length_sequence_tag ) + : c_( n ) + { + constructor_impl( first, last, +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#else + BOOST_DEDUCED_TYPENAME +#endif + iterator_category::type() ); + } + + template< class Compare > + reversible_ptr_container( const Compare& comp, + const allocator_type& a, + associative_container_tag ) + : c_( comp, a ) + { } + + template< class InputIterator > + reversible_ptr_container( InputIterator first, + InputIterator last, + associative_container_tag ) + { + associative_constructor_impl( first, last ); + } + + template< class InputIterator, class Compare > + reversible_ptr_container( InputIterator first, + InputIterator last, + const Compare& comp, + const allocator_type& a, + associative_container_tag ) + : c_( comp, a ) + { + associative_constructor_impl( first, last ); + } + + explicit reversible_ptr_container( size_type n ) + : c_( n ) {} + + template< class Hash, class Pred > + reversible_ptr_container( const Hash& h, + const Pred& pred, + const allocator_type& a ) + : c_( h, pred, a ) {} + + template< class InputIterator, class Hash, class Pred > + reversible_ptr_container( InputIterator first, + InputIterator last, + const Hash& h, + const Pred& pred, + const allocator_type& a ) + : c_( h, pred, a ) + { + associative_constructor_impl( first, last ); + } + + public: + ~reversible_ptr_container() + { + remove_all(); + } + + public: + + allocator_type get_allocator() const + { + return c_.get_allocator(); + } + + public: // container requirements + iterator begin() + { return iterator( c_.begin() ); } + const_iterator begin() const + { return const_iterator( c_.begin() ); } + iterator end() + { return iterator( c_.end() ); } + const_iterator end() const + { return const_iterator( c_.end() ); } + + reverse_iterator rbegin() + { return reverse_iterator( this->end() ); } + const_reverse_iterator rbegin() const + { return const_reverse_iterator( this->end() ); } + reverse_iterator rend() + { return reverse_iterator( this->begin() ); } + const_reverse_iterator rend() const + { return const_reverse_iterator( this->begin() ); } + + const_iterator cbegin() const + { return const_iterator( c_.begin() ); } + const_iterator cend() const + { return const_iterator( c_.end() ); } + + const_reverse_iterator crbegin() const + { return const_reverse_iterator( this->end() ); } + const_reverse_iterator crend() const + { return const_reverse_iterator( this->begin() ); } + + void swap( reversible_ptr_container& r ) // nothrow + { + c_.swap( r.c_ ); + } + + size_type size() const // nothrow + { + return c_.size(); + } + + size_type max_size() const // nothrow + { + return c_.max_size(); + } + + bool empty() const // nothrow + { + return c_.empty(); + } + + public: // optional container requirements + + bool operator==( const reversible_ptr_container& r ) const // nothrow + { + if( size() != r.size() ) + return false; + else + return std::equal( begin(), end(), r.begin() ); + } + + bool operator!=( const reversible_ptr_container& r ) const // nothrow + { + return !(*this == r); + } + + bool operator<( const reversible_ptr_container& r ) const // nothrow + { + return std::lexicographical_compare( begin(), end(), r.begin(), r.end() ); + } + + bool operator<=( const reversible_ptr_container& r ) const // nothrow + { + return !(r < *this); + } + + bool operator>( const reversible_ptr_container& r ) const // nothrow + { + return r < *this; + } + + bool operator>=( const reversible_ptr_container& r ) const // nothrow + { + return !(*this < r); + } + + public: // modifiers + + iterator insert( iterator before, Ty_* x ) + { + enforce_null_policy( x, "Null pointer in 'insert()'" ); + + auto_type ptr( x ); // nothrow + iterator res( c_.insert( before.base(), x ) ); // strong, commit + ptr.release(); // nothrow + return res; + } + + template< class U > + iterator insert( iterator before, std::unique_ptr x ) + { + return insert( before, x.release() ); + } + + iterator erase( iterator x ) // nothrow + { + BOOST_ASSERT( !empty() ); + BOOST_ASSERT( x != end() ); + + remove( x ); + return iterator( c_.erase( x.base() ) ); + } + + iterator erase( iterator first, iterator last ) // nothrow + { + remove( first, last ); + return iterator( c_.erase( first.base(), + last.base() ) ); + } + + template< class Range > + iterator erase( const Range& r ) + { + return erase( boost::begin(r), boost::end(r) ); + } + + void clear() + { + remove_all(); + c_.clear(); + } + + public: // access interface + + auto_type release( iterator where ) + { + BOOST_ASSERT( where != end() ); + + BOOST_PTR_CONTAINER_THROW_EXCEPTION( empty(), bad_ptr_container_operation, + "'release()' on empty container" ); + + auto_type ptr( Config::get_pointer( where ) ); // nothrow + c_.erase( where.base() ); // nothrow + return boost::ptr_container_detail::move( ptr ); + } + + auto_type replace( iterator where, Ty_* x ) // strong + { + BOOST_ASSERT( where != end() ); + + enforce_null_policy( x, "Null pointer in 'replace()'" ); + + auto_type ptr( x ); + + BOOST_PTR_CONTAINER_THROW_EXCEPTION( empty(), bad_ptr_container_operation, + "'replace()' on empty container" ); + + auto_type old( Config::get_pointer( where ) ); // nothrow + const_cast(*where.base()) = ptr.release(); + return boost::ptr_container_detail::move( old ); + } + + template< class U > + auto_type replace( iterator where, std::unique_ptr x ) + { + return replace( where, x.release() ); + } + + auto_type replace( size_type idx, Ty_* x ) // strong + { + enforce_null_policy( x, "Null pointer in 'replace()'" ); + + auto_type ptr( x ); + + BOOST_PTR_CONTAINER_THROW_EXCEPTION( idx >= size(), bad_index, + "'replace()' out of bounds" ); + + auto_type old( static_cast( c_[idx] ) ); // nothrow + c_[idx] = ptr.release(); // nothrow, commit + return boost::ptr_container_detail::move( old ); + } + + template< class U > + auto_type replace( size_type idx, std::unique_ptr x ) + { + return replace( idx, x.release() ); + } + + }; // 'reversible_ptr_container' + + +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#define BOOST_PTR_CONTAINER_DEFINE_RELEASE( base_type ) \ + typename base_type::auto_type \ + release( typename base_type::iterator i ) \ + { \ + return boost::ptr_container_detail::move(base_type::release(i)); \ + } +#else +#define BOOST_PTR_CONTAINER_DEFINE_RELEASE( base_type ) \ + using base_type::release; +#endif + + // + // two-phase lookup of template functions + // is buggy on most compilers, so we use a macro instead + // +#define BOOST_PTR_CONTAINER_DEFINE_RELEASE_AND_CLONE( PC, base_type, this_type ) \ + explicit PC( std::unique_ptr r ) \ + : base_type ( r ) { } \ + \ + PC& operator=( std::unique_ptr r ) \ + { \ + base_type::operator=( r ); \ + return *this; \ + } \ + \ + std::unique_ptr release() \ + { \ + std::unique_ptr ptr( new this_type );\ + this->swap( *ptr ); \ + return ptr; \ + } \ + BOOST_PTR_CONTAINER_DEFINE_RELEASE( base_type ) \ + \ + std::unique_ptr clone() const \ + { \ + return std::unique_ptr( new this_type( this->begin(), this->end() ) ); \ + } + +#define BOOST_PTR_CONTAINER_DEFINE_COPY_CONSTRUCTORS( PC, base_type ) \ + \ + template< class U > \ + PC( const PC& r ) : base_type( r ) { } \ + \ + PC& operator=( PC r ) \ + { \ + this->swap( r ); \ + return *this; \ + } \ + + +#define BOOST_PTR_CONTAINER_DEFINE_CONSTRUCTORS( PC, base_type ) \ + typedef BOOST_DEDUCED_TYPENAME base_type::iterator iterator; \ + typedef BOOST_DEDUCED_TYPENAME base_type::size_type size_type; \ + typedef BOOST_DEDUCED_TYPENAME base_type::const_reference const_reference; \ + typedef BOOST_DEDUCED_TYPENAME base_type::allocator_type allocator_type; \ + PC() {} \ + explicit PC( const allocator_type& a ) : base_type(a) {} \ + template< class InputIterator > \ + PC( InputIterator first, InputIterator last ) : base_type( first, last ) {} \ + template< class InputIterator > \ + PC( InputIterator first, InputIterator last, \ + const allocator_type& a ) : base_type( first, last, a ) {} + +#define BOOST_PTR_CONTAINER_DEFINE_NON_INHERITED_MEMBERS( PC, base_type, this_type ) \ + BOOST_PTR_CONTAINER_DEFINE_CONSTRUCTORS( PC, base_type ) \ + BOOST_PTR_CONTAINER_DEFINE_RELEASE_AND_CLONE( PC, base_type, this_type ) + +#define BOOST_PTR_CONTAINER_DEFINE_SEQEUENCE_MEMBERS( PC, base_type, this_type ) \ + BOOST_PTR_CONTAINER_DEFINE_NON_INHERITED_MEMBERS( PC, base_type, this_type ) \ + BOOST_PTR_CONTAINER_DEFINE_COPY_CONSTRUCTORS( PC, base_type ) + +} // namespace 'ptr_container_detail' + + // + // @remark: expose movability of internal move-pointer + // + namespace ptr_container + { + using ptr_container_detail::move; + } + +} // namespace 'boost' + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/ptr_array.hpp b/src/external/3rd/library/boost/boost/ptr_container/ptr_array.hpp index 5e2999f61..ffa7ce22d 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/ptr_array.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/ptr_array.hpp @@ -1,234 +1,234 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2003-2005. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - -#ifndef BOOST_PTR_CONTAINER_PTR_ARRAY_HPP -#define BOOST_PTR_CONTAINER_PTR_ARRAY_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include -#include - -namespace boost -{ - - namespace ptr_container_detail - { - template - < - class T, - size_t N, - class Allocator = int // dummy - > - class ptr_array_impl : public boost::array - { - public: - typedef Allocator allocator_type; - - ptr_array_impl( Allocator /*a*/ = Allocator() ) - { - this->assign( 0 ); - } - - ptr_array_impl( size_t, T*, Allocator /*a*/ = Allocator() ) - { - this->assign( 0 ); - } - }; - } - - template - < - class T, - size_t N, - class CloneAllocator = heap_clone_allocator - > - class ptr_array : public - ptr_sequence_adapter< T, - ptr_container_detail::ptr_array_impl, - CloneAllocator > - { - private: - typedef ptr_sequence_adapter< T, - ptr_container_detail::ptr_array_impl, - CloneAllocator > - base_class; - - typedef BOOST_DEDUCED_TYPENAME remove_nullable::type U; - - typedef ptr_array - this_type; - - public: - typedef std::size_t size_type; - typedef U* value_type; - typedef U* pointer; - typedef U& reference; - typedef const U& const_reference; - typedef BOOST_DEDUCED_TYPENAME base_class::auto_type - auto_type; - - public: // constructors - ptr_array() : base_class() - { } - - ptr_array( const ptr_array& r ) - { - size_t i = 0; - for( ; i != N; ++i ) - this->base()[i] = this->null_policy_allocate_clone( - static_cast( &r[i] ) ); - } - - template< class U > - ptr_array( const ptr_array& r ) - { - size_t i = 0; - for( ; i != N; ++i ) - this->base()[i] = this->null_policy_allocate_clone( - static_cast( &r[i] ) ); - } - - explicit ptr_array( std::unique_ptr r ) - : base_class( r ) { } - - ptr_array& operator=( ptr_array r ) - { - this->swap( r ); - return *this; - } - - ptr_array& operator=( std::unique_ptr r ) - { - base_class::operator=(r); - return *this; - } - - std::unique_ptr release() - { - std::unique_ptr ptr( new this_type ); - this->swap( *ptr ); - return ptr; - } - - std::unique_ptr clone() const - { - std::unique_ptr pa( new this_type ); - for( size_t i = 0; i != N; ++i ) - { - if( ! is_null(i) ) - pa->replace( i, this->null_policy_allocate_clone( &(*this)[i] ) ); - } - return pa; - } - - private: // hide some members - using base_class::insert; - using base_class::erase; - using base_class::push_back; - using base_class::push_front; - using base_class::pop_front; - using base_class::pop_back; - using base_class::transfer; - using base_class::get_allocator; - - public: // compile-time interface - - template< size_t idx > - auto_type replace( U* r ) // strong - { - BOOST_STATIC_ASSERT( idx < N ); - - this->enforce_null_policy( r, "Null pointer in 'ptr_array::replace()'" ); - - auto_type res( static_cast( this->base()[idx] ) ); // nothrow - this->base()[idx] = r; // nothrow - return boost::ptr_container::move(res); // nothrow - } - - template< size_t idx, class V > - auto_type replace( std::unique_ptr r ) - { - return replace( r.release() ); - } - - auto_type replace( size_t idx, U* r ) // strong - { - this->enforce_null_policy( r, "Null pointer in 'ptr_array::replace()'" ); - - auto_type ptr( r ); - - BOOST_PTR_CONTAINER_THROW_EXCEPTION( idx >= N, bad_index, - "'replace()' aout of bounds" ); - - auto_type res( static_cast( this->base()[idx] ) ); // nothrow - this->base()[idx] = ptr.release(); // nothrow - return boost::ptr_container::move(res); // nothrow - } - - template< class V > - auto_type replace( size_t idx, std::unique_ptr r ) - { - return replace( idx, r.release() ); - } - - using base_class::at; - - template< size_t idx > - T& at() - { - BOOST_STATIC_ASSERT( idx < N ); - return (*this)[idx]; - } - - template< size_t idx > - const T& at() const - { - BOOST_STATIC_ASSERT( idx < N ); - return (*this)[idx]; - } - - bool is_null( size_t idx ) const - { - return base_class::is_null(idx); - } - - template< size_t idx > - bool is_null() const - { - BOOST_STATIC_ASSERT( idx < N ); - return this->base()[idx] == 0; - } - }; - - ////////////////////////////////////////////////////////////////////////////// - // clonability - - template< typename T, size_t size, typename CA > - inline ptr_array* new_clone( const ptr_array& r ) - { - return r.clone().release(); - } - - ///////////////////////////////////////////////////////////////////////// - // swap - - template< typename T, size_t size, typename CA > - inline void swap( ptr_array& l, ptr_array& r ) - { - l.swap(r); - } -} - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2003-2005. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + +#ifndef BOOST_PTR_CONTAINER_PTR_ARRAY_HPP +#define BOOST_PTR_CONTAINER_PTR_ARRAY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include + +namespace boost +{ + + namespace ptr_container_detail + { + template + < + class T, + size_t N, + class Allocator = int // dummy + > + class ptr_array_impl : public boost::array + { + public: + typedef Allocator allocator_type; + + ptr_array_impl( Allocator /*a*/ = Allocator() ) + { + this->assign( 0 ); + } + + ptr_array_impl( size_t, T*, Allocator /*a*/ = Allocator() ) + { + this->assign( 0 ); + } + }; + } + + template + < + class T, + size_t N, + class CloneAllocator = heap_clone_allocator + > + class ptr_array : public + ptr_sequence_adapter< T, + ptr_container_detail::ptr_array_impl, + CloneAllocator > + { + private: + typedef ptr_sequence_adapter< T, + ptr_container_detail::ptr_array_impl, + CloneAllocator > + base_class; + + typedef BOOST_DEDUCED_TYPENAME remove_nullable::type U; + + typedef ptr_array + this_type; + + public: + typedef std::size_t size_type; + typedef U* value_type; + typedef U* pointer; + typedef U& reference; + typedef const U& const_reference; + typedef BOOST_DEDUCED_TYPENAME base_class::auto_type + auto_type; + + public: // constructors + ptr_array() : base_class() + { } + + ptr_array( const ptr_array& r ) + { + size_t i = 0; + for( ; i != N; ++i ) + this->base()[i] = this->null_policy_allocate_clone( + static_cast( &r[i] ) ); + } + + template< class U > + ptr_array( const ptr_array& r ) + { + size_t i = 0; + for( ; i != N; ++i ) + this->base()[i] = this->null_policy_allocate_clone( + static_cast( &r[i] ) ); + } + + explicit ptr_array( std::unique_ptr r ) + : base_class( r ) { } + + ptr_array& operator=( ptr_array r ) + { + this->swap( r ); + return *this; + } + + ptr_array& operator=( std::unique_ptr r ) + { + base_class::operator=(r); + return *this; + } + + std::unique_ptr release() + { + std::unique_ptr ptr( new this_type ); + this->swap( *ptr ); + return ptr; + } + + std::unique_ptr clone() const + { + std::unique_ptr pa( new this_type ); + for( size_t i = 0; i != N; ++i ) + { + if( ! is_null(i) ) + pa->replace( i, this->null_policy_allocate_clone( &(*this)[i] ) ); + } + return pa; + } + + private: // hide some members + using base_class::insert; + using base_class::erase; + using base_class::push_back; + using base_class::push_front; + using base_class::pop_front; + using base_class::pop_back; + using base_class::transfer; + using base_class::get_allocator; + + public: // compile-time interface + + template< size_t idx > + auto_type replace( U* r ) // strong + { + BOOST_STATIC_ASSERT( idx < N ); + + this->enforce_null_policy( r, "Null pointer in 'ptr_array::replace()'" ); + + auto_type res( static_cast( this->base()[idx] ) ); // nothrow + this->base()[idx] = r; // nothrow + return boost::ptr_container::move(res); // nothrow + } + + template< size_t idx, class V > + auto_type replace( std::unique_ptr r ) + { + return replace( r.release() ); + } + + auto_type replace( size_t idx, U* r ) // strong + { + this->enforce_null_policy( r, "Null pointer in 'ptr_array::replace()'" ); + + auto_type ptr( r ); + + BOOST_PTR_CONTAINER_THROW_EXCEPTION( idx >= N, bad_index, + "'replace()' aout of bounds" ); + + auto_type res( static_cast( this->base()[idx] ) ); // nothrow + this->base()[idx] = ptr.release(); // nothrow + return boost::ptr_container::move(res); // nothrow + } + + template< class V > + auto_type replace( size_t idx, std::unique_ptr r ) + { + return replace( idx, r.release() ); + } + + using base_class::at; + + template< size_t idx > + T& at() + { + BOOST_STATIC_ASSERT( idx < N ); + return (*this)[idx]; + } + + template< size_t idx > + const T& at() const + { + BOOST_STATIC_ASSERT( idx < N ); + return (*this)[idx]; + } + + bool is_null( size_t idx ) const + { + return base_class::is_null(idx); + } + + template< size_t idx > + bool is_null() const + { + BOOST_STATIC_ASSERT( idx < N ); + return this->base()[idx] == 0; + } + }; + + ////////////////////////////////////////////////////////////////////////////// + // clonability + + template< typename T, size_t size, typename CA > + inline ptr_array* new_clone( const ptr_array& r ) + { + return r.clone().release(); + } + + ///////////////////////////////////////////////////////////////////////// + // swap + + template< typename T, size_t size, typename CA > + inline void swap( ptr_array& l, ptr_array& r ) + { + l.swap(r); + } +} + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/ptr_circular_buffer.hpp b/src/external/3rd/library/boost/boost/ptr_container/ptr_circular_buffer.hpp index 35dbfa8a8..d95a35df8 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/ptr_circular_buffer.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/ptr_circular_buffer.hpp @@ -1,531 +1,531 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2008. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - -#ifndef BOOST_PTR_CONTAINER_PTR_CIRCULAR_BUFFER_HPP -#define BOOST_PTR_CONTAINER_PTR_CIRCULAR_BUFFER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include - -namespace boost -{ - - template - < - class T, - class CloneAllocator = heap_clone_allocator, - class Allocator = std::allocator - > - class ptr_circular_buffer : public - ptr_sequence_adapter< T, - boost::circular_buffer, - CloneAllocator > - { - typedef ptr_sequence_adapter< T, - boost::circular_buffer, - CloneAllocator > - base_type; - - typedef boost::circular_buffer circular_buffer_type; - typedef ptr_circular_buffer this_type; - - public: // typedefs - typedef typename base_type::value_type value_type; - typedef value_type* pointer; - typedef const value_type* const_pointer; - typedef typename base_type::size_type size_type; - typedef typename base_type::allocator_type allocator_type; - typedef typename base_type::iterator iterator; - typedef typename base_type::const_iterator const_iterator; - typedef typename base_type::auto_type auto_type; - - typedef std::pair array_range; - typedef std::pair const_array_range; - typedef typename circular_buffer_type::capacity_type capacity_type; - - public: // constructors - ptr_circular_buffer() - { } - - explicit ptr_circular_buffer( capacity_type n ) - : base_type( n, ptr_container_detail::fixed_length_sequence_tag() ) - { } - - ptr_circular_buffer( capacity_type n, - const allocator_type& alloc ) - : base_type( n, alloc, ptr_container_detail::fixed_length_sequence_tag() ) - { } - - template< class ForwardIterator > - ptr_circular_buffer( ForwardIterator first, ForwardIterator last ) - : base_type( first, last, ptr_container_detail::fixed_length_sequence_tag() ) - { } - - template< class InputIterator > - ptr_circular_buffer( capacity_type n, InputIterator first, InputIterator last ) - : base_type( n, first, last, ptr_container_detail::fixed_length_sequence_tag() ) - { } - - ptr_circular_buffer( const ptr_circular_buffer& r ) - : base_type( r.size(), r.begin(), r.end(), - ptr_container_detail::fixed_length_sequence_tag() ) - { } - - template< class U > - ptr_circular_buffer( const ptr_circular_buffer& r ) - : base_type( r.size(), r.begin(), r.end(), - ptr_container_detail::fixed_length_sequence_tag() ) - { } - - ptr_circular_buffer& operator=( ptr_circular_buffer r ) - { - this->swap( r ); - return *this; - } - - BOOST_PTR_CONTAINER_DEFINE_RELEASE_AND_CLONE( ptr_circular_buffer, - base_type, this_type ) - - public: // allocators - allocator_type& get_allocator() - { - return this->base().get_allocator(); - } - - allocator_type get_allocator() const - { - return this->base().get_allocator(); - } - - public: // circular buffer functions - array_range array_one() // nothrow - { - typename circular_buffer_type::array_range r = this->base().array_one(); - return array_range( reinterpret_cast(r.first), r.second ); - } - - const_array_range array_one() const // nothrow - { - typename circular_buffer_type::const_array_range r = this->base().array_one(); - return const_array_range( reinterpret_cast(r.first), r.second ); - } - - array_range array_two() // nothrow - { - typename circular_buffer_type::array_range r = this->base().array_two(); - return array_range( reinterpret_cast(r.first), r.second ); - } - - const_array_range array_two() const // nothrow - { - typename circular_buffer_type::const_array_range r = this->base().array_two(); - return const_array_range( reinterpret_cast(r.first), r.second ); - } - - pointer linearize() // nothrow - { - return reinterpret_cast(this->base().linearize()); - } - - bool full() const // nothrow - { - return this->base().full(); - } - - size_type reserve() const // nothrow - { - return this->base().reserve(); - } - - void reserve( size_type n ) // strong - { - if( capacity() < n ) - set_capacity( n ); - } - - capacity_type capacity() const // nothrow - { - return this->base().capacity(); - } - - void set_capacity( capacity_type new_capacity ) // strong - { - if( this->size() > new_capacity ) - { - this->erase( this->begin() + new_capacity, this->end() ); - } - this->base().set_capacity( new_capacity ); - } - - void rset_capacity( capacity_type new_capacity ) // strong - { - if( this->size() > new_capacity ) - { - this->erase( this->begin(), - this->begin() + (this->size()-new_capacity) ); - } - this->base().rset_capacity( new_capacity ); - } - - void resize( size_type size ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( boost::next( this->begin(), size ), this->end() ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_back( new BOOST_DEDUCED_TYPENAME - boost::remove_pointer::type() ); - } - - BOOST_ASSERT( this->size() == size ); - } - - void resize( size_type size, value_type to_clone ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( boost::next( this->begin(), size ), this->end() ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_back( this->null_policy_allocate_clone( to_clone ) ); - } - - BOOST_ASSERT( this->size() == size ); - } - - void rresize( size_type size ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( this->begin(), - boost::next( this->begin(), old_size - size ) ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_front( new BOOST_DEDUCED_TYPENAME - boost::remove_pointer::type() ); - } - - BOOST_ASSERT( this->size() == size ); - } - - void rresize( size_type size, value_type to_clone ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( this->begin(), - boost::next( this->begin(), old_size - size ) ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_front( this->null_policy_allocate_clone( to_clone ) ); - } - - BOOST_ASSERT( this->size() == size ); - } - - template< class InputIterator > - void assign( InputIterator first, InputIterator last ) // strong - { - ptr_circular_buffer temp( first, last ); - this->swap( temp ); - } - - template< class Range > - void assign( const Range& r ) // strong - { - assign( boost::begin(r), boost::end(r ) ); - } - - void assign( size_type n, value_type to_clone ) // strong - { - ptr_circular_buffer temp( n ); - for( size_type i = 0u; i != n; ++i ) - temp.push_back( this->null_policy_allocate_clone( to_clone ) ); - this->swap( temp ); - } - - void assign( capacity_type capacity, size_type n, - value_type to_clone ) // basic - { - this->assign( (std::min)(n,capacity), to_clone ); - } - - template< class InputIterator > - void assign( capacity_type capacity, - InputIterator first, InputIterator last ) // basic - { - this->assign( first, last ); - this->set_capacity( capacity ); - } - - void push_back( value_type ptr ) // nothrow - { - BOOST_ASSERT( capacity() > 0 ); - this->enforce_null_policy( ptr, "Null pointer in 'push_back()'" ); - - auto_type old_ptr; - if( full() ) - old_ptr.reset( &*this->begin() ); - this->base().push_back( ptr ); - } - - template< class U > - void push_back( std::unique_ptr ptr ) // nothrow - { - push_back( ptr.release() ); - } - - void push_front( value_type ptr ) // nothrow - { - BOOST_ASSERT( capacity() > 0 ); - this->enforce_null_policy( ptr, "Null pointer in 'push_front()'" ); - - auto_type old_ptr; - if( full() ) - old_ptr.reset( &*(--this->end()) ); - this->base().push_front( ptr ); - } - - template< class U > - void push_front( std::unique_ptr ptr ) // nothrow - { - push_front( ptr.release() ); - } - - iterator insert( iterator pos, value_type ptr ) // nothrow - { - BOOST_ASSERT( capacity() > 0 ); - this->enforce_null_policy( ptr, "Null pointer in 'insert()'" ); - - auto_type new_ptr( ptr ); - iterator b = this->begin(); - if( full() && pos == b ) - return b; - - auto_type old_ptr; - if( full() ) - old_ptr.reset( &*this->begin() ); - - new_ptr.release(); - return this->base().insert( pos.base(), ptr ); - } - - template< class U > - iterator insert( iterator pos, std::unique_ptr ptr ) // nothrow - { - return insert( pos, ptr.release() ); - } - - template< class InputIterator > - void insert( iterator pos, InputIterator first, InputIterator last ) // basic - { - for( ; first != last; ++first, ++pos ) - pos = insert( pos, this->null_policy_allocate_clone( &*first ) ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - template< class Range > - BOOST_DEDUCED_TYPENAME - boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type - insert( iterator before, const Range& r ) - { - insert( before, boost::begin(r), boost::end(r) ); - } - -#endif - - iterator rinsert( iterator pos, value_type ptr ) // nothrow - { - BOOST_ASSERT( capacity() > 0 ); - this->enforce_null_policy( ptr, "Null pointer in 'rinsert()'" ); - - auto_type new_ptr( ptr ); - iterator b = this->end(); - if (full() && pos == b) - return b; - - auto_type old_ptr; - if( full() ) - old_ptr.reset( &this->back() ); - - new_ptr.release(); - return this->base().rinsert( pos.base(), ptr ); - } - - template< class U > - iterator rinsert( iterator pos, std::unique_ptr ptr ) // nothrow - { - return rinsert( pos, ptr.release() ); - } - - - template< class InputIterator > - void rinsert( iterator pos, InputIterator first, InputIterator last ) // basic - { - for( ; first != last; ++first, ++pos ) - pos = rinsert( pos, this->null_policy_allocate_clone( &*first ) ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - template< class Range > - BOOST_DEDUCED_TYPENAME - boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type - rinsert( iterator before, const Range& r ) - { - rinsert( before, boost::begin(r), boost::end(r) ); - } - -#endif - - iterator rerase( iterator pos ) // nothrow - { - BOOST_ASSERT( !this->empty() ); - BOOST_ASSERT( pos != this->end() ); - - this->remove( pos ); - return iterator( this->base().rerase( pos.base() ) ); - } - - iterator rerase( iterator first, iterator last ) // nothrow - { - this->remove( first, last ); - return iterator( this->base().rerase( first.base(), - last.base() ) ); - } - - template< class Range > - iterator rerase( const Range& r ) // nothrow - { - return rerase( boost::begin(r), boost::end(r) ); - } - - void rotate( const_iterator new_begin ) // nothrow - { - this->base().rotate( new_begin.base() ); - } - - public: // transfer - template< class PtrSeqAdapter > - void transfer( iterator before, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator first, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator last, - PtrSeqAdapter& from ) // nothrow - { - BOOST_ASSERT( (void*)&from != (void*)this ); - if( from.empty() ) - return; - for( BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator begin = first; - begin != last; ++begin, ++before ) - before = insert( before, &*begin ); // nothrow - from.base().erase( first.base(), last.base() ); // nothrow - } - - template< class PtrSeqAdapter > - void transfer( iterator before, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator object, - PtrSeqAdapter& from ) // nothrow - { - BOOST_ASSERT( (void*)&from != (void*)this ); - if( from.empty() ) - return; - insert( before, &*object ); // nothrow - from.base().erase( object.base() ); // nothrow - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class PtrSeqAdapter, class Range > - BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator > >::type - transfer( iterator before, const Range& r, PtrSeqAdapter& from ) // nothrow - { - transfer( before, boost::begin(r), boost::end(r), from ); - } - -#endif - template< class PtrSeqAdapter > - void transfer( iterator before, PtrSeqAdapter& from ) // nothrow - { - transfer( before, from.begin(), from.end(), from ); - } - - public: // C-array support - - void transfer( iterator before, value_type* from, - size_type size, bool delete_from = true ) // nothrow - { - BOOST_ASSERT( from != 0 ); - if( delete_from ) - { - BOOST_DEDUCED_TYPENAME base_type::scoped_deleter - deleter( from, size ); // nothrow - for( size_type i = 0u; i != size; ++i, ++before ) - before = insert( before, *(from+i) ); // nothrow - deleter.release(); // nothrow - } - else - { - for( size_type i = 0u; i != size; ++i, ++before ) - before = insert( before, *(from+i) ); // nothrow - } - } - - value_type* c_array() // nothrow - { - if( this->empty() ) - return 0; - this->linearize(); - T** res = reinterpret_cast( &this->begin().base()[0] ); - return res; - } - - }; - - ////////////////////////////////////////////////////////////////////////////// - // clonability - - template< typename T, typename CA, typename A > - inline ptr_circular_buffer* new_clone( const ptr_circular_buffer& r ) - { - return r.clone().release(); - } - - ///////////////////////////////////////////////////////////////////////// - // swap - - template< typename T, typename CA, typename A > - inline void swap( ptr_circular_buffer& l, ptr_circular_buffer& r ) - { - l.swap(r); - } - -} - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2008. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + +#ifndef BOOST_PTR_CONTAINER_PTR_CIRCULAR_BUFFER_HPP +#define BOOST_PTR_CONTAINER_PTR_CIRCULAR_BUFFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include + +namespace boost +{ + + template + < + class T, + class CloneAllocator = heap_clone_allocator, + class Allocator = std::allocator + > + class ptr_circular_buffer : public + ptr_sequence_adapter< T, + boost::circular_buffer, + CloneAllocator > + { + typedef ptr_sequence_adapter< T, + boost::circular_buffer, + CloneAllocator > + base_type; + + typedef boost::circular_buffer circular_buffer_type; + typedef ptr_circular_buffer this_type; + + public: // typedefs + typedef typename base_type::value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef typename base_type::size_type size_type; + typedef typename base_type::allocator_type allocator_type; + typedef typename base_type::iterator iterator; + typedef typename base_type::const_iterator const_iterator; + typedef typename base_type::auto_type auto_type; + + typedef std::pair array_range; + typedef std::pair const_array_range; + typedef typename circular_buffer_type::capacity_type capacity_type; + + public: // constructors + ptr_circular_buffer() + { } + + explicit ptr_circular_buffer( capacity_type n ) + : base_type( n, ptr_container_detail::fixed_length_sequence_tag() ) + { } + + ptr_circular_buffer( capacity_type n, + const allocator_type& alloc ) + : base_type( n, alloc, ptr_container_detail::fixed_length_sequence_tag() ) + { } + + template< class ForwardIterator > + ptr_circular_buffer( ForwardIterator first, ForwardIterator last ) + : base_type( first, last, ptr_container_detail::fixed_length_sequence_tag() ) + { } + + template< class InputIterator > + ptr_circular_buffer( capacity_type n, InputIterator first, InputIterator last ) + : base_type( n, first, last, ptr_container_detail::fixed_length_sequence_tag() ) + { } + + ptr_circular_buffer( const ptr_circular_buffer& r ) + : base_type( r.size(), r.begin(), r.end(), + ptr_container_detail::fixed_length_sequence_tag() ) + { } + + template< class U > + ptr_circular_buffer( const ptr_circular_buffer& r ) + : base_type( r.size(), r.begin(), r.end(), + ptr_container_detail::fixed_length_sequence_tag() ) + { } + + ptr_circular_buffer& operator=( ptr_circular_buffer r ) + { + this->swap( r ); + return *this; + } + + BOOST_PTR_CONTAINER_DEFINE_RELEASE_AND_CLONE( ptr_circular_buffer, + base_type, this_type ) + + public: // allocators + allocator_type& get_allocator() + { + return this->base().get_allocator(); + } + + allocator_type get_allocator() const + { + return this->base().get_allocator(); + } + + public: // circular buffer functions + array_range array_one() // nothrow + { + typename circular_buffer_type::array_range r = this->base().array_one(); + return array_range( reinterpret_cast(r.first), r.second ); + } + + const_array_range array_one() const // nothrow + { + typename circular_buffer_type::const_array_range r = this->base().array_one(); + return const_array_range( reinterpret_cast(r.first), r.second ); + } + + array_range array_two() // nothrow + { + typename circular_buffer_type::array_range r = this->base().array_two(); + return array_range( reinterpret_cast(r.first), r.second ); + } + + const_array_range array_two() const // nothrow + { + typename circular_buffer_type::const_array_range r = this->base().array_two(); + return const_array_range( reinterpret_cast(r.first), r.second ); + } + + pointer linearize() // nothrow + { + return reinterpret_cast(this->base().linearize()); + } + + bool full() const // nothrow + { + return this->base().full(); + } + + size_type reserve() const // nothrow + { + return this->base().reserve(); + } + + void reserve( size_type n ) // strong + { + if( capacity() < n ) + set_capacity( n ); + } + + capacity_type capacity() const // nothrow + { + return this->base().capacity(); + } + + void set_capacity( capacity_type new_capacity ) // strong + { + if( this->size() > new_capacity ) + { + this->erase( this->begin() + new_capacity, this->end() ); + } + this->base().set_capacity( new_capacity ); + } + + void rset_capacity( capacity_type new_capacity ) // strong + { + if( this->size() > new_capacity ) + { + this->erase( this->begin(), + this->begin() + (this->size()-new_capacity) ); + } + this->base().rset_capacity( new_capacity ); + } + + void resize( size_type size ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( boost::next( this->begin(), size ), this->end() ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_back( new BOOST_DEDUCED_TYPENAME + boost::remove_pointer::type() ); + } + + BOOST_ASSERT( this->size() == size ); + } + + void resize( size_type size, value_type to_clone ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( boost::next( this->begin(), size ), this->end() ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_back( this->null_policy_allocate_clone( to_clone ) ); + } + + BOOST_ASSERT( this->size() == size ); + } + + void rresize( size_type size ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( this->begin(), + boost::next( this->begin(), old_size - size ) ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_front( new BOOST_DEDUCED_TYPENAME + boost::remove_pointer::type() ); + } + + BOOST_ASSERT( this->size() == size ); + } + + void rresize( size_type size, value_type to_clone ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( this->begin(), + boost::next( this->begin(), old_size - size ) ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_front( this->null_policy_allocate_clone( to_clone ) ); + } + + BOOST_ASSERT( this->size() == size ); + } + + template< class InputIterator > + void assign( InputIterator first, InputIterator last ) // strong + { + ptr_circular_buffer temp( first, last ); + this->swap( temp ); + } + + template< class Range > + void assign( const Range& r ) // strong + { + assign( boost::begin(r), boost::end(r ) ); + } + + void assign( size_type n, value_type to_clone ) // strong + { + ptr_circular_buffer temp( n ); + for( size_type i = 0u; i != n; ++i ) + temp.push_back( this->null_policy_allocate_clone( to_clone ) ); + this->swap( temp ); + } + + void assign( capacity_type capacity, size_type n, + value_type to_clone ) // basic + { + this->assign( (std::min)(n,capacity), to_clone ); + } + + template< class InputIterator > + void assign( capacity_type capacity, + InputIterator first, InputIterator last ) // basic + { + this->assign( first, last ); + this->set_capacity( capacity ); + } + + void push_back( value_type ptr ) // nothrow + { + BOOST_ASSERT( capacity() > 0 ); + this->enforce_null_policy( ptr, "Null pointer in 'push_back()'" ); + + auto_type old_ptr; + if( full() ) + old_ptr.reset( &*this->begin() ); + this->base().push_back( ptr ); + } + + template< class U > + void push_back( std::unique_ptr ptr ) // nothrow + { + push_back( ptr.release() ); + } + + void push_front( value_type ptr ) // nothrow + { + BOOST_ASSERT( capacity() > 0 ); + this->enforce_null_policy( ptr, "Null pointer in 'push_front()'" ); + + auto_type old_ptr; + if( full() ) + old_ptr.reset( &*(--this->end()) ); + this->base().push_front( ptr ); + } + + template< class U > + void push_front( std::unique_ptr ptr ) // nothrow + { + push_front( ptr.release() ); + } + + iterator insert( iterator pos, value_type ptr ) // nothrow + { + BOOST_ASSERT( capacity() > 0 ); + this->enforce_null_policy( ptr, "Null pointer in 'insert()'" ); + + auto_type new_ptr( ptr ); + iterator b = this->begin(); + if( full() && pos == b ) + return b; + + auto_type old_ptr; + if( full() ) + old_ptr.reset( &*this->begin() ); + + new_ptr.release(); + return this->base().insert( pos.base(), ptr ); + } + + template< class U > + iterator insert( iterator pos, std::unique_ptr ptr ) // nothrow + { + return insert( pos, ptr.release() ); + } + + template< class InputIterator > + void insert( iterator pos, InputIterator first, InputIterator last ) // basic + { + for( ; first != last; ++first, ++pos ) + pos = insert( pos, this->null_policy_allocate_clone( &*first ) ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + template< class Range > + BOOST_DEDUCED_TYPENAME + boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type + insert( iterator before, const Range& r ) + { + insert( before, boost::begin(r), boost::end(r) ); + } + +#endif + + iterator rinsert( iterator pos, value_type ptr ) // nothrow + { + BOOST_ASSERT( capacity() > 0 ); + this->enforce_null_policy( ptr, "Null pointer in 'rinsert()'" ); + + auto_type new_ptr( ptr ); + iterator b = this->end(); + if (full() && pos == b) + return b; + + auto_type old_ptr; + if( full() ) + old_ptr.reset( &this->back() ); + + new_ptr.release(); + return this->base().rinsert( pos.base(), ptr ); + } + + template< class U > + iterator rinsert( iterator pos, std::unique_ptr ptr ) // nothrow + { + return rinsert( pos, ptr.release() ); + } + + + template< class InputIterator > + void rinsert( iterator pos, InputIterator first, InputIterator last ) // basic + { + for( ; first != last; ++first, ++pos ) + pos = rinsert( pos, this->null_policy_allocate_clone( &*first ) ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + template< class Range > + BOOST_DEDUCED_TYPENAME + boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type + rinsert( iterator before, const Range& r ) + { + rinsert( before, boost::begin(r), boost::end(r) ); + } + +#endif + + iterator rerase( iterator pos ) // nothrow + { + BOOST_ASSERT( !this->empty() ); + BOOST_ASSERT( pos != this->end() ); + + this->remove( pos ); + return iterator( this->base().rerase( pos.base() ) ); + } + + iterator rerase( iterator first, iterator last ) // nothrow + { + this->remove( first, last ); + return iterator( this->base().rerase( first.base(), + last.base() ) ); + } + + template< class Range > + iterator rerase( const Range& r ) // nothrow + { + return rerase( boost::begin(r), boost::end(r) ); + } + + void rotate( const_iterator new_begin ) // nothrow + { + this->base().rotate( new_begin.base() ); + } + + public: // transfer + template< class PtrSeqAdapter > + void transfer( iterator before, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator first, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator last, + PtrSeqAdapter& from ) // nothrow + { + BOOST_ASSERT( (void*)&from != (void*)this ); + if( from.empty() ) + return; + for( BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator begin = first; + begin != last; ++begin, ++before ) + before = insert( before, &*begin ); // nothrow + from.base().erase( first.base(), last.base() ); // nothrow + } + + template< class PtrSeqAdapter > + void transfer( iterator before, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator object, + PtrSeqAdapter& from ) // nothrow + { + BOOST_ASSERT( (void*)&from != (void*)this ); + if( from.empty() ) + return; + insert( before, &*object ); // nothrow + from.base().erase( object.base() ); // nothrow + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class PtrSeqAdapter, class Range > + BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator > >::type + transfer( iterator before, const Range& r, PtrSeqAdapter& from ) // nothrow + { + transfer( before, boost::begin(r), boost::end(r), from ); + } + +#endif + template< class PtrSeqAdapter > + void transfer( iterator before, PtrSeqAdapter& from ) // nothrow + { + transfer( before, from.begin(), from.end(), from ); + } + + public: // C-array support + + void transfer( iterator before, value_type* from, + size_type size, bool delete_from = true ) // nothrow + { + BOOST_ASSERT( from != 0 ); + if( delete_from ) + { + BOOST_DEDUCED_TYPENAME base_type::scoped_deleter + deleter( from, size ); // nothrow + for( size_type i = 0u; i != size; ++i, ++before ) + before = insert( before, *(from+i) ); // nothrow + deleter.release(); // nothrow + } + else + { + for( size_type i = 0u; i != size; ++i, ++before ) + before = insert( before, *(from+i) ); // nothrow + } + } + + value_type* c_array() // nothrow + { + if( this->empty() ) + return 0; + this->linearize(); + T** res = reinterpret_cast( &this->begin().base()[0] ); + return res; + } + + }; + + ////////////////////////////////////////////////////////////////////////////// + // clonability + + template< typename T, typename CA, typename A > + inline ptr_circular_buffer* new_clone( const ptr_circular_buffer& r ) + { + return r.clone().release(); + } + + ///////////////////////////////////////////////////////////////////////// + // swap + + template< typename T, typename CA, typename A > + inline void swap( ptr_circular_buffer& l, ptr_circular_buffer& r ) + { + l.swap(r); + } + +} + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/ptr_inserter.hpp b/src/external/3rd/library/boost/boost/ptr_container/ptr_inserter.hpp index bf379b036..b4a1e135b 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/ptr_inserter.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/ptr_inserter.hpp @@ -1,258 +1,258 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2008. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - -#ifndef BOOST_PTR_CONTAINER_PTR_INSERTER_HPP -#define BOOST_PTR_CONTAINER_PTR_INSERTER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) - #pragma once -#endif - -#include -#include -#include - -namespace boost -{ -namespace ptr_container -{ - template< class PtrContainer > - class ptr_back_insert_iterator; - - template< class PtrContainer > - class ptr_front_insert_iterator; - - template< class PtrContainer > - class ptr_insert_iterator; - - template< class PtrContainer > - ptr_back_insert_iterator - ptr_back_inserter( PtrContainer& cont ); - - template< class PtrContainer > - ptr_front_insert_iterator - ptr_front_inserter( PtrContainer& cont ); - - template< class PtrContainer > - ptr_insert_iterator - ptr_inserter( PtrContainer& cont, typename PtrContainer::iterator before ); - - ////////////////////////////////////////////////////////////////////////// - // Implementation - ////////////////////////////////////////////////////////////////////////// - - - template< class PtrContainer > - class ptr_back_insert_iterator : - public std::iterator - { - public: - typedef PtrContainer container_type; - - public: - explicit ptr_back_insert_iterator( PtrContainer& cont ) - : container(&cont) - { } - - ptr_back_insert_iterator& - operator=( typename PtrContainer::value_type r ) - { - typename PtrContainer::value_type obj = 0; - if( r != 0 ) - obj = container_type::clone_allocator_type::allocate_clone(*r); - - container->push_back( obj ); - return *this; - } - - template< class T > - ptr_back_insert_iterator& - operator=( std::unique_ptr r ) - { - container->push_back( r ); - return *this; - } - - ptr_back_insert_iterator& - operator=( typename PtrContainer::const_reference r ) - { - container->push_back( container_type::clone_allocator_type:: - allocate_clone(r) ); - return *this; - } - - ptr_back_insert_iterator& operator*() - { - return *this; - } - - ptr_back_insert_iterator& operator++() - { - return *this; - } - - ptr_back_insert_iterator operator++(int) - { - return *this; - } - - protected: - PtrContainer* container; - }; - - - - template< class PtrContainer > - class ptr_front_insert_iterator : - public std::iterator - { - public: - typedef PtrContainer container_type; - - public: - explicit ptr_front_insert_iterator( PtrContainer& cont ) - : container(&cont) - { } - - ptr_front_insert_iterator& - operator=( typename PtrContainer::value_type r ) - { - typename PtrContainer::value_type obj = 0; - if( r != 0 ) - obj = container_type::clone_allocator_type::allocate_clone(*r); - - container->push_front( obj ); - return *this; - } - - template< class T > - ptr_front_insert_iterator& - operator=( std::unique_ptr r ) - { - container->push_front( r ); - return *this; - } - - ptr_front_insert_iterator& - operator=( typename PtrContainer::const_reference r ) - { - container->push_front( container_type::clone_allocator_type:: - allocate_clone(r) ); - return *this; - } - - ptr_front_insert_iterator& operator*() - { - return *this; - } - - ptr_front_insert_iterator& operator++() - { - return *this; - } - - ptr_front_insert_iterator operator++(int) - { - return *this; - } - - protected: - PtrContainer* container; - }; - - - - template< class PtrContainer > - class ptr_insert_iterator : - public std::iterator - { - public: - typedef PtrContainer container_type; - - public: - ptr_insert_iterator( PtrContainer& cont, - typename PtrContainer::iterator before ) - : container(&cont), iter(before) - { } - - ptr_insert_iterator& - operator=( typename PtrContainer::value_type r ) - { - typename PtrContainer::value_type obj = 0; - if( r != 0 ) - obj = container_type::clone_allocator_type::allocate_clone(*r); - - iter = container->insert( iter, obj ); - return *this; - } - - template< class T > - ptr_insert_iterator& - operator=( std::unique_ptr r ) - { - iter = container->insert( iter, r ); - return *this; - } - - ptr_insert_iterator& - operator=( typename PtrContainer::const_reference r ) - { - iter = container->insert( iter, container_type::clone_allocator_type:: - allocate_clone(r) ); - return *this; - } - - ptr_insert_iterator& operator*() - { - return *this; - } - - ptr_insert_iterator& operator++() - { - return *this; - } - - ptr_insert_iterator operator++(int) - { - return *this; - } - - protected: - PtrContainer* container; - typename PtrContainer::iterator iter; - }; - - template< class PtrContainer > - inline ptr_back_insert_iterator - ptr_back_inserter( PtrContainer& cont ) - { - return ptr_back_insert_iterator( cont ); - } - - template< class PtrContainer > - inline ptr_front_insert_iterator - ptr_front_inserter( PtrContainer& cont ) - { - return ptr_front_insert_iterator( cont ); - } - - template< class PtrContainer > - inline ptr_insert_iterator - ptr_inserter( PtrContainer& cont, - typename PtrContainer::iterator before ) - { - return ptr_insert_iterator( cont, before ); - } - -} // namespace 'ptr_container' -} // namespace 'boost' - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2008. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + +#ifndef BOOST_PTR_CONTAINER_PTR_INSERTER_HPP +#define BOOST_PTR_CONTAINER_PTR_INSERTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) + #pragma once +#endif + +#include +#include +#include + +namespace boost +{ +namespace ptr_container +{ + template< class PtrContainer > + class ptr_back_insert_iterator; + + template< class PtrContainer > + class ptr_front_insert_iterator; + + template< class PtrContainer > + class ptr_insert_iterator; + + template< class PtrContainer > + ptr_back_insert_iterator + ptr_back_inserter( PtrContainer& cont ); + + template< class PtrContainer > + ptr_front_insert_iterator + ptr_front_inserter( PtrContainer& cont ); + + template< class PtrContainer > + ptr_insert_iterator + ptr_inserter( PtrContainer& cont, typename PtrContainer::iterator before ); + + ////////////////////////////////////////////////////////////////////////// + // Implementation + ////////////////////////////////////////////////////////////////////////// + + + template< class PtrContainer > + class ptr_back_insert_iterator : + public std::iterator + { + public: + typedef PtrContainer container_type; + + public: + explicit ptr_back_insert_iterator( PtrContainer& cont ) + : container(&cont) + { } + + ptr_back_insert_iterator& + operator=( typename PtrContainer::value_type r ) + { + typename PtrContainer::value_type obj = 0; + if( r != 0 ) + obj = container_type::clone_allocator_type::allocate_clone(*r); + + container->push_back( obj ); + return *this; + } + + template< class T > + ptr_back_insert_iterator& + operator=( std::unique_ptr r ) + { + container->push_back( r ); + return *this; + } + + ptr_back_insert_iterator& + operator=( typename PtrContainer::const_reference r ) + { + container->push_back( container_type::clone_allocator_type:: + allocate_clone(r) ); + return *this; + } + + ptr_back_insert_iterator& operator*() + { + return *this; + } + + ptr_back_insert_iterator& operator++() + { + return *this; + } + + ptr_back_insert_iterator operator++(int) + { + return *this; + } + + protected: + PtrContainer* container; + }; + + + + template< class PtrContainer > + class ptr_front_insert_iterator : + public std::iterator + { + public: + typedef PtrContainer container_type; + + public: + explicit ptr_front_insert_iterator( PtrContainer& cont ) + : container(&cont) + { } + + ptr_front_insert_iterator& + operator=( typename PtrContainer::value_type r ) + { + typename PtrContainer::value_type obj = 0; + if( r != 0 ) + obj = container_type::clone_allocator_type::allocate_clone(*r); + + container->push_front( obj ); + return *this; + } + + template< class T > + ptr_front_insert_iterator& + operator=( std::unique_ptr r ) + { + container->push_front( r ); + return *this; + } + + ptr_front_insert_iterator& + operator=( typename PtrContainer::const_reference r ) + { + container->push_front( container_type::clone_allocator_type:: + allocate_clone(r) ); + return *this; + } + + ptr_front_insert_iterator& operator*() + { + return *this; + } + + ptr_front_insert_iterator& operator++() + { + return *this; + } + + ptr_front_insert_iterator operator++(int) + { + return *this; + } + + protected: + PtrContainer* container; + }; + + + + template< class PtrContainer > + class ptr_insert_iterator : + public std::iterator + { + public: + typedef PtrContainer container_type; + + public: + ptr_insert_iterator( PtrContainer& cont, + typename PtrContainer::iterator before ) + : container(&cont), iter(before) + { } + + ptr_insert_iterator& + operator=( typename PtrContainer::value_type r ) + { + typename PtrContainer::value_type obj = 0; + if( r != 0 ) + obj = container_type::clone_allocator_type::allocate_clone(*r); + + iter = container->insert( iter, obj ); + return *this; + } + + template< class T > + ptr_insert_iterator& + operator=( std::unique_ptr r ) + { + iter = container->insert( iter, r ); + return *this; + } + + ptr_insert_iterator& + operator=( typename PtrContainer::const_reference r ) + { + iter = container->insert( iter, container_type::clone_allocator_type:: + allocate_clone(r) ); + return *this; + } + + ptr_insert_iterator& operator*() + { + return *this; + } + + ptr_insert_iterator& operator++() + { + return *this; + } + + ptr_insert_iterator operator++(int) + { + return *this; + } + + protected: + PtrContainer* container; + typename PtrContainer::iterator iter; + }; + + template< class PtrContainer > + inline ptr_back_insert_iterator + ptr_back_inserter( PtrContainer& cont ) + { + return ptr_back_insert_iterator( cont ); + } + + template< class PtrContainer > + inline ptr_front_insert_iterator + ptr_front_inserter( PtrContainer& cont ) + { + return ptr_front_insert_iterator( cont ); + } + + template< class PtrContainer > + inline ptr_insert_iterator + ptr_inserter( PtrContainer& cont, + typename PtrContainer::iterator before ) + { + return ptr_insert_iterator( cont, before ); + } + +} // namespace 'ptr_container' +} // namespace 'boost' + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/ptr_map_adapter.hpp b/src/external/3rd/library/boost/boost/ptr_container/ptr_map_adapter.hpp index 9edc42927..d03dbcc95 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/ptr_map_adapter.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/ptr_map_adapter.hpp @@ -1,874 +1,874 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2003-2005. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - -#ifndef BOOST_PTR_CONTAINER_DETAIL_PTR_MAP_ADAPTER_HPP -#define BOOST_PTR_CONTAINER_DETAIL_PTR_MAP_ADAPTER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include -#include -#include -#include - -namespace boost -{ -namespace ptr_container_detail -{ - - template - < - class T, - class VoidPtrMap, - bool Ordered - > - struct map_config - { - typedef BOOST_DEDUCED_TYPENAME remove_nullable::type - U; - typedef VoidPtrMap - void_container_type; - - typedef BOOST_DEDUCED_TYPENAME VoidPtrMap::allocator_type - allocator_type; - - typedef BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - mpl::identity >::type - value_compare; - - typedef BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - mpl::identity >::type - key_compare; - - typedef BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_hasher >::type - hasher; - - typedef BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_key_equal >::type - key_equal; - - typedef BOOST_DEDUCED_TYPENAME - mpl::if_c::type - container_type; - - typedef BOOST_DEDUCED_TYPENAME VoidPtrMap::key_type - key_type; - - typedef U value_type; - - typedef ptr_map_iterator< BOOST_DEDUCED_TYPENAME VoidPtrMap::iterator, key_type, U* const > - iterator; - - typedef ptr_map_iterator< BOOST_DEDUCED_TYPENAME VoidPtrMap::const_iterator, key_type, const U* const> - const_iterator; - - typedef ptr_map_iterator< - BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_local_iterator >::type, - key_type, U* const > - local_iterator; - - typedef ptr_map_iterator< - BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_const_local_iterator >::type, - key_type, const U* const > - const_local_iterator; - - template< class Iter > - static U* get_pointer( Iter i ) - { - return i->second; - } - - template< class Iter > - static const U* get_const_pointer( Iter i ) - { - return i->second; - } - - BOOST_STATIC_CONSTANT( bool, allow_null = boost::is_nullable::value ); - }; - - - - template - < - class T, - class VoidPtrMap, - class CloneAllocator, - bool Ordered - > - class ptr_map_adapter_base : - public ptr_container_detail::associative_ptr_container< map_config, - CloneAllocator > - { - typedef ptr_container_detail::associative_ptr_container< map_config, - CloneAllocator > - base_type; - - typedef map_config config; - typedef ptr_map_adapter_base this_type; - - public: - - typedef BOOST_DEDUCED_TYPENAME base_type::allocator_type - allocator_type; - typedef BOOST_DEDUCED_TYPENAME base_type::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator - const_iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type - size_type; - typedef BOOST_DEDUCED_TYPENAME base_type::key_type - key_type; - typedef BOOST_DEDUCED_TYPENAME base_type::auto_type - auto_type; - typedef BOOST_DEDUCED_TYPENAME base_type::value_type - mapped_type; - typedef BOOST_DEDUCED_TYPENAME base_type::reference - mapped_reference; - typedef BOOST_DEDUCED_TYPENAME base_type::const_reference - const_mapped_reference; - typedef BOOST_DEDUCED_TYPENAME iterator_value::type - value_type; - typedef value_type - reference; - typedef BOOST_DEDUCED_TYPENAME iterator_value::type - const_reference; - typedef value_type - pointer; - typedef const_reference - const_pointer; - - private: - const_mapped_reference lookup( const key_type& key ) const - { - const_iterator i = this->find( key ); - if( i != this->end() ) - return *i->second; - else - BOOST_PTR_CONTAINER_THROW_EXCEPTION( true, bad_ptr_container_operation, - "'ptr_map/multimap::at()' could" - " not find key" ); - } - - struct eraser // scope guard - { - bool released_; - VoidPtrMap* m_; - const key_type& key_; - - eraser( VoidPtrMap* m, const key_type& key ) - : released_(false), m_(m), key_(key) - {} - - ~eraser() - { - if( !released_ ) - m_->erase(key_); - } - - void release() { released_ = true; } - - private: - eraser& operator=(const eraser&); - }; - - mapped_reference insert_lookup( const key_type& key ) - { - void*& ref = this->base()[key]; - if( ref ) - { - return *static_cast(ref); - } - else - { - eraser e(&this->base(),key); // nothrow - mapped_type res = new T(); // strong - ref = res; // nothrow - e.release(); // nothrow - return *res; - } - } - - public: - - ptr_map_adapter_base() - { } - - template< class SizeType > - explicit ptr_map_adapter_base( SizeType n, - ptr_container_detail::unordered_associative_container_tag tag ) - : base_type( n, tag ) - { } - - template< class Compare, class Allocator > - ptr_map_adapter_base( const Compare& comp, - const Allocator& a ) - : base_type( comp, a ) - { } - - template< class Hash, class Pred, class Allocator > - ptr_map_adapter_base( const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { } - - template< class InputIterator > - ptr_map_adapter_base( InputIterator first, InputIterator last ) - : base_type( first, last ) - { } - - template< class InputIterator, class Comp > - ptr_map_adapter_base( InputIterator first, InputIterator last, - const Comp& comp, - const allocator_type& a = allocator_type() ) - : base_type( first, last, comp, a ) - { } - - template< class InputIterator, class Hash, class Pred, class Allocator > - ptr_map_adapter_base( InputIterator first, InputIterator last, - const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( first, last, hash, pred, a ) - { } - - template< class PtrContainer > - explicit ptr_map_adapter_base( std::unique_ptr clone ) - : base_type( clone ) - { } - - template< typename PtrContainer > - ptr_map_adapter_base& operator=( std::unique_ptr clone ) - { - base_type::operator=( clone ); - return *this; - } - - iterator find( const key_type& x ) - { - return iterator( this->base().find( x ) ); - } - - const_iterator find( const key_type& x ) const - { - return const_iterator( this->base().find( x ) ); - } - - size_type count( const key_type& x ) const - { - return this->base().count( x ); - } - - iterator lower_bound( const key_type& x ) - { - return iterator( this->base().lower_bound( x ) ); - } - - const_iterator lower_bound( const key_type& x ) const - { - return const_iterator( this->base().lower_bound( x ) ); - } - - iterator upper_bound( const key_type& x ) - { - return iterator( this->base().upper_bound( x ) ); - } - - const_iterator upper_bound( const key_type& x ) const - { - return const_iterator( this->base().upper_bound( x ) ); - } - - iterator_range equal_range( const key_type& x ) - { - std::pair - p = this->base().equal_range( x ); - return make_iterator_range( iterator( p.first ), iterator( p.second ) ); - } - - iterator_range equal_range( const key_type& x ) const - { - std::pair - p = this->base().equal_range( x ); - return make_iterator_range( const_iterator( p.first ), - const_iterator( p.second ) ); - } - - mapped_reference at( const key_type& key ) - { - return const_cast( lookup( key ) ); - } - - const_mapped_reference at( const key_type& key ) const - { - return lookup( key ); - } - - mapped_reference operator[]( const key_type& key ) - { - return insert_lookup( key ); - } - - auto_type replace( iterator where, mapped_type x ) // strong - { - BOOST_ASSERT( where != this->end() ); - - this->enforce_null_policy( x, "Null pointer in 'replace()'" ); - - auto_type ptr( x ); - - BOOST_PTR_CONTAINER_THROW_EXCEPTION( this->empty(), - bad_ptr_container_operation, - "'replace()' on empty container" ); - - auto_type old( where->second ); // nothrow - where.base()->second = ptr.release(); // nothrow, commit - return boost::ptr_container::move( old ); - } - - template< class U > - auto_type replace( iterator where, std::unique_ptr x ) - { - return replace( where, x.release() ); - } - - protected: - size_type bucket( const key_type& key ) const - { - return this->base().bucket( key ); - } - }; - -} // ptr_container_detail - - ///////////////////////////////////////////////////////////////////////// - // ptr_map_adapter - ///////////////////////////////////////////////////////////////////////// - - template - < - class T, - class VoidPtrMap, - class CloneAllocator = heap_clone_allocator, - bool Ordered = true - > - class ptr_map_adapter : - public ptr_container_detail::ptr_map_adapter_base - { - typedef ptr_container_detail::ptr_map_adapter_base - base_type; - - public: - typedef BOOST_DEDUCED_TYPENAME base_type::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator - const_iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type - size_type; - typedef BOOST_DEDUCED_TYPENAME base_type::key_type - key_type; - typedef BOOST_DEDUCED_TYPENAME base_type::const_reference - const_reference; - typedef BOOST_DEDUCED_TYPENAME base_type::auto_type - auto_type; - typedef BOOST_DEDUCED_TYPENAME VoidPtrMap::allocator_type - allocator_type; - typedef BOOST_DEDUCED_TYPENAME base_type::mapped_type - mapped_type; - private: - - void safe_insert( const key_type& key, auto_type ptr ) // strong - { - std::pair - res = - this->base().insert( std::make_pair( key, ptr.get() ) ); // strong, commit - if( res.second ) // nothrow - ptr.release(); // nothrow - } - - template< class II > - void map_basic_clone_and_insert( II first, II last ) - { - while( first != last ) - { - if( this->find( first->first ) == this->end() ) - { - const_reference p = *first.base(); // nothrow - auto_type ptr( this->null_policy_allocate_clone( p.second ) ); - // strong - this->safe_insert( p.first, - boost::ptr_container::move( ptr ) ); - // strong, commit - } - ++first; - } - } - - public: - ptr_map_adapter( ) - { } - - template< class Comp > - explicit ptr_map_adapter( const Comp& comp, - const allocator_type& a ) - : base_type( comp, a ) { } - - template< class Hash, class Pred, class Allocator > - ptr_map_adapter( const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { } - - template< class InputIterator > - ptr_map_adapter( InputIterator first, InputIterator last ) - { - map_basic_clone_and_insert( first, last ); - } - - template< class InputIterator, class Comp > - ptr_map_adapter( InputIterator first, InputIterator last, - const Comp& comp, - const allocator_type& a = allocator_type() ) - : base_type( comp, a ) - { - map_basic_clone_and_insert( first, last ); - } - - template< class InputIterator, class Hash, class Pred, class Allocator > - ptr_map_adapter( InputIterator first, InputIterator last, - const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { - map_basic_clone_and_insert( first, last ); - } - - ptr_map_adapter( const ptr_map_adapter& r ) - { - map_basic_clone_and_insert( r.begin(), r.end() ); - } - - template< class Key, class U, class CA, bool b > - ptr_map_adapter( const ptr_map_adapter& r ) - { - map_basic_clone_and_insert( r.begin(), r.end() ); - } - - template< class U > - ptr_map_adapter( std::unique_ptr r ) : base_type( r ) - { } - - ptr_map_adapter& operator=( ptr_map_adapter r ) - { - this->swap( r ); - return *this; - } - - template< class U > - ptr_map_adapter& operator=( std::unique_ptr r ) - { - base_type::operator=( r ); - return *this; - } - - using base_type::release; - - template< typename InputIterator > - void insert( InputIterator first, InputIterator last ) // basic - { - map_basic_clone_and_insert( first, last ); - } - - template< class Range > - void insert( const Range& r ) - { - insert( boost::begin(r), boost::end(r) ); - } - - private: - std::pair insert_impl( const key_type& key, mapped_type x ) // strong - { - this->enforce_null_policy( x, "Null pointer in ptr_map_adapter::insert()" ); - auto_type ptr( x ); // nothrow - - std::pair - res = this->base().insert( std::make_pair( key, x ) ); // strong, commit - if( res.second ) // nothrow - ptr.release(); // nothrow - return std::make_pair( iterator( res.first ), res.second ); // nothrow - } - - iterator insert_impl( iterator before, const key_type& key, mapped_type x ) // strong - { - this->enforce_null_policy( x, - "Null pointer in 'ptr_map_adapter::insert()'" ); - auto_type ptr( x ); // nothrow - BOOST_DEDUCED_TYPENAME base_type::ptr_iterator - res = this->base().insert( before.base(), std::make_pair( key, x ) ); - // strong, commit - ptr.release(); // notrow - return iterator( res ); - } - - public: - - std::pair insert( key_type& key, mapped_type x ) - { - return insert_impl( key, x ); - } - - template< class U > - std::pair insert( const key_type& key, std::unique_ptr x ) - { - return insert_impl( key, x.release() ); - } - - template< class F, class S > - iterator insert( iterator before, ptr_container_detail::ref_pair p ) // strong - { - this->enforce_null_policy( p.second, - "Null pointer in 'ptr_map_adapter::insert()'" ); - - auto_type ptr( this->null_policy_allocate_clone( p.second ) ); - BOOST_DEDUCED_TYPENAME base_type::ptr_iterator - result = this->base().insert( before.base(), - std::make_pair(p.first,ptr.get()) ); // strong - if( ptr.get() == result->second ) - ptr.release(); - - return iterator( result ); - } - - iterator insert( iterator before, key_type& key, mapped_type x ) // strong - { - return insert_impl( before, key, x ); - } - - template< class U > - iterator insert( iterator before, const key_type& key, std::unique_ptr x ) // strong - { - return insert_impl( before, key, x.release() ); - } - - template< class PtrMapAdapter > - bool transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator object, - PtrMapAdapter& from ) // strong - { - return this->single_transfer( object, from ); - } - - template< class PtrMapAdapter > - size_type transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator first, - BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator last, - PtrMapAdapter& from ) // basic - { - return this->single_transfer( first, last, from ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class PtrMapAdapter, class Range > - BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, - BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator >, - size_type >::type - transfer( const Range& r, PtrMapAdapter& from ) // basic - { - return transfer( boost::begin(r), boost::end(r), from ); - } - -#endif - - template< class PtrMapAdapter > - size_type transfer( PtrMapAdapter& from ) // basic - { - return transfer( from.begin(), from.end(), from ); - } - }; - - ///////////////////////////////////////////////////////////////////////// - // ptr_multimap_adapter - ///////////////////////////////////////////////////////////////////////// - - template - < - class T, - class VoidPtrMultiMap, - class CloneAllocator = heap_clone_allocator, - bool Ordered = true - > - class ptr_multimap_adapter : - public ptr_container_detail::ptr_map_adapter_base - { - typedef ptr_container_detail::ptr_map_adapter_base - base_type; - - public: // typedefs - typedef BOOST_DEDUCED_TYPENAME base_type::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator - const_iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type - size_type; - typedef BOOST_DEDUCED_TYPENAME base_type::key_type - key_type; - typedef BOOST_DEDUCED_TYPENAME base_type::const_reference - const_reference; - typedef BOOST_DEDUCED_TYPENAME base_type::mapped_type - mapped_type; - typedef BOOST_DEDUCED_TYPENAME base_type::auto_type - auto_type; - typedef BOOST_DEDUCED_TYPENAME VoidPtrMultiMap::allocator_type - allocator_type; - private: - - void safe_insert( const key_type& key, auto_type ptr ) // strong - { - this->base().insert( - std::make_pair( key, ptr.get() ) ); // strong, commit - ptr.release(); // nothrow - } - - template< typename II > - void map_basic_clone_and_insert( II first, II last ) - { - while( first != last ) - { - const_reference pair = *first.base(); // nothrow - auto_type ptr( this->null_policy_allocate_clone( pair.second ) ); - // strong - safe_insert( pair.first, - boost::ptr_container::move( ptr ) ); - // strong, commit - ++first; - } - } - - public: - - ptr_multimap_adapter() - { } - - template< class SizeType > - ptr_multimap_adapter( SizeType n, - ptr_container_detail::unordered_associative_container_tag tag ) - : base_type( n, tag ) - { } - - template< class Comp > - explicit ptr_multimap_adapter( const Comp& comp, - const allocator_type& a ) - : base_type( comp, a ) { } - - template< class Hash, class Pred, class Allocator > - ptr_multimap_adapter( const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { } - - template< class InputIterator > - ptr_multimap_adapter( InputIterator first, InputIterator last ) - { - map_basic_clone_and_insert( first, last ); - } - - template< class InputIterator, class Comp > - ptr_multimap_adapter( InputIterator first, InputIterator last, - const Comp& comp, - const allocator_type& a ) - : base_type( comp, a ) - { - map_basic_clone_and_insert( first, last ); - } - - template< class InputIterator, class Hash, class Pred, class Allocator > - ptr_multimap_adapter( InputIterator first, InputIterator last, - const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { - map_basic_clone_and_insert( first, last ); - } - - ptr_multimap_adapter( const ptr_multimap_adapter& r ) - { - map_basic_clone_and_insert( r.begin(), r.end() ); - } - - template< class Key, class U, class CA, bool b > - ptr_multimap_adapter( const ptr_multimap_adapter& r ) - { - map_basic_clone_and_insert( r.begin(), r.end() ); - } - - template< class U > - explicit ptr_multimap_adapter( std::unique_ptr r ) : base_type( r ) - { } - - ptr_multimap_adapter& operator=( ptr_multimap_adapter r ) - { - this->swap( r ); - return *this; - } - - template< class U > - ptr_multimap_adapter& operator=( std::unique_ptr r ) - { - base_type::operator=( r ); - return *this; - } - - using base_type::release; - - private: - iterator insert_impl( const key_type& key, mapped_type x ) // strong - { - this->enforce_null_policy( x, - "Null pointer in 'ptr_multimap_adapter::insert()'" ); - auto_type ptr( x ); // nothrow - BOOST_DEDUCED_TYPENAME base_type::ptr_iterator - res = this->base().insert( std::make_pair( key, x ) ); - // strong, commit - ptr.release(); // notrow - return iterator( res ); - } - - iterator insert_impl( iterator before, const key_type& key, mapped_type x ) // strong - { - this->enforce_null_policy( x, - "Null pointer in 'ptr_multimap_adapter::insert()'" ); - auto_type ptr( x ); // nothrow - BOOST_DEDUCED_TYPENAME base_type::ptr_iterator - res = this->base().insert( before.base(), - std::make_pair( key, x ) ); - // strong, commit - ptr.release(); // notrow - return iterator( res ); - } - - public: - template< typename InputIterator > - void insert( InputIterator first, InputIterator last ) // basic - { - map_basic_clone_and_insert( first, last ); - } - - template< class Range > - void insert( const Range& r ) - { - insert( boost::begin(r), boost::end(r) ); - } - - iterator insert( key_type& key, mapped_type x ) // strong - { - return insert_impl( key, x ); - } - - template< class U > - iterator insert( const key_type& key, std::unique_ptr x ) - { - return insert_impl( key, x.release() ); - } - - template< class F, class S > - iterator insert( iterator before, ptr_container_detail::ref_pair p ) // strong - { - this->enforce_null_policy( p.second, - "Null pointer in 'ptr_multimap_adapter::insert()'" ); - iterator res = insert_impl( before, p.first, - this->null_policy_allocate_clone( p.second ) ); - return res; - } - - iterator insert( iterator before, key_type& key, mapped_type x ) // strong - { - return insert_impl( before, key, x ); - } - - template< class U > - iterator insert( iterator before, const key_type& key, std::unique_ptr x ) // strong - { - return insert_impl( before, key, x.release() ); - } - - template< class PtrMapAdapter > - void transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator object, - PtrMapAdapter& from ) // strong - { - this->multi_transfer( object, from ); - } - - template< class PtrMapAdapter > - size_type transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator first, - BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator last, - PtrMapAdapter& from ) // basic - { - return this->multi_transfer( first, last, from ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class PtrMapAdapter, class Range > - BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, - BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator >, - size_type >::type - transfer( const Range& r, PtrMapAdapter& from ) // basic - { - return transfer( boost::begin(r), boost::end(r), from ); - } - -#endif - template< class PtrMapAdapter > - void transfer( PtrMapAdapter& from ) // basic - { - transfer( from.begin(), from.end(), from ); - BOOST_ASSERT( from.empty() ); - } - - }; - - template< class I, class F, class S > - inline bool is_null( const ptr_map_iterator& i ) - { - return i->second == 0; - } - -} // namespace 'boost' - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2003-2005. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + +#ifndef BOOST_PTR_CONTAINER_DETAIL_PTR_MAP_ADAPTER_HPP +#define BOOST_PTR_CONTAINER_DETAIL_PTR_MAP_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include +#include + +namespace boost +{ +namespace ptr_container_detail +{ + + template + < + class T, + class VoidPtrMap, + bool Ordered + > + struct map_config + { + typedef BOOST_DEDUCED_TYPENAME remove_nullable::type + U; + typedef VoidPtrMap + void_container_type; + + typedef BOOST_DEDUCED_TYPENAME VoidPtrMap::allocator_type + allocator_type; + + typedef BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + mpl::identity >::type + value_compare; + + typedef BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + mpl::identity >::type + key_compare; + + typedef BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_hasher >::type + hasher; + + typedef BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_key_equal >::type + key_equal; + + typedef BOOST_DEDUCED_TYPENAME + mpl::if_c::type + container_type; + + typedef BOOST_DEDUCED_TYPENAME VoidPtrMap::key_type + key_type; + + typedef U value_type; + + typedef ptr_map_iterator< BOOST_DEDUCED_TYPENAME VoidPtrMap::iterator, key_type, U* const > + iterator; + + typedef ptr_map_iterator< BOOST_DEDUCED_TYPENAME VoidPtrMap::const_iterator, key_type, const U* const> + const_iterator; + + typedef ptr_map_iterator< + BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_local_iterator >::type, + key_type, U* const > + local_iterator; + + typedef ptr_map_iterator< + BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_const_local_iterator >::type, + key_type, const U* const > + const_local_iterator; + + template< class Iter > + static U* get_pointer( Iter i ) + { + return i->second; + } + + template< class Iter > + static const U* get_const_pointer( Iter i ) + { + return i->second; + } + + BOOST_STATIC_CONSTANT( bool, allow_null = boost::is_nullable::value ); + }; + + + + template + < + class T, + class VoidPtrMap, + class CloneAllocator, + bool Ordered + > + class ptr_map_adapter_base : + public ptr_container_detail::associative_ptr_container< map_config, + CloneAllocator > + { + typedef ptr_container_detail::associative_ptr_container< map_config, + CloneAllocator > + base_type; + + typedef map_config config; + typedef ptr_map_adapter_base this_type; + + public: + + typedef BOOST_DEDUCED_TYPENAME base_type::allocator_type + allocator_type; + typedef BOOST_DEDUCED_TYPENAME base_type::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator + const_iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type + size_type; + typedef BOOST_DEDUCED_TYPENAME base_type::key_type + key_type; + typedef BOOST_DEDUCED_TYPENAME base_type::auto_type + auto_type; + typedef BOOST_DEDUCED_TYPENAME base_type::value_type + mapped_type; + typedef BOOST_DEDUCED_TYPENAME base_type::reference + mapped_reference; + typedef BOOST_DEDUCED_TYPENAME base_type::const_reference + const_mapped_reference; + typedef BOOST_DEDUCED_TYPENAME iterator_value::type + value_type; + typedef value_type + reference; + typedef BOOST_DEDUCED_TYPENAME iterator_value::type + const_reference; + typedef value_type + pointer; + typedef const_reference + const_pointer; + + private: + const_mapped_reference lookup( const key_type& key ) const + { + const_iterator i = this->find( key ); + if( i != this->end() ) + return *i->second; + else + BOOST_PTR_CONTAINER_THROW_EXCEPTION( true, bad_ptr_container_operation, + "'ptr_map/multimap::at()' could" + " not find key" ); + } + + struct eraser // scope guard + { + bool released_; + VoidPtrMap* m_; + const key_type& key_; + + eraser( VoidPtrMap* m, const key_type& key ) + : released_(false), m_(m), key_(key) + {} + + ~eraser() + { + if( !released_ ) + m_->erase(key_); + } + + void release() { released_ = true; } + + private: + eraser& operator=(const eraser&); + }; + + mapped_reference insert_lookup( const key_type& key ) + { + void*& ref = this->base()[key]; + if( ref ) + { + return *static_cast(ref); + } + else + { + eraser e(&this->base(),key); // nothrow + mapped_type res = new T(); // strong + ref = res; // nothrow + e.release(); // nothrow + return *res; + } + } + + public: + + ptr_map_adapter_base() + { } + + template< class SizeType > + explicit ptr_map_adapter_base( SizeType n, + ptr_container_detail::unordered_associative_container_tag tag ) + : base_type( n, tag ) + { } + + template< class Compare, class Allocator > + ptr_map_adapter_base( const Compare& comp, + const Allocator& a ) + : base_type( comp, a ) + { } + + template< class Hash, class Pred, class Allocator > + ptr_map_adapter_base( const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { } + + template< class InputIterator > + ptr_map_adapter_base( InputIterator first, InputIterator last ) + : base_type( first, last ) + { } + + template< class InputIterator, class Comp > + ptr_map_adapter_base( InputIterator first, InputIterator last, + const Comp& comp, + const allocator_type& a = allocator_type() ) + : base_type( first, last, comp, a ) + { } + + template< class InputIterator, class Hash, class Pred, class Allocator > + ptr_map_adapter_base( InputIterator first, InputIterator last, + const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( first, last, hash, pred, a ) + { } + + template< class PtrContainer > + explicit ptr_map_adapter_base( std::unique_ptr clone ) + : base_type( clone ) + { } + + template< typename PtrContainer > + ptr_map_adapter_base& operator=( std::unique_ptr clone ) + { + base_type::operator=( clone ); + return *this; + } + + iterator find( const key_type& x ) + { + return iterator( this->base().find( x ) ); + } + + const_iterator find( const key_type& x ) const + { + return const_iterator( this->base().find( x ) ); + } + + size_type count( const key_type& x ) const + { + return this->base().count( x ); + } + + iterator lower_bound( const key_type& x ) + { + return iterator( this->base().lower_bound( x ) ); + } + + const_iterator lower_bound( const key_type& x ) const + { + return const_iterator( this->base().lower_bound( x ) ); + } + + iterator upper_bound( const key_type& x ) + { + return iterator( this->base().upper_bound( x ) ); + } + + const_iterator upper_bound( const key_type& x ) const + { + return const_iterator( this->base().upper_bound( x ) ); + } + + iterator_range equal_range( const key_type& x ) + { + std::pair + p = this->base().equal_range( x ); + return make_iterator_range( iterator( p.first ), iterator( p.second ) ); + } + + iterator_range equal_range( const key_type& x ) const + { + std::pair + p = this->base().equal_range( x ); + return make_iterator_range( const_iterator( p.first ), + const_iterator( p.second ) ); + } + + mapped_reference at( const key_type& key ) + { + return const_cast( lookup( key ) ); + } + + const_mapped_reference at( const key_type& key ) const + { + return lookup( key ); + } + + mapped_reference operator[]( const key_type& key ) + { + return insert_lookup( key ); + } + + auto_type replace( iterator where, mapped_type x ) // strong + { + BOOST_ASSERT( where != this->end() ); + + this->enforce_null_policy( x, "Null pointer in 'replace()'" ); + + auto_type ptr( x ); + + BOOST_PTR_CONTAINER_THROW_EXCEPTION( this->empty(), + bad_ptr_container_operation, + "'replace()' on empty container" ); + + auto_type old( where->second ); // nothrow + where.base()->second = ptr.release(); // nothrow, commit + return boost::ptr_container::move( old ); + } + + template< class U > + auto_type replace( iterator where, std::unique_ptr x ) + { + return replace( where, x.release() ); + } + + protected: + size_type bucket( const key_type& key ) const + { + return this->base().bucket( key ); + } + }; + +} // ptr_container_detail + + ///////////////////////////////////////////////////////////////////////// + // ptr_map_adapter + ///////////////////////////////////////////////////////////////////////// + + template + < + class T, + class VoidPtrMap, + class CloneAllocator = heap_clone_allocator, + bool Ordered = true + > + class ptr_map_adapter : + public ptr_container_detail::ptr_map_adapter_base + { + typedef ptr_container_detail::ptr_map_adapter_base + base_type; + + public: + typedef BOOST_DEDUCED_TYPENAME base_type::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator + const_iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type + size_type; + typedef BOOST_DEDUCED_TYPENAME base_type::key_type + key_type; + typedef BOOST_DEDUCED_TYPENAME base_type::const_reference + const_reference; + typedef BOOST_DEDUCED_TYPENAME base_type::auto_type + auto_type; + typedef BOOST_DEDUCED_TYPENAME VoidPtrMap::allocator_type + allocator_type; + typedef BOOST_DEDUCED_TYPENAME base_type::mapped_type + mapped_type; + private: + + void safe_insert( const key_type& key, auto_type ptr ) // strong + { + std::pair + res = + this->base().insert( std::make_pair( key, ptr.get() ) ); // strong, commit + if( res.second ) // nothrow + ptr.release(); // nothrow + } + + template< class II > + void map_basic_clone_and_insert( II first, II last ) + { + while( first != last ) + { + if( this->find( first->first ) == this->end() ) + { + const_reference p = *first.base(); // nothrow + auto_type ptr( this->null_policy_allocate_clone( p.second ) ); + // strong + this->safe_insert( p.first, + boost::ptr_container::move( ptr ) ); + // strong, commit + } + ++first; + } + } + + public: + ptr_map_adapter( ) + { } + + template< class Comp > + explicit ptr_map_adapter( const Comp& comp, + const allocator_type& a ) + : base_type( comp, a ) { } + + template< class Hash, class Pred, class Allocator > + ptr_map_adapter( const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { } + + template< class InputIterator > + ptr_map_adapter( InputIterator first, InputIterator last ) + { + map_basic_clone_and_insert( first, last ); + } + + template< class InputIterator, class Comp > + ptr_map_adapter( InputIterator first, InputIterator last, + const Comp& comp, + const allocator_type& a = allocator_type() ) + : base_type( comp, a ) + { + map_basic_clone_and_insert( first, last ); + } + + template< class InputIterator, class Hash, class Pred, class Allocator > + ptr_map_adapter( InputIterator first, InputIterator last, + const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { + map_basic_clone_and_insert( first, last ); + } + + ptr_map_adapter( const ptr_map_adapter& r ) + { + map_basic_clone_and_insert( r.begin(), r.end() ); + } + + template< class Key, class U, class CA, bool b > + ptr_map_adapter( const ptr_map_adapter& r ) + { + map_basic_clone_and_insert( r.begin(), r.end() ); + } + + template< class U > + ptr_map_adapter( std::unique_ptr r ) : base_type( r ) + { } + + ptr_map_adapter& operator=( ptr_map_adapter r ) + { + this->swap( r ); + return *this; + } + + template< class U > + ptr_map_adapter& operator=( std::unique_ptr r ) + { + base_type::operator=( r ); + return *this; + } + + using base_type::release; + + template< typename InputIterator > + void insert( InputIterator first, InputIterator last ) // basic + { + map_basic_clone_and_insert( first, last ); + } + + template< class Range > + void insert( const Range& r ) + { + insert( boost::begin(r), boost::end(r) ); + } + + private: + std::pair insert_impl( const key_type& key, mapped_type x ) // strong + { + this->enforce_null_policy( x, "Null pointer in ptr_map_adapter::insert()" ); + auto_type ptr( x ); // nothrow + + std::pair + res = this->base().insert( std::make_pair( key, x ) ); // strong, commit + if( res.second ) // nothrow + ptr.release(); // nothrow + return std::make_pair( iterator( res.first ), res.second ); // nothrow + } + + iterator insert_impl( iterator before, const key_type& key, mapped_type x ) // strong + { + this->enforce_null_policy( x, + "Null pointer in 'ptr_map_adapter::insert()'" ); + auto_type ptr( x ); // nothrow + BOOST_DEDUCED_TYPENAME base_type::ptr_iterator + res = this->base().insert( before.base(), std::make_pair( key, x ) ); + // strong, commit + ptr.release(); // notrow + return iterator( res ); + } + + public: + + std::pair insert( key_type& key, mapped_type x ) + { + return insert_impl( key, x ); + } + + template< class U > + std::pair insert( const key_type& key, std::unique_ptr x ) + { + return insert_impl( key, x.release() ); + } + + template< class F, class S > + iterator insert( iterator before, ptr_container_detail::ref_pair p ) // strong + { + this->enforce_null_policy( p.second, + "Null pointer in 'ptr_map_adapter::insert()'" ); + + auto_type ptr( this->null_policy_allocate_clone( p.second ) ); + BOOST_DEDUCED_TYPENAME base_type::ptr_iterator + result = this->base().insert( before.base(), + std::make_pair(p.first,ptr.get()) ); // strong + if( ptr.get() == result->second ) + ptr.release(); + + return iterator( result ); + } + + iterator insert( iterator before, key_type& key, mapped_type x ) // strong + { + return insert_impl( before, key, x ); + } + + template< class U > + iterator insert( iterator before, const key_type& key, std::unique_ptr x ) // strong + { + return insert_impl( before, key, x.release() ); + } + + template< class PtrMapAdapter > + bool transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator object, + PtrMapAdapter& from ) // strong + { + return this->single_transfer( object, from ); + } + + template< class PtrMapAdapter > + size_type transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator first, + BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator last, + PtrMapAdapter& from ) // basic + { + return this->single_transfer( first, last, from ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class PtrMapAdapter, class Range > + BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, + BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator >, + size_type >::type + transfer( const Range& r, PtrMapAdapter& from ) // basic + { + return transfer( boost::begin(r), boost::end(r), from ); + } + +#endif + + template< class PtrMapAdapter > + size_type transfer( PtrMapAdapter& from ) // basic + { + return transfer( from.begin(), from.end(), from ); + } + }; + + ///////////////////////////////////////////////////////////////////////// + // ptr_multimap_adapter + ///////////////////////////////////////////////////////////////////////// + + template + < + class T, + class VoidPtrMultiMap, + class CloneAllocator = heap_clone_allocator, + bool Ordered = true + > + class ptr_multimap_adapter : + public ptr_container_detail::ptr_map_adapter_base + { + typedef ptr_container_detail::ptr_map_adapter_base + base_type; + + public: // typedefs + typedef BOOST_DEDUCED_TYPENAME base_type::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator + const_iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type + size_type; + typedef BOOST_DEDUCED_TYPENAME base_type::key_type + key_type; + typedef BOOST_DEDUCED_TYPENAME base_type::const_reference + const_reference; + typedef BOOST_DEDUCED_TYPENAME base_type::mapped_type + mapped_type; + typedef BOOST_DEDUCED_TYPENAME base_type::auto_type + auto_type; + typedef BOOST_DEDUCED_TYPENAME VoidPtrMultiMap::allocator_type + allocator_type; + private: + + void safe_insert( const key_type& key, auto_type ptr ) // strong + { + this->base().insert( + std::make_pair( key, ptr.get() ) ); // strong, commit + ptr.release(); // nothrow + } + + template< typename II > + void map_basic_clone_and_insert( II first, II last ) + { + while( first != last ) + { + const_reference pair = *first.base(); // nothrow + auto_type ptr( this->null_policy_allocate_clone( pair.second ) ); + // strong + safe_insert( pair.first, + boost::ptr_container::move( ptr ) ); + // strong, commit + ++first; + } + } + + public: + + ptr_multimap_adapter() + { } + + template< class SizeType > + ptr_multimap_adapter( SizeType n, + ptr_container_detail::unordered_associative_container_tag tag ) + : base_type( n, tag ) + { } + + template< class Comp > + explicit ptr_multimap_adapter( const Comp& comp, + const allocator_type& a ) + : base_type( comp, a ) { } + + template< class Hash, class Pred, class Allocator > + ptr_multimap_adapter( const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { } + + template< class InputIterator > + ptr_multimap_adapter( InputIterator first, InputIterator last ) + { + map_basic_clone_and_insert( first, last ); + } + + template< class InputIterator, class Comp > + ptr_multimap_adapter( InputIterator first, InputIterator last, + const Comp& comp, + const allocator_type& a ) + : base_type( comp, a ) + { + map_basic_clone_and_insert( first, last ); + } + + template< class InputIterator, class Hash, class Pred, class Allocator > + ptr_multimap_adapter( InputIterator first, InputIterator last, + const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { + map_basic_clone_and_insert( first, last ); + } + + ptr_multimap_adapter( const ptr_multimap_adapter& r ) + { + map_basic_clone_and_insert( r.begin(), r.end() ); + } + + template< class Key, class U, class CA, bool b > + ptr_multimap_adapter( const ptr_multimap_adapter& r ) + { + map_basic_clone_and_insert( r.begin(), r.end() ); + } + + template< class U > + explicit ptr_multimap_adapter( std::unique_ptr r ) : base_type( r ) + { } + + ptr_multimap_adapter& operator=( ptr_multimap_adapter r ) + { + this->swap( r ); + return *this; + } + + template< class U > + ptr_multimap_adapter& operator=( std::unique_ptr r ) + { + base_type::operator=( r ); + return *this; + } + + using base_type::release; + + private: + iterator insert_impl( const key_type& key, mapped_type x ) // strong + { + this->enforce_null_policy( x, + "Null pointer in 'ptr_multimap_adapter::insert()'" ); + auto_type ptr( x ); // nothrow + BOOST_DEDUCED_TYPENAME base_type::ptr_iterator + res = this->base().insert( std::make_pair( key, x ) ); + // strong, commit + ptr.release(); // notrow + return iterator( res ); + } + + iterator insert_impl( iterator before, const key_type& key, mapped_type x ) // strong + { + this->enforce_null_policy( x, + "Null pointer in 'ptr_multimap_adapter::insert()'" ); + auto_type ptr( x ); // nothrow + BOOST_DEDUCED_TYPENAME base_type::ptr_iterator + res = this->base().insert( before.base(), + std::make_pair( key, x ) ); + // strong, commit + ptr.release(); // notrow + return iterator( res ); + } + + public: + template< typename InputIterator > + void insert( InputIterator first, InputIterator last ) // basic + { + map_basic_clone_and_insert( first, last ); + } + + template< class Range > + void insert( const Range& r ) + { + insert( boost::begin(r), boost::end(r) ); + } + + iterator insert( key_type& key, mapped_type x ) // strong + { + return insert_impl( key, x ); + } + + template< class U > + iterator insert( const key_type& key, std::unique_ptr x ) + { + return insert_impl( key, x.release() ); + } + + template< class F, class S > + iterator insert( iterator before, ptr_container_detail::ref_pair p ) // strong + { + this->enforce_null_policy( p.second, + "Null pointer in 'ptr_multimap_adapter::insert()'" ); + iterator res = insert_impl( before, p.first, + this->null_policy_allocate_clone( p.second ) ); + return res; + } + + iterator insert( iterator before, key_type& key, mapped_type x ) // strong + { + return insert_impl( before, key, x ); + } + + template< class U > + iterator insert( iterator before, const key_type& key, std::unique_ptr x ) // strong + { + return insert_impl( before, key, x.release() ); + } + + template< class PtrMapAdapter > + void transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator object, + PtrMapAdapter& from ) // strong + { + this->multi_transfer( object, from ); + } + + template< class PtrMapAdapter > + size_type transfer( BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator first, + BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator last, + PtrMapAdapter& from ) // basic + { + return this->multi_transfer( first, last, from ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class PtrMapAdapter, class Range > + BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, + BOOST_DEDUCED_TYPENAME PtrMapAdapter::iterator >, + size_type >::type + transfer( const Range& r, PtrMapAdapter& from ) // basic + { + return transfer( boost::begin(r), boost::end(r), from ); + } + +#endif + template< class PtrMapAdapter > + void transfer( PtrMapAdapter& from ) // basic + { + transfer( from.begin(), from.end(), from ); + BOOST_ASSERT( from.empty() ); + } + + }; + + template< class I, class F, class S > + inline bool is_null( const ptr_map_iterator& i ) + { + return i->second == 0; + } + +} // namespace 'boost' + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/ptr_sequence_adapter.hpp b/src/external/3rd/library/boost/boost/ptr_container/ptr_sequence_adapter.hpp index 1f78b8c45..8ec017e2c 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/ptr_sequence_adapter.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/ptr_sequence_adapter.hpp @@ -1,775 +1,775 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2003-2005. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - -#ifndef BOOST_PTR_CONTAINER_PTR_SEQUENCE_ADAPTER_HPP -#define BOOST_PTR_CONTAINER_PTR_SEQUENCE_ADAPTER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - - -#include -#include -#include -#include -#include - - -namespace boost -{ -namespace ptr_container_detail -{ - template - < - class T, - class VoidPtrSeq - > - struct sequence_config - { - typedef BOOST_DEDUCED_TYPENAME remove_nullable::type - U; - typedef VoidPtrSeq - void_container_type; - - typedef BOOST_DEDUCED_TYPENAME VoidPtrSeq::allocator_type - allocator_type; - - typedef U value_type; - - typedef void_ptr_iterator< - BOOST_DEDUCED_TYPENAME VoidPtrSeq::iterator, U > - iterator; - - typedef void_ptr_iterator< - BOOST_DEDUCED_TYPENAME VoidPtrSeq::const_iterator, const U > - const_iterator; - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) - - template< class Iter > - static U* get_pointer( Iter i ) - { - return static_cast( *i.base() ); - } - -#else - template< class Iter > - static U* get_pointer( void_ptr_iterator i ) - { - return static_cast( *i.base() ); - } - - template< class Iter > - static U* get_pointer( Iter i ) - { - return &*i; - } -#endif - -#if defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) - - template< class Iter > - static const U* get_const_pointer( Iter i ) - { - return static_cast( *i.base() ); - } - -#else // BOOST_NO_SFINAE - -#if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) - template< class Iter > - static const U* get_const_pointer( void_ptr_iterator i ) - { - return static_cast( *i.base() ); - } -#else // BOOST_WORKAROUND - template< class Iter > - static const U* get_const_pointer( void_ptr_iterator i ) - { - return static_cast( *i.base() ); - } -#endif // BOOST_WORKAROUND - - template< class Iter > - static const U* get_const_pointer( Iter i ) - { - return &*i; - } -#endif // BOOST_NO_SFINAE - - BOOST_STATIC_CONSTANT(bool, allow_null = boost::is_nullable::value ); - }; - -} // ptr_container_detail - - - template< class Iterator, class T > - inline bool is_null( void_ptr_iterator i ) - { - return *i.base() == 0; - } - - - - template - < - class T, - class VoidPtrSeq, - class CloneAllocator = heap_clone_allocator - > - class ptr_sequence_adapter : public - ptr_container_detail::reversible_ptr_container< ptr_container_detail::sequence_config, - CloneAllocator > - { - typedef ptr_container_detail::reversible_ptr_container< ptr_container_detail::sequence_config, - CloneAllocator > - base_type; - - typedef ptr_sequence_adapter - this_type; - - protected: - typedef BOOST_DEDUCED_TYPENAME base_type::scoped_deleter scoped_deleter; - - public: - typedef BOOST_DEDUCED_TYPENAME base_type::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME base_type::reference reference; - typedef BOOST_DEDUCED_TYPENAME base_type::const_reference - const_reference; - typedef BOOST_DEDUCED_TYPENAME base_type::auto_type auto_type; - typedef BOOST_DEDUCED_TYPENAME base_type::clone_allocator_type - clone_allocator_type; - typedef BOOST_DEDUCED_TYPENAME base_type::iterator iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type size_type; - typedef BOOST_DEDUCED_TYPENAME base_type::allocator_type - allocator_type; - - ptr_sequence_adapter() - { } - - template< class Allocator > - explicit ptr_sequence_adapter( const Allocator& a ) - : base_type( a ) - { } - - template< class SizeType > - ptr_sequence_adapter( SizeType n, - ptr_container_detail::fixed_length_sequence_tag tag ) - : base_type( n, tag ) - { } - - template< class SizeType, class Allocator > - ptr_sequence_adapter( SizeType n, const Allocator& a, - ptr_container_detail::fixed_length_sequence_tag tag ) - : base_type( n, a, tag ) - { } - - template< class InputIterator > - ptr_sequence_adapter( InputIterator first, InputIterator last ) - : base_type( first, last ) - { } - - template< class InputIterator, class Allocator > - ptr_sequence_adapter( InputIterator first, InputIterator last, - const Allocator& a ) - : base_type( first, last, a ) - { } - - template< class ForwardIterator > - ptr_sequence_adapter( ForwardIterator first, - ForwardIterator last, - ptr_container_detail::fixed_length_sequence_tag tag ) - : base_type( first, last, tag ) - { } - - template< class SizeType, class ForwardIterator > - ptr_sequence_adapter( SizeType n, - ForwardIterator first, - ForwardIterator last, - ptr_container_detail::fixed_length_sequence_tag tag ) - : base_type( n, first, last, tag ) - { } - - ptr_sequence_adapter( const ptr_sequence_adapter& r ) - : base_type( r ) - { } - - template< class U > - ptr_sequence_adapter( const ptr_sequence_adapter& r ) - : base_type( r ) - { } - - ptr_sequence_adapter( const ptr_sequence_adapter& r, - ptr_container_detail::fixed_length_sequence_tag tag ) - : base_type( r, tag ) - { } - - template< class U > - ptr_sequence_adapter( const ptr_sequence_adapter& r, - ptr_container_detail::fixed_length_sequence_tag tag ) - : base_type( r, tag ) - { } - - template< class PtrContainer > - explicit ptr_sequence_adapter( std::unique_ptr clone ) - : base_type( clone ) - { } - - ptr_sequence_adapter& operator=( const ptr_sequence_adapter r ) - { - this->swap( r ); - return *this; - } - - template< class PtrContainer > - ptr_sequence_adapter& operator=( std::unique_ptr clone ) - { - base_type::operator=( clone ); - return *this; - } - - ///////////////////////////////////////////////////////////// - // modifiers - ///////////////////////////////////////////////////////////// - - void push_back( value_type x ) // strong - { - this->enforce_null_policy( x, "Null pointer in 'push_back()'" ); - - auto_type ptr( x ); // notrow - this->base().push_back( x ); // strong, commit - ptr.release(); // nothrow - } - - template< class U > - void push_back( std::unique_ptr x ) - { - push_back( x.release() ); - } - - void push_front( value_type x ) - { - this->enforce_null_policy( x, "Null pointer in 'push_front()'" ); - - auto_type ptr( x ); // nothrow - this->base().push_front( x ); // strong, commit - ptr.release(); // nothrow - } - - template< class U > - void push_front( std::unique_ptr x ) - { - push_front( x.release() ); - } - - auto_type pop_back() - { - BOOST_ASSERT( !this->empty() && - "'pop_back()' on empty container" ); - auto_type ptr( static_cast( this->base().back() ) ); - // nothrow - this->base().pop_back(); // nothrow - return ptr_container_detail::move( ptr ); // nothrow - } - - auto_type pop_front() - { - BOOST_ASSERT( !this->empty() && - "'pop_front()' on empty container" ); - auto_type ptr( static_cast( this->base().front() ) ); - // nothrow - this->base().pop_front(); // nothrow - return ptr_container_detail::move( ptr ); - } - - reference front() - { - BOOST_ASSERT( !this->empty() && - "accessing 'front()' on empty container" ); - - BOOST_ASSERT( !::boost::is_null( this->begin() ) ); - return *this->begin(); - } - - const_reference front() const - { - return const_cast(this)->front(); - } - - reference back() - { - BOOST_ASSERT( !this->empty() && - "accessing 'back()' on empty container" ); - BOOST_ASSERT( !::boost::is_null( --this->end() ) ); - return *--this->end(); - } - - const_reference back() const - { - return const_cast(this)->back(); - } - - public: // deque/vector inerface - - reference operator[]( size_type n ) // nothrow - { - BOOST_ASSERT( n < this->size() ); - BOOST_ASSERT( !this->is_null( n ) ); - return *static_cast( this->base()[n] ); - } - - const_reference operator[]( size_type n ) const // nothrow - { - BOOST_ASSERT( n < this->size() ); - BOOST_ASSERT( !this->is_null( n ) ); - return *static_cast( this->base()[n] ); - } - - reference at( size_type n ) - { - BOOST_PTR_CONTAINER_THROW_EXCEPTION( n >= this->size(), bad_index, - "'at()' out of bounds" ); - BOOST_ASSERT( !this->is_null( n ) ); - return (*this)[n]; - } - - const_reference at( size_type n ) const - { - BOOST_PTR_CONTAINER_THROW_EXCEPTION( n >= this->size(), bad_index, - "'at()' out of bounds" ); - BOOST_ASSERT( !this->is_null( n ) ); - return (*this)[n]; - } - - public: // vector interface - - size_type capacity() const - { - return this->base().capacity(); - } - - void reserve( size_type n ) - { - this->base().reserve( n ); - } - - void reverse() - { - this->base().reverse(); - } - - public: // assign, insert, transfer - - // overhead: 1 heap allocation (very cheap compared to cloning) - template< class InputIterator > - void assign( InputIterator first, InputIterator last ) // strong - { - base_type temp( first, last ); - this->swap( temp ); - } - - template< class Range > - void assign( const Range& r ) // strong - { - assign( boost::begin(r), boost::end(r ) ); - } - - private: - template< class I > - void insert_impl( iterator before, I first, I last, std::input_iterator_tag ) // strong - { - ptr_sequence_adapter temp(first,last); // strong - transfer( before, temp ); // strong, commit - } - - template< class I > - void insert_impl( iterator before, I first, I last, std::forward_iterator_tag ) // strong - { - if( first == last ) - return; - scoped_deleter sd( first, last ); // strong - this->insert_clones_and_release( sd, before ); // strong, commit - } - - public: - - using base_type::insert; - - template< class InputIterator > - void insert( iterator before, InputIterator first, InputIterator last ) // strong - { - insert_impl( before, first, last, BOOST_DEDUCED_TYPENAME - iterator_category::type() ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - template< class Range > - BOOST_DEDUCED_TYPENAME - boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type - insert( iterator before, const Range& r ) - { - insert( before, boost::begin(r), boost::end(r) ); - } - -#endif - - template< class PtrSeqAdapter > - void transfer( iterator before, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator first, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator last, - PtrSeqAdapter& from ) // strong - { - BOOST_ASSERT( (void*)&from != (void*)this ); - if( from.empty() ) - return; - this->base(). - insert( before.base(), first.base(), last.base() ); // strong - from.base().erase( first.base(), last.base() ); // nothrow - } - - template< class PtrSeqAdapter > - void transfer( iterator before, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator object, - PtrSeqAdapter& from ) // strong - { - BOOST_ASSERT( (void*)&from != (void*)this ); - if( from.empty() ) - return; - this->base().insert( before.base(), *object.base() ); // strong - from.base().erase( object.base() ); // nothrow - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class PtrSeqAdapter, class Range > - BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, - BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator > >::type - transfer( iterator before, const Range& r, PtrSeqAdapter& from ) // strong - { - transfer( before, boost::begin(r), boost::end(r), from ); - } - -#endif - template< class PtrSeqAdapter > - void transfer( iterator before, PtrSeqAdapter& from ) // strong - { - BOOST_ASSERT( (void*)&from != (void*)this ); - if( from.empty() ) - return; - this->base(). - insert( before.base(), - from.begin().base(), from.end().base() ); // strong - from.base().clear(); // nothrow - } - - public: // C-array support - - void transfer( iterator before, value_type* from, - size_type size, bool delete_from = true ) // strong - { - BOOST_ASSERT( from != 0 ); - if( delete_from ) - { - BOOST_DEDUCED_TYPENAME base_type::scoped_deleter - deleter( from, size ); // nothrow - this->base().insert( before.base(), from, from + size ); // strong - deleter.release(); // nothrow - } - else - { - this->base().insert( before.base(), from, from + size ); // strong - } - } - - value_type* c_array() // nothrow - { - if( this->empty() ) - return 0; - T** res = reinterpret_cast( &this->begin().base()[0] ); - return res; - } - - public: // null functions - - bool is_null( size_type idx ) const - { - BOOST_ASSERT( idx < this->size() ); - return this->base()[idx] == 0; - } - - public: // resize - - void resize( size_type size ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( boost::next( this->begin(), size ), this->end() ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_back( new BOOST_DEDUCED_TYPENAME - boost::remove_pointer::type() ); - } - - BOOST_ASSERT( this->size() == size ); - } - - void resize( size_type size, value_type to_clone ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( boost::next( this->begin(), size ), this->end() ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_back( this->null_policy_allocate_clone( to_clone ) ); - } - - BOOST_ASSERT( this->size() == size ); - } - - void rresize( size_type size ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( this->begin(), - boost::next( this->begin(), old_size - size ) ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_front( new BOOST_DEDUCED_TYPENAME - boost::remove_pointer::type() ); - } - - BOOST_ASSERT( this->size() == size ); - } - - void rresize( size_type size, value_type to_clone ) // basic - { - size_type old_size = this->size(); - if( old_size > size ) - { - this->erase( this->begin(), - boost::next( this->begin(), old_size - size ) ); - } - else if( size > old_size ) - { - for( ; old_size != size; ++old_size ) - this->push_front( this->null_policy_allocate_clone( to_clone ) ); - } - - BOOST_ASSERT( this->size() == size ); - } - - public: // algorithms - - void sort( iterator first, iterator last ) - { - sort( first, last, std::less() ); - } - - void sort() - { - sort( this->begin(), this->end() ); - } - - template< class Compare > - void sort( iterator first, iterator last, Compare comp ) - { - BOOST_ASSERT( first <= last && "out of range sort()" ); - BOOST_ASSERT( this->begin() <= first && "out of range sort()" ); - BOOST_ASSERT( last <= this->end() && "out of range sort()" ); - // some static assert on the arguments of the comparison - std::sort( first.base(), last.base(), - void_ptr_indirect_fun(comp) ); - } - - template< class Compare > - void sort( Compare comp ) - { - sort( this->begin(), this->end(), comp ); - } - - void unique( iterator first, iterator last ) - { - unique( first, last, std::equal_to() ); - } - - void unique() - { - unique( this->begin(), this->end() ); - } - - private: - struct is_not_zero_ptr - { - template< class U > - bool operator()( const U* r ) const - { - return r != 0; - } - }; - - protected: - template< class Fun, class Arg1 > - class void_ptr_delete_if - { - Fun fun; - public: - - void_ptr_delete_if() : fun(Fun()) - { } - - void_ptr_delete_if( Fun f ) : fun(f) - { } - - bool operator()( void* r ) const - { - BOOST_ASSERT( r != 0 ); - Arg1 arg1 = static_cast(r); - if( fun( *arg1 ) ) - { - clone_allocator_type::deallocate_clone( arg1 ); - return true; - } - return false; - } - }; - - private: - void compact_and_erase_nulls( iterator first, iterator last ) // nothrow - { - typename base_type::ptr_iterator p = std::stable_partition( - first.base(), - last.base(), - is_not_zero_ptr() ); - this->base().erase( p, this->end().base() ); - - } - - void range_check_impl( iterator first, iterator last, - std::bidirectional_iterator_tag ) - { /* do nothing */ } - - void range_check_impl( iterator first, iterator last, - std::random_access_iterator_tag ) - { - BOOST_ASSERT( first <= last && "out of range unique()/erase_if()" ); - BOOST_ASSERT( this->begin() <= first && "out of range unique()/erase_if()" ); - BOOST_ASSERT( last <= this->end() && "out of range unique()/erase_if)(" ); - } - - void range_check( iterator first, iterator last ) - { - range_check_impl( first, last, - BOOST_DEDUCED_TYPENAME iterator_category::type() ); - } - - public: - - template< class Compare > - void unique( iterator first, iterator last, Compare comp ) - { - range_check(first,last); - - iterator prev = first; - iterator next = first; - ++next; - for( ; next != last; ++next ) - { - BOOST_ASSERT( !::boost::is_null(prev) ); - BOOST_ASSERT( !::boost::is_null(next) ); - if( comp( *prev, *next ) ) - { - this->remove( next ); // delete object - *next.base() = 0; // mark pointer as deleted - } - else - { - prev = next; - } - // ++next - } - - compact_and_erase_nulls( first, last ); - } - - template< class Compare > - void unique( Compare comp ) - { - unique( this->begin(), this->end(), comp ); - } - - template< class Pred > - void erase_if( iterator first, iterator last, Pred pred ) - { - range_check(first,last); - this->base().erase( std::remove_if( first.base(), last.base(), - void_ptr_delete_if(pred) ), - last.base() ); - } - - template< class Pred > - void erase_if( Pred pred ) - { - erase_if( this->begin(), this->end(), pred ); - } - - - void merge( iterator first, iterator last, - ptr_sequence_adapter& from ) - { - merge( first, last, from, std::less() ); - } - - template< class BinPred > - void merge( iterator first, iterator last, - ptr_sequence_adapter& from, BinPred pred ) - { - void_ptr_indirect_fun bin_pred(pred); - size_type current_size = this->size(); - this->transfer( this->end(), first, last, from ); - typename base_type::ptr_iterator middle = this->begin().base(); - std::advance(middle,current_size); - std::inplace_merge( this->begin().base(), - middle, - this->end().base(), - bin_pred ); - } - - void merge( ptr_sequence_adapter& r ) - { - merge( r, std::less() ); - BOOST_ASSERT( r.empty() ); - } - - template< class BinPred > - void merge( ptr_sequence_adapter& r, BinPred pred ) - { - merge( r.begin(), r.end(), r, pred ); - BOOST_ASSERT( r.empty() ); - } - - }; - - -} // namespace 'boost' - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2003-2005. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + +#ifndef BOOST_PTR_CONTAINER_PTR_SEQUENCE_ADAPTER_HPP +#define BOOST_PTR_CONTAINER_PTR_SEQUENCE_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + + +#include +#include +#include +#include +#include + + +namespace boost +{ +namespace ptr_container_detail +{ + template + < + class T, + class VoidPtrSeq + > + struct sequence_config + { + typedef BOOST_DEDUCED_TYPENAME remove_nullable::type + U; + typedef VoidPtrSeq + void_container_type; + + typedef BOOST_DEDUCED_TYPENAME VoidPtrSeq::allocator_type + allocator_type; + + typedef U value_type; + + typedef void_ptr_iterator< + BOOST_DEDUCED_TYPENAME VoidPtrSeq::iterator, U > + iterator; + + typedef void_ptr_iterator< + BOOST_DEDUCED_TYPENAME VoidPtrSeq::const_iterator, const U > + const_iterator; + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + + template< class Iter > + static U* get_pointer( Iter i ) + { + return static_cast( *i.base() ); + } + +#else + template< class Iter > + static U* get_pointer( void_ptr_iterator i ) + { + return static_cast( *i.base() ); + } + + template< class Iter > + static U* get_pointer( Iter i ) + { + return &*i; + } +#endif + +#if defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__MWERKS__, <= 0x3003) + + template< class Iter > + static const U* get_const_pointer( Iter i ) + { + return static_cast( *i.base() ); + } + +#else // BOOST_NO_SFINAE + +#if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) + template< class Iter > + static const U* get_const_pointer( void_ptr_iterator i ) + { + return static_cast( *i.base() ); + } +#else // BOOST_WORKAROUND + template< class Iter > + static const U* get_const_pointer( void_ptr_iterator i ) + { + return static_cast( *i.base() ); + } +#endif // BOOST_WORKAROUND + + template< class Iter > + static const U* get_const_pointer( Iter i ) + { + return &*i; + } +#endif // BOOST_NO_SFINAE + + BOOST_STATIC_CONSTANT(bool, allow_null = boost::is_nullable::value ); + }; + +} // ptr_container_detail + + + template< class Iterator, class T > + inline bool is_null( void_ptr_iterator i ) + { + return *i.base() == 0; + } + + + + template + < + class T, + class VoidPtrSeq, + class CloneAllocator = heap_clone_allocator + > + class ptr_sequence_adapter : public + ptr_container_detail::reversible_ptr_container< ptr_container_detail::sequence_config, + CloneAllocator > + { + typedef ptr_container_detail::reversible_ptr_container< ptr_container_detail::sequence_config, + CloneAllocator > + base_type; + + typedef ptr_sequence_adapter + this_type; + + protected: + typedef BOOST_DEDUCED_TYPENAME base_type::scoped_deleter scoped_deleter; + + public: + typedef BOOST_DEDUCED_TYPENAME base_type::value_type value_type; + typedef BOOST_DEDUCED_TYPENAME base_type::reference reference; + typedef BOOST_DEDUCED_TYPENAME base_type::const_reference + const_reference; + typedef BOOST_DEDUCED_TYPENAME base_type::auto_type auto_type; + typedef BOOST_DEDUCED_TYPENAME base_type::clone_allocator_type + clone_allocator_type; + typedef BOOST_DEDUCED_TYPENAME base_type::iterator iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type size_type; + typedef BOOST_DEDUCED_TYPENAME base_type::allocator_type + allocator_type; + + ptr_sequence_adapter() + { } + + template< class Allocator > + explicit ptr_sequence_adapter( const Allocator& a ) + : base_type( a ) + { } + + template< class SizeType > + ptr_sequence_adapter( SizeType n, + ptr_container_detail::fixed_length_sequence_tag tag ) + : base_type( n, tag ) + { } + + template< class SizeType, class Allocator > + ptr_sequence_adapter( SizeType n, const Allocator& a, + ptr_container_detail::fixed_length_sequence_tag tag ) + : base_type( n, a, tag ) + { } + + template< class InputIterator > + ptr_sequence_adapter( InputIterator first, InputIterator last ) + : base_type( first, last ) + { } + + template< class InputIterator, class Allocator > + ptr_sequence_adapter( InputIterator first, InputIterator last, + const Allocator& a ) + : base_type( first, last, a ) + { } + + template< class ForwardIterator > + ptr_sequence_adapter( ForwardIterator first, + ForwardIterator last, + ptr_container_detail::fixed_length_sequence_tag tag ) + : base_type( first, last, tag ) + { } + + template< class SizeType, class ForwardIterator > + ptr_sequence_adapter( SizeType n, + ForwardIterator first, + ForwardIterator last, + ptr_container_detail::fixed_length_sequence_tag tag ) + : base_type( n, first, last, tag ) + { } + + ptr_sequence_adapter( const ptr_sequence_adapter& r ) + : base_type( r ) + { } + + template< class U > + ptr_sequence_adapter( const ptr_sequence_adapter& r ) + : base_type( r ) + { } + + ptr_sequence_adapter( const ptr_sequence_adapter& r, + ptr_container_detail::fixed_length_sequence_tag tag ) + : base_type( r, tag ) + { } + + template< class U > + ptr_sequence_adapter( const ptr_sequence_adapter& r, + ptr_container_detail::fixed_length_sequence_tag tag ) + : base_type( r, tag ) + { } + + template< class PtrContainer > + explicit ptr_sequence_adapter( std::unique_ptr clone ) + : base_type( clone ) + { } + + ptr_sequence_adapter& operator=( const ptr_sequence_adapter r ) + { + this->swap( r ); + return *this; + } + + template< class PtrContainer > + ptr_sequence_adapter& operator=( std::unique_ptr clone ) + { + base_type::operator=( clone ); + return *this; + } + + ///////////////////////////////////////////////////////////// + // modifiers + ///////////////////////////////////////////////////////////// + + void push_back( value_type x ) // strong + { + this->enforce_null_policy( x, "Null pointer in 'push_back()'" ); + + auto_type ptr( x ); // notrow + this->base().push_back( x ); // strong, commit + ptr.release(); // nothrow + } + + template< class U > + void push_back( std::unique_ptr x ) + { + push_back( x.release() ); + } + + void push_front( value_type x ) + { + this->enforce_null_policy( x, "Null pointer in 'push_front()'" ); + + auto_type ptr( x ); // nothrow + this->base().push_front( x ); // strong, commit + ptr.release(); // nothrow + } + + template< class U > + void push_front( std::unique_ptr x ) + { + push_front( x.release() ); + } + + auto_type pop_back() + { + BOOST_ASSERT( !this->empty() && + "'pop_back()' on empty container" ); + auto_type ptr( static_cast( this->base().back() ) ); + // nothrow + this->base().pop_back(); // nothrow + return ptr_container_detail::move( ptr ); // nothrow + } + + auto_type pop_front() + { + BOOST_ASSERT( !this->empty() && + "'pop_front()' on empty container" ); + auto_type ptr( static_cast( this->base().front() ) ); + // nothrow + this->base().pop_front(); // nothrow + return ptr_container_detail::move( ptr ); + } + + reference front() + { + BOOST_ASSERT( !this->empty() && + "accessing 'front()' on empty container" ); + + BOOST_ASSERT( !::boost::is_null( this->begin() ) ); + return *this->begin(); + } + + const_reference front() const + { + return const_cast(this)->front(); + } + + reference back() + { + BOOST_ASSERT( !this->empty() && + "accessing 'back()' on empty container" ); + BOOST_ASSERT( !::boost::is_null( --this->end() ) ); + return *--this->end(); + } + + const_reference back() const + { + return const_cast(this)->back(); + } + + public: // deque/vector inerface + + reference operator[]( size_type n ) // nothrow + { + BOOST_ASSERT( n < this->size() ); + BOOST_ASSERT( !this->is_null( n ) ); + return *static_cast( this->base()[n] ); + } + + const_reference operator[]( size_type n ) const // nothrow + { + BOOST_ASSERT( n < this->size() ); + BOOST_ASSERT( !this->is_null( n ) ); + return *static_cast( this->base()[n] ); + } + + reference at( size_type n ) + { + BOOST_PTR_CONTAINER_THROW_EXCEPTION( n >= this->size(), bad_index, + "'at()' out of bounds" ); + BOOST_ASSERT( !this->is_null( n ) ); + return (*this)[n]; + } + + const_reference at( size_type n ) const + { + BOOST_PTR_CONTAINER_THROW_EXCEPTION( n >= this->size(), bad_index, + "'at()' out of bounds" ); + BOOST_ASSERT( !this->is_null( n ) ); + return (*this)[n]; + } + + public: // vector interface + + size_type capacity() const + { + return this->base().capacity(); + } + + void reserve( size_type n ) + { + this->base().reserve( n ); + } + + void reverse() + { + this->base().reverse(); + } + + public: // assign, insert, transfer + + // overhead: 1 heap allocation (very cheap compared to cloning) + template< class InputIterator > + void assign( InputIterator first, InputIterator last ) // strong + { + base_type temp( first, last ); + this->swap( temp ); + } + + template< class Range > + void assign( const Range& r ) // strong + { + assign( boost::begin(r), boost::end(r ) ); + } + + private: + template< class I > + void insert_impl( iterator before, I first, I last, std::input_iterator_tag ) // strong + { + ptr_sequence_adapter temp(first,last); // strong + transfer( before, temp ); // strong, commit + } + + template< class I > + void insert_impl( iterator before, I first, I last, std::forward_iterator_tag ) // strong + { + if( first == last ) + return; + scoped_deleter sd( first, last ); // strong + this->insert_clones_and_release( sd, before ); // strong, commit + } + + public: + + using base_type::insert; + + template< class InputIterator > + void insert( iterator before, InputIterator first, InputIterator last ) // strong + { + insert_impl( before, first, last, BOOST_DEDUCED_TYPENAME + iterator_category::type() ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + template< class Range > + BOOST_DEDUCED_TYPENAME + boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type + insert( iterator before, const Range& r ) + { + insert( before, boost::begin(r), boost::end(r) ); + } + +#endif + + template< class PtrSeqAdapter > + void transfer( iterator before, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator first, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator last, + PtrSeqAdapter& from ) // strong + { + BOOST_ASSERT( (void*)&from != (void*)this ); + if( from.empty() ) + return; + this->base(). + insert( before.base(), first.base(), last.base() ); // strong + from.base().erase( first.base(), last.base() ); // nothrow + } + + template< class PtrSeqAdapter > + void transfer( iterator before, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator object, + PtrSeqAdapter& from ) // strong + { + BOOST_ASSERT( (void*)&from != (void*)this ); + if( from.empty() ) + return; + this->base().insert( before.base(), *object.base() ); // strong + from.base().erase( object.base() ); // nothrow + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class PtrSeqAdapter, class Range > + BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, + BOOST_DEDUCED_TYPENAME PtrSeqAdapter::iterator > >::type + transfer( iterator before, const Range& r, PtrSeqAdapter& from ) // strong + { + transfer( before, boost::begin(r), boost::end(r), from ); + } + +#endif + template< class PtrSeqAdapter > + void transfer( iterator before, PtrSeqAdapter& from ) // strong + { + BOOST_ASSERT( (void*)&from != (void*)this ); + if( from.empty() ) + return; + this->base(). + insert( before.base(), + from.begin().base(), from.end().base() ); // strong + from.base().clear(); // nothrow + } + + public: // C-array support + + void transfer( iterator before, value_type* from, + size_type size, bool delete_from = true ) // strong + { + BOOST_ASSERT( from != 0 ); + if( delete_from ) + { + BOOST_DEDUCED_TYPENAME base_type::scoped_deleter + deleter( from, size ); // nothrow + this->base().insert( before.base(), from, from + size ); // strong + deleter.release(); // nothrow + } + else + { + this->base().insert( before.base(), from, from + size ); // strong + } + } + + value_type* c_array() // nothrow + { + if( this->empty() ) + return 0; + T** res = reinterpret_cast( &this->begin().base()[0] ); + return res; + } + + public: // null functions + + bool is_null( size_type idx ) const + { + BOOST_ASSERT( idx < this->size() ); + return this->base()[idx] == 0; + } + + public: // resize + + void resize( size_type size ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( boost::next( this->begin(), size ), this->end() ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_back( new BOOST_DEDUCED_TYPENAME + boost::remove_pointer::type() ); + } + + BOOST_ASSERT( this->size() == size ); + } + + void resize( size_type size, value_type to_clone ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( boost::next( this->begin(), size ), this->end() ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_back( this->null_policy_allocate_clone( to_clone ) ); + } + + BOOST_ASSERT( this->size() == size ); + } + + void rresize( size_type size ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( this->begin(), + boost::next( this->begin(), old_size - size ) ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_front( new BOOST_DEDUCED_TYPENAME + boost::remove_pointer::type() ); + } + + BOOST_ASSERT( this->size() == size ); + } + + void rresize( size_type size, value_type to_clone ) // basic + { + size_type old_size = this->size(); + if( old_size > size ) + { + this->erase( this->begin(), + boost::next( this->begin(), old_size - size ) ); + } + else if( size > old_size ) + { + for( ; old_size != size; ++old_size ) + this->push_front( this->null_policy_allocate_clone( to_clone ) ); + } + + BOOST_ASSERT( this->size() == size ); + } + + public: // algorithms + + void sort( iterator first, iterator last ) + { + sort( first, last, std::less() ); + } + + void sort() + { + sort( this->begin(), this->end() ); + } + + template< class Compare > + void sort( iterator first, iterator last, Compare comp ) + { + BOOST_ASSERT( first <= last && "out of range sort()" ); + BOOST_ASSERT( this->begin() <= first && "out of range sort()" ); + BOOST_ASSERT( last <= this->end() && "out of range sort()" ); + // some static assert on the arguments of the comparison + std::sort( first.base(), last.base(), + void_ptr_indirect_fun(comp) ); + } + + template< class Compare > + void sort( Compare comp ) + { + sort( this->begin(), this->end(), comp ); + } + + void unique( iterator first, iterator last ) + { + unique( first, last, std::equal_to() ); + } + + void unique() + { + unique( this->begin(), this->end() ); + } + + private: + struct is_not_zero_ptr + { + template< class U > + bool operator()( const U* r ) const + { + return r != 0; + } + }; + + protected: + template< class Fun, class Arg1 > + class void_ptr_delete_if + { + Fun fun; + public: + + void_ptr_delete_if() : fun(Fun()) + { } + + void_ptr_delete_if( Fun f ) : fun(f) + { } + + bool operator()( void* r ) const + { + BOOST_ASSERT( r != 0 ); + Arg1 arg1 = static_cast(r); + if( fun( *arg1 ) ) + { + clone_allocator_type::deallocate_clone( arg1 ); + return true; + } + return false; + } + }; + + private: + void compact_and_erase_nulls( iterator first, iterator last ) // nothrow + { + typename base_type::ptr_iterator p = std::stable_partition( + first.base(), + last.base(), + is_not_zero_ptr() ); + this->base().erase( p, this->end().base() ); + + } + + void range_check_impl( iterator first, iterator last, + std::bidirectional_iterator_tag ) + { /* do nothing */ } + + void range_check_impl( iterator first, iterator last, + std::random_access_iterator_tag ) + { + BOOST_ASSERT( first <= last && "out of range unique()/erase_if()" ); + BOOST_ASSERT( this->begin() <= first && "out of range unique()/erase_if()" ); + BOOST_ASSERT( last <= this->end() && "out of range unique()/erase_if)(" ); + } + + void range_check( iterator first, iterator last ) + { + range_check_impl( first, last, + BOOST_DEDUCED_TYPENAME iterator_category::type() ); + } + + public: + + template< class Compare > + void unique( iterator first, iterator last, Compare comp ) + { + range_check(first,last); + + iterator prev = first; + iterator next = first; + ++next; + for( ; next != last; ++next ) + { + BOOST_ASSERT( !::boost::is_null(prev) ); + BOOST_ASSERT( !::boost::is_null(next) ); + if( comp( *prev, *next ) ) + { + this->remove( next ); // delete object + *next.base() = 0; // mark pointer as deleted + } + else + { + prev = next; + } + // ++next + } + + compact_and_erase_nulls( first, last ); + } + + template< class Compare > + void unique( Compare comp ) + { + unique( this->begin(), this->end(), comp ); + } + + template< class Pred > + void erase_if( iterator first, iterator last, Pred pred ) + { + range_check(first,last); + this->base().erase( std::remove_if( first.base(), last.base(), + void_ptr_delete_if(pred) ), + last.base() ); + } + + template< class Pred > + void erase_if( Pred pred ) + { + erase_if( this->begin(), this->end(), pred ); + } + + + void merge( iterator first, iterator last, + ptr_sequence_adapter& from ) + { + merge( first, last, from, std::less() ); + } + + template< class BinPred > + void merge( iterator first, iterator last, + ptr_sequence_adapter& from, BinPred pred ) + { + void_ptr_indirect_fun bin_pred(pred); + size_type current_size = this->size(); + this->transfer( this->end(), first, last, from ); + typename base_type::ptr_iterator middle = this->begin().base(); + std::advance(middle,current_size); + std::inplace_merge( this->begin().base(), + middle, + this->end().base(), + bin_pred ); + } + + void merge( ptr_sequence_adapter& r ) + { + merge( r, std::less() ); + BOOST_ASSERT( r.empty() ); + } + + template< class BinPred > + void merge( ptr_sequence_adapter& r, BinPred pred ) + { + merge( r.begin(), r.end(), r, pred ); + BOOST_ASSERT( r.empty() ); + } + + }; + + +} // namespace 'boost' + +#endif diff --git a/src/external/3rd/library/boost/boost/ptr_container/ptr_set_adapter.hpp b/src/external/3rd/library/boost/boost/ptr_container/ptr_set_adapter.hpp index 7a89772e2..eb918d874 100644 --- a/src/external/3rd/library/boost/boost/ptr_container/ptr_set_adapter.hpp +++ b/src/external/3rd/library/boost/boost/ptr_container/ptr_set_adapter.hpp @@ -1,692 +1,692 @@ -// -// Boost.Pointer Container -// -// Copyright Thorsten Ottosen 2003-2005. Use, modification and -// distribution is subject to the Boost Software License, Version -// 1.0. (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// For more information, see http://www.boost.org/libs/ptr_container/ -// - -#ifndef BOOST_PTR_CONTAINER_PTR_SET_ADAPTER_HPP -#define BOOST_PTR_CONTAINER_PTR_SET_ADAPTER_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif - -#include -#include -#include -#include - -namespace boost -{ -namespace ptr_container_detail -{ - template - < - class Key, - class VoidPtrSet, - bool Ordered - > - struct set_config - { - typedef VoidPtrSet - void_container_type; - - typedef BOOST_DEDUCED_TYPENAME VoidPtrSet::allocator_type - allocator_type; - - typedef Key value_type; - - typedef value_type - key_type; - - typedef BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - mpl::identity >::type - value_compare; - - typedef value_compare - key_compare; - - typedef BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_hasher >::type - hasher; - - typedef BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_key_equal >::type - key_equal; - - typedef BOOST_DEDUCED_TYPENAME - mpl::if_c::type - container_type; - - typedef void_ptr_iterator< - BOOST_DEDUCED_TYPENAME VoidPtrSet::iterator, Key > - iterator; - - typedef void_ptr_iterator< - BOOST_DEDUCED_TYPENAME VoidPtrSet::const_iterator, const Key > - const_iterator; - - typedef void_ptr_iterator< - BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_local_iterator >::type, - Key > - local_iterator; - - typedef void_ptr_iterator< - BOOST_DEDUCED_TYPENAME - mpl::eval_if_c, - select_const_local_iterator >::type, - const Key > - const_local_iterator; - - template< class Iter > - static Key* get_pointer( Iter i ) - { - return static_cast( *i.base() ); - } - - template< class Iter > - static const Key* get_const_pointer( Iter i ) - { - return static_cast( *i.base() ); - } - - BOOST_STATIC_CONSTANT(bool, allow_null = false ); - }; - - - - template - < - class Key, - class VoidPtrSet, - class CloneAllocator = heap_clone_allocator, - bool Ordered = true - > - class ptr_set_adapter_base - : public ptr_container_detail::associative_ptr_container< set_config, - CloneAllocator > - { - typedef ptr_container_detail::associative_ptr_container< set_config, - CloneAllocator > - base_type; - public: - typedef BOOST_DEDUCED_TYPENAME base_type::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator - const_iterator; - typedef Key key_type; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type - size_type; - - public: - ptr_set_adapter_base() - { } - - template< class SizeType > - ptr_set_adapter_base( SizeType n, - ptr_container_detail::unordered_associative_container_tag tag ) - : base_type( n, tag ) - { } - - template< class Compare, class Allocator > - ptr_set_adapter_base( const Compare& comp, - const Allocator& a ) - : base_type( comp, a ) - { } - - template< class Hash, class Pred, class Allocator > - ptr_set_adapter_base( const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { } - - template< class InputIterator, class Compare, class Allocator > - ptr_set_adapter_base( InputIterator first, InputIterator last, - const Compare& comp, - const Allocator& a ) - : base_type( first, last, comp, a ) - { } - - template< class InputIterator, class Hash, class Pred, class Allocator > - ptr_set_adapter_base( InputIterator first, InputIterator last, - const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( first, last, hash, pred, a ) - { } - - template< class U, class Set, class CA, bool b > - ptr_set_adapter_base( const ptr_set_adapter_base& r ) - : base_type( r ) - { } - - ptr_set_adapter_base( const ptr_set_adapter_base& r ) - : base_type( r ) - { } - - template< class PtrContainer > - explicit ptr_set_adapter_base( std::unique_ptr clone ) - : base_type( clone ) - { } - - ptr_set_adapter_base& operator=( ptr_set_adapter_base r ) - { - this->swap( r ); - return *this; - } - - template< typename PtrContainer > - ptr_set_adapter_base& operator=( std::unique_ptr clone ) - { - base_type::operator=( clone ); - return *this; - } - - using base_type::erase; - - size_type erase( const key_type& x ) // nothrow - { - key_type* key = const_cast(&x); - iterator i( this->base().find( key ) ); - if( i == this->end() ) // nothrow - return 0u; // nothrow - key = static_cast(*i.base()); // nothrow - size_type res = this->base().erase( key ); // nothrow - this->remove( key ); // nothrow - return res; - } - - - iterator find( const key_type& x ) - { - return iterator( this->base(). - find( const_cast(&x) ) ); - } - - const_iterator find( const key_type& x ) const - { - return const_iterator( this->base(). - find( const_cast(&x) ) ); - } - - size_type count( const key_type& x ) const - { - return this->base().count( const_cast(&x) ); - } - - iterator lower_bound( const key_type& x ) - { - return iterator( this->base(). - lower_bound( const_cast(&x) ) ); - } - - const_iterator lower_bound( const key_type& x ) const - { - return const_iterator( this->base(). - lower_bound( const_cast(&x) ) ); - } - - iterator upper_bound( const key_type& x ) - { - return iterator( this->base(). - upper_bound( const_cast(&x) ) ); - } - - const_iterator upper_bound( const key_type& x ) const - { - return const_iterator( this->base(). - upper_bound( const_cast(&x) ) ); - } - - iterator_range equal_range( const key_type& x ) - { - std::pair - p = this->base(). - equal_range( const_cast(&x) ); - return make_iterator_range( iterator( p.first ), - iterator( p.second ) ); - } - - iterator_range equal_range( const key_type& x ) const - { - std::pair - p = this->base(). - equal_range( const_cast(&x) ); - return make_iterator_range( const_iterator( p.first ), - const_iterator( p.second ) ); - } - - protected: - size_type bucket( const key_type& key ) const - { - return this->base().bucket( const_cast(&key) ); - } - }; - -} // ptr_container_detail - - ///////////////////////////////////////////////////////////////////////// - // ptr_set_adapter - ///////////////////////////////////////////////////////////////////////// - - template - < - class Key, - class VoidPtrSet, - class CloneAllocator = heap_clone_allocator, - bool Ordered = true - > - class ptr_set_adapter : - public ptr_container_detail::ptr_set_adapter_base - { - typedef ptr_container_detail::ptr_set_adapter_base - base_type; - - public: // typedefs - - typedef BOOST_DEDUCED_TYPENAME base_type::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator - const_iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type - size_type; - typedef Key key_type; - typedef BOOST_DEDUCED_TYPENAME base_type::auto_type - auto_type; - typedef BOOST_DEDUCED_TYPENAME VoidPtrSet::allocator_type - allocator_type; - private: - - template< typename II > - void set_basic_clone_and_insert( II first, II last ) // basic - { - while( first != last ) - { - if( this->find( *first ) == this->end() ) - insert( CloneAllocator::allocate_clone( *first ) ); // strong, commit - ++first; - } - } - - public: - ptr_set_adapter() - { } - - template< class SizeType > - ptr_set_adapter( SizeType n, - ptr_container_detail::unordered_associative_container_tag tag ) - : base_type( n, tag ) - { } - - template< class Comp > - explicit ptr_set_adapter( const Comp& comp, - const allocator_type& a ) - : base_type( comp, a ) - { - BOOST_ASSERT( this->empty() ); - } - - template< class Hash, class Pred, class Allocator > - ptr_set_adapter( const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { } - - template< class InputIterator > - ptr_set_adapter( InputIterator first, InputIterator last ) - : base_type( first, last ) - { } - - template< class InputIterator, class Compare, class Allocator > - ptr_set_adapter( InputIterator first, InputIterator last, - const Compare& comp, - const Allocator a = Allocator() ) - : base_type( comp, a ) - { - BOOST_ASSERT( this->empty() ); - set_basic_clone_and_insert( first, last ); - } - - template< class InputIterator, class Hash, class Pred, class Allocator > - ptr_set_adapter( InputIterator first, InputIterator last, - const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( first, last, hash, pred, a ) - { } - - explicit ptr_set_adapter( const ptr_set_adapter& r ) - : base_type( r ) - { } - - template< class U, class Set, class CA, bool b > - explicit ptr_set_adapter( const ptr_set_adapter& r ) - : base_type( r ) - { } - - template< class PtrContainer > - explicit ptr_set_adapter( std::unique_ptr clone ) - : base_type( clone ) - { } - - template< class U, class Set, class CA, bool b > - ptr_set_adapter& operator=( const ptr_set_adapter& r ) - { - base_type::operator=( r ); - return *this; - } - - template< class T > - void operator=( std::unique_ptr r ) - { - base_type::operator=( r ); - } - - std::pair insert( key_type* x ) // strong - { - this->enforce_null_policy( x, "Null pointer in 'ptr_set::insert()'" ); - - auto_type ptr( x ); - std::pair - res = this->base().insert( x ); - if( res.second ) - ptr.release(); - return std::make_pair( iterator( res.first ), res.second ); - } - - template< class U > - std::pair insert( std::unique_ptr x ) - { - return insert( x.release() ); - } - - - iterator insert( iterator where, key_type* x ) // strong - { - this->enforce_null_policy( x, "Null pointer in 'ptr_set::insert()'" ); - - auto_type ptr( x ); - BOOST_DEDUCED_TYPENAME base_type::ptr_iterator - res = this->base().insert( where.base(), x ); - if( *res == x ) - ptr.release(); - return iterator( res); - } - - template< class U > - iterator insert( iterator where, std::unique_ptr x ) - { - return insert( where, x.release() ); - } - - template< typename InputIterator > - void insert( InputIterator first, InputIterator last ) // basic - { - set_basic_clone_and_insert( first, last ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class Range > - BOOST_DEDUCED_TYPENAME - boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type - insert( const Range& r ) - { - insert( boost::begin(r), boost::end(r) ); - } - -#endif - - template< class PtrSetAdapter > - bool transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator object, - PtrSetAdapter& from ) // strong - { - return this->single_transfer( object, from ); - } - - template< class PtrSetAdapter > - size_type - transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator first, - BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator last, - PtrSetAdapter& from ) // basic - { - return this->single_transfer( first, last, from ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class PtrSetAdapter, class Range > - BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, - BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator >, - size_type >::type - transfer( const Range& r, PtrSetAdapter& from ) // basic - { - return transfer( boost::begin(r), boost::end(r), from ); - } - -#endif - - template< class PtrSetAdapter > - size_type transfer( PtrSetAdapter& from ) // basic - { - return transfer( from.begin(), from.end(), from ); - } - - }; - - ///////////////////////////////////////////////////////////////////////// - // ptr_multiset_adapter - ///////////////////////////////////////////////////////////////////////// - - template - < - class Key, - class VoidPtrMultiSet, - class CloneAllocator = heap_clone_allocator, - bool Ordered = true - > - class ptr_multiset_adapter : - public ptr_container_detail::ptr_set_adapter_base - { - typedef ptr_container_detail::ptr_set_adapter_base base_type; - - public: // typedefs - - typedef BOOST_DEDUCED_TYPENAME base_type::iterator - iterator; - typedef BOOST_DEDUCED_TYPENAME base_type::size_type - size_type; - typedef Key key_type; - typedef BOOST_DEDUCED_TYPENAME base_type::auto_type - auto_type; - typedef BOOST_DEDUCED_TYPENAME VoidPtrMultiSet::allocator_type - allocator_type; - private: - template< typename II > - void set_basic_clone_and_insert( II first, II last ) // basic - { - while( first != last ) - { - insert( CloneAllocator::allocate_clone( *first ) ); // strong, commit - ++first; - } - } - - public: - ptr_multiset_adapter() - { } - - template< class SizeType > - ptr_multiset_adapter( SizeType n, - ptr_container_detail::unordered_associative_container_tag tag ) - : base_type( n, tag ) - { } - - template< class Comp > - explicit ptr_multiset_adapter( const Comp& comp, - const allocator_type& a ) - : base_type( comp, a ) - { } - - template< class Hash, class Pred, class Allocator > - ptr_multiset_adapter( const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( hash, pred, a ) - { } - - template< class InputIterator > - ptr_multiset_adapter( InputIterator first, InputIterator last ) - : base_type( first, last ) - { } - - template< class InputIterator, class Comp > - ptr_multiset_adapter( InputIterator first, InputIterator last, - const Comp& comp, - const allocator_type& a = allocator_type() ) - : base_type( comp, a ) - { - set_basic_clone_and_insert( first, last ); - } - - template< class InputIterator, class Hash, class Pred, class Allocator > - ptr_multiset_adapter( InputIterator first, InputIterator last, - const Hash& hash, - const Pred& pred, - const Allocator& a ) - : base_type( first, last, hash, pred, a ) - { } - - template< class U, class Set, class CA, bool b > - explicit ptr_multiset_adapter( const ptr_multiset_adapter& r ) - : base_type( r ) - { } - - template< class PtrContainer > - explicit ptr_multiset_adapter( std::unique_ptr clone ) - : base_type( clone ) - { } - - template< class U, class Set, class CA, bool b > - ptr_multiset_adapter& operator=( const ptr_multiset_adapter& r ) - { - base_type::operator=( r ); - return *this; - } - - template< class T > - void operator=( std::unique_ptr r ) - { - base_type::operator=( r ); - } - - iterator insert( iterator before, key_type* x ) // strong - { - return base_type::insert( before, x ); - } - - template< class U > - iterator insert( iterator before, std::unique_ptr x ) - { - return insert( before, x.release() ); - } - - iterator insert( key_type* x ) // strong - { - this->enforce_null_policy( x, "Null pointer in 'ptr_multiset::insert()'" ); - - auto_type ptr( x ); - BOOST_DEDUCED_TYPENAME base_type::ptr_iterator - res = this->base().insert( x ); - ptr.release(); - return iterator( res ); - } - - template< class U > - iterator insert( std::unique_ptr x ) - { - return insert( x.release() ); - } - - template< typename InputIterator > - void insert( InputIterator first, InputIterator last ) // basic - { - set_basic_clone_and_insert( first, last ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class Range > - BOOST_DEDUCED_TYPENAME - boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type - insert( const Range& r ) - { - insert( boost::begin(r), boost::end(r) ); - } - -#endif - - template< class PtrSetAdapter > - void transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator object, - PtrSetAdapter& from ) // strong - { - this->multi_transfer( object, from ); - } - - template< class PtrSetAdapter > - size_type transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator first, - BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator last, - PtrSetAdapter& from ) // basic - { - return this->multi_transfer( first, last, from ); - } - -#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) -#else - - template< class PtrSetAdapter, class Range > - BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, - BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator >, size_type >::type - transfer( const Range& r, PtrSetAdapter& from ) // basic - { - return transfer( boost::begin(r), boost::end(r), from ); - } - -#endif - - template< class PtrSetAdapter > - void transfer( PtrSetAdapter& from ) // basic - { - transfer( from.begin(), from.end(), from ); - BOOST_ASSERT( from.empty() ); - } - - }; - -} // namespace 'boost' - -#endif +// +// Boost.Pointer Container +// +// Copyright Thorsten Ottosen 2003-2005. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/ptr_container/ +// + +#ifndef BOOST_PTR_CONTAINER_PTR_SET_ADAPTER_HPP +#define BOOST_PTR_CONTAINER_PTR_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif + +#include +#include +#include +#include + +namespace boost +{ +namespace ptr_container_detail +{ + template + < + class Key, + class VoidPtrSet, + bool Ordered + > + struct set_config + { + typedef VoidPtrSet + void_container_type; + + typedef BOOST_DEDUCED_TYPENAME VoidPtrSet::allocator_type + allocator_type; + + typedef Key value_type; + + typedef value_type + key_type; + + typedef BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + mpl::identity >::type + value_compare; + + typedef value_compare + key_compare; + + typedef BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_hasher >::type + hasher; + + typedef BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_key_equal >::type + key_equal; + + typedef BOOST_DEDUCED_TYPENAME + mpl::if_c::type + container_type; + + typedef void_ptr_iterator< + BOOST_DEDUCED_TYPENAME VoidPtrSet::iterator, Key > + iterator; + + typedef void_ptr_iterator< + BOOST_DEDUCED_TYPENAME VoidPtrSet::const_iterator, const Key > + const_iterator; + + typedef void_ptr_iterator< + BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_local_iterator >::type, + Key > + local_iterator; + + typedef void_ptr_iterator< + BOOST_DEDUCED_TYPENAME + mpl::eval_if_c, + select_const_local_iterator >::type, + const Key > + const_local_iterator; + + template< class Iter > + static Key* get_pointer( Iter i ) + { + return static_cast( *i.base() ); + } + + template< class Iter > + static const Key* get_const_pointer( Iter i ) + { + return static_cast( *i.base() ); + } + + BOOST_STATIC_CONSTANT(bool, allow_null = false ); + }; + + + + template + < + class Key, + class VoidPtrSet, + class CloneAllocator = heap_clone_allocator, + bool Ordered = true + > + class ptr_set_adapter_base + : public ptr_container_detail::associative_ptr_container< set_config, + CloneAllocator > + { + typedef ptr_container_detail::associative_ptr_container< set_config, + CloneAllocator > + base_type; + public: + typedef BOOST_DEDUCED_TYPENAME base_type::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator + const_iterator; + typedef Key key_type; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type + size_type; + + public: + ptr_set_adapter_base() + { } + + template< class SizeType > + ptr_set_adapter_base( SizeType n, + ptr_container_detail::unordered_associative_container_tag tag ) + : base_type( n, tag ) + { } + + template< class Compare, class Allocator > + ptr_set_adapter_base( const Compare& comp, + const Allocator& a ) + : base_type( comp, a ) + { } + + template< class Hash, class Pred, class Allocator > + ptr_set_adapter_base( const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { } + + template< class InputIterator, class Compare, class Allocator > + ptr_set_adapter_base( InputIterator first, InputIterator last, + const Compare& comp, + const Allocator& a ) + : base_type( first, last, comp, a ) + { } + + template< class InputIterator, class Hash, class Pred, class Allocator > + ptr_set_adapter_base( InputIterator first, InputIterator last, + const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( first, last, hash, pred, a ) + { } + + template< class U, class Set, class CA, bool b > + ptr_set_adapter_base( const ptr_set_adapter_base& r ) + : base_type( r ) + { } + + ptr_set_adapter_base( const ptr_set_adapter_base& r ) + : base_type( r ) + { } + + template< class PtrContainer > + explicit ptr_set_adapter_base( std::unique_ptr clone ) + : base_type( clone ) + { } + + ptr_set_adapter_base& operator=( ptr_set_adapter_base r ) + { + this->swap( r ); + return *this; + } + + template< typename PtrContainer > + ptr_set_adapter_base& operator=( std::unique_ptr clone ) + { + base_type::operator=( clone ); + return *this; + } + + using base_type::erase; + + size_type erase( const key_type& x ) // nothrow + { + key_type* key = const_cast(&x); + iterator i( this->base().find( key ) ); + if( i == this->end() ) // nothrow + return 0u; // nothrow + key = static_cast(*i.base()); // nothrow + size_type res = this->base().erase( key ); // nothrow + this->remove( key ); // nothrow + return res; + } + + + iterator find( const key_type& x ) + { + return iterator( this->base(). + find( const_cast(&x) ) ); + } + + const_iterator find( const key_type& x ) const + { + return const_iterator( this->base(). + find( const_cast(&x) ) ); + } + + size_type count( const key_type& x ) const + { + return this->base().count( const_cast(&x) ); + } + + iterator lower_bound( const key_type& x ) + { + return iterator( this->base(). + lower_bound( const_cast(&x) ) ); + } + + const_iterator lower_bound( const key_type& x ) const + { + return const_iterator( this->base(). + lower_bound( const_cast(&x) ) ); + } + + iterator upper_bound( const key_type& x ) + { + return iterator( this->base(). + upper_bound( const_cast(&x) ) ); + } + + const_iterator upper_bound( const key_type& x ) const + { + return const_iterator( this->base(). + upper_bound( const_cast(&x) ) ); + } + + iterator_range equal_range( const key_type& x ) + { + std::pair + p = this->base(). + equal_range( const_cast(&x) ); + return make_iterator_range( iterator( p.first ), + iterator( p.second ) ); + } + + iterator_range equal_range( const key_type& x ) const + { + std::pair + p = this->base(). + equal_range( const_cast(&x) ); + return make_iterator_range( const_iterator( p.first ), + const_iterator( p.second ) ); + } + + protected: + size_type bucket( const key_type& key ) const + { + return this->base().bucket( const_cast(&key) ); + } + }; + +} // ptr_container_detail + + ///////////////////////////////////////////////////////////////////////// + // ptr_set_adapter + ///////////////////////////////////////////////////////////////////////// + + template + < + class Key, + class VoidPtrSet, + class CloneAllocator = heap_clone_allocator, + bool Ordered = true + > + class ptr_set_adapter : + public ptr_container_detail::ptr_set_adapter_base + { + typedef ptr_container_detail::ptr_set_adapter_base + base_type; + + public: // typedefs + + typedef BOOST_DEDUCED_TYPENAME base_type::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::const_iterator + const_iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type + size_type; + typedef Key key_type; + typedef BOOST_DEDUCED_TYPENAME base_type::auto_type + auto_type; + typedef BOOST_DEDUCED_TYPENAME VoidPtrSet::allocator_type + allocator_type; + private: + + template< typename II > + void set_basic_clone_and_insert( II first, II last ) // basic + { + while( first != last ) + { + if( this->find( *first ) == this->end() ) + insert( CloneAllocator::allocate_clone( *first ) ); // strong, commit + ++first; + } + } + + public: + ptr_set_adapter() + { } + + template< class SizeType > + ptr_set_adapter( SizeType n, + ptr_container_detail::unordered_associative_container_tag tag ) + : base_type( n, tag ) + { } + + template< class Comp > + explicit ptr_set_adapter( const Comp& comp, + const allocator_type& a ) + : base_type( comp, a ) + { + BOOST_ASSERT( this->empty() ); + } + + template< class Hash, class Pred, class Allocator > + ptr_set_adapter( const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { } + + template< class InputIterator > + ptr_set_adapter( InputIterator first, InputIterator last ) + : base_type( first, last ) + { } + + template< class InputIterator, class Compare, class Allocator > + ptr_set_adapter( InputIterator first, InputIterator last, + const Compare& comp, + const Allocator a = Allocator() ) + : base_type( comp, a ) + { + BOOST_ASSERT( this->empty() ); + set_basic_clone_and_insert( first, last ); + } + + template< class InputIterator, class Hash, class Pred, class Allocator > + ptr_set_adapter( InputIterator first, InputIterator last, + const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( first, last, hash, pred, a ) + { } + + explicit ptr_set_adapter( const ptr_set_adapter& r ) + : base_type( r ) + { } + + template< class U, class Set, class CA, bool b > + explicit ptr_set_adapter( const ptr_set_adapter& r ) + : base_type( r ) + { } + + template< class PtrContainer > + explicit ptr_set_adapter( std::unique_ptr clone ) + : base_type( clone ) + { } + + template< class U, class Set, class CA, bool b > + ptr_set_adapter& operator=( const ptr_set_adapter& r ) + { + base_type::operator=( r ); + return *this; + } + + template< class T > + void operator=( std::unique_ptr r ) + { + base_type::operator=( r ); + } + + std::pair insert( key_type* x ) // strong + { + this->enforce_null_policy( x, "Null pointer in 'ptr_set::insert()'" ); + + auto_type ptr( x ); + std::pair + res = this->base().insert( x ); + if( res.second ) + ptr.release(); + return std::make_pair( iterator( res.first ), res.second ); + } + + template< class U > + std::pair insert( std::unique_ptr x ) + { + return insert( x.release() ); + } + + + iterator insert( iterator where, key_type* x ) // strong + { + this->enforce_null_policy( x, "Null pointer in 'ptr_set::insert()'" ); + + auto_type ptr( x ); + BOOST_DEDUCED_TYPENAME base_type::ptr_iterator + res = this->base().insert( where.base(), x ); + if( *res == x ) + ptr.release(); + return iterator( res); + } + + template< class U > + iterator insert( iterator where, std::unique_ptr x ) + { + return insert( where, x.release() ); + } + + template< typename InputIterator > + void insert( InputIterator first, InputIterator last ) // basic + { + set_basic_clone_and_insert( first, last ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class Range > + BOOST_DEDUCED_TYPENAME + boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type + insert( const Range& r ) + { + insert( boost::begin(r), boost::end(r) ); + } + +#endif + + template< class PtrSetAdapter > + bool transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator object, + PtrSetAdapter& from ) // strong + { + return this->single_transfer( object, from ); + } + + template< class PtrSetAdapter > + size_type + transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator first, + BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator last, + PtrSetAdapter& from ) // basic + { + return this->single_transfer( first, last, from ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class PtrSetAdapter, class Range > + BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, + BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator >, + size_type >::type + transfer( const Range& r, PtrSetAdapter& from ) // basic + { + return transfer( boost::begin(r), boost::end(r), from ); + } + +#endif + + template< class PtrSetAdapter > + size_type transfer( PtrSetAdapter& from ) // basic + { + return transfer( from.begin(), from.end(), from ); + } + + }; + + ///////////////////////////////////////////////////////////////////////// + // ptr_multiset_adapter + ///////////////////////////////////////////////////////////////////////// + + template + < + class Key, + class VoidPtrMultiSet, + class CloneAllocator = heap_clone_allocator, + bool Ordered = true + > + class ptr_multiset_adapter : + public ptr_container_detail::ptr_set_adapter_base + { + typedef ptr_container_detail::ptr_set_adapter_base base_type; + + public: // typedefs + + typedef BOOST_DEDUCED_TYPENAME base_type::iterator + iterator; + typedef BOOST_DEDUCED_TYPENAME base_type::size_type + size_type; + typedef Key key_type; + typedef BOOST_DEDUCED_TYPENAME base_type::auto_type + auto_type; + typedef BOOST_DEDUCED_TYPENAME VoidPtrMultiSet::allocator_type + allocator_type; + private: + template< typename II > + void set_basic_clone_and_insert( II first, II last ) // basic + { + while( first != last ) + { + insert( CloneAllocator::allocate_clone( *first ) ); // strong, commit + ++first; + } + } + + public: + ptr_multiset_adapter() + { } + + template< class SizeType > + ptr_multiset_adapter( SizeType n, + ptr_container_detail::unordered_associative_container_tag tag ) + : base_type( n, tag ) + { } + + template< class Comp > + explicit ptr_multiset_adapter( const Comp& comp, + const allocator_type& a ) + : base_type( comp, a ) + { } + + template< class Hash, class Pred, class Allocator > + ptr_multiset_adapter( const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( hash, pred, a ) + { } + + template< class InputIterator > + ptr_multiset_adapter( InputIterator first, InputIterator last ) + : base_type( first, last ) + { } + + template< class InputIterator, class Comp > + ptr_multiset_adapter( InputIterator first, InputIterator last, + const Comp& comp, + const allocator_type& a = allocator_type() ) + : base_type( comp, a ) + { + set_basic_clone_and_insert( first, last ); + } + + template< class InputIterator, class Hash, class Pred, class Allocator > + ptr_multiset_adapter( InputIterator first, InputIterator last, + const Hash& hash, + const Pred& pred, + const Allocator& a ) + : base_type( first, last, hash, pred, a ) + { } + + template< class U, class Set, class CA, bool b > + explicit ptr_multiset_adapter( const ptr_multiset_adapter& r ) + : base_type( r ) + { } + + template< class PtrContainer > + explicit ptr_multiset_adapter( std::unique_ptr clone ) + : base_type( clone ) + { } + + template< class U, class Set, class CA, bool b > + ptr_multiset_adapter& operator=( const ptr_multiset_adapter& r ) + { + base_type::operator=( r ); + return *this; + } + + template< class T > + void operator=( std::unique_ptr r ) + { + base_type::operator=( r ); + } + + iterator insert( iterator before, key_type* x ) // strong + { + return base_type::insert( before, x ); + } + + template< class U > + iterator insert( iterator before, std::unique_ptr x ) + { + return insert( before, x.release() ); + } + + iterator insert( key_type* x ) // strong + { + this->enforce_null_policy( x, "Null pointer in 'ptr_multiset::insert()'" ); + + auto_type ptr( x ); + BOOST_DEDUCED_TYPENAME base_type::ptr_iterator + res = this->base().insert( x ); + ptr.release(); + return iterator( res ); + } + + template< class U > + iterator insert( std::unique_ptr x ) + { + return insert( x.release() ); + } + + template< typename InputIterator > + void insert( InputIterator first, InputIterator last ) // basic + { + set_basic_clone_and_insert( first, last ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class Range > + BOOST_DEDUCED_TYPENAME + boost::disable_if< ptr_container_detail::is_pointer_or_integral >::type + insert( const Range& r ) + { + insert( boost::begin(r), boost::end(r) ); + } + +#endif + + template< class PtrSetAdapter > + void transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator object, + PtrSetAdapter& from ) // strong + { + this->multi_transfer( object, from ); + } + + template< class PtrSetAdapter > + size_type transfer( BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator first, + BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator last, + PtrSetAdapter& from ) // basic + { + return this->multi_transfer( first, last, from ); + } + +#if defined(BOOST_NO_SFINAE) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +#else + + template< class PtrSetAdapter, class Range > + BOOST_DEDUCED_TYPENAME boost::disable_if< boost::is_same< Range, + BOOST_DEDUCED_TYPENAME PtrSetAdapter::iterator >, size_type >::type + transfer( const Range& r, PtrSetAdapter& from ) // basic + { + return transfer( boost::begin(r), boost::end(r), from ); + } + +#endif + + template< class PtrSetAdapter > + void transfer( PtrSetAdapter& from ) // basic + { + transfer( from.begin(), from.end(), from ); + BOOST_ASSERT( from.empty() ); + } + + }; + +} // namespace 'boost' + +#endif diff --git a/src/external/3rd/library/boost/boost/python/converter/arg_from_python.hpp b/src/external/3rd/library/boost/boost/python/converter/arg_from_python.hpp index 0d6aa1934..c9c94798c 100644 --- a/src/external/3rd/library/boost/boost/python/converter/arg_from_python.hpp +++ b/src/external/3rd/library/boost/boost/python/converter/arg_from_python.hpp @@ -1,336 +1,336 @@ -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ARG_FROM_PYTHON_DWA2002127_HPP -# define ARG_FROM_PYTHON_DWA2002127_HPP - -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -namespace boost { namespace python -{ - template struct arg_from_python; -}} - -// This header defines Python->C++ function argument converters, -// parametrized on the argument type. - -namespace boost { namespace python { namespace converter { - -// -// lvalue converters -// -// These require that an lvalue of the type U is stored somewhere in -// the Python object being converted. - -// Used when T == U*const& -template -struct pointer_cref_arg_from_python -{ - typedef T result_type; - - pointer_cref_arg_from_python(PyObject*); - T operator()() const; - bool convertible() const; - - private: // storage for a U* - // needed because not all compilers will let us declare U* as the - // return type of operator() -- we return U*const& instead - typename python::detail::referent_storage::type m_result; -}; - -// Base class for pointer and reference converters -struct arg_lvalue_from_python_base -{ - public: // member functions - arg_lvalue_from_python_base(void* result); - bool convertible() const; - - protected: // member functions - void*const& result() const; - - private: // data members - void* m_result; -}; - -// Used when T == U* -template -struct pointer_arg_from_python : arg_lvalue_from_python_base -{ - typedef T result_type; - - pointer_arg_from_python(PyObject*); - T operator()() const; -}; - -// Used when T == U& and (T != V const& or T == W volatile&) -template -struct reference_arg_from_python : arg_lvalue_from_python_base -{ - typedef T result_type; - - reference_arg_from_python(PyObject*); - T operator()() const; -}; - -// =================== - -// -// rvalue converters -// -// These require only that an object of type T can be created from -// the given Python object, but not that the T object exist -// somewhere in storage. -// - -// Used when T is a plain value (non-pointer, non-reference) type or -// a (non-volatile) const reference to a plain value type. -template -struct arg_rvalue_from_python -{ - typedef typename boost::add_reference< - T - // We can't add_const here, or it would be impossible to pass - // unique_ptr args from Python to C++ - >::type result_type; - - arg_rvalue_from_python(PyObject*); - bool convertible() const; - -# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196 - typename arg_rvalue_from_python:: -# endif - result_type operator()(); - - private: - rvalue_from_python_data m_data; - PyObject* m_source; -}; - - -// ================== - -// Converts to a (PyObject*,T) bundle, for when you need a reference -// back to the Python object -template -struct back_reference_arg_from_python - : boost::python::arg_from_python -{ - typedef T result_type; - - back_reference_arg_from_python(PyObject*); - T operator()(); - private: - typedef boost::python::arg_from_python base; - PyObject* m_source; -}; - - -// ================== - -template -struct if_2 -{ - typedef typename mpl::eval_if, F>::type type; -}; - -// This metafunction selects the appropriate arg_from_python converter -// type for an argument of type T. -template -struct select_arg_from_python -{ - typedef typename if_2< - is_object_manager - , object_manager_value_arg_from_python - , if_2< - is_reference_to_object_manager - , object_manager_ref_arg_from_python - , if_2< - is_pointer - , pointer_arg_from_python - , if_2< - mpl::and_< - indirect_traits::is_reference_to_pointer - , indirect_traits::is_reference_to_const - , mpl::not_ > - > - , pointer_cref_arg_from_python - , if_2< - mpl::or_< - indirect_traits::is_reference_to_non_const - , indirect_traits::is_reference_to_volatile - > - , reference_arg_from_python - , mpl::if_< - boost::python::is_back_reference - , back_reference_arg_from_python - , arg_rvalue_from_python - > - > - > - > - > - >::type type; -}; - -// ================== - -// -// implementations -// - -// arg_lvalue_from_python_base -// -inline arg_lvalue_from_python_base::arg_lvalue_from_python_base(void* result) - : m_result(result) -{ -} - -inline bool arg_lvalue_from_python_base::convertible() const -{ - return m_result != 0; -} - -inline void*const& arg_lvalue_from_python_base::result() const -{ - return m_result; -} - -// pointer_cref_arg_from_python -// -namespace detail -{ - // null_ptr_reference -- a function returning a reference to a null - // pointer of type U. Needed so that extractors for T*const& can - // convert Python's None. - template - struct null_ptr_owner - { - static T value; - }; - template T null_ptr_owner::value = 0; - - template - inline U& null_ptr_reference(U&(*)()) - { - return null_ptr_owner::value; - } -} - -template -inline pointer_cref_arg_from_python::pointer_cref_arg_from_python(PyObject* p) -{ - // T == U*const&: store a U* in the m_result storage. Nonzero - // indicates success. If find returns nonzero, it's a pointer to - // a U object. - python::detail::write_void_ptr_reference( - m_result.bytes - , p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee::converters) - , (T(*)())0); -} - -template -inline bool pointer_cref_arg_from_python::convertible() const -{ - return python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0) != 0; -} -template -inline T pointer_cref_arg_from_python::operator()() const -{ - return (*(void**)m_result.bytes == Py_None) // None ==> 0 - ? detail::null_ptr_reference((T(*)())0) - // Otherwise, return a U*const& to the m_result storage. - : python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0); -} - -// pointer_arg_from_python -// -template -inline pointer_arg_from_python::pointer_arg_from_python(PyObject* p) - : arg_lvalue_from_python_base( - p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee::converters)) -{ -} - -template -inline T pointer_arg_from_python::operator()() const -{ - return (result() == Py_None) ? 0 : T(result()); -} - -// reference_arg_from_python -// -template -inline reference_arg_from_python::reference_arg_from_python(PyObject* p) - : arg_lvalue_from_python_base(converter::get_lvalue_from_python(p,registered::converters)) -{ -} - -template -inline T reference_arg_from_python::operator()() const -{ - return python::detail::void_ptr_to_reference(result(), (T(*)())0); -} - - -// arg_rvalue_from_python -// -template -inline arg_rvalue_from_python::arg_rvalue_from_python(PyObject* obj) - : m_data(converter::rvalue_from_python_stage1(obj, registered::converters)) - , m_source(obj) -{ -} - -template -inline bool arg_rvalue_from_python::convertible() const -{ - return m_data.stage1.convertible != 0; -} - -template -inline typename arg_rvalue_from_python::result_type -arg_rvalue_from_python::operator()() -{ - if (m_data.stage1.construct != 0) - m_data.stage1.construct(m_source, &m_data.stage1); - - return python::detail::void_ptr_to_reference(m_data.stage1.convertible, (result_type(*)())0); -} - -// back_reference_arg_from_python -// -template -back_reference_arg_from_python::back_reference_arg_from_python(PyObject* x) - : base(x), m_source(x) -{ -} - -template -inline T -back_reference_arg_from_python::operator()() -{ - return T(m_source, base::operator()()); -} - -}}} // namespace boost::python::converter - -#endif // ARG_FROM_PYTHON_DWA2002127_HPP +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef ARG_FROM_PYTHON_DWA2002127_HPP +# define ARG_FROM_PYTHON_DWA2002127_HPP + +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include + +namespace boost { namespace python +{ + template struct arg_from_python; +}} + +// This header defines Python->C++ function argument converters, +// parametrized on the argument type. + +namespace boost { namespace python { namespace converter { + +// +// lvalue converters +// +// These require that an lvalue of the type U is stored somewhere in +// the Python object being converted. + +// Used when T == U*const& +template +struct pointer_cref_arg_from_python +{ + typedef T result_type; + + pointer_cref_arg_from_python(PyObject*); + T operator()() const; + bool convertible() const; + + private: // storage for a U* + // needed because not all compilers will let us declare U* as the + // return type of operator() -- we return U*const& instead + typename python::detail::referent_storage::type m_result; +}; + +// Base class for pointer and reference converters +struct arg_lvalue_from_python_base +{ + public: // member functions + arg_lvalue_from_python_base(void* result); + bool convertible() const; + + protected: // member functions + void*const& result() const; + + private: // data members + void* m_result; +}; + +// Used when T == U* +template +struct pointer_arg_from_python : arg_lvalue_from_python_base +{ + typedef T result_type; + + pointer_arg_from_python(PyObject*); + T operator()() const; +}; + +// Used when T == U& and (T != V const& or T == W volatile&) +template +struct reference_arg_from_python : arg_lvalue_from_python_base +{ + typedef T result_type; + + reference_arg_from_python(PyObject*); + T operator()() const; +}; + +// =================== + +// +// rvalue converters +// +// These require only that an object of type T can be created from +// the given Python object, but not that the T object exist +// somewhere in storage. +// + +// Used when T is a plain value (non-pointer, non-reference) type or +// a (non-volatile) const reference to a plain value type. +template +struct arg_rvalue_from_python +{ + typedef typename boost::add_reference< + T + // We can't add_const here, or it would be impossible to pass + // unique_ptr args from Python to C++ + >::type result_type; + + arg_rvalue_from_python(PyObject*); + bool convertible() const; + +# if BOOST_MSVC < 1301 || _MSC_FULL_VER > 13102196 + typename arg_rvalue_from_python:: +# endif + result_type operator()(); + + private: + rvalue_from_python_data m_data; + PyObject* m_source; +}; + + +// ================== + +// Converts to a (PyObject*,T) bundle, for when you need a reference +// back to the Python object +template +struct back_reference_arg_from_python + : boost::python::arg_from_python +{ + typedef T result_type; + + back_reference_arg_from_python(PyObject*); + T operator()(); + private: + typedef boost::python::arg_from_python base; + PyObject* m_source; +}; + + +// ================== + +template +struct if_2 +{ + typedef typename mpl::eval_if, F>::type type; +}; + +// This metafunction selects the appropriate arg_from_python converter +// type for an argument of type T. +template +struct select_arg_from_python +{ + typedef typename if_2< + is_object_manager + , object_manager_value_arg_from_python + , if_2< + is_reference_to_object_manager + , object_manager_ref_arg_from_python + , if_2< + is_pointer + , pointer_arg_from_python + , if_2< + mpl::and_< + indirect_traits::is_reference_to_pointer + , indirect_traits::is_reference_to_const + , mpl::not_ > + > + , pointer_cref_arg_from_python + , if_2< + mpl::or_< + indirect_traits::is_reference_to_non_const + , indirect_traits::is_reference_to_volatile + > + , reference_arg_from_python + , mpl::if_< + boost::python::is_back_reference + , back_reference_arg_from_python + , arg_rvalue_from_python + > + > + > + > + > + >::type type; +}; + +// ================== + +// +// implementations +// + +// arg_lvalue_from_python_base +// +inline arg_lvalue_from_python_base::arg_lvalue_from_python_base(void* result) + : m_result(result) +{ +} + +inline bool arg_lvalue_from_python_base::convertible() const +{ + return m_result != 0; +} + +inline void*const& arg_lvalue_from_python_base::result() const +{ + return m_result; +} + +// pointer_cref_arg_from_python +// +namespace detail +{ + // null_ptr_reference -- a function returning a reference to a null + // pointer of type U. Needed so that extractors for T*const& can + // convert Python's None. + template + struct null_ptr_owner + { + static T value; + }; + template T null_ptr_owner::value = 0; + + template + inline U& null_ptr_reference(U&(*)()) + { + return null_ptr_owner::value; + } +} + +template +inline pointer_cref_arg_from_python::pointer_cref_arg_from_python(PyObject* p) +{ + // T == U*const&: store a U* in the m_result storage. Nonzero + // indicates success. If find returns nonzero, it's a pointer to + // a U object. + python::detail::write_void_ptr_reference( + m_result.bytes + , p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee::converters) + , (T(*)())0); +} + +template +inline bool pointer_cref_arg_from_python::convertible() const +{ + return python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0) != 0; +} +template +inline T pointer_cref_arg_from_python::operator()() const +{ + return (*(void**)m_result.bytes == Py_None) // None ==> 0 + ? detail::null_ptr_reference((T(*)())0) + // Otherwise, return a U*const& to the m_result storage. + : python::detail::void_ptr_to_reference(m_result.bytes, (T(*)())0); +} + +// pointer_arg_from_python +// +template +inline pointer_arg_from_python::pointer_arg_from_python(PyObject* p) + : arg_lvalue_from_python_base( + p == Py_None ? p : converter::get_lvalue_from_python(p, registered_pointee::converters)) +{ +} + +template +inline T pointer_arg_from_python::operator()() const +{ + return (result() == Py_None) ? 0 : T(result()); +} + +// reference_arg_from_python +// +template +inline reference_arg_from_python::reference_arg_from_python(PyObject* p) + : arg_lvalue_from_python_base(converter::get_lvalue_from_python(p,registered::converters)) +{ +} + +template +inline T reference_arg_from_python::operator()() const +{ + return python::detail::void_ptr_to_reference(result(), (T(*)())0); +} + + +// arg_rvalue_from_python +// +template +inline arg_rvalue_from_python::arg_rvalue_from_python(PyObject* obj) + : m_data(converter::rvalue_from_python_stage1(obj, registered::converters)) + , m_source(obj) +{ +} + +template +inline bool arg_rvalue_from_python::convertible() const +{ + return m_data.stage1.convertible != 0; +} + +template +inline typename arg_rvalue_from_python::result_type +arg_rvalue_from_python::operator()() +{ + if (m_data.stage1.construct != 0) + m_data.stage1.construct(m_source, &m_data.stage1); + + return python::detail::void_ptr_to_reference(m_data.stage1.convertible, (result_type(*)())0); +} + +// back_reference_arg_from_python +// +template +back_reference_arg_from_python::back_reference_arg_from_python(PyObject* x) + : base(x), m_source(x) +{ +} + +template +inline T +back_reference_arg_from_python::operator()() +{ + return T(m_source, base::operator()()); +} + +}}} // namespace boost::python::converter + +#endif // ARG_FROM_PYTHON_DWA2002127_HPP diff --git a/src/external/3rd/library/boost/boost/python/converter/as_to_python_function.hpp b/src/external/3rd/library/boost/boost/python/converter/as_to_python_function.hpp index d97b535c2..61721a779 100644 --- a/src/external/3rd/library/boost/boost/python/converter/as_to_python_function.hpp +++ b/src/external/3rd/library/boost/boost/python/converter/as_to_python_function.hpp @@ -1,49 +1,49 @@ -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef AS_TO_PYTHON_FUNCTION_DWA2002121_HPP -# define AS_TO_PYTHON_FUNCTION_DWA2002121_HPP -# include - -namespace boost { namespace python { namespace converter { - -// Given a typesafe to_python conversion function, produces a -// to_python_function_t which can be registered in the usual way. -template -struct as_to_python_function -{ - // Assertion functions used to prevent wrapping of converters - // which take non-const reference parameters. The T* argument in - // the first overload ensures it isn't used in case T is a - // reference. - template - static void convert_function_must_take_value_or_const_reference(U(*)(T), int, T* = 0) {} - template - static void convert_function_must_take_value_or_const_reference(U(*)(T const&), long ...) {} - - static PyObject* convert(void const* x) - { - convert_function_must_take_value_or_const_reference(&ToPython::convert, 1L); - - // Yes, the const_cast below opens a hole in const-correctness, - // but it's needed to convert unique_ptr to python. - // - // How big a hole is it? It allows ToPython::convert() to be - // a function which modifies its argument. The upshot is that - // client converters applied to const objects may invoke - // undefined behavior. The damage, however, is limited by the - // use of the assertion function. Thus, the only way this can - // modify its argument is if T is an unique_ptr-like type. There - // is still a const-correctness hole w.r.t. unique_ptr const, - // but c'est la vie. - return ToPython::convert(*const_cast(static_cast(x))); - } -#ifndef BOOST_PYTHON_NO_PY_SIGNATURES - static PyTypeObject const * get_pytype() { return ToPython::get_pytype(); } -#endif -}; - -}}} // namespace boost::python::converter - -#endif // AS_TO_PYTHON_FUNCTION_DWA2002121_HPP +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef AS_TO_PYTHON_FUNCTION_DWA2002121_HPP +# define AS_TO_PYTHON_FUNCTION_DWA2002121_HPP +# include + +namespace boost { namespace python { namespace converter { + +// Given a typesafe to_python conversion function, produces a +// to_python_function_t which can be registered in the usual way. +template +struct as_to_python_function +{ + // Assertion functions used to prevent wrapping of converters + // which take non-const reference parameters. The T* argument in + // the first overload ensures it isn't used in case T is a + // reference. + template + static void convert_function_must_take_value_or_const_reference(U(*)(T), int, T* = 0) {} + template + static void convert_function_must_take_value_or_const_reference(U(*)(T const&), long ...) {} + + static PyObject* convert(void const* x) + { + convert_function_must_take_value_or_const_reference(&ToPython::convert, 1L); + + // Yes, the const_cast below opens a hole in const-correctness, + // but it's needed to convert unique_ptr to python. + // + // How big a hole is it? It allows ToPython::convert() to be + // a function which modifies its argument. The upshot is that + // client converters applied to const objects may invoke + // undefined behavior. The damage, however, is limited by the + // use of the assertion function. Thus, the only way this can + // modify its argument is if T is an unique_ptr-like type. There + // is still a const-correctness hole w.r.t. unique_ptr const, + // but c'est la vie. + return ToPython::convert(*const_cast(static_cast(x))); + } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + static PyTypeObject const * get_pytype() { return ToPython::get_pytype(); } +#endif +}; + +}}} // namespace boost::python::converter + +#endif // AS_TO_PYTHON_FUNCTION_DWA2002121_HPP diff --git a/src/external/3rd/library/boost/boost/python/detail/copy_ctor_mutates_rhs.hpp b/src/external/3rd/library/boost/boost/python/detail/copy_ctor_mutates_rhs.hpp index 6d710674a..506019a62 100644 --- a/src/external/3rd/library/boost/boost/python/detail/copy_ctor_mutates_rhs.hpp +++ b/src/external/3rd/library/boost/boost/python/detail/copy_ctor_mutates_rhs.hpp @@ -1,21 +1,21 @@ -// Copyright David Abrahams 2003. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef COPY_CTOR_MUTATES_RHS_DWA2003219_HPP -# define COPY_CTOR_MUTATES_RHS_DWA2003219_HPP - -#include -#include - -namespace boost { namespace python { namespace detail { - -template -struct copy_ctor_mutates_rhs - : is_unique_ptr -{ -}; - -}}} // namespace boost::python::detail - -#endif // COPY_CTOR_MUTATES_RHS_DWA2003219_HPP +// Copyright David Abrahams 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef COPY_CTOR_MUTATES_RHS_DWA2003219_HPP +# define COPY_CTOR_MUTATES_RHS_DWA2003219_HPP + +#include +#include + +namespace boost { namespace python { namespace detail { + +template +struct copy_ctor_mutates_rhs + : is_unique_ptr +{ +}; + +}}} // namespace boost::python::detail + +#endif // COPY_CTOR_MUTATES_RHS_DWA2003219_HPP diff --git a/src/external/3rd/library/boost/boost/python/detail/is_auto_ptr.hpp b/src/external/3rd/library/boost/boost/python/detail/is_auto_ptr.hpp index ce0d4ae06..5e30e808d 100644 --- a/src/external/3rd/library/boost/boost/python/detail/is_auto_ptr.hpp +++ b/src/external/3rd/library/boost/boost/python/detail/is_auto_ptr.hpp @@ -1,30 +1,30 @@ -// Copyright David Abrahams 2003. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef IS_AUTO_PTR_DWA2003224_HPP -# define IS_AUTO_PTR_DWA2003224_HPP - -# ifndef BOOST_NO_AUTO_PTR -# include -# include -# endif - -namespace boost { namespace python { namespace detail { - -# if !defined(BOOST_NO_AUTO_PTR) - -BOOST_PYTHON_IS_XXX_DEF(unique_ptr, std::unique_ptr, 1) - -# else - -template -struct is_unique_ptr : mpl::false_ -{ -}; - -# endif - -}}} // namespace boost::python::detail - -#endif // IS_AUTO_PTR_DWA2003224_HPP +// Copyright David Abrahams 2003. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef IS_AUTO_PTR_DWA2003224_HPP +# define IS_AUTO_PTR_DWA2003224_HPP + +# ifndef BOOST_NO_AUTO_PTR +# include +# include +# endif + +namespace boost { namespace python { namespace detail { + +# if !defined(BOOST_NO_AUTO_PTR) + +BOOST_PYTHON_IS_XXX_DEF(unique_ptr, std::unique_ptr, 1) + +# else + +template +struct is_unique_ptr : mpl::false_ +{ +}; + +# endif + +}}} // namespace boost::python::detail + +#endif // IS_AUTO_PTR_DWA2003224_HPP diff --git a/src/external/3rd/library/boost/boost/python/make_constructor.hpp b/src/external/3rd/library/boost/boost/python/make_constructor.hpp index 11d01d3af..5a9565c9d 100644 --- a/src/external/3rd/library/boost/boost/python/make_constructor.hpp +++ b/src/external/3rd/library/boost/boost/python/make_constructor.hpp @@ -1,290 +1,290 @@ -// Copyright David Abrahams 2001. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef MAKE_CONSTRUCTOR_DWA20011221_HPP -# define MAKE_CONSTRUCTOR_DWA20011221_HPP - -# include - -# include -# include -# include - -# include -# include -# include -# include - -# include -# include - -# include -# include -# include -# include -# include - -namespace boost { namespace python { - -namespace detail -{ - template - struct install_holder : converter::context_result_converter - { - install_holder(PyObject* args_) - : m_self(PyTuple_GetItem(args_, 0)) {} - - PyObject* operator()(T x) const - { - dispatch(x, is_pointer()); - return none(); - } - - private: - template - void dispatch(U* x, mpl::true_) const - { - std::unique_ptr owner(x); - dispatch(owner, mpl::false_()); - } - - template - void dispatch(Ptr x, mpl::false_) const - { - typedef typename pointee::type value_type; - typedef objects::pointer_holder holder; - typedef objects::instance instance_t; - - void* memory = holder::allocate(this->m_self, offsetof(instance_t, storage), sizeof(holder)); - try { - (new (memory) holder(x))->install(this->m_self); - } - catch(...) { - holder::deallocate(this->m_self, memory); - throw; - } - } - - PyObject* m_self; - }; - - struct constructor_result_converter - { - template - struct apply - { - typedef install_holder type; - }; - }; - - template - struct offset_args - { - offset_args(BaseArgs base_) : base(base_) {} - BaseArgs base; - }; - - template - inline PyObject* get(mpl::int_, offset_args const& args_) - { - return get(mpl::int_<(N+Offset::value)>(), args_.base); - } - - template - inline unsigned arity(offset_args const& args_) - { - return arity(args_.base) - Offset::value; - } - - template - struct constructor_policy : BasePolicy_ - { - constructor_policy(BasePolicy_ base) : BasePolicy_(base) {} - - // If the BasePolicy_ supplied a result converter it would be - // ignored; issue an error if it's not the default. -#if defined _MSC_VER && _MSC_VER < 1300 - typedef is_same< - typename BasePolicy_::result_converter - , default_result_converter - > same_result_converter; - //see above for explanation - BOOST_STATIC_ASSERT(same_result_converter::value) ; -#else - BOOST_MPL_ASSERT_MSG( - (is_same< - typename BasePolicy_::result_converter - , default_result_converter - >::value) - , MAKE_CONSTRUCTOR_SUPPLIES_ITS_OWN_RESULT_CONVERTER_THAT_WOULD_OVERRIDE_YOURS - , (typename BasePolicy_::result_converter) - ); -#endif - typedef constructor_result_converter result_converter; - typedef offset_args > argument_package; - }; - - template - struct outer_constructor_signature - { - typedef typename mpl::pop_front::type inner_args; - typedef typename mpl::push_front::type outer_args; - typedef typename mpl::push_front::type type; - }; - - // ETI workaround - template <> - struct outer_constructor_signature - { - typedef int type; - }; - - // - // These helper functions for make_constructor (below) do the raw work - // of constructing a Python object from some invokable entity. See - // for more information about how - // the Sig arguments is used. - // - // @group make_constructor_aux { - template - object make_constructor_aux( - F f // An object that can be invoked by detail::invoke() - , CallPolicies const& p // CallPolicies to use in the invocation - , Sig const& // An MPL sequence of argument types expected by F - ) - { - typedef typename outer_constructor_signature::type outer_signature; - - typedef constructor_policy inner_policy; - - return objects::function_object( - objects::py_function( - detail::caller(f, inner_policy(p)) - , outer_signature() - ) - ); - } - - // As above, except that it accepts argument keywords. NumKeywords - // is used only for a compile-time assertion to make sure the user - // doesn't pass more keywords than the function can accept. To - // disable all checking, pass mpl::int_<0> for NumKeywords. - template - object make_constructor_aux( - F f - , CallPolicies const& p - , Sig const& - , detail::keyword_range const& kw // a [begin,end) pair of iterators over keyword names - , NumKeywords // An MPL integral type wrapper: the size of kw - ) - { - enum { arity = mpl::size::value - 1 }; - - typedef typename detail::error::more_keywords_than_function_arguments< - NumKeywords::value, arity - >::too_many_keywords assertion; - - typedef typename outer_constructor_signature::type outer_signature; - - typedef constructor_policy inner_policy; - - return objects::function_object( - objects::py_function( - detail::caller(f, inner_policy(p)) - , outer_signature() - ) - , kw - ); - } - // } - - // - // These dispatch functions are used to discriminate between the - // cases when the 3rd argument is keywords or when it is a - // signature. - // - // @group Helpers for make_constructor when called with 3 arguments. { - // - template - object make_constructor_dispatch(F f, CallPolicies const& policies, Keywords const& kw, mpl::true_) - { - return detail::make_constructor_aux( - f - , policies - , detail::get_signature(f) - , kw.range() - , mpl::int_() - ); - } - - template - object make_constructor_dispatch(F f, CallPolicies const& policies, Signature const& sig, mpl::false_) - { - return detail::make_constructor_aux( - f - , policies - , sig - ); - } - // } -} - -// These overloaded functions wrap a function or member function -// pointer as a Python object, using optional CallPolicies, -// Keywords, and/or Signature. @group { -// -template -object make_constructor(F f) -{ - return detail::make_constructor_aux( - f,default_call_policies(), detail::get_signature(f)); -} - -template -object make_constructor(F f, CallPolicies const& policies) -{ - return detail::make_constructor_aux( - f, policies, detail::get_signature(f)); -} - -template -object make_constructor( - F f - , CallPolicies const& policies - , KeywordsOrSignature const& keywords_or_signature) -{ - typedef typename - detail::is_reference_to_keywords::type - is_kw; - - return detail::make_constructor_dispatch( - f - , policies - , keywords_or_signature - , is_kw() - ); -} - -template -object make_constructor( - F f - , CallPolicies const& policies - , Keywords const& kw - , Signature const& sig - ) -{ - return detail::make_constructor_aux( - f - , policies - , sig - , kw.range() - , mpl::int_() - ); -} -// } - -}} - - -#endif // MAKE_CONSTRUCTOR_DWA20011221_HPP +// Copyright David Abrahams 2001. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef MAKE_CONSTRUCTOR_DWA20011221_HPP +# define MAKE_CONSTRUCTOR_DWA20011221_HPP + +# include + +# include +# include +# include + +# include +# include +# include +# include + +# include +# include + +# include +# include +# include +# include +# include + +namespace boost { namespace python { + +namespace detail +{ + template + struct install_holder : converter::context_result_converter + { + install_holder(PyObject* args_) + : m_self(PyTuple_GetItem(args_, 0)) {} + + PyObject* operator()(T x) const + { + dispatch(x, is_pointer()); + return none(); + } + + private: + template + void dispatch(U* x, mpl::true_) const + { + std::unique_ptr owner(x); + dispatch(owner, mpl::false_()); + } + + template + void dispatch(Ptr x, mpl::false_) const + { + typedef typename pointee::type value_type; + typedef objects::pointer_holder holder; + typedef objects::instance instance_t; + + void* memory = holder::allocate(this->m_self, offsetof(instance_t, storage), sizeof(holder)); + try { + (new (memory) holder(x))->install(this->m_self); + } + catch(...) { + holder::deallocate(this->m_self, memory); + throw; + } + } + + PyObject* m_self; + }; + + struct constructor_result_converter + { + template + struct apply + { + typedef install_holder type; + }; + }; + + template + struct offset_args + { + offset_args(BaseArgs base_) : base(base_) {} + BaseArgs base; + }; + + template + inline PyObject* get(mpl::int_, offset_args const& args_) + { + return get(mpl::int_<(N+Offset::value)>(), args_.base); + } + + template + inline unsigned arity(offset_args const& args_) + { + return arity(args_.base) - Offset::value; + } + + template + struct constructor_policy : BasePolicy_ + { + constructor_policy(BasePolicy_ base) : BasePolicy_(base) {} + + // If the BasePolicy_ supplied a result converter it would be + // ignored; issue an error if it's not the default. +#if defined _MSC_VER && _MSC_VER < 1300 + typedef is_same< + typename BasePolicy_::result_converter + , default_result_converter + > same_result_converter; + //see above for explanation + BOOST_STATIC_ASSERT(same_result_converter::value) ; +#else + BOOST_MPL_ASSERT_MSG( + (is_same< + typename BasePolicy_::result_converter + , default_result_converter + >::value) + , MAKE_CONSTRUCTOR_SUPPLIES_ITS_OWN_RESULT_CONVERTER_THAT_WOULD_OVERRIDE_YOURS + , (typename BasePolicy_::result_converter) + ); +#endif + typedef constructor_result_converter result_converter; + typedef offset_args > argument_package; + }; + + template + struct outer_constructor_signature + { + typedef typename mpl::pop_front::type inner_args; + typedef typename mpl::push_front::type outer_args; + typedef typename mpl::push_front::type type; + }; + + // ETI workaround + template <> + struct outer_constructor_signature + { + typedef int type; + }; + + // + // These helper functions for make_constructor (below) do the raw work + // of constructing a Python object from some invokable entity. See + // for more information about how + // the Sig arguments is used. + // + // @group make_constructor_aux { + template + object make_constructor_aux( + F f // An object that can be invoked by detail::invoke() + , CallPolicies const& p // CallPolicies to use in the invocation + , Sig const& // An MPL sequence of argument types expected by F + ) + { + typedef typename outer_constructor_signature::type outer_signature; + + typedef constructor_policy inner_policy; + + return objects::function_object( + objects::py_function( + detail::caller(f, inner_policy(p)) + , outer_signature() + ) + ); + } + + // As above, except that it accepts argument keywords. NumKeywords + // is used only for a compile-time assertion to make sure the user + // doesn't pass more keywords than the function can accept. To + // disable all checking, pass mpl::int_<0> for NumKeywords. + template + object make_constructor_aux( + F f + , CallPolicies const& p + , Sig const& + , detail::keyword_range const& kw // a [begin,end) pair of iterators over keyword names + , NumKeywords // An MPL integral type wrapper: the size of kw + ) + { + enum { arity = mpl::size::value - 1 }; + + typedef typename detail::error::more_keywords_than_function_arguments< + NumKeywords::value, arity + >::too_many_keywords assertion; + + typedef typename outer_constructor_signature::type outer_signature; + + typedef constructor_policy inner_policy; + + return objects::function_object( + objects::py_function( + detail::caller(f, inner_policy(p)) + , outer_signature() + ) + , kw + ); + } + // } + + // + // These dispatch functions are used to discriminate between the + // cases when the 3rd argument is keywords or when it is a + // signature. + // + // @group Helpers for make_constructor when called with 3 arguments. { + // + template + object make_constructor_dispatch(F f, CallPolicies const& policies, Keywords const& kw, mpl::true_) + { + return detail::make_constructor_aux( + f + , policies + , detail::get_signature(f) + , kw.range() + , mpl::int_() + ); + } + + template + object make_constructor_dispatch(F f, CallPolicies const& policies, Signature const& sig, mpl::false_) + { + return detail::make_constructor_aux( + f + , policies + , sig + ); + } + // } +} + +// These overloaded functions wrap a function or member function +// pointer as a Python object, using optional CallPolicies, +// Keywords, and/or Signature. @group { +// +template +object make_constructor(F f) +{ + return detail::make_constructor_aux( + f,default_call_policies(), detail::get_signature(f)); +} + +template +object make_constructor(F f, CallPolicies const& policies) +{ + return detail::make_constructor_aux( + f, policies, detail::get_signature(f)); +} + +template +object make_constructor( + F f + , CallPolicies const& policies + , KeywordsOrSignature const& keywords_or_signature) +{ + typedef typename + detail::is_reference_to_keywords::type + is_kw; + + return detail::make_constructor_dispatch( + f + , policies + , keywords_or_signature + , is_kw() + ); +} + +template +object make_constructor( + F f + , CallPolicies const& policies + , Keywords const& kw + , Signature const& sig + ) +{ + return detail::make_constructor_aux( + f + , policies + , sig + , kw.range() + , mpl::int_() + ); +} +// } + +}} + + +#endif // MAKE_CONSTRUCTOR_DWA20011221_HPP diff --git a/src/external/3rd/library/boost/boost/python/object/py_function.hpp b/src/external/3rd/library/boost/boost/python/object/py_function.hpp index fec0fc357..9b85dd269 100644 --- a/src/external/3rd/library/boost/boost/python/object/py_function.hpp +++ b/src/external/3rd/library/boost/boost/python/object/py_function.hpp @@ -1,172 +1,172 @@ -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef PY_FUNCTION_DWA200286_HPP -# define PY_FUNCTION_DWA200286_HPP - -# include -# include -# include -# include - -namespace boost { namespace python { namespace objects { - -// This type is used as a "generalized Python callback", wrapping the -// function signature: -// -// PyObject* (PyObject* args, PyObject* keywords) - -struct BOOST_PYTHON_DECL py_function_impl_base -{ - virtual ~py_function_impl_base(); - virtual PyObject* operator()(PyObject*, PyObject*) = 0; - virtual unsigned min_arity() const = 0; - virtual unsigned max_arity() const; - virtual python::detail::py_func_sig_info signature() const = 0; -}; - -template -struct caller_py_function_impl : py_function_impl_base -{ - caller_py_function_impl(Caller const& caller) - : m_caller(caller) - {} - - PyObject* operator()(PyObject* args, PyObject* kw) - { - return m_caller(args, kw); - } - - virtual unsigned min_arity() const - { - return m_caller.min_arity(); - } - - virtual python::detail::py_func_sig_info signature() const - { - return m_caller.signature(); - } - - private: - Caller m_caller; -}; - -template -struct signature_py_function_impl : py_function_impl_base -{ - signature_py_function_impl(Caller const& caller) - : m_caller(caller) - {} - - PyObject* operator()(PyObject* args, PyObject* kw) - { - return m_caller(args, kw); - } - - virtual unsigned min_arity() const - { - return mpl::size::value - 1; - } - - virtual python::detail::py_func_sig_info signature() const - { - python::detail::signature_element const* sig = python::detail::signature::elements(); - python::detail::py_func_sig_info res = {sig, sig}; - return res; - } - - private: - Caller m_caller; -}; - -template -struct full_py_function_impl : py_function_impl_base -{ - full_py_function_impl(Caller const& caller, unsigned min_arity, unsigned max_arity) - : m_caller(caller) - , m_min_arity(min_arity) - , m_max_arity(max_arity > min_arity ? max_arity : min_arity) - {} - - PyObject* operator()(PyObject* args, PyObject* kw) - { - return m_caller(args, kw); - } - - virtual unsigned min_arity() const - { - return m_min_arity; - } - - virtual unsigned max_arity() const - { - return m_max_arity; - } - - virtual python::detail::py_func_sig_info signature() const - { - python::detail::signature_element const* sig = python::detail::signature::elements(); - python::detail::py_func_sig_info res = {sig, sig}; - return res; - } - - private: - Caller m_caller; - unsigned m_min_arity; - unsigned m_max_arity; -}; - -struct py_function -{ - template - py_function(Caller const& caller) - : m_impl(new caller_py_function_impl(caller)) - {} - - template - py_function(Caller const& caller, Sig) - : m_impl(new signature_py_function_impl(caller)) - {} - - template - py_function(Caller const& caller, Sig, int min_arity, int max_arity = 0) - : m_impl(new full_py_function_impl(caller, min_arity, max_arity)) - {} - - py_function(py_function const& rhs) - : m_impl(rhs.m_impl) - {} - - PyObject* operator()(PyObject* args, PyObject* kw) const - { - return (*m_impl)(args, kw); - } - - unsigned min_arity() const - { - return m_impl->min_arity(); - } - - unsigned max_arity() const - { - return m_impl->max_arity(); - } - - python::detail::signature_element const* signature() const - { - return m_impl->signature().signature; - } - - python::detail::signature_element const& get_return_type() const - { - return *m_impl->signature().ret; - } - - private: - mutable std::unique_ptr m_impl; -}; - -}}} // namespace boost::python::objects - -#endif // PY_FUNCTION_DWA200286_HPP +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef PY_FUNCTION_DWA200286_HPP +# define PY_FUNCTION_DWA200286_HPP + +# include +# include +# include +# include + +namespace boost { namespace python { namespace objects { + +// This type is used as a "generalized Python callback", wrapping the +// function signature: +// +// PyObject* (PyObject* args, PyObject* keywords) + +struct BOOST_PYTHON_DECL py_function_impl_base +{ + virtual ~py_function_impl_base(); + virtual PyObject* operator()(PyObject*, PyObject*) = 0; + virtual unsigned min_arity() const = 0; + virtual unsigned max_arity() const; + virtual python::detail::py_func_sig_info signature() const = 0; +}; + +template +struct caller_py_function_impl : py_function_impl_base +{ + caller_py_function_impl(Caller const& caller) + : m_caller(caller) + {} + + PyObject* operator()(PyObject* args, PyObject* kw) + { + return m_caller(args, kw); + } + + virtual unsigned min_arity() const + { + return m_caller.min_arity(); + } + + virtual python::detail::py_func_sig_info signature() const + { + return m_caller.signature(); + } + + private: + Caller m_caller; +}; + +template +struct signature_py_function_impl : py_function_impl_base +{ + signature_py_function_impl(Caller const& caller) + : m_caller(caller) + {} + + PyObject* operator()(PyObject* args, PyObject* kw) + { + return m_caller(args, kw); + } + + virtual unsigned min_arity() const + { + return mpl::size::value - 1; + } + + virtual python::detail::py_func_sig_info signature() const + { + python::detail::signature_element const* sig = python::detail::signature::elements(); + python::detail::py_func_sig_info res = {sig, sig}; + return res; + } + + private: + Caller m_caller; +}; + +template +struct full_py_function_impl : py_function_impl_base +{ + full_py_function_impl(Caller const& caller, unsigned min_arity, unsigned max_arity) + : m_caller(caller) + , m_min_arity(min_arity) + , m_max_arity(max_arity > min_arity ? max_arity : min_arity) + {} + + PyObject* operator()(PyObject* args, PyObject* kw) + { + return m_caller(args, kw); + } + + virtual unsigned min_arity() const + { + return m_min_arity; + } + + virtual unsigned max_arity() const + { + return m_max_arity; + } + + virtual python::detail::py_func_sig_info signature() const + { + python::detail::signature_element const* sig = python::detail::signature::elements(); + python::detail::py_func_sig_info res = {sig, sig}; + return res; + } + + private: + Caller m_caller; + unsigned m_min_arity; + unsigned m_max_arity; +}; + +struct py_function +{ + template + py_function(Caller const& caller) + : m_impl(new caller_py_function_impl(caller)) + {} + + template + py_function(Caller const& caller, Sig) + : m_impl(new signature_py_function_impl(caller)) + {} + + template + py_function(Caller const& caller, Sig, int min_arity, int max_arity = 0) + : m_impl(new full_py_function_impl(caller, min_arity, max_arity)) + {} + + py_function(py_function const& rhs) + : m_impl(rhs.m_impl) + {} + + PyObject* operator()(PyObject* args, PyObject* kw) const + { + return (*m_impl)(args, kw); + } + + unsigned min_arity() const + { + return m_impl->min_arity(); + } + + unsigned max_arity() const + { + return m_impl->max_arity(); + } + + python::detail::signature_element const* signature() const + { + return m_impl->signature().signature; + } + + python::detail::signature_element const& get_return_type() const + { + return *m_impl->signature().ret; + } + + private: + mutable std::unique_ptr m_impl; +}; + +}}} // namespace boost::python::objects + +#endif // PY_FUNCTION_DWA200286_HPP diff --git a/src/external/3rd/library/boost/boost/python/to_python_indirect.hpp b/src/external/3rd/library/boost/boost/python/to_python_indirect.hpp index dd5fb1e51..10775021d 100644 --- a/src/external/3rd/library/boost/boost/python/to_python_indirect.hpp +++ b/src/external/3rd/library/boost/boost/python/to_python_indirect.hpp @@ -1,113 +1,113 @@ -// Copyright David Abrahams 2002. -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef TO_PYTHON_INDIRECT_DWA200221_HPP -# define TO_PYTHON_INDIRECT_DWA200221_HPP - -# include - -# include -# include - -# include - -#ifndef BOOST_PYTHON_NO_PY_SIGNATURES -# include -#endif - -# include - -# include -# include - -# include - -# if defined(__ICL) && __ICL < 600 -# include -# else -# include -# endif - -namespace boost { namespace python { - -template -struct to_python_indirect -{ - template - inline PyObject* - operator()(U const& ref) const - { - return this->execute(const_cast(ref), is_pointer()); - } -#ifndef BOOST_PYTHON_NO_PY_SIGNATURES - inline PyTypeObject const* - get_pytype()const - { - return converter::registered_pytype::get_pytype(); - } -#endif - private: - template - inline PyObject* execute(U* ptr, mpl::true_) const - { - // No special NULL treatment for references - if (ptr == 0) - return python::detail::none(); - else - return this->execute(*ptr, mpl::false_()); - } - - template - inline PyObject* execute(U const& x, mpl::false_) const - { - U* const p = &const_cast(x); - if (is_polymorphic::value) - { - if (PyObject* o = detail::wrapper_base_::owner(p)) - return incref(o); - } - return MakeHolder::execute(p); - } -}; - -// -// implementations -// -namespace detail -{ - struct make_owning_holder - { - template - static PyObject* execute(T* p) - { - // can't use unique_ptr with Intel 5 and VC6 Dinkum library - // for some reason. We get link errors against the unique_ptr - // copy constructor. -# if defined(__ICL) && __ICL < 600 - typedef boost::shared_ptr smart_pointer; -# else - typedef std::unique_ptr smart_pointer; -# endif - typedef objects::pointer_holder holder_t; - - smart_pointer ptr(const_cast(p)); - return objects::make_ptr_instance::execute(ptr); - } - }; - - struct make_reference_holder - { - template - static PyObject* execute(T* p) - { - typedef objects::pointer_holder holder_t; - T* q = const_cast(p); - return objects::make_ptr_instance::execute(q); - } - }; -} - -}} // namespace boost::python - -#endif // TO_PYTHON_INDIRECT_DWA200221_HPP +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef TO_PYTHON_INDIRECT_DWA200221_HPP +# define TO_PYTHON_INDIRECT_DWA200221_HPP + +# include + +# include +# include + +# include + +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES +# include +#endif + +# include + +# include +# include + +# include + +# if defined(__ICL) && __ICL < 600 +# include +# else +# include +# endif + +namespace boost { namespace python { + +template +struct to_python_indirect +{ + template + inline PyObject* + operator()(U const& ref) const + { + return this->execute(const_cast(ref), is_pointer()); + } +#ifndef BOOST_PYTHON_NO_PY_SIGNATURES + inline PyTypeObject const* + get_pytype()const + { + return converter::registered_pytype::get_pytype(); + } +#endif + private: + template + inline PyObject* execute(U* ptr, mpl::true_) const + { + // No special NULL treatment for references + if (ptr == 0) + return python::detail::none(); + else + return this->execute(*ptr, mpl::false_()); + } + + template + inline PyObject* execute(U const& x, mpl::false_) const + { + U* const p = &const_cast(x); + if (is_polymorphic::value) + { + if (PyObject* o = detail::wrapper_base_::owner(p)) + return incref(o); + } + return MakeHolder::execute(p); + } +}; + +// +// implementations +// +namespace detail +{ + struct make_owning_holder + { + template + static PyObject* execute(T* p) + { + // can't use unique_ptr with Intel 5 and VC6 Dinkum library + // for some reason. We get link errors against the unique_ptr + // copy constructor. +# if defined(__ICL) && __ICL < 600 + typedef boost::shared_ptr smart_pointer; +# else + typedef std::unique_ptr smart_pointer; +# endif + typedef objects::pointer_holder holder_t; + + smart_pointer ptr(const_cast(p)); + return objects::make_ptr_instance::execute(ptr); + } + }; + + struct make_reference_holder + { + template + static PyObject* execute(T* p) + { + typedef objects::pointer_holder holder_t; + T* q = const_cast(p); + return objects::make_ptr_instance::execute(q); + } + }; +} + +}} // namespace boost::python + +#endif // TO_PYTHON_INDIRECT_DWA200221_HPP diff --git a/src/external/3rd/library/boost/boost/serialization/detail/shared_count_132.hpp b/src/external/3rd/library/boost/boost/serialization/detail/shared_count_132.hpp index 1f6b37ed9..39d2dd97d 100644 --- a/src/external/3rd/library/boost/boost/serialization/detail/shared_count_132.hpp +++ b/src/external/3rd/library/boost/boost/serialization/detail/shared_count_132.hpp @@ -1,569 +1,569 @@ -#ifndef BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED -#define BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED - -// MS compatible compilers support #pragma once - -#if defined(_MSC_VER) -# pragma once -#endif - -// -// detail/shared_count.hpp -// -// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// - -#include - -#if defined(BOOST_SP_USE_STD_ALLOCATOR) && defined(BOOST_SP_USE_QUICK_ALLOCATOR) -# error BOOST_SP_USE_STD_ALLOCATOR and BOOST_SP_USE_QUICK_ALLOCATOR are incompatible. -#endif - -#include -#include -#include - -#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) -#include -#endif - -#include // std::unique_ptr, std::allocator -#include // std::less -#include // std::exception -#include // std::bad_alloc -#include // std::type_info in get_deleter -#include // std::size_t - -#include // msvc 6.0 needs this for warning suppression -#if defined(BOOST_NO_STDC_NAMESPACE) -namespace std{ - using ::size_t; -} // namespace std -#endif - -#ifdef __BORLANDC__ -# pragma warn -8026 // Functions with excep. spec. are not expanded inline -# pragma warn -8027 // Functions containing try are not expanded inline -#endif - -namespace boost_132 { - -// Debug hooks - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - -void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn); -void sp_array_constructor_hook(void * px); -void sp_scalar_destructor_hook(void * px, std::size_t size, void * pn); -void sp_array_destructor_hook(void * px); - -#endif - - -// The standard library that comes with Borland C++ 5.5.1 -// defines std::exception and its members as having C calling -// convention (-pc). When the definition of bad_weak_ptr -// is compiled with -ps, the compiler issues an error. -// Hence, the temporary #pragma option -pc below. The version -// check is deliberately conservative. - -#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 -# pragma option push -pc -#endif - -class bad_weak_ptr: public std::exception -{ -public: - - virtual char const * what() const throw() - { - return "boost::bad_weak_ptr"; - } -}; - -#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 -# pragma option pop -#endif - -namespace detail{ - -class sp_counted_base -{ -//private: - - typedef boost::detail::lightweight_mutex mutex_type; - -public: - - sp_counted_base(): use_count_(1), weak_count_(1) - { - } - - virtual ~sp_counted_base() // nothrow - { - } - - // dispose() is called when use_count_ drops to zero, to release - // the resources managed by *this. - - virtual void dispose() = 0; // nothrow - - // destruct() is called when weak_count_ drops to zero. - - virtual void destruct() // nothrow - { - delete this; - } - - virtual void * get_deleter(std::type_info const & ti) = 0; - - void add_ref_copy() - { -#if defined(BOOST_HAS_THREADS) - mutex_type::scoped_lock lock(mtx_); -#endif - ++use_count_; - } - - void add_ref_lock() - { -#if defined(BOOST_HAS_THREADS) - mutex_type::scoped_lock lock(mtx_); -#endif - if(use_count_ == 0) boost::serialization::throw_exception(bad_weak_ptr()); - ++use_count_; - } - - void release() // nothrow - { - { -#if defined(BOOST_HAS_THREADS) - mutex_type::scoped_lock lock(mtx_); -#endif - long new_use_count = --use_count_; - - if(new_use_count != 0) return; - } - - dispose(); - weak_release(); - } - - void weak_add_ref() // nothrow - { -#if defined(BOOST_HAS_THREADS) - mutex_type::scoped_lock lock(mtx_); -#endif - ++weak_count_; - } - - void weak_release() // nothrow - { - long new_weak_count; - - { -#if defined(BOOST_HAS_THREADS) - mutex_type::scoped_lock lock(mtx_); -#endif - new_weak_count = --weak_count_; - } - - if(new_weak_count == 0) - { - destruct(); - } - } - - long use_count() const // nothrow - { -#if defined(BOOST_HAS_THREADS) - mutex_type::scoped_lock lock(mtx_); -#endif - return use_count_; - } - -//private: -public: - sp_counted_base(sp_counted_base const &); - sp_counted_base & operator= (sp_counted_base const &); - - long use_count_; // #shared - long weak_count_; // #weak + (#shared != 0) - -#if defined(BOOST_HAS_THREADS) || defined(BOOST_LWM_WIN32) - mutable mutex_type mtx_; -#endif -}; - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - -template void cbi_call_constructor_hook(sp_counted_base * pn, T * px, boost::checked_deleter< T > const &, int) -{ - boost::sp_scalar_constructor_hook(px, sizeof(T), pn); -} - -template void cbi_call_constructor_hook(sp_counted_base *, T * px, boost::checked_array_deleter< T > const &, int) -{ - boost::sp_array_constructor_hook(px); -} - -template void cbi_call_constructor_hook(sp_counted_base *, P const &, D const &, long) -{ -} - -template void cbi_call_destructor_hook(sp_counted_base * pn, T * px, boost::checked_deleter< T > const &, int) -{ - boost::sp_scalar_destructor_hook(px, sizeof(T), pn); -} - -template void cbi_call_destructor_hook(sp_counted_base *, T * px, boost::checked_array_deleter< T > const &, int) -{ - boost::sp_array_destructor_hook(px); -} - -template void cbi_call_destructor_hook(sp_counted_base *, P const &, D const &, long) -{ -} - -#endif - -// -// Borland's Codeguard trips up over the -Vx- option here: -// -#ifdef __CODEGUARD__ -# pragma option push -Vx- -#endif - -template class sp_counted_base_impl: public sp_counted_base -{ -//private: -public: - P ptr; // copy constructor must not throw - D del; // copy constructor must not throw - - sp_counted_base_impl(sp_counted_base_impl const &); - sp_counted_base_impl & operator= (sp_counted_base_impl const &); - - typedef sp_counted_base_impl this_type; - -public: - - // pre: initial_use_count <= initial_weak_count, d(p) must not throw - - sp_counted_base_impl(P p, D d): ptr(p), del(d) - { -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - detail::cbi_call_constructor_hook(this, p, d, 0); -#endif - } - - virtual void dispose() // nothrow - { -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - detail::cbi_call_destructor_hook(this, ptr, del, 0); -#endif - del(ptr); - } - - virtual void * get_deleter(std::type_info const & ti) - { - return ti == typeid(D)? &del: 0; - } - -#if defined(BOOST_SP_USE_STD_ALLOCATOR) - - void * operator new(std::size_t) - { - return std::allocator().allocate(1, static_cast(0)); - } - - void operator delete(void * p) - { - std::allocator().deallocate(static_cast(p), 1); - } - -#endif - -#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) - - void * operator new(std::size_t) - { - return boost::detail::quick_allocator::alloc(); - } - - void operator delete(void * p) - { - boost::detail::quick_allocator::dealloc(p); - } - -#endif -}; - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - -int const shared_count_id = 0x2C35F101; -int const weak_count_id = 0x298C38A4; - -#endif - -class weak_count; - -class shared_count -{ -//private: -public: - sp_counted_base * pi_; - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - int id_; -#endif - - friend class weak_count; - -public: - - shared_count(): pi_(0) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - } - - template shared_count(P p, D d): pi_(0) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { -#ifndef BOOST_NO_EXCEPTIONS - - try - { - pi_ = new sp_counted_base_impl(p, d); - } - catch(...) - { - d(p); // delete p - throw; - } - -#else - - pi_ = new sp_counted_base_impl(p, d); - - if(pi_ == 0) - { - d(p); // delete p - boost::serialization::throw_exception(std::bad_alloc()); - } - -#endif - } - -#ifndef BOOST_NO_AUTO_PTR - - // unique_ptr is special cased to provide the strong guarantee - - template - explicit shared_count(std::unique_ptr & r): pi_( - new sp_counted_base_impl< - Y *, - boost::checked_deleter - >(r.get(), boost::checked_deleter())) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - r.release(); - } - -#endif - - ~shared_count() // nothrow - { - if(pi_ != 0) pi_->release(); -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - id_ = 0; -#endif - } - - shared_count(shared_count const & r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - if(pi_ != 0) pi_->add_ref_copy(); - } - - explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 - - shared_count & operator= (shared_count const & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - - if(tmp != pi_) - { - if(tmp != 0) tmp->add_ref_copy(); - if(pi_ != 0) pi_->release(); - pi_ = tmp; - } - - return *this; - } - - void swap(shared_count & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - r.pi_ = pi_; - pi_ = tmp; - } - - long use_count() const // nothrow - { - return pi_ != 0? pi_->use_count(): 0; - } - - bool unique() const // nothrow - { - return use_count() == 1; - } - - friend inline bool operator==(shared_count const & a, shared_count const & b) - { - return a.pi_ == b.pi_; - } - - friend inline bool operator<(shared_count const & a, shared_count const & b) - { - return std::less()(a.pi_, b.pi_); - } - - void * get_deleter(std::type_info const & ti) const - { - return pi_? pi_->get_deleter(ti): 0; - } -}; - -#ifdef __CODEGUARD__ -# pragma option pop -#endif - - -class weak_count -{ -private: - - sp_counted_base * pi_; - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - int id_; -#endif - - friend class shared_count; - -public: - - weak_count(): pi_(0) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(weak_count_id) -#endif - { - } - - weak_count(shared_count const & r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - if(pi_ != 0) pi_->weak_add_ref(); - } - - weak_count(weak_count const & r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - if(pi_ != 0) pi_->weak_add_ref(); - } - - ~weak_count() // nothrow - { - if(pi_ != 0) pi_->weak_release(); -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - id_ = 0; -#endif - } - - weak_count & operator= (shared_count const & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - if(tmp != 0) tmp->weak_add_ref(); - if(pi_ != 0) pi_->weak_release(); - pi_ = tmp; - - return *this; - } - - weak_count & operator= (weak_count const & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - if(tmp != 0) tmp->weak_add_ref(); - if(pi_ != 0) pi_->weak_release(); - pi_ = tmp; - - return *this; - } - - void swap(weak_count & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - r.pi_ = pi_; - pi_ = tmp; - } - - long use_count() const // nothrow - { - return pi_ != 0? pi_->use_count(): 0; - } - - friend inline bool operator==(weak_count const & a, weak_count const & b) - { - return a.pi_ == b.pi_; - } - - friend inline bool operator<(weak_count const & a, weak_count const & b) - { - return std::less()(a.pi_, b.pi_); - } -}; - -inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif -{ - if(pi_ != 0) - { - pi_->add_ref_lock(); - } - else - { - boost::serialization::throw_exception(bad_weak_ptr()); - } -} - -} // namespace detail - -} // namespace boost - -BOOST_SERIALIZATION_ASSUME_ABSTRACT(boost_132::detail::sp_counted_base) - -#ifdef __BORLANDC__ -# pragma warn .8027 // Functions containing try are not expanded inline -# pragma warn .8026 // Functions with excep. spec. are not expanded inline -#endif - -#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED +#ifndef BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED +#define BOOST_DETAIL_SHARED_COUNT_132_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) +# pragma once +#endif + +// +// detail/shared_count.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include + +#if defined(BOOST_SP_USE_STD_ALLOCATOR) && defined(BOOST_SP_USE_QUICK_ALLOCATOR) +# error BOOST_SP_USE_STD_ALLOCATOR and BOOST_SP_USE_QUICK_ALLOCATOR are incompatible. +#endif + +#include +#include +#include + +#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) +#include +#endif + +#include // std::unique_ptr, std::allocator +#include // std::less +#include // std::exception +#include // std::bad_alloc +#include // std::type_info in get_deleter +#include // std::size_t + +#include // msvc 6.0 needs this for warning suppression +#if defined(BOOST_NO_STDC_NAMESPACE) +namespace std{ + using ::size_t; +} // namespace std +#endif + +#ifdef __BORLANDC__ +# pragma warn -8026 // Functions with excep. spec. are not expanded inline +# pragma warn -8027 // Functions containing try are not expanded inline +#endif + +namespace boost_132 { + +// Debug hooks + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn); +void sp_array_constructor_hook(void * px); +void sp_scalar_destructor_hook(void * px, std::size_t size, void * pn); +void sp_array_destructor_hook(void * px); + +#endif + + +// The standard library that comes with Borland C++ 5.5.1 +// defines std::exception and its members as having C calling +// convention (-pc). When the definition of bad_weak_ptr +// is compiled with -ps, the compiler issues an error. +// Hence, the temporary #pragma option -pc below. The version +// check is deliberately conservative. + +#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 +# pragma option push -pc +#endif + +class bad_weak_ptr: public std::exception +{ +public: + + virtual char const * what() const throw() + { + return "boost::bad_weak_ptr"; + } +}; + +#if defined(__BORLANDC__) && __BORLANDC__ == 0x551 +# pragma option pop +#endif + +namespace detail{ + +class sp_counted_base +{ +//private: + + typedef boost::detail::lightweight_mutex mutex_type; + +public: + + sp_counted_base(): use_count_(1), weak_count_(1) + { + } + + virtual ~sp_counted_base() // nothrow + { + } + + // dispose() is called when use_count_ drops to zero, to release + // the resources managed by *this. + + virtual void dispose() = 0; // nothrow + + // destruct() is called when weak_count_ drops to zero. + + virtual void destruct() // nothrow + { + delete this; + } + + virtual void * get_deleter(std::type_info const & ti) = 0; + + void add_ref_copy() + { +#if defined(BOOST_HAS_THREADS) + mutex_type::scoped_lock lock(mtx_); +#endif + ++use_count_; + } + + void add_ref_lock() + { +#if defined(BOOST_HAS_THREADS) + mutex_type::scoped_lock lock(mtx_); +#endif + if(use_count_ == 0) boost::serialization::throw_exception(bad_weak_ptr()); + ++use_count_; + } + + void release() // nothrow + { + { +#if defined(BOOST_HAS_THREADS) + mutex_type::scoped_lock lock(mtx_); +#endif + long new_use_count = --use_count_; + + if(new_use_count != 0) return; + } + + dispose(); + weak_release(); + } + + void weak_add_ref() // nothrow + { +#if defined(BOOST_HAS_THREADS) + mutex_type::scoped_lock lock(mtx_); +#endif + ++weak_count_; + } + + void weak_release() // nothrow + { + long new_weak_count; + + { +#if defined(BOOST_HAS_THREADS) + mutex_type::scoped_lock lock(mtx_); +#endif + new_weak_count = --weak_count_; + } + + if(new_weak_count == 0) + { + destruct(); + } + } + + long use_count() const // nothrow + { +#if defined(BOOST_HAS_THREADS) + mutex_type::scoped_lock lock(mtx_); +#endif + return use_count_; + } + +//private: +public: + sp_counted_base(sp_counted_base const &); + sp_counted_base & operator= (sp_counted_base const &); + + long use_count_; // #shared + long weak_count_; // #weak + (#shared != 0) + +#if defined(BOOST_HAS_THREADS) || defined(BOOST_LWM_WIN32) + mutable mutex_type mtx_; +#endif +}; + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +template void cbi_call_constructor_hook(sp_counted_base * pn, T * px, boost::checked_deleter< T > const &, int) +{ + boost::sp_scalar_constructor_hook(px, sizeof(T), pn); +} + +template void cbi_call_constructor_hook(sp_counted_base *, T * px, boost::checked_array_deleter< T > const &, int) +{ + boost::sp_array_constructor_hook(px); +} + +template void cbi_call_constructor_hook(sp_counted_base *, P const &, D const &, long) +{ +} + +template void cbi_call_destructor_hook(sp_counted_base * pn, T * px, boost::checked_deleter< T > const &, int) +{ + boost::sp_scalar_destructor_hook(px, sizeof(T), pn); +} + +template void cbi_call_destructor_hook(sp_counted_base *, T * px, boost::checked_array_deleter< T > const &, int) +{ + boost::sp_array_destructor_hook(px); +} + +template void cbi_call_destructor_hook(sp_counted_base *, P const &, D const &, long) +{ +} + +#endif + +// +// Borland's Codeguard trips up over the -Vx- option here: +// +#ifdef __CODEGUARD__ +# pragma option push -Vx- +#endif + +template class sp_counted_base_impl: public sp_counted_base +{ +//private: +public: + P ptr; // copy constructor must not throw + D del; // copy constructor must not throw + + sp_counted_base_impl(sp_counted_base_impl const &); + sp_counted_base_impl & operator= (sp_counted_base_impl const &); + + typedef sp_counted_base_impl this_type; + +public: + + // pre: initial_use_count <= initial_weak_count, d(p) must not throw + + sp_counted_base_impl(P p, D d): ptr(p), del(d) + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + detail::cbi_call_constructor_hook(this, p, d, 0); +#endif + } + + virtual void dispose() // nothrow + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + detail::cbi_call_destructor_hook(this, ptr, del, 0); +#endif + del(ptr); + } + + virtual void * get_deleter(std::type_info const & ti) + { + return ti == typeid(D)? &del: 0; + } + +#if defined(BOOST_SP_USE_STD_ALLOCATOR) + + void * operator new(std::size_t) + { + return std::allocator().allocate(1, static_cast(0)); + } + + void operator delete(void * p) + { + std::allocator().deallocate(static_cast(p), 1); + } + +#endif + +#if defined(BOOST_SP_USE_QUICK_ALLOCATOR) + + void * operator new(std::size_t) + { + return boost::detail::quick_allocator::alloc(); + } + + void operator delete(void * p) + { + boost::detail::quick_allocator::dealloc(p); + } + +#endif +}; + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +int const shared_count_id = 0x2C35F101; +int const weak_count_id = 0x298C38A4; + +#endif + +class weak_count; + +class shared_count +{ +//private: +public: + sp_counted_base * pi_; + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + int id_; +#endif + + friend class weak_count; + +public: + + shared_count(): pi_(0) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + } + + template shared_count(P p, D d): pi_(0) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#ifndef BOOST_NO_EXCEPTIONS + + try + { + pi_ = new sp_counted_base_impl(p, d); + } + catch(...) + { + d(p); // delete p + throw; + } + +#else + + pi_ = new sp_counted_base_impl(p, d); + + if(pi_ == 0) + { + d(p); // delete p + boost::serialization::throw_exception(std::bad_alloc()); + } + +#endif + } + +#ifndef BOOST_NO_AUTO_PTR + + // unique_ptr is special cased to provide the strong guarantee + + template + explicit shared_count(std::unique_ptr & r): pi_( + new sp_counted_base_impl< + Y *, + boost::checked_deleter + >(r.get(), boost::checked_deleter())) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + r.release(); + } + +#endif + + ~shared_count() // nothrow + { + if(pi_ != 0) pi_->release(); +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + id_ = 0; +#endif + } + + shared_count(shared_count const & r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + if(pi_ != 0) pi_->add_ref_copy(); + } + + explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 + + shared_count & operator= (shared_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + + if(tmp != pi_) + { + if(tmp != 0) tmp->add_ref_copy(); + if(pi_ != 0) pi_->release(); + pi_ = tmp; + } + + return *this; + } + + void swap(shared_count & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_ != 0? pi_->use_count(): 0; + } + + bool unique() const // nothrow + { + return use_count() == 1; + } + + friend inline bool operator==(shared_count const & a, shared_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(shared_count const & a, shared_count const & b) + { + return std::less()(a.pi_, b.pi_); + } + + void * get_deleter(std::type_info const & ti) const + { + return pi_? pi_->get_deleter(ti): 0; + } +}; + +#ifdef __CODEGUARD__ +# pragma option pop +#endif + + +class weak_count +{ +private: + + sp_counted_base * pi_; + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + int id_; +#endif + + friend class shared_count; + +public: + + weak_count(): pi_(0) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(weak_count_id) +#endif + { + } + + weak_count(shared_count const & r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + if(pi_ != 0) pi_->weak_add_ref(); + } + + weak_count(weak_count const & r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + if(pi_ != 0) pi_->weak_add_ref(); + } + + ~weak_count() // nothrow + { + if(pi_ != 0) pi_->weak_release(); +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + id_ = 0; +#endif + } + + weak_count & operator= (shared_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + if(tmp != 0) tmp->weak_add_ref(); + if(pi_ != 0) pi_->weak_release(); + pi_ = tmp; + + return *this; + } + + weak_count & operator= (weak_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + if(tmp != 0) tmp->weak_add_ref(); + if(pi_ != 0) pi_->weak_release(); + pi_ = tmp; + + return *this; + } + + void swap(weak_count & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_ != 0? pi_->use_count(): 0; + } + + friend inline bool operator==(weak_count const & a, weak_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(weak_count const & a, weak_count const & b) + { + return std::less()(a.pi_, b.pi_); + } +}; + +inline shared_count::shared_count(weak_count const & r): pi_(r.pi_) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif +{ + if(pi_ != 0) + { + pi_->add_ref_lock(); + } + else + { + boost::serialization::throw_exception(bad_weak_ptr()); + } +} + +} // namespace detail + +} // namespace boost + +BOOST_SERIALIZATION_ASSUME_ABSTRACT(boost_132::detail::sp_counted_base) + +#ifdef __BORLANDC__ +# pragma warn .8027 // Functions containing try are not expanded inline +# pragma warn .8026 // Functions with excep. spec. are not expanded inline +#endif + +#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_132.hpp b/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_132.hpp index de071fe46..5f3b8c24f 100644 --- a/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_132.hpp +++ b/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_132.hpp @@ -1,450 +1,450 @@ -#ifndef BOOST_SHARED_PTR_132_HPP_INCLUDED -#define BOOST_SHARED_PTR_132_HPP_INCLUDED - -// -// shared_ptr.hpp -// -// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. -// Copyright (c) 2001, 2002, 2003 Peter Dimov -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. -// - -#include // for broken compiler workarounds - -#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) -#include -#else - -#include -#include -#include -#include - -#include -#include - -#include // for std::unique_ptr -#include // for std::swap -#include // for std::less -#include // for std::bad_cast -#include // for std::basic_ostream - -#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash -# pragma warning(push) -# pragma warning(disable:4284) // odd return type for operator-> -#endif - -namespace boost_132 { - -template class weak_ptr; -template class enable_shared_from_this; - -namespace detail -{ - -struct static_cast_tag {}; -struct const_cast_tag {}; -struct dynamic_cast_tag {}; -struct polymorphic_cast_tag {}; - -template struct shared_ptr_traits -{ - typedef T & reference; -}; - -template<> struct shared_ptr_traits -{ - typedef void reference; -}; - -#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) - -template<> struct shared_ptr_traits -{ - typedef void reference; -}; - -template<> struct shared_ptr_traits -{ - typedef void reference; -}; - -template<> struct shared_ptr_traits -{ - typedef void reference; -}; - -#endif - -// enable_shared_from_this support - -template void sp_enable_shared_from_this( shared_count const & pn, enable_shared_from_this< T > const * pe, Y const * px ) -{ - if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast(px), pn); -} - -inline void sp_enable_shared_from_this( shared_count const & /*pn*/, ... ) -{ -} - -} // namespace detail - - -// -// shared_ptr -// -// An enhanced relative of scoped_ptr with reference counted copy semantics. -// The object pointed to is deleted when the last shared_ptr pointing to it -// is destroyed or reset. -// - -template class shared_ptr -{ -private: - // Borland 5.5.1 specific workaround - typedef shared_ptr< T > this_type; - -public: - - typedef T element_type; - typedef T value_type; - typedef T * pointer; - typedef typename detail::shared_ptr_traits< T >::reference reference; - - shared_ptr(): px(0), pn() // never throws in 1.30+ - { - } - -#if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x564) ) - template - explicit shared_ptr(Y * p): px(p), pn(p, boost::checked_deleter()) // Y must be complete -#else - template - explicit shared_ptr(Y * p): px(p), pn(p, boost::checked_deleter()) // Y must be complete -#endif - { - detail::sp_enable_shared_from_this( pn, p, p ); - } - - // - // Requirements: D's copy constructor must not throw - // - // shared_ptr will release p by calling d(p) - // - - template shared_ptr(Y * p, D d): px(p), pn(p, d) - { - detail::sp_enable_shared_from_this( pn, p, p ); - } - -// generated copy constructor, assignment, destructor are fine... - -// except that Borland C++ has a bug, and g++ with -Wsynth warns -#if defined(__BORLANDC__) || defined(__GNUC__) - - shared_ptr & operator=(shared_ptr const & r) // never throws - { - px = r.px; - pn = r.pn; // shared_count::op= doesn't throw - return *this; - } - -#endif - - template - explicit shared_ptr(weak_ptr const & r): pn(r.pn) // may throw - { - // it is now safe to copy r.px, as pn(r.pn) did not throw - px = r.px; - } - - template - shared_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws - { - } - - template - shared_ptr(shared_ptr const & r, detail::static_cast_tag): px(static_cast(r.px)), pn(r.pn) - { - } - - template - shared_ptr(shared_ptr const & r, detail::const_cast_tag): px(const_cast(r.px)), pn(r.pn) - { - } - - template - shared_ptr(shared_ptr const & r, detail::dynamic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) - { - if(px == 0) // need to allocate new counter -- the cast failed - { - pn = detail::shared_count(); - } - } - - template - shared_ptr(shared_ptr const & r, detail::polymorphic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) - { - if(px == 0) - { - boost::serialization::throw_exception(std::bad_cast()); - } - } - -#ifndef BOOST_NO_AUTO_PTR - - template - explicit shared_ptr(std::unique_ptr & r): px(r.get()), pn() - { - Y * tmp = r.get(); - pn = detail::shared_count(r); - detail::sp_enable_shared_from_this( pn, tmp, tmp ); - } - -#endif - -#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200) - - template - shared_ptr & operator=(shared_ptr const & r) // never throws - { - px = r.px; - pn = r.pn; // shared_count::op= doesn't throw - return *this; - } - -#endif - -#ifndef BOOST_NO_AUTO_PTR - - template - shared_ptr & operator=(std::unique_ptr & r) - { - this_type(r).swap(*this); - return *this; - } - -#endif - - void reset() // never throws in 1.30+ - { - this_type().swap(*this); - } - - template void reset(Y * p) // Y must be complete - { - BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors - this_type(p).swap(*this); - } - - template void reset(Y * p, D d) - { - this_type(p, d).swap(*this); - } - - reference operator* () const // never throws - { - BOOST_ASSERT(px != 0); - return *px; - } - - T * operator-> () const // never throws - { - BOOST_ASSERT(px != 0); - return px; - } - - T * get() const // never throws - { - return px; - } - - // implicit conversion to "bool" - -#if defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530) - - operator bool () const - { - return px != 0; - } - -#elif defined(__MWERKS__) && BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) - typedef T * (this_type::*unspecified_bool_type)() const; - - operator unspecified_bool_type() const // never throws - { - return px == 0? 0: &this_type::get; - } - -#else - - typedef T * this_type::*unspecified_bool_type; - - operator unspecified_bool_type() const // never throws - { - return px == 0? 0: &this_type::px; - } - -#endif - - // operator! is redundant, but some compilers need it - - bool operator! () const // never throws - { - return px == 0; - } - - bool unique() const // never throws - { - return pn.unique(); - } - - long use_count() const // never throws - { - return pn.use_count(); - } - - void swap(shared_ptr< T > & other) // never throws - { - std::swap(px, other.px); - pn.swap(other.pn); - } - - template bool _internal_less(shared_ptr const & rhs) const - { - return pn < rhs.pn; - } - - void * _internal_get_deleter(std::type_info const & ti) const - { - return pn.get_deleter(ti); - } - -// Tasteless as this may seem, making all members public allows member templates -// to work in the absence of member template friends. (Matthew Langston) - -#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS - -private: - - template friend class shared_ptr; - template friend class weak_ptr; - - -#endif -public: // for serialization - T * px; // contained pointer - detail::shared_count pn; // reference counter - -}; // shared_ptr - -template inline bool operator==(shared_ptr< T > const & a, shared_ptr const & b) -{ - return a.get() == b.get(); -} - -template inline bool operator!=(shared_ptr< T > const & a, shared_ptr const & b) -{ - return a.get() != b.get(); -} - -template inline bool operator<(shared_ptr< T > const & a, shared_ptr const & b) -{ - return a._internal_less(b); -} - -template inline void swap(shared_ptr< T > & a, shared_ptr< T > & b) -{ - a.swap(b); -} - -template shared_ptr< T > static_pointer_cast(shared_ptr const & r) -{ - return shared_ptr< T >(r, detail::static_cast_tag()); -} - -template shared_ptr< T > const_pointer_cast(shared_ptr const & r) -{ - return shared_ptr< T >(r, detail::const_cast_tag()); -} - -template shared_ptr< T > dynamic_pointer_cast(shared_ptr const & r) -{ - return shared_ptr< T >(r, detail::dynamic_cast_tag()); -} - -// shared_*_cast names are deprecated. Use *_pointer_cast instead. - -template shared_ptr< T > shared_static_cast(shared_ptr const & r) -{ - return shared_ptr< T >(r, detail::static_cast_tag()); -} - -template shared_ptr< T > shared_dynamic_cast(shared_ptr const & r) -{ - return shared_ptr< T >(r, detail::dynamic_cast_tag()); -} - -template shared_ptr< T > shared_polymorphic_cast(shared_ptr const & r) -{ - return shared_ptr< T >(r, detail::polymorphic_cast_tag()); -} - -template shared_ptr< T > shared_polymorphic_downcast(shared_ptr const & r) -{ - BOOST_ASSERT(dynamic_cast(r.get()) == r.get()); - return shared_static_cast< T >(r); -} - -// get_pointer() enables boost::mem_fn to recognize shared_ptr - -template inline T * get_pointer(shared_ptr< T > const & p) -{ - return p.get(); -} - -// operator<< - - -template std::basic_ostream & operator<< (std::basic_ostream & os, shared_ptr const & p) -{ - os << p.get(); - return os; -} - -// get_deleter (experimental) - -#if defined(__EDG_VERSION__) && (__EDG_VERSION__ <= 238) - -// g++ 2.9x doesn't allow static_cast(void *) -// apparently EDG 2.38 also doesn't accept it - -template D * get_deleter(shared_ptr< T > const & p) -{ - void const * q = p._internal_get_deleter(typeid(D)); - return const_cast(static_cast(q)); -} - -#else - -template D * get_deleter(shared_ptr< T > const & p) -{ - return static_cast(p._internal_get_deleter(typeid(D))); -} - -#endif - -} // namespace boost - -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif - -#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) - -#endif // #ifndef BOOST_SHARED_PTR_132_HPP_INCLUDED +#ifndef BOOST_SHARED_PTR_132_HPP_INCLUDED +#define BOOST_SHARED_PTR_132_HPP_INCLUDED + +// +// shared_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002, 2003 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include // for broken compiler workarounds + +#if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) +#include +#else + +#include +#include +#include +#include + +#include +#include + +#include // for std::unique_ptr +#include // for std::swap +#include // for std::less +#include // for std::bad_cast +#include // for std::basic_ostream + +#ifdef BOOST_MSVC // moved here to work around VC++ compiler crash +# pragma warning(push) +# pragma warning(disable:4284) // odd return type for operator-> +#endif + +namespace boost_132 { + +template class weak_ptr; +template class enable_shared_from_this; + +namespace detail +{ + +struct static_cast_tag {}; +struct const_cast_tag {}; +struct dynamic_cast_tag {}; +struct polymorphic_cast_tag {}; + +template struct shared_ptr_traits +{ + typedef T & reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +template<> struct shared_ptr_traits +{ + typedef void reference; +}; + +#endif + +// enable_shared_from_this support + +template void sp_enable_shared_from_this( shared_count const & pn, enable_shared_from_this< T > const * pe, Y const * px ) +{ + if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast(px), pn); +} + +inline void sp_enable_shared_from_this( shared_count const & /*pn*/, ... ) +{ +} + +} // namespace detail + + +// +// shared_ptr +// +// An enhanced relative of scoped_ptr with reference counted copy semantics. +// The object pointed to is deleted when the last shared_ptr pointing to it +// is destroyed or reset. +// + +template class shared_ptr +{ +private: + // Borland 5.5.1 specific workaround + typedef shared_ptr< T > this_type; + +public: + + typedef T element_type; + typedef T value_type; + typedef T * pointer; + typedef typename detail::shared_ptr_traits< T >::reference reference; + + shared_ptr(): px(0), pn() // never throws in 1.30+ + { + } + +#if BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x564) ) + template + explicit shared_ptr(Y * p): px(p), pn(p, boost::checked_deleter()) // Y must be complete +#else + template + explicit shared_ptr(Y * p): px(p), pn(p, boost::checked_deleter()) // Y must be complete +#endif + { + detail::sp_enable_shared_from_this( pn, p, p ); + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_ptr will release p by calling d(p) + // + + template shared_ptr(Y * p, D d): px(p), pn(p, d) + { + detail::sp_enable_shared_from_this( pn, p, p ); + } + +// generated copy constructor, assignment, destructor are fine... + +// except that Borland C++ has a bug, and g++ with -Wsynth warns +#if defined(__BORLANDC__) || defined(__GNUC__) + + shared_ptr & operator=(shared_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; // shared_count::op= doesn't throw + return *this; + } + +#endif + + template + explicit shared_ptr(weak_ptr const & r): pn(r.pn) // may throw + { + // it is now safe to copy r.px, as pn(r.pn) did not throw + px = r.px; + } + + template + shared_ptr(shared_ptr const & r): px(r.px), pn(r.pn) // never throws + { + } + + template + shared_ptr(shared_ptr const & r, detail::static_cast_tag): px(static_cast(r.px)), pn(r.pn) + { + } + + template + shared_ptr(shared_ptr const & r, detail::const_cast_tag): px(const_cast(r.px)), pn(r.pn) + { + } + + template + shared_ptr(shared_ptr const & r, detail::dynamic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if(px == 0) // need to allocate new counter -- the cast failed + { + pn = detail::shared_count(); + } + } + + template + shared_ptr(shared_ptr const & r, detail::polymorphic_cast_tag): px(dynamic_cast(r.px)), pn(r.pn) + { + if(px == 0) + { + boost::serialization::throw_exception(std::bad_cast()); + } + } + +#ifndef BOOST_NO_AUTO_PTR + + template + explicit shared_ptr(std::unique_ptr & r): px(r.get()), pn() + { + Y * tmp = r.get(); + pn = detail::shared_count(r); + detail::sp_enable_shared_from_this( pn, tmp, tmp ); + } + +#endif + +#if !defined(BOOST_MSVC) || (BOOST_MSVC > 1200) + + template + shared_ptr & operator=(shared_ptr const & r) // never throws + { + px = r.px; + pn = r.pn; // shared_count::op= doesn't throw + return *this; + } + +#endif + +#ifndef BOOST_NO_AUTO_PTR + + template + shared_ptr & operator=(std::unique_ptr & r) + { + this_type(r).swap(*this); + return *this; + } + +#endif + + void reset() // never throws in 1.30+ + { + this_type().swap(*this); + } + + template void reset(Y * p) // Y must be complete + { + BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors + this_type(p).swap(*this); + } + + template void reset(Y * p, D d) + { + this_type(p, d).swap(*this); + } + + reference operator* () const // never throws + { + BOOST_ASSERT(px != 0); + return *px; + } + + T * operator-> () const // never throws + { + BOOST_ASSERT(px != 0); + return px; + } + + T * get() const // never throws + { + return px; + } + + // implicit conversion to "bool" + +#if defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530) + + operator bool () const + { + return px != 0; + } + +#elif defined(__MWERKS__) && BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3003)) + typedef T * (this_type::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::get; + } + +#else + + typedef T * this_type::*unspecified_bool_type; + + operator unspecified_bool_type() const // never throws + { + return px == 0? 0: &this_type::px; + } + +#endif + + // operator! is redundant, but some compilers need it + + bool operator! () const // never throws + { + return px == 0; + } + + bool unique() const // never throws + { + return pn.unique(); + } + + long use_count() const // never throws + { + return pn.use_count(); + } + + void swap(shared_ptr< T > & other) // never throws + { + std::swap(px, other.px); + pn.swap(other.pn); + } + + template bool _internal_less(shared_ptr const & rhs) const + { + return pn < rhs.pn; + } + + void * _internal_get_deleter(std::type_info const & ti) const + { + return pn.get_deleter(ti); + } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + +private: + + template friend class shared_ptr; + template friend class weak_ptr; + + +#endif +public: // for serialization + T * px; // contained pointer + detail::shared_count pn; // reference counter + +}; // shared_ptr + +template inline bool operator==(shared_ptr< T > const & a, shared_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr< T > const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_ptr< T > const & a, shared_ptr const & b) +{ + return a._internal_less(b); +} + +template inline void swap(shared_ptr< T > & a, shared_ptr< T > & b) +{ + a.swap(b); +} + +template shared_ptr< T > static_pointer_cast(shared_ptr const & r) +{ + return shared_ptr< T >(r, detail::static_cast_tag()); +} + +template shared_ptr< T > const_pointer_cast(shared_ptr const & r) +{ + return shared_ptr< T >(r, detail::const_cast_tag()); +} + +template shared_ptr< T > dynamic_pointer_cast(shared_ptr const & r) +{ + return shared_ptr< T >(r, detail::dynamic_cast_tag()); +} + +// shared_*_cast names are deprecated. Use *_pointer_cast instead. + +template shared_ptr< T > shared_static_cast(shared_ptr const & r) +{ + return shared_ptr< T >(r, detail::static_cast_tag()); +} + +template shared_ptr< T > shared_dynamic_cast(shared_ptr const & r) +{ + return shared_ptr< T >(r, detail::dynamic_cast_tag()); +} + +template shared_ptr< T > shared_polymorphic_cast(shared_ptr const & r) +{ + return shared_ptr< T >(r, detail::polymorphic_cast_tag()); +} + +template shared_ptr< T > shared_polymorphic_downcast(shared_ptr const & r) +{ + BOOST_ASSERT(dynamic_cast(r.get()) == r.get()); + return shared_static_cast< T >(r); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline T * get_pointer(shared_ptr< T > const & p) +{ + return p.get(); +} + +// operator<< + + +template std::basic_ostream & operator<< (std::basic_ostream & os, shared_ptr const & p) +{ + os << p.get(); + return os; +} + +// get_deleter (experimental) + +#if defined(__EDG_VERSION__) && (__EDG_VERSION__ <= 238) + +// g++ 2.9x doesn't allow static_cast(void *) +// apparently EDG 2.38 also doesn't accept it + +template D * get_deleter(shared_ptr< T > const & p) +{ + void const * q = p._internal_get_deleter(typeid(D)); + return const_cast(static_cast(q)); +} + +#else + +template D * get_deleter(shared_ptr< T > const & p) +{ + return static_cast(p._internal_get_deleter(typeid(D))); +} + +#endif + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + +#endif // #if defined(BOOST_NO_MEMBER_TEMPLATES) && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) + +#endif // #ifndef BOOST_SHARED_PTR_132_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_nmt_132.hpp b/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_nmt_132.hpp index e4fca5196..b37a9253a 100644 --- a/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_nmt_132.hpp +++ b/src/external/3rd/library/boost/boost/serialization/detail/shared_ptr_nmt_132.hpp @@ -1,182 +1,182 @@ -#ifndef BOOST_DETAIL_SHARED_PTR_NMT_132_HPP_INCLUDED -#define BOOST_DETAIL_SHARED_PTR_NMT_132_HPP_INCLUDED - -// -// detail/shared_ptr_nmt.hpp - shared_ptr.hpp without member templates -// -// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. -// Copyright (c) 2001, 2002 Peter Dimov -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. -// - -#include -#include -#include -#include - -#ifndef BOOST_NO_AUTO_PTR -# include // for std::unique_ptr -#endif - -#include // for std::swap -#include // for std::less -#include // for std::bad_alloc - -namespace boost -{ - -template class shared_ptr -{ -private: - - typedef detail::atomic_count count_type; - -public: - - typedef T element_type; - typedef T value_type; - - explicit shared_ptr(T * p = 0): px(p) - { -#ifndef BOOST_NO_EXCEPTIONS - - try // prevent leak if new throws - { - pn = new count_type(1); - } - catch(...) - { - boost::checked_delete(p); - throw; - } - -#else - - pn = new count_type(1); - - if(pn == 0) - { - boost::checked_delete(p); - boost::serialization::throw_exception(std::bad_alloc()); - } - -#endif - } - - ~shared_ptr() - { - if(--*pn == 0) - { - boost::checked_delete(px); - delete pn; - } - } - - shared_ptr(shared_ptr const & r): px(r.px) // never throws - { - pn = r.pn; - ++*pn; - } - - shared_ptr & operator=(shared_ptr const & r) - { - shared_ptr(r).swap(*this); - return *this; - } - -#ifndef BOOST_NO_AUTO_PTR - - explicit shared_ptr(std::unique_ptr< T > & r) - { - pn = new count_type(1); // may throw - px = r.release(); // fix: moved here to stop leak if new throws - } - - shared_ptr & operator=(std::unique_ptr< T > & r) - { - shared_ptr(r).swap(*this); - return *this; - } - -#endif - - void reset(T * p = 0) - { - BOOST_ASSERT(p == 0 || p != px); - shared_ptr(p).swap(*this); - } - - T & operator*() const // never throws - { - BOOST_ASSERT(px != 0); - return *px; - } - - T * operator->() const // never throws - { - BOOST_ASSERT(px != 0); - return px; - } - - T * get() const // never throws - { - return px; - } - - long use_count() const // never throws - { - return *pn; - } - - bool unique() const // never throws - { - return *pn == 1; - } - - void swap(shared_ptr< T > & other) // never throws - { - std::swap(px, other.px); - std::swap(pn, other.pn); - } - -private: - - T * px; // contained pointer - count_type * pn; // ptr to reference counter -}; - -template inline bool operator==(shared_ptr< T > const & a, shared_ptr const & b) -{ - return a.get() == b.get(); -} - -template inline bool operator!=(shared_ptr< T > const & a, shared_ptr const & b) -{ - return a.get() != b.get(); -} - -template inline bool operator<(shared_ptr< T > const & a, shared_ptr< T > const & b) -{ - return std::less()(a.get(), b.get()); -} - -template void swap(shared_ptr< T > & a, shared_ptr< T > & b) -{ - a.swap(b); -} - -// get_pointer() enables boost::mem_fn to recognize shared_ptr - -template inline T * get_pointer(shared_ptr< T > const & p) -{ - return p.get(); -} - -} // namespace boost - -#endif // #ifndef BOOST_DETAIL_SHARED_PTR_NMT_132_HPP_INCLUDED +#ifndef BOOST_DETAIL_SHARED_PTR_NMT_132_HPP_INCLUDED +#define BOOST_DETAIL_SHARED_PTR_NMT_132_HPP_INCLUDED + +// +// detail/shared_ptr_nmt.hpp - shared_ptr.hpp without member templates +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include +#include +#include +#include + +#ifndef BOOST_NO_AUTO_PTR +# include // for std::unique_ptr +#endif + +#include // for std::swap +#include // for std::less +#include // for std::bad_alloc + +namespace boost +{ + +template class shared_ptr +{ +private: + + typedef detail::atomic_count count_type; + +public: + + typedef T element_type; + typedef T value_type; + + explicit shared_ptr(T * p = 0): px(p) + { +#ifndef BOOST_NO_EXCEPTIONS + + try // prevent leak if new throws + { + pn = new count_type(1); + } + catch(...) + { + boost::checked_delete(p); + throw; + } + +#else + + pn = new count_type(1); + + if(pn == 0) + { + boost::checked_delete(p); + boost::serialization::throw_exception(std::bad_alloc()); + } + +#endif + } + + ~shared_ptr() + { + if(--*pn == 0) + { + boost::checked_delete(px); + delete pn; + } + } + + shared_ptr(shared_ptr const & r): px(r.px) // never throws + { + pn = r.pn; + ++*pn; + } + + shared_ptr & operator=(shared_ptr const & r) + { + shared_ptr(r).swap(*this); + return *this; + } + +#ifndef BOOST_NO_AUTO_PTR + + explicit shared_ptr(std::unique_ptr< T > & r) + { + pn = new count_type(1); // may throw + px = r.release(); // fix: moved here to stop leak if new throws + } + + shared_ptr & operator=(std::unique_ptr< T > & r) + { + shared_ptr(r).swap(*this); + return *this; + } + +#endif + + void reset(T * p = 0) + { + BOOST_ASSERT(p == 0 || p != px); + shared_ptr(p).swap(*this); + } + + T & operator*() const // never throws + { + BOOST_ASSERT(px != 0); + return *px; + } + + T * operator->() const // never throws + { + BOOST_ASSERT(px != 0); + return px; + } + + T * get() const // never throws + { + return px; + } + + long use_count() const // never throws + { + return *pn; + } + + bool unique() const // never throws + { + return *pn == 1; + } + + void swap(shared_ptr< T > & other) // never throws + { + std::swap(px, other.px); + std::swap(pn, other.pn); + } + +private: + + T * px; // contained pointer + count_type * pn; // ptr to reference counter +}; + +template inline bool operator==(shared_ptr< T > const & a, shared_ptr const & b) +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr< T > const & a, shared_ptr const & b) +{ + return a.get() != b.get(); +} + +template inline bool operator<(shared_ptr< T > const & a, shared_ptr< T > const & b) +{ + return std::less()(a.get(), b.get()); +} + +template void swap(shared_ptr< T > & a, shared_ptr< T > & b) +{ + a.swap(b); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline T * get_pointer(shared_ptr< T > const & p) +{ + return p.get(); +} + +} // namespace boost + +#endif // #ifndef BOOST_DETAIL_SHARED_PTR_NMT_132_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/smart_ptr/detail/shared_count.hpp b/src/external/3rd/library/boost/boost/smart_ptr/detail/shared_count.hpp index ab3ac948f..51ff3dc1a 100644 --- a/src/external/3rd/library/boost/boost/smart_ptr/detail/shared_count.hpp +++ b/src/external/3rd/library/boost/boost/smart_ptr/detail/shared_count.hpp @@ -1,675 +1,675 @@ -#ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED -#define BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED - -// MS compatible compilers support #pragma once - -#if defined(_MSC_VER) && (_MSC_VER >= 1020) -# pragma once -#endif - -// -// detail/shared_count.hpp -// -// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. -// Copyright 2004-2005 Peter Dimov -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// - -#ifdef __BORLANDC__ -# pragma warn -8027 // Functions containing try are not expanded inline -#endif - -#include -#include -#include -#include -#include -#include -#include -// In order to avoid circular dependencies with Boost.TR1 -// we make sure that our include of doesn't try to -// pull in the TR1 headers: that's why we use this header -// rather than including directly: -#include // std::unique_ptr -#include // std::less - -#ifdef BOOST_NO_EXCEPTIONS -# include // std::bad_alloc -#endif - -#if !defined( BOOST_NO_CXX11_SMART_PTR ) -# include -#endif - -namespace boost -{ - -namespace detail -{ - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - -int const shared_count_id = 0x2C35F101; -int const weak_count_id = 0x298C38A4; - -#endif - -struct sp_nothrow_tag {}; - -template< class D > struct sp_inplace_tag -{ -}; - -#if !defined( BOOST_NO_CXX11_SMART_PTR ) - -template< class T > class sp_reference_wrapper -{ -public: - - explicit sp_reference_wrapper( T & t): t_( boost::addressof( t ) ) - { - } - - template< class Y > void operator()( Y * p ) const - { - (*t_)( p ); - } - -private: - - T * t_; -}; - -template< class D > struct sp_convert_reference -{ - typedef D type; -}; - -template< class D > struct sp_convert_reference< D& > -{ - typedef sp_reference_wrapper< D > type; -}; - -#endif - -class weak_count; - -class shared_count -{ -private: - - sp_counted_base * pi_; - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - int id_; -#endif - - friend class weak_count; - -public: - - shared_count(): pi_(0) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - } - - template explicit shared_count( Y * p ): pi_( 0 ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { -#ifndef BOOST_NO_EXCEPTIONS - - try - { - pi_ = new sp_counted_impl_p( p ); - } - catch(...) - { - boost::checked_delete( p ); - throw; - } - -#else - - pi_ = new sp_counted_impl_p( p ); - - if( pi_ == 0 ) - { - boost::checked_delete( p ); - boost::throw_exception( std::bad_alloc() ); - } - -#endif - } - -#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 ) - template shared_count( Y * p, D d ): pi_(0) -#else - template shared_count( P p, D d ): pi_(0) -#endif -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { -#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 ) - typedef Y* P; -#endif -#ifndef BOOST_NO_EXCEPTIONS - - try - { - pi_ = new sp_counted_impl_pd(p, d); - } - catch(...) - { - d(p); // delete p - throw; - } - -#else - - pi_ = new sp_counted_impl_pd(p, d); - - if(pi_ == 0) - { - d(p); // delete p - boost::throw_exception(std::bad_alloc()); - } - -#endif - } - -#if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) - - template< class P, class D > shared_count( P p, sp_inplace_tag ): pi_( 0 ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { -#ifndef BOOST_NO_EXCEPTIONS - - try - { - pi_ = new sp_counted_impl_pd< P, D >( p ); - } - catch( ... ) - { - D::operator_fn( p ); // delete p - throw; - } - -#else - - pi_ = new sp_counted_impl_pd< P, D >( p ); - - if( pi_ == 0 ) - { - D::operator_fn( p ); // delete p - boost::throw_exception( std::bad_alloc() ); - } - -#endif // #ifndef BOOST_NO_EXCEPTIONS - } - -#endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) - - template shared_count( P p, D d, A a ): pi_( 0 ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - typedef sp_counted_impl_pda impl_type; - -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - typedef typename std::allocator_traits::template rebind_alloc< impl_type > A2; - -#else - - typedef typename A::template rebind< impl_type >::other A2; - -#endif - - A2 a2( a ); - -#ifndef BOOST_NO_EXCEPTIONS - - try - { -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - impl_type * pi = std::allocator_traits::allocate( a2, 1 ); - pi_ = pi; - std::allocator_traits::construct( a2, pi, p, d, a ); - -#else - - pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); - ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a ); - -#endif - } - catch(...) - { - d( p ); - - if( pi_ != 0 ) - { - a2.deallocate( static_cast< impl_type* >( pi_ ), 1 ); - } - - throw; - } - -#else - -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - impl_type * pi = std::allocator_traits::allocate( a2, 1 ); - pi_ = pi; - -#else - - pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); - -#endif - - if( pi_ != 0 ) - { -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - std::allocator_traits::construct( a2, pi, p, d, a ); - -#else - - ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a ); - -#endif - } - else - { - d( p ); - boost::throw_exception( std::bad_alloc() ); - } - -#endif - } - -#if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) - - template< class P, class D, class A > shared_count( P p, sp_inplace_tag< D >, A a ): pi_( 0 ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - typedef sp_counted_impl_pda< P, D, A > impl_type; - -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - typedef typename std::allocator_traits::template rebind_alloc< impl_type > A2; - -#else - - typedef typename A::template rebind< impl_type >::other A2; - -#endif - - A2 a2( a ); - -#ifndef BOOST_NO_EXCEPTIONS - - try - { -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - impl_type * pi = std::allocator_traits::allocate( a2, 1 ); - pi_ = pi; - std::allocator_traits::construct( a2, pi, p, a ); - -#else - - pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); - ::new( static_cast< void* >( pi_ ) ) impl_type( p, a ); - -#endif - } - catch(...) - { - D::operator_fn( p ); - - if( pi_ != 0 ) - { - a2.deallocate( static_cast< impl_type* >( pi_ ), 1 ); - } - - throw; - } - -#else - -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - impl_type * pi = std::allocator_traits::allocate( a2, 1 ); - pi_ = pi; - -#else - - pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); - -#endif - - if( pi_ != 0 ) - { -#if !defined( BOOST_NO_CXX11_ALLOCATOR ) - - std::allocator_traits::construct( a2, pi, p, a ); - -#else - - ::new( static_cast< void* >( pi_ ) ) impl_type( p, a ); - -#endif - } - else - { - D::operator_fn( p ); - boost::throw_exception( std::bad_alloc() ); - } - -#endif // #ifndef BOOST_NO_EXCEPTIONS - } - -#endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) - -#ifndef BOOST_NO_AUTO_PTR - - // unique_ptr is special cased to provide the strong guarantee - - template - explicit shared_count( std::unique_ptr & r ): pi_( new sp_counted_impl_p( r.get() ) ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { -#ifdef BOOST_NO_EXCEPTIONS - - if( pi_ == 0 ) - { - boost::throw_exception(std::bad_alloc()); - } - -#endif - - r.release(); - } - -#endif - -#if !defined( BOOST_NO_CXX11_SMART_PTR ) - - template - explicit shared_count( std::unique_ptr & r ): pi_( 0 ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - typedef typename sp_convert_reference::type D2; - - D2 d2( r.get_deleter() ); - pi_ = new sp_counted_impl_pd< typename std::unique_ptr::pointer, D2 >( r.get(), d2 ); - -#ifdef BOOST_NO_EXCEPTIONS - - if( pi_ == 0 ) - { - boost::throw_exception( std::bad_alloc() ); - } - -#endif - - r.release(); - } - -#endif - - ~shared_count() // nothrow - { - if( pi_ != 0 ) pi_->release(); -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - id_ = 0; -#endif - } - - shared_count(shared_count const & r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - if( pi_ != 0 ) pi_->add_ref_copy(); - } - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - shared_count(shared_count && r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif - { - r.pi_ = 0; - } - -#endif - - explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 - shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this when r.use_count() == 0 - - shared_count & operator= (shared_count const & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - - if( tmp != pi_ ) - { - if( tmp != 0 ) tmp->add_ref_copy(); - if( pi_ != 0 ) pi_->release(); - pi_ = tmp; - } - - return *this; - } - - void swap(shared_count & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - r.pi_ = pi_; - pi_ = tmp; - } - - long use_count() const // nothrow - { - return pi_ != 0? pi_->use_count(): 0; - } - - bool unique() const // nothrow - { - return use_count() == 1; - } - - bool empty() const // nothrow - { - return pi_ == 0; - } - - friend inline bool operator==(shared_count const & a, shared_count const & b) - { - return a.pi_ == b.pi_; - } - - friend inline bool operator<(shared_count const & a, shared_count const & b) - { - return std::less()( a.pi_, b.pi_ ); - } - - void * get_deleter( sp_typeinfo const & ti ) const - { - return pi_? pi_->get_deleter( ti ): 0; - } - - void * get_untyped_deleter() const - { - return pi_? pi_->get_untyped_deleter(): 0; - } -}; - - -class weak_count -{ -private: - - sp_counted_base * pi_; - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - int id_; -#endif - - friend class shared_count; - -public: - - weak_count(): pi_(0) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(weak_count_id) -#endif - { - } - - weak_count(shared_count const & r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(weak_count_id) -#endif - { - if(pi_ != 0) pi_->weak_add_ref(); - } - - weak_count(weak_count const & r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(weak_count_id) -#endif - { - if(pi_ != 0) pi_->weak_add_ref(); - } - -// Move support - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - weak_count(weak_count && r): pi_(r.pi_) // nothrow -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(weak_count_id) -#endif - { - r.pi_ = 0; - } - -#endif - - ~weak_count() // nothrow - { - if(pi_ != 0) pi_->weak_release(); -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - id_ = 0; -#endif - } - - weak_count & operator= (shared_count const & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - - if( tmp != pi_ ) - { - if(tmp != 0) tmp->weak_add_ref(); - if(pi_ != 0) pi_->weak_release(); - pi_ = tmp; - } - - return *this; - } - - weak_count & operator= (weak_count const & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - - if( tmp != pi_ ) - { - if(tmp != 0) tmp->weak_add_ref(); - if(pi_ != 0) pi_->weak_release(); - pi_ = tmp; - } - - return *this; - } - - void swap(weak_count & r) // nothrow - { - sp_counted_base * tmp = r.pi_; - r.pi_ = pi_; - pi_ = tmp; - } - - long use_count() const // nothrow - { - return pi_ != 0? pi_->use_count(): 0; - } - - bool empty() const // nothrow - { - return pi_ == 0; - } - - friend inline bool operator==(weak_count const & a, weak_count const & b) - { - return a.pi_ == b.pi_; - } - - friend inline bool operator<(weak_count const & a, weak_count const & b) - { - return std::less()(a.pi_, b.pi_); - } -}; - -inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif -{ - if( pi_ == 0 || !pi_->add_ref_lock() ) - { - boost::throw_exception( boost::bad_weak_ptr() ); - } -} - -inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ ) -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - , id_(shared_count_id) -#endif -{ - if( pi_ != 0 && !pi_->add_ref_lock() ) - { - pi_ = 0; - } -} - -} // namespace detail - -} // namespace boost - -#ifdef __BORLANDC__ -# pragma warn .8027 // Functions containing try are not expanded inline -#endif - -#endif // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED +#ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// detail/shared_count.hpp +// +// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd. +// Copyright 2004-2005 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#ifdef __BORLANDC__ +# pragma warn -8027 // Functions containing try are not expanded inline +#endif + +#include +#include +#include +#include +#include +#include +#include +// In order to avoid circular dependencies with Boost.TR1 +// we make sure that our include of doesn't try to +// pull in the TR1 headers: that's why we use this header +// rather than including directly: +#include // std::unique_ptr +#include // std::less + +#ifdef BOOST_NO_EXCEPTIONS +# include // std::bad_alloc +#endif + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) +# include +#endif + +namespace boost +{ + +namespace detail +{ + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +int const shared_count_id = 0x2C35F101; +int const weak_count_id = 0x298C38A4; + +#endif + +struct sp_nothrow_tag {}; + +template< class D > struct sp_inplace_tag +{ +}; + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + +template< class T > class sp_reference_wrapper +{ +public: + + explicit sp_reference_wrapper( T & t): t_( boost::addressof( t ) ) + { + } + + template< class Y > void operator()( Y * p ) const + { + (*t_)( p ); + } + +private: + + T * t_; +}; + +template< class D > struct sp_convert_reference +{ + typedef D type; +}; + +template< class D > struct sp_convert_reference< D& > +{ + typedef sp_reference_wrapper< D > type; +}; + +#endif + +class weak_count; + +class shared_count +{ +private: + + sp_counted_base * pi_; + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + int id_; +#endif + + friend class weak_count; + +public: + + shared_count(): pi_(0) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + } + + template explicit shared_count( Y * p ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#ifndef BOOST_NO_EXCEPTIONS + + try + { + pi_ = new sp_counted_impl_p( p ); + } + catch(...) + { + boost::checked_delete( p ); + throw; + } + +#else + + pi_ = new sp_counted_impl_p( p ); + + if( pi_ == 0 ) + { + boost::checked_delete( p ); + boost::throw_exception( std::bad_alloc() ); + } + +#endif + } + +#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 ) + template shared_count( Y * p, D d ): pi_(0) +#else + template shared_count( P p, D d ): pi_(0) +#endif +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, <= 1200 ) + typedef Y* P; +#endif +#ifndef BOOST_NO_EXCEPTIONS + + try + { + pi_ = new sp_counted_impl_pd(p, d); + } + catch(...) + { + d(p); // delete p + throw; + } + +#else + + pi_ = new sp_counted_impl_pd(p, d); + + if(pi_ == 0) + { + d(p); // delete p + boost::throw_exception(std::bad_alloc()); + } + +#endif + } + +#if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) + + template< class P, class D > shared_count( P p, sp_inplace_tag ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#ifndef BOOST_NO_EXCEPTIONS + + try + { + pi_ = new sp_counted_impl_pd< P, D >( p ); + } + catch( ... ) + { + D::operator_fn( p ); // delete p + throw; + } + +#else + + pi_ = new sp_counted_impl_pd< P, D >( p ); + + if( pi_ == 0 ) + { + D::operator_fn( p ); // delete p + boost::throw_exception( std::bad_alloc() ); + } + +#endif // #ifndef BOOST_NO_EXCEPTIONS + } + +#endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) + + template shared_count( P p, D d, A a ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + typedef sp_counted_impl_pda impl_type; + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + typedef typename std::allocator_traits::template rebind_alloc< impl_type > A2; + +#else + + typedef typename A::template rebind< impl_type >::other A2; + +#endif + + A2 a2( a ); + +#ifndef BOOST_NO_EXCEPTIONS + + try + { +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + impl_type * pi = std::allocator_traits::allocate( a2, 1 ); + pi_ = pi; + std::allocator_traits::construct( a2, pi, p, d, a ); + +#else + + pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); + ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a ); + +#endif + } + catch(...) + { + d( p ); + + if( pi_ != 0 ) + { + a2.deallocate( static_cast< impl_type* >( pi_ ), 1 ); + } + + throw; + } + +#else + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + impl_type * pi = std::allocator_traits::allocate( a2, 1 ); + pi_ = pi; + +#else + + pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); + +#endif + + if( pi_ != 0 ) + { +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::construct( a2, pi, p, d, a ); + +#else + + ::new( static_cast< void* >( pi_ ) ) impl_type( p, d, a ); + +#endif + } + else + { + d( p ); + boost::throw_exception( std::bad_alloc() ); + } + +#endif + } + +#if !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) + + template< class P, class D, class A > shared_count( P p, sp_inplace_tag< D >, A a ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + typedef sp_counted_impl_pda< P, D, A > impl_type; + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + typedef typename std::allocator_traits::template rebind_alloc< impl_type > A2; + +#else + + typedef typename A::template rebind< impl_type >::other A2; + +#endif + + A2 a2( a ); + +#ifndef BOOST_NO_EXCEPTIONS + + try + { +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + impl_type * pi = std::allocator_traits::allocate( a2, 1 ); + pi_ = pi; + std::allocator_traits::construct( a2, pi, p, a ); + +#else + + pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); + ::new( static_cast< void* >( pi_ ) ) impl_type( p, a ); + +#endif + } + catch(...) + { + D::operator_fn( p ); + + if( pi_ != 0 ) + { + a2.deallocate( static_cast< impl_type* >( pi_ ), 1 ); + } + + throw; + } + +#else + +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + impl_type * pi = std::allocator_traits::allocate( a2, 1 ); + pi_ = pi; + +#else + + pi_ = a2.allocate( 1, static_cast< impl_type* >( 0 ) ); + +#endif + + if( pi_ != 0 ) + { +#if !defined( BOOST_NO_CXX11_ALLOCATOR ) + + std::allocator_traits::construct( a2, pi, p, a ); + +#else + + ::new( static_cast< void* >( pi_ ) ) impl_type( p, a ); + +#endif + } + else + { + D::operator_fn( p ); + boost::throw_exception( std::bad_alloc() ); + } + +#endif // #ifndef BOOST_NO_EXCEPTIONS + } + +#endif // !defined( BOOST_NO_FUNCTION_TEMPLATE_ORDERING ) + +#ifndef BOOST_NO_AUTO_PTR + + // unique_ptr is special cased to provide the strong guarantee + + template + explicit shared_count( std::unique_ptr & r ): pi_( new sp_counted_impl_p( r.get() ) ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { +#ifdef BOOST_NO_EXCEPTIONS + + if( pi_ == 0 ) + { + boost::throw_exception(std::bad_alloc()); + } + +#endif + + r.release(); + } + +#endif + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + + template + explicit shared_count( std::unique_ptr & r ): pi_( 0 ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + typedef typename sp_convert_reference::type D2; + + D2 d2( r.get_deleter() ); + pi_ = new sp_counted_impl_pd< typename std::unique_ptr::pointer, D2 >( r.get(), d2 ); + +#ifdef BOOST_NO_EXCEPTIONS + + if( pi_ == 0 ) + { + boost::throw_exception( std::bad_alloc() ); + } + +#endif + + r.release(); + } + +#endif + + ~shared_count() // nothrow + { + if( pi_ != 0 ) pi_->release(); +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + id_ = 0; +#endif + } + + shared_count(shared_count const & r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + if( pi_ != 0 ) pi_->add_ref_copy(); + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + shared_count(shared_count && r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif + { + r.pi_ = 0; + } + +#endif + + explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0 + shared_count( weak_count const & r, sp_nothrow_tag ); // constructs an empty *this when r.use_count() == 0 + + shared_count & operator= (shared_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + + if( tmp != pi_ ) + { + if( tmp != 0 ) tmp->add_ref_copy(); + if( pi_ != 0 ) pi_->release(); + pi_ = tmp; + } + + return *this; + } + + void swap(shared_count & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_ != 0? pi_->use_count(): 0; + } + + bool unique() const // nothrow + { + return use_count() == 1; + } + + bool empty() const // nothrow + { + return pi_ == 0; + } + + friend inline bool operator==(shared_count const & a, shared_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(shared_count const & a, shared_count const & b) + { + return std::less()( a.pi_, b.pi_ ); + } + + void * get_deleter( sp_typeinfo const & ti ) const + { + return pi_? pi_->get_deleter( ti ): 0; + } + + void * get_untyped_deleter() const + { + return pi_? pi_->get_untyped_deleter(): 0; + } +}; + + +class weak_count +{ +private: + + sp_counted_base * pi_; + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + int id_; +#endif + + friend class shared_count; + +public: + + weak_count(): pi_(0) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(weak_count_id) +#endif + { + } + + weak_count(shared_count const & r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(weak_count_id) +#endif + { + if(pi_ != 0) pi_->weak_add_ref(); + } + + weak_count(weak_count const & r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(weak_count_id) +#endif + { + if(pi_ != 0) pi_->weak_add_ref(); + } + +// Move support + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + weak_count(weak_count && r): pi_(r.pi_) // nothrow +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(weak_count_id) +#endif + { + r.pi_ = 0; + } + +#endif + + ~weak_count() // nothrow + { + if(pi_ != 0) pi_->weak_release(); +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + id_ = 0; +#endif + } + + weak_count & operator= (shared_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + + if( tmp != pi_ ) + { + if(tmp != 0) tmp->weak_add_ref(); + if(pi_ != 0) pi_->weak_release(); + pi_ = tmp; + } + + return *this; + } + + weak_count & operator= (weak_count const & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + + if( tmp != pi_ ) + { + if(tmp != 0) tmp->weak_add_ref(); + if(pi_ != 0) pi_->weak_release(); + pi_ = tmp; + } + + return *this; + } + + void swap(weak_count & r) // nothrow + { + sp_counted_base * tmp = r.pi_; + r.pi_ = pi_; + pi_ = tmp; + } + + long use_count() const // nothrow + { + return pi_ != 0? pi_->use_count(): 0; + } + + bool empty() const // nothrow + { + return pi_ == 0; + } + + friend inline bool operator==(weak_count const & a, weak_count const & b) + { + return a.pi_ == b.pi_; + } + + friend inline bool operator<(weak_count const & a, weak_count const & b) + { + return std::less()(a.pi_, b.pi_); + } +}; + +inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif +{ + if( pi_ == 0 || !pi_->add_ref_lock() ) + { + boost::throw_exception( boost::bad_weak_ptr() ); + } +} + +inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ ) +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + , id_(shared_count_id) +#endif +{ + if( pi_ != 0 && !pi_->add_ref_lock() ) + { + pi_ = 0; + } +} + +} // namespace detail + +} // namespace boost + +#ifdef __BORLANDC__ +# pragma warn .8027 // Functions containing try are not expanded inline +#endif + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SHARED_COUNT_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/smart_ptr/scoped_ptr.hpp b/src/external/3rd/library/boost/boost/smart_ptr/scoped_ptr.hpp index 2ccc00278..1edf1aa06 100644 --- a/src/external/3rd/library/boost/boost/smart_ptr/scoped_ptr.hpp +++ b/src/external/3rd/library/boost/boost/smart_ptr/scoped_ptr.hpp @@ -1,157 +1,157 @@ -#ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED -#define BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED - -// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. -// Copyright (c) 2001, 2002 Peter Dimov -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// http://www.boost.org/libs/smart_ptr/scoped_ptr.htm -// - -#include -#include -#include -#include -#include - -#ifndef BOOST_NO_AUTO_PTR -# include // for std::unique_ptr -#endif - -namespace boost -{ - -// Debug hooks - -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - -void sp_scalar_constructor_hook(void * p); -void sp_scalar_destructor_hook(void * p); - -#endif - -// scoped_ptr mimics a built-in pointer except that it guarantees deletion -// of the object pointed to, either on destruction of the scoped_ptr or via -// an explicit reset(). scoped_ptr is a simple solution for simple needs; -// use shared_ptr or std::unique_ptr if your needs are more complex. - -template class scoped_ptr // noncopyable -{ -private: - - T * px; - - scoped_ptr(scoped_ptr const &); - scoped_ptr & operator=(scoped_ptr const &); - - typedef scoped_ptr this_type; - - void operator==( scoped_ptr const& ) const; - void operator!=( scoped_ptr const& ) const; - -public: - - typedef T element_type; - - explicit scoped_ptr( T * p = 0 ): px( p ) // never throws - { -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - boost::sp_scalar_constructor_hook( px ); -#endif - } - -#ifndef BOOST_NO_AUTO_PTR - - explicit scoped_ptr( std::unique_ptr p ) BOOST_NOEXCEPT : px( p.release() ) - { -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - boost::sp_scalar_constructor_hook( px ); -#endif - } - -#endif - - ~scoped_ptr() // never throws - { -#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) - boost::sp_scalar_destructor_hook( px ); -#endif - boost::checked_delete( px ); - } - - void reset(T * p = 0) // never throws - { - BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors - this_type(p).swap(*this); - } - - T & operator*() const // never throws - { - BOOST_ASSERT( px != 0 ); - return *px; - } - - T * operator->() const // never throws - { - BOOST_ASSERT( px != 0 ); - return px; - } - - T * get() const BOOST_NOEXCEPT - { - return px; - } - -// implicit conversion to "bool" -#include - - void swap(scoped_ptr & b) BOOST_NOEXCEPT - { - T * tmp = b.px; - b.px = px; - px = tmp; - } -}; - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - -template inline bool operator==( scoped_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT -{ - return p.get() == 0; -} - -template inline bool operator==( boost::detail::sp_nullptr_t, scoped_ptr const & p ) BOOST_NOEXCEPT -{ - return p.get() == 0; -} - -template inline bool operator!=( scoped_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT -{ - return p.get() != 0; -} - -template inline bool operator!=( boost::detail::sp_nullptr_t, scoped_ptr const & p ) BOOST_NOEXCEPT -{ - return p.get() != 0; -} - -#endif - -template inline void swap(scoped_ptr & a, scoped_ptr & b) BOOST_NOEXCEPT -{ - a.swap(b); -} - -// get_pointer(p) is a generic way to say p.get() - -template inline T * get_pointer(scoped_ptr const & p) BOOST_NOEXCEPT -{ - return p.get(); -} - -} // namespace boost - -#endif // #ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED +#ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED + +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// http://www.boost.org/libs/smart_ptr/scoped_ptr.htm +// + +#include +#include +#include +#include +#include + +#ifndef BOOST_NO_AUTO_PTR +# include // for std::unique_ptr +#endif + +namespace boost +{ + +// Debug hooks + +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + +void sp_scalar_constructor_hook(void * p); +void sp_scalar_destructor_hook(void * p); + +#endif + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// use shared_ptr or std::unique_ptr if your needs are more complex. + +template class scoped_ptr // noncopyable +{ +private: + + T * px; + + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + + typedef scoped_ptr this_type; + + void operator==( scoped_ptr const& ) const; + void operator!=( scoped_ptr const& ) const; + +public: + + typedef T element_type; + + explicit scoped_ptr( T * p = 0 ): px( p ) // never throws + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_constructor_hook( px ); +#endif + } + +#ifndef BOOST_NO_AUTO_PTR + + explicit scoped_ptr( std::unique_ptr p ) BOOST_NOEXCEPT : px( p.release() ) + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_constructor_hook( px ); +#endif + } + +#endif + + ~scoped_ptr() // never throws + { +#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) + boost::sp_scalar_destructor_hook( px ); +#endif + boost::checked_delete( px ); + } + + void reset(T * p = 0) // never throws + { + BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors + this_type(p).swap(*this); + } + + T & operator*() const // never throws + { + BOOST_ASSERT( px != 0 ); + return *px; + } + + T * operator->() const // never throws + { + BOOST_ASSERT( px != 0 ); + return px; + } + + T * get() const BOOST_NOEXCEPT + { + return px; + } + +// implicit conversion to "bool" +#include + + void swap(scoped_ptr & b) BOOST_NOEXCEPT + { + T * tmp = b.px; + b.px = px; + px = tmp; + } +}; + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + +template inline bool operator==( scoped_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT +{ + return p.get() == 0; +} + +template inline bool operator==( boost::detail::sp_nullptr_t, scoped_ptr const & p ) BOOST_NOEXCEPT +{ + return p.get() == 0; +} + +template inline bool operator!=( scoped_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT +{ + return p.get() != 0; +} + +template inline bool operator!=( boost::detail::sp_nullptr_t, scoped_ptr const & p ) BOOST_NOEXCEPT +{ + return p.get() != 0; +} + +#endif + +template inline void swap(scoped_ptr & a, scoped_ptr & b) BOOST_NOEXCEPT +{ + a.swap(b); +} + +// get_pointer(p) is a generic way to say p.get() + +template inline T * get_pointer(scoped_ptr const & p) BOOST_NOEXCEPT +{ + return p.get(); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_SCOPED_PTR_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/smart_ptr/shared_ptr.hpp b/src/external/3rd/library/boost/boost/smart_ptr/shared_ptr.hpp index ffcc55afb..7970f8408 100644 --- a/src/external/3rd/library/boost/boost/smart_ptr/shared_ptr.hpp +++ b/src/external/3rd/library/boost/boost/smart_ptr/shared_ptr.hpp @@ -1,1028 +1,1028 @@ -#ifndef BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED -#define BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED - -// -// shared_ptr.hpp -// -// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. -// Copyright (c) 2001-2008 Peter Dimov -// -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. -// - -#include // for broken compiler workarounds - -// In order to avoid circular dependencies with Boost.TR1 -// we make sure that our include of doesn't try to -// pull in the TR1 headers: that's why we use this header -// rather than including directly: -#include // std::unique_ptr - -#include -#include -#include -#include -#include -#include -#include - -#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) -#include -#endif - -#include // for std::swap -#include // for std::less -#include // for std::bad_cast -#include // for std::size_t - -#if !defined(BOOST_NO_IOSTREAM) -#if !defined(BOOST_NO_IOSFWD) -#include // for std::basic_ostream -#else -#include -#endif -#endif - -namespace boost -{ - -template class shared_ptr; -template class weak_ptr; -template class enable_shared_from_this; -class enable_shared_from_raw; - -namespace detail -{ - -// sp_element, element_type - -template< class T > struct sp_element -{ - typedef T type; -}; - -#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -template< class T > struct sp_element< T[] > -{ - typedef T type; -}; - -#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) - -template< class T, std::size_t N > struct sp_element< T[N] > -{ - typedef T type; -}; - -#endif - -#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -// sp_dereference, return type of operator* - -template< class T > struct sp_dereference -{ - typedef T & type; -}; - -template<> struct sp_dereference< void > -{ - typedef void type; -}; - -#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) - -template<> struct sp_dereference< void const > -{ - typedef void type; -}; - -template<> struct sp_dereference< void volatile > -{ - typedef void type; -}; - -template<> struct sp_dereference< void const volatile > -{ - typedef void type; -}; - -#endif // !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) - -#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -template< class T > struct sp_dereference< T[] > -{ - typedef void type; -}; - -#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) - -template< class T, std::size_t N > struct sp_dereference< T[N] > -{ - typedef void type; -}; - -#endif - -#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -// sp_member_access, return type of operator-> - -template< class T > struct sp_member_access -{ - typedef T * type; -}; - -#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -template< class T > struct sp_member_access< T[] > -{ - typedef void type; -}; - -#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) - -template< class T, std::size_t N > struct sp_member_access< T[N] > -{ - typedef void type; -}; - -#endif - -#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -// sp_array_access, return type of operator[] - -template< class T > struct sp_array_access -{ - typedef void type; -}; - -#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -template< class T > struct sp_array_access< T[] > -{ - typedef T & type; -}; - -#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) - -template< class T, std::size_t N > struct sp_array_access< T[N] > -{ - typedef T & type; -}; - -#endif - -#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -// sp_extent, for operator[] index check - -template< class T > struct sp_extent -{ - enum _vt { value = 0 }; -}; - -#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -template< class T, std::size_t N > struct sp_extent< T[N] > -{ - enum _vt { value = N }; -}; - -#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -// enable_shared_from_this support - -template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe ) -{ - if( pe != 0 ) - { - pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) ); - } -} - -template< class X, class Y > inline void sp_enable_shared_from_this( boost::shared_ptr * ppx, Y const * py, boost::enable_shared_from_raw const * pe ); - -#ifdef _MANAGED - -// Avoid C4793, ... causes native code generation - -struct sp_any_pointer -{ - template sp_any_pointer( T* ) {} -}; - -inline void sp_enable_shared_from_this( sp_any_pointer, sp_any_pointer, sp_any_pointer ) -{ -} - -#else // _MANAGED - -inline void sp_enable_shared_from_this( ... ) -{ -} - -#endif // _MANAGED - -#if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && !defined( BOOST_NO_AUTO_PTR ) - -// rvalue unique_ptr support based on a technique by Dave Abrahams - -template< class T, class R > struct sp_enable_if_unique_ptr -{ -}; - -template< class T, class R > struct sp_enable_if_unique_ptr< std::unique_ptr< T >, R > -{ - typedef R type; -}; - -#endif - -// sp_assert_convertible - -template< class Y, class T > inline void sp_assert_convertible() -{ -#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) - - // static_assert( sp_convertible< Y, T >::value ); - typedef char tmp[ sp_convertible< Y, T >::value? 1: -1 ]; - (void)sizeof( tmp ); - -#else - - T* p = static_cast< Y* >( 0 ); - (void)p; - -#endif -} - -// pointer constructor helper - -template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T > * ppx, Y * p, boost::detail::shared_count & pn ) -{ - boost::detail::shared_count( p ).swap( pn ); - boost::detail::sp_enable_shared_from_this( ppx, p, p ); -} - -#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T[] > * /*ppx*/, Y * p, boost::detail::shared_count & pn ) -{ - sp_assert_convertible< Y[], T[] >(); - boost::detail::shared_count( p, boost::checked_array_deleter< T >() ).swap( pn ); -} - -template< class T, std::size_t N, class Y > inline void sp_pointer_construct( boost::shared_ptr< T[N] > * /*ppx*/, Y * p, boost::detail::shared_count & pn ) -{ - sp_assert_convertible< Y[N], T[N] >(); - boost::detail::shared_count( p, boost::checked_array_deleter< T >() ).swap( pn ); -} - -#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -// deleter constructor helper - -template< class T, class Y > inline void sp_deleter_construct( boost::shared_ptr< T > * ppx, Y * p ) -{ - boost::detail::sp_enable_shared_from_this( ppx, p, p ); -} - -#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -template< class T, class Y > inline void sp_deleter_construct( boost::shared_ptr< T[] > * /*ppx*/, Y * /*p*/ ) -{ - sp_assert_convertible< Y[], T[] >(); -} - -template< class T, std::size_t N, class Y > inline void sp_deleter_construct( boost::shared_ptr< T[N] > * /*ppx*/, Y * /*p*/ ) -{ - sp_assert_convertible< Y[N], T[N] >(); -} - -#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - -} // namespace detail - - -// -// shared_ptr -// -// An enhanced relative of scoped_ptr with reference counted copy semantics. -// The object pointed to is deleted when the last shared_ptr pointing to it -// is destroyed or reset. -// - -template class shared_ptr -{ -private: - - // Borland 5.5.1 specific workaround - typedef shared_ptr this_type; - -public: - - typedef typename boost::detail::sp_element< T >::type element_type; - - shared_ptr() BOOST_NOEXCEPT : px( 0 ), pn() // never throws in 1.30+ - { - } - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - - shared_ptr( boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT : px( 0 ), pn() // never throws - { - } - -#endif - - template - explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete - { - boost::detail::sp_pointer_construct( this, p, pn ); - } - - // - // Requirements: D's copy constructor must not throw - // - // shared_ptr will release p by calling d(p) - // - - template shared_ptr( Y * p, D d ): px( p ), pn( p, d ) - { - boost::detail::sp_deleter_construct( this, p ); - } - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - - template shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( p, d ) - { - } - -#endif - - // As above, but with allocator. A's copy constructor shall not throw. - - template shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a ) - { - boost::detail::sp_deleter_construct( this, p ); - } - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - - template shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), pn( p, d, a ) - { - } - -#endif - -// generated copy constructor, destructor are fine... - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - -// ... except in C++0x, move disables the implicit copy - - shared_ptr( shared_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) - { - } - -#endif - - template - explicit shared_ptr( weak_ptr const & r ): pn( r.pn ) // may throw - { - boost::detail::sp_assert_convertible< Y, T >(); - - // it is now safe to copy r.px, as pn(r.pn) did not throw - px = r.px; - } - - template - shared_ptr( weak_ptr const & r, boost::detail::sp_nothrow_tag ) - BOOST_NOEXCEPT : px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() ) - { - if( !pn.empty() ) - { - px = r.px; - } - } - - template -#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) - - shared_ptr( shared_ptr const & r, typename boost::detail::sp_enable_if_convertible::type = boost::detail::sp_empty() ) - -#else - - shared_ptr( shared_ptr const & r ) - -#endif - BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) - { - boost::detail::sp_assert_convertible< Y, T >(); - } - - // aliasing - template< class Y > - shared_ptr( shared_ptr const & r, element_type * p ) BOOST_NOEXCEPT : px( p ), pn( r.pn ) - { - } - -#ifndef BOOST_NO_AUTO_PTR - - template - explicit shared_ptr( std::unique_ptr & r ): px(r.get()), pn() - { - boost::detail::sp_assert_convertible< Y, T >(); - - Y * tmp = r.get(); - pn = boost::detail::shared_count( r ); - - boost::detail::sp_deleter_construct( this, tmp ); - } - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - template - shared_ptr( std::unique_ptr && r ): px(r.get()), pn() - { - boost::detail::sp_assert_convertible< Y, T >(); - - Y * tmp = r.get(); - pn = boost::detail::shared_count( r ); - - boost::detail::sp_deleter_construct( this, tmp ); - } - -#elif !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - - template - explicit shared_ptr( Ap r, typename boost::detail::sp_enable_if_unique_ptr::type = 0 ): px( r.get() ), pn() - { - typedef typename Ap::element_type Y; - - boost::detail::sp_assert_convertible< Y, T >(); - - Y * tmp = r.get(); - pn = boost::detail::shared_count( r ); - - boost::detail::sp_deleter_construct( this, tmp ); - } - -#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - -#endif // BOOST_NO_AUTO_PTR - -#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - template< class Y, class D > - shared_ptr( std::unique_ptr< Y, D > && r ): px( r.get() ), pn() - { - boost::detail::sp_assert_convertible< Y, T >(); - - typename std::unique_ptr< Y, D >::pointer tmp = r.get(); - pn = boost::detail::shared_count( r ); - - boost::detail::sp_deleter_construct( this, tmp ); - } - -#endif - - // assignment - - shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT - { - this_type(r).swap(*this); - return *this; - } - -#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1400) - - template - shared_ptr & operator=(shared_ptr const & r) BOOST_NOEXCEPT - { - this_type(r).swap(*this); - return *this; - } - -#endif - -#ifndef BOOST_NO_AUTO_PTR - - template - shared_ptr & operator=( std::unique_ptr & r ) - { - this_type( r ).swap( *this ); - return *this; - } - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - template - shared_ptr & operator=( std::unique_ptr && r ) - { - this_type( static_cast< std::unique_ptr && >( r ) ).swap( *this ); - return *this; - } - -#elif !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) - - template - typename boost::detail::sp_enable_if_unique_ptr< Ap, shared_ptr & >::type operator=( Ap r ) - { - this_type( r ).swap( *this ); - return *this; - } - -#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION - -#endif // BOOST_NO_AUTO_PTR - -#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - template - shared_ptr & operator=( std::unique_ptr && r ) - { - this_type( static_cast< std::unique_ptr && >( r ) ).swap(*this); - return *this; - } - -#endif - -// Move support - -#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) - - shared_ptr( shared_ptr && r ) BOOST_NOEXCEPT : px( r.px ), pn() - { - pn.swap( r.pn ); - r.px = 0; - } - - template -#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) - - shared_ptr( shared_ptr && r, typename boost::detail::sp_enable_if_convertible::type = boost::detail::sp_empty() ) - -#else - - shared_ptr( shared_ptr && r ) - -#endif - BOOST_NOEXCEPT : px( r.px ), pn() - { - boost::detail::sp_assert_convertible< Y, T >(); - - pn.swap( r.pn ); - r.px = 0; - } - - shared_ptr & operator=( shared_ptr && r ) BOOST_NOEXCEPT - { - this_type( static_cast< shared_ptr && >( r ) ).swap( *this ); - return *this; - } - - template - shared_ptr & operator=( shared_ptr && r ) BOOST_NOEXCEPT - { - this_type( static_cast< shared_ptr && >( r ) ).swap( *this ); - return *this; - } - -#endif - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - - shared_ptr & operator=( boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT // never throws - { - this_type().swap(*this); - return *this; - } - -#endif - - void reset() BOOST_NOEXCEPT // never throws in 1.30+ - { - this_type().swap(*this); - } - - template void reset( Y * p ) // Y must be complete - { - BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors - this_type( p ).swap( *this ); - } - - template void reset( Y * p, D d ) - { - this_type( p, d ).swap( *this ); - } - - template void reset( Y * p, D d, A a ) - { - this_type( p, d, a ).swap( *this ); - } - - template void reset( shared_ptr const & r, element_type * p ) - { - this_type( r, p ).swap( *this ); - } - - // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) - typename boost::detail::sp_dereference< T >::type operator* () const - { - BOOST_ASSERT( px != 0 ); - return *px; - } - - // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) - typename boost::detail::sp_member_access< T >::type operator-> () const - { - BOOST_ASSERT( px != 0 ); - return px; - } - - // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) - typename boost::detail::sp_array_access< T >::type operator[] ( std::ptrdiff_t i ) const - { - BOOST_ASSERT( px != 0 ); - BOOST_ASSERT( i >= 0 && ( i < boost::detail::sp_extent< T >::value || boost::detail::sp_extent< T >::value == 0 ) ); - - return static_cast< typename boost::detail::sp_array_access< T >::type >( px[ i ] ); - } - - element_type * get() const BOOST_NOEXCEPT - { - return px; - } - -// implicit conversion to "bool" -#include - - bool unique() const BOOST_NOEXCEPT - { - return pn.unique(); - } - - long use_count() const BOOST_NOEXCEPT - { - return pn.use_count(); - } - - void swap( shared_ptr & other ) BOOST_NOEXCEPT - { - std::swap(px, other.px); - pn.swap(other.pn); - } - - template bool owner_before( shared_ptr const & rhs ) const BOOST_NOEXCEPT - { - return pn < rhs.pn; - } - - template bool owner_before( weak_ptr const & rhs ) const BOOST_NOEXCEPT - { - return pn < rhs.pn; - } - - void * _internal_get_deleter( boost::detail::sp_typeinfo const & ti ) const BOOST_NOEXCEPT - { - return pn.get_deleter( ti ); - } - - void * _internal_get_untyped_deleter() const BOOST_NOEXCEPT - { - return pn.get_untyped_deleter(); - } - - bool _internal_equiv( shared_ptr const & r ) const BOOST_NOEXCEPT - { - return px == r.px && pn == r.pn; - } - -// Tasteless as this may seem, making all members public allows member templates -// to work in the absence of member template friends. (Matthew Langston) - -#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS - -private: - - template friend class shared_ptr; - template friend class weak_ptr; - - -#endif - - element_type * px; // contained pointer - boost::detail::shared_count pn; // reference counter - -}; // shared_ptr - -template inline bool operator==(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT -{ - return a.get() == b.get(); -} - -template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT -{ - return a.get() != b.get(); -} - -#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 - -// Resolve the ambiguity between our op!= and the one in rel_ops - -template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT -{ - return a.get() != b.get(); -} - -#endif - -#if !defined( BOOST_NO_CXX11_NULLPTR ) - -template inline bool operator==( shared_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT -{ - return p.get() == 0; -} - -template inline bool operator==( boost::detail::sp_nullptr_t, shared_ptr const & p ) BOOST_NOEXCEPT -{ - return p.get() == 0; -} - -template inline bool operator!=( shared_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT -{ - return p.get() != 0; -} - -template inline bool operator!=( boost::detail::sp_nullptr_t, shared_ptr const & p ) BOOST_NOEXCEPT -{ - return p.get() != 0; -} - -#endif - -template inline bool operator<(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT -{ - return a.owner_before( b ); -} - -template inline void swap(shared_ptr & a, shared_ptr & b) BOOST_NOEXCEPT -{ - a.swap(b); -} - -template shared_ptr static_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT -{ - (void) static_cast< T* >( static_cast< U* >( 0 ) ); - - typedef typename shared_ptr::element_type E; - - E * p = static_cast< E* >( r.get() ); - return shared_ptr( r, p ); -} - -template shared_ptr const_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT -{ - (void) const_cast< T* >( static_cast< U* >( 0 ) ); - - typedef typename shared_ptr::element_type E; - - E * p = const_cast< E* >( r.get() ); - return shared_ptr( r, p ); -} - -template shared_ptr dynamic_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT -{ - (void) dynamic_cast< T* >( static_cast< U* >( 0 ) ); - - typedef typename shared_ptr::element_type E; - - E * p = dynamic_cast< E* >( r.get() ); - return p? shared_ptr( r, p ): shared_ptr(); -} - -template shared_ptr reinterpret_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT -{ - (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) ); - - typedef typename shared_ptr::element_type E; - - E * p = reinterpret_cast< E* >( r.get() ); - return shared_ptr( r, p ); -} - -// get_pointer() enables boost::mem_fn to recognize shared_ptr - -template inline typename shared_ptr::element_type * get_pointer(shared_ptr const & p) BOOST_NOEXCEPT -{ - return p.get(); -} - -// operator<< - -#if !defined(BOOST_NO_IOSTREAM) - -#if defined(BOOST_NO_TEMPLATED_IOSTREAMS) || ( defined(__GNUC__) && (__GNUC__ < 3) ) - -template std::ostream & operator<< (std::ostream & os, shared_ptr const & p) -{ - os << p.get(); - return os; -} - -#else - -// in STLport's no-iostreams mode no iostream symbols can be used -#ifndef _STLP_NO_IOSTREAMS - -# if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300 && __SGI_STL_PORT) -// MSVC6 has problems finding std::basic_ostream through the using declaration in namespace _STL -using std::basic_ostream; -template basic_ostream & operator<< (basic_ostream & os, shared_ptr const & p) -# else -template std::basic_ostream & operator<< (std::basic_ostream & os, shared_ptr const & p) -# endif -{ - os << p.get(); - return os; -} - -#endif // _STLP_NO_IOSTREAMS - -#endif // __GNUC__ < 3 - -#endif // !defined(BOOST_NO_IOSTREAM) - -// get_deleter - -namespace detail -{ - -#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ - ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \ - ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) ) - -// g++ 2.9x doesn't allow static_cast(void *) -// apparently EDG 2.38 and HP aCC A.03.35 also don't accept it - -template D * basic_get_deleter(shared_ptr const & p) -{ - void const * q = p._internal_get_deleter(BOOST_SP_TYPEID(D)); - return const_cast(static_cast(q)); -} - -#else - -template D * basic_get_deleter( shared_ptr const & p ) BOOST_NOEXCEPT -{ - return static_cast( p._internal_get_deleter(BOOST_SP_TYPEID(D)) ); -} - -#endif - -class esft2_deleter_wrapper -{ -private: - - shared_ptr deleter_; - -public: - - esft2_deleter_wrapper() - { - } - - template< class T > void set_deleter( shared_ptr const & deleter ) - { - deleter_ = deleter; - } - - template D* get_deleter() const BOOST_NOEXCEPT - { - return boost::detail::basic_get_deleter( deleter_ ); - } - - template< class T> void operator()( T* ) - { - BOOST_ASSERT( deleter_.use_count() <= 1 ); - deleter_.reset(); - } -}; - -} // namespace detail - -template D * get_deleter( shared_ptr const & p ) BOOST_NOEXCEPT -{ - D *del = boost::detail::basic_get_deleter(p); - - if(del == 0) - { - boost::detail::esft2_deleter_wrapper *del_wrapper = boost::detail::basic_get_deleter(p); -// The following get_deleter method call is fully qualified because -// older versions of gcc (2.95, 3.2.3) fail to compile it when written del_wrapper->get_deleter() - if(del_wrapper) del = del_wrapper->::boost::detail::esft2_deleter_wrapper::get_deleter(); - } - - return del; -} - -// atomic access - -#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) - -template inline bool atomic_is_lock_free( shared_ptr const * /*p*/ ) BOOST_NOEXCEPT -{ - return false; -} - -template shared_ptr atomic_load( shared_ptr const * p ) -{ - boost::detail::spinlock_pool<2>::scoped_lock lock( p ); - return *p; -} - -template inline shared_ptr atomic_load_explicit( shared_ptr const * p, /*memory_order mo*/ int ) -{ - return atomic_load( p ); -} - -template void atomic_store( shared_ptr * p, shared_ptr r ) -{ - boost::detail::spinlock_pool<2>::scoped_lock lock( p ); - p->swap( r ); -} - -template inline void atomic_store_explicit( shared_ptr * p, shared_ptr r, /*memory_order mo*/ int ) -{ - atomic_store( p, r ); // std::move( r ) -} - -template shared_ptr atomic_exchange( shared_ptr * p, shared_ptr r ) -{ - boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p ); - - sp.lock(); - p->swap( r ); - sp.unlock(); - - return r; // return std::move( r ) -} - -template shared_ptr atomic_exchange_explicit( shared_ptr * p, shared_ptr r, /*memory_order mo*/ int ) -{ - return atomic_exchange( p, r ); // std::move( r ) -} - -template bool atomic_compare_exchange( shared_ptr * p, shared_ptr * v, shared_ptr w ) -{ - boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p ); - - sp.lock(); - - if( p->_internal_equiv( *v ) ) - { - p->swap( w ); - - sp.unlock(); - - return true; - } - else - { - shared_ptr tmp( *p ); - - sp.unlock(); - - tmp.swap( *v ); - return false; - } -} - -template inline bool atomic_compare_exchange_explicit( shared_ptr * p, shared_ptr * v, shared_ptr w, /*memory_order success*/ int, /*memory_order failure*/ int ) -{ - return atomic_compare_exchange( p, v, w ); // std::move( w ) -} - -#endif // !defined(BOOST_SP_NO_ATOMIC_ACCESS) - -// hash_value - -template< class T > struct hash; - -template< class T > std::size_t hash_value( boost::shared_ptr const & p ) BOOST_NOEXCEPT -{ - return boost::hash< T* >()( p.get() ); -} - -} // namespace boost - -#endif // #ifndef BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED +#ifndef BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED +#define BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED + +// +// shared_ptr.hpp +// +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001-2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation. +// + +#include // for broken compiler workarounds + +// In order to avoid circular dependencies with Boost.TR1 +// we make sure that our include of doesn't try to +// pull in the TR1 headers: that's why we use this header +// rather than including directly: +#include // std::unique_ptr + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) +#include +#endif + +#include // for std::swap +#include // for std::less +#include // for std::bad_cast +#include // for std::size_t + +#if !defined(BOOST_NO_IOSTREAM) +#if !defined(BOOST_NO_IOSFWD) +#include // for std::basic_ostream +#else +#include +#endif +#endif + +namespace boost +{ + +template class shared_ptr; +template class weak_ptr; +template class enable_shared_from_this; +class enable_shared_from_raw; + +namespace detail +{ + +// sp_element, element_type + +template< class T > struct sp_element +{ + typedef T type; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T > struct sp_element< T[] > +{ + typedef T type; +}; + +#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) + +template< class T, std::size_t N > struct sp_element< T[N] > +{ + typedef T type; +}; + +#endif + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +// sp_dereference, return type of operator* + +template< class T > struct sp_dereference +{ + typedef T & type; +}; + +template<> struct sp_dereference< void > +{ + typedef void type; +}; + +#if !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) + +template<> struct sp_dereference< void const > +{ + typedef void type; +}; + +template<> struct sp_dereference< void volatile > +{ + typedef void type; +}; + +template<> struct sp_dereference< void const volatile > +{ + typedef void type; +}; + +#endif // !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T > struct sp_dereference< T[] > +{ + typedef void type; +}; + +#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) + +template< class T, std::size_t N > struct sp_dereference< T[N] > +{ + typedef void type; +}; + +#endif + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +// sp_member_access, return type of operator-> + +template< class T > struct sp_member_access +{ + typedef T * type; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T > struct sp_member_access< T[] > +{ + typedef void type; +}; + +#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) + +template< class T, std::size_t N > struct sp_member_access< T[N] > +{ + typedef void type; +}; + +#endif + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +// sp_array_access, return type of operator[] + +template< class T > struct sp_array_access +{ + typedef void type; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T > struct sp_array_access< T[] > +{ + typedef T & type; +}; + +#if !defined( __BORLANDC__ ) || !BOOST_WORKAROUND( __BORLANDC__, < 0x600 ) + +template< class T, std::size_t N > struct sp_array_access< T[N] > +{ + typedef T & type; +}; + +#endif + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +// sp_extent, for operator[] index check + +template< class T > struct sp_extent +{ + enum _vt { value = 0 }; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T, std::size_t N > struct sp_extent< T[N] > +{ + enum _vt { value = N }; +}; + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +// enable_shared_from_this support + +template< class X, class Y, class T > inline void sp_enable_shared_from_this( boost::shared_ptr const * ppx, Y const * py, boost::enable_shared_from_this< T > const * pe ) +{ + if( pe != 0 ) + { + pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) ); + } +} + +template< class X, class Y > inline void sp_enable_shared_from_this( boost::shared_ptr * ppx, Y const * py, boost::enable_shared_from_raw const * pe ); + +#ifdef _MANAGED + +// Avoid C4793, ... causes native code generation + +struct sp_any_pointer +{ + template sp_any_pointer( T* ) {} +}; + +inline void sp_enable_shared_from_this( sp_any_pointer, sp_any_pointer, sp_any_pointer ) +{ +} + +#else // _MANAGED + +inline void sp_enable_shared_from_this( ... ) +{ +} + +#endif // _MANAGED + +#if !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && !defined( BOOST_NO_AUTO_PTR ) + +// rvalue unique_ptr support based on a technique by Dave Abrahams + +template< class T, class R > struct sp_enable_if_unique_ptr +{ +}; + +template< class T, class R > struct sp_enable_if_unique_ptr< std::unique_ptr< T >, R > +{ + typedef R type; +}; + +#endif + +// sp_assert_convertible + +template< class Y, class T > inline void sp_assert_convertible() +{ +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + // static_assert( sp_convertible< Y, T >::value ); + typedef char tmp[ sp_convertible< Y, T >::value? 1: -1 ]; + (void)sizeof( tmp ); + +#else + + T* p = static_cast< Y* >( 0 ); + (void)p; + +#endif +} + +// pointer constructor helper + +template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T > * ppx, Y * p, boost::detail::shared_count & pn ) +{ + boost::detail::shared_count( p ).swap( pn ); + boost::detail::sp_enable_shared_from_this( ppx, p, p ); +} + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T, class Y > inline void sp_pointer_construct( boost::shared_ptr< T[] > * /*ppx*/, Y * p, boost::detail::shared_count & pn ) +{ + sp_assert_convertible< Y[], T[] >(); + boost::detail::shared_count( p, boost::checked_array_deleter< T >() ).swap( pn ); +} + +template< class T, std::size_t N, class Y > inline void sp_pointer_construct( boost::shared_ptr< T[N] > * /*ppx*/, Y * p, boost::detail::shared_count & pn ) +{ + sp_assert_convertible< Y[N], T[N] >(); + boost::detail::shared_count( p, boost::checked_array_deleter< T >() ).swap( pn ); +} + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +// deleter constructor helper + +template< class T, class Y > inline void sp_deleter_construct( boost::shared_ptr< T > * ppx, Y * p ) +{ + boost::detail::sp_enable_shared_from_this( ppx, p, p ); +} + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class T, class Y > inline void sp_deleter_construct( boost::shared_ptr< T[] > * /*ppx*/, Y * /*p*/ ) +{ + sp_assert_convertible< Y[], T[] >(); +} + +template< class T, std::size_t N, class Y > inline void sp_deleter_construct( boost::shared_ptr< T[N] > * /*ppx*/, Y * /*p*/ ) +{ + sp_assert_convertible< Y[N], T[N] >(); +} + +#endif // !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +} // namespace detail + + +// +// shared_ptr +// +// An enhanced relative of scoped_ptr with reference counted copy semantics. +// The object pointed to is deleted when the last shared_ptr pointing to it +// is destroyed or reset. +// + +template class shared_ptr +{ +private: + + // Borland 5.5.1 specific workaround + typedef shared_ptr this_type; + +public: + + typedef typename boost::detail::sp_element< T >::type element_type; + + shared_ptr() BOOST_NOEXCEPT : px( 0 ), pn() // never throws in 1.30+ + { + } + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + + shared_ptr( boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT : px( 0 ), pn() // never throws + { + } + +#endif + + template + explicit shared_ptr( Y * p ): px( p ), pn() // Y must be complete + { + boost::detail::sp_pointer_construct( this, p, pn ); + } + + // + // Requirements: D's copy constructor must not throw + // + // shared_ptr will release p by calling d(p) + // + + template shared_ptr( Y * p, D d ): px( p ), pn( p, d ) + { + boost::detail::sp_deleter_construct( this, p ); + } + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + + template shared_ptr( boost::detail::sp_nullptr_t p, D d ): px( p ), pn( p, d ) + { + } + +#endif + + // As above, but with allocator. A's copy constructor shall not throw. + + template shared_ptr( Y * p, D d, A a ): px( p ), pn( p, d, a ) + { + boost::detail::sp_deleter_construct( this, p ); + } + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + + template shared_ptr( boost::detail::sp_nullptr_t p, D d, A a ): px( p ), pn( p, d, a ) + { + } + +#endif + +// generated copy constructor, destructor are fine... + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +// ... except in C++0x, move disables the implicit copy + + shared_ptr( shared_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) + { + } + +#endif + + template + explicit shared_ptr( weak_ptr const & r ): pn( r.pn ) // may throw + { + boost::detail::sp_assert_convertible< Y, T >(); + + // it is now safe to copy r.px, as pn(r.pn) did not throw + px = r.px; + } + + template + shared_ptr( weak_ptr const & r, boost::detail::sp_nothrow_tag ) + BOOST_NOEXCEPT : px( 0 ), pn( r.pn, boost::detail::sp_nothrow_tag() ) + { + if( !pn.empty() ) + { + px = r.px; + } + } + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + shared_ptr( shared_ptr const & r, typename boost::detail::sp_enable_if_convertible::type = boost::detail::sp_empty() ) + +#else + + shared_ptr( shared_ptr const & r ) + +#endif + BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) + { + boost::detail::sp_assert_convertible< Y, T >(); + } + + // aliasing + template< class Y > + shared_ptr( shared_ptr const & r, element_type * p ) BOOST_NOEXCEPT : px( p ), pn( r.pn ) + { + } + +#ifndef BOOST_NO_AUTO_PTR + + template + explicit shared_ptr( std::unique_ptr & r ): px(r.get()), pn() + { + boost::detail::sp_assert_convertible< Y, T >(); + + Y * tmp = r.get(); + pn = boost::detail::shared_count( r ); + + boost::detail::sp_deleter_construct( this, tmp ); + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + template + shared_ptr( std::unique_ptr && r ): px(r.get()), pn() + { + boost::detail::sp_assert_convertible< Y, T >(); + + Y * tmp = r.get(); + pn = boost::detail::shared_count( r ); + + boost::detail::sp_deleter_construct( this, tmp ); + } + +#elif !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + + template + explicit shared_ptr( Ap r, typename boost::detail::sp_enable_if_unique_ptr::type = 0 ): px( r.get() ), pn() + { + typedef typename Ap::element_type Y; + + boost::detail::sp_assert_convertible< Y, T >(); + + Y * tmp = r.get(); + pn = boost::detail::shared_count( r ); + + boost::detail::sp_deleter_construct( this, tmp ); + } + +#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#endif // BOOST_NO_AUTO_PTR + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + template< class Y, class D > + shared_ptr( std::unique_ptr< Y, D > && r ): px( r.get() ), pn() + { + boost::detail::sp_assert_convertible< Y, T >(); + + typename std::unique_ptr< Y, D >::pointer tmp = r.get(); + pn = boost::detail::shared_count( r ); + + boost::detail::sp_deleter_construct( this, tmp ); + } + +#endif + + // assignment + + shared_ptr & operator=( shared_ptr const & r ) BOOST_NOEXCEPT + { + this_type(r).swap(*this); + return *this; + } + +#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1400) + + template + shared_ptr & operator=(shared_ptr const & r) BOOST_NOEXCEPT + { + this_type(r).swap(*this); + return *this; + } + +#endif + +#ifndef BOOST_NO_AUTO_PTR + + template + shared_ptr & operator=( std::unique_ptr & r ) + { + this_type( r ).swap( *this ); + return *this; + } + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + template + shared_ptr & operator=( std::unique_ptr && r ) + { + this_type( static_cast< std::unique_ptr && >( r ) ).swap( *this ); + return *this; + } + +#elif !defined( BOOST_NO_SFINAE ) && !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + + template + typename boost::detail::sp_enable_if_unique_ptr< Ap, shared_ptr & >::type operator=( Ap r ) + { + this_type( r ).swap( *this ); + return *this; + } + +#endif // BOOST_NO_SFINAE, BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + +#endif // BOOST_NO_AUTO_PTR + +#if !defined( BOOST_NO_CXX11_SMART_PTR ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + template + shared_ptr & operator=( std::unique_ptr && r ) + { + this_type( static_cast< std::unique_ptr && >( r ) ).swap(*this); + return *this; + } + +#endif + +// Move support + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + + shared_ptr( shared_ptr && r ) BOOST_NOEXCEPT : px( r.px ), pn() + { + pn.swap( r.pn ); + r.px = 0; + } + + template +#if !defined( BOOST_SP_NO_SP_CONVERTIBLE ) + + shared_ptr( shared_ptr && r, typename boost::detail::sp_enable_if_convertible::type = boost::detail::sp_empty() ) + +#else + + shared_ptr( shared_ptr && r ) + +#endif + BOOST_NOEXCEPT : px( r.px ), pn() + { + boost::detail::sp_assert_convertible< Y, T >(); + + pn.swap( r.pn ); + r.px = 0; + } + + shared_ptr & operator=( shared_ptr && r ) BOOST_NOEXCEPT + { + this_type( static_cast< shared_ptr && >( r ) ).swap( *this ); + return *this; + } + + template + shared_ptr & operator=( shared_ptr && r ) BOOST_NOEXCEPT + { + this_type( static_cast< shared_ptr && >( r ) ).swap( *this ); + return *this; + } + +#endif + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + + shared_ptr & operator=( boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT // never throws + { + this_type().swap(*this); + return *this; + } + +#endif + + void reset() BOOST_NOEXCEPT // never throws in 1.30+ + { + this_type().swap(*this); + } + + template void reset( Y * p ) // Y must be complete + { + BOOST_ASSERT( p == 0 || p != px ); // catch self-reset errors + this_type( p ).swap( *this ); + } + + template void reset( Y * p, D d ) + { + this_type( p, d ).swap( *this ); + } + + template void reset( Y * p, D d, A a ) + { + this_type( p, d, a ).swap( *this ); + } + + template void reset( shared_ptr const & r, element_type * p ) + { + this_type( r, p ).swap( *this ); + } + + // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) + typename boost::detail::sp_dereference< T >::type operator* () const + { + BOOST_ASSERT( px != 0 ); + return *px; + } + + // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) + typename boost::detail::sp_member_access< T >::type operator-> () const + { + BOOST_ASSERT( px != 0 ); + return px; + } + + // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) + typename boost::detail::sp_array_access< T >::type operator[] ( std::ptrdiff_t i ) const + { + BOOST_ASSERT( px != 0 ); + BOOST_ASSERT( i >= 0 && ( i < boost::detail::sp_extent< T >::value || boost::detail::sp_extent< T >::value == 0 ) ); + + return static_cast< typename boost::detail::sp_array_access< T >::type >( px[ i ] ); + } + + element_type * get() const BOOST_NOEXCEPT + { + return px; + } + +// implicit conversion to "bool" +#include + + bool unique() const BOOST_NOEXCEPT + { + return pn.unique(); + } + + long use_count() const BOOST_NOEXCEPT + { + return pn.use_count(); + } + + void swap( shared_ptr & other ) BOOST_NOEXCEPT + { + std::swap(px, other.px); + pn.swap(other.pn); + } + + template bool owner_before( shared_ptr const & rhs ) const BOOST_NOEXCEPT + { + return pn < rhs.pn; + } + + template bool owner_before( weak_ptr const & rhs ) const BOOST_NOEXCEPT + { + return pn < rhs.pn; + } + + void * _internal_get_deleter( boost::detail::sp_typeinfo const & ti ) const BOOST_NOEXCEPT + { + return pn.get_deleter( ti ); + } + + void * _internal_get_untyped_deleter() const BOOST_NOEXCEPT + { + return pn.get_untyped_deleter(); + } + + bool _internal_equiv( shared_ptr const & r ) const BOOST_NOEXCEPT + { + return px == r.px && pn == r.pn; + } + +// Tasteless as this may seem, making all members public allows member templates +// to work in the absence of member template friends. (Matthew Langston) + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + +private: + + template friend class shared_ptr; + template friend class weak_ptr; + + +#endif + + element_type * px; // contained pointer + boost::detail::shared_count pn; // reference counter + +}; // shared_ptr + +template inline bool operator==(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT +{ + return a.get() == b.get(); +} + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT +{ + return a.get() != b.get(); +} + +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96 + +// Resolve the ambiguity between our op!= and the one in rel_ops + +template inline bool operator!=(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT +{ + return a.get() != b.get(); +} + +#endif + +#if !defined( BOOST_NO_CXX11_NULLPTR ) + +template inline bool operator==( shared_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT +{ + return p.get() == 0; +} + +template inline bool operator==( boost::detail::sp_nullptr_t, shared_ptr const & p ) BOOST_NOEXCEPT +{ + return p.get() == 0; +} + +template inline bool operator!=( shared_ptr const & p, boost::detail::sp_nullptr_t ) BOOST_NOEXCEPT +{ + return p.get() != 0; +} + +template inline bool operator!=( boost::detail::sp_nullptr_t, shared_ptr const & p ) BOOST_NOEXCEPT +{ + return p.get() != 0; +} + +#endif + +template inline bool operator<(shared_ptr const & a, shared_ptr const & b) BOOST_NOEXCEPT +{ + return a.owner_before( b ); +} + +template inline void swap(shared_ptr & a, shared_ptr & b) BOOST_NOEXCEPT +{ + a.swap(b); +} + +template shared_ptr static_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT +{ + (void) static_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename shared_ptr::element_type E; + + E * p = static_cast< E* >( r.get() ); + return shared_ptr( r, p ); +} + +template shared_ptr const_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT +{ + (void) const_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename shared_ptr::element_type E; + + E * p = const_cast< E* >( r.get() ); + return shared_ptr( r, p ); +} + +template shared_ptr dynamic_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT +{ + (void) dynamic_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename shared_ptr::element_type E; + + E * p = dynamic_cast< E* >( r.get() ); + return p? shared_ptr( r, p ): shared_ptr(); +} + +template shared_ptr reinterpret_pointer_cast( shared_ptr const & r ) BOOST_NOEXCEPT +{ + (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename shared_ptr::element_type E; + + E * p = reinterpret_cast< E* >( r.get() ); + return shared_ptr( r, p ); +} + +// get_pointer() enables boost::mem_fn to recognize shared_ptr + +template inline typename shared_ptr::element_type * get_pointer(shared_ptr const & p) BOOST_NOEXCEPT +{ + return p.get(); +} + +// operator<< + +#if !defined(BOOST_NO_IOSTREAM) + +#if defined(BOOST_NO_TEMPLATED_IOSTREAMS) || ( defined(__GNUC__) && (__GNUC__ < 3) ) + +template std::ostream & operator<< (std::ostream & os, shared_ptr const & p) +{ + os << p.get(); + return os; +} + +#else + +// in STLport's no-iostreams mode no iostream symbols can be used +#ifndef _STLP_NO_IOSTREAMS + +# if defined(BOOST_MSVC) && BOOST_WORKAROUND(BOOST_MSVC, < 1300 && __SGI_STL_PORT) +// MSVC6 has problems finding std::basic_ostream through the using declaration in namespace _STL +using std::basic_ostream; +template basic_ostream & operator<< (basic_ostream & os, shared_ptr const & p) +# else +template std::basic_ostream & operator<< (std::basic_ostream & os, shared_ptr const & p) +# endif +{ + os << p.get(); + return os; +} + +#endif // _STLP_NO_IOSTREAMS + +#endif // __GNUC__ < 3 + +#endif // !defined(BOOST_NO_IOSTREAM) + +// get_deleter + +namespace detail +{ + +#if ( defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) ) || \ + ( defined(__EDG_VERSION__) && BOOST_WORKAROUND(__EDG_VERSION__, <= 238) ) || \ + ( defined(__HP_aCC) && BOOST_WORKAROUND(__HP_aCC, <= 33500) ) + +// g++ 2.9x doesn't allow static_cast(void *) +// apparently EDG 2.38 and HP aCC A.03.35 also don't accept it + +template D * basic_get_deleter(shared_ptr const & p) +{ + void const * q = p._internal_get_deleter(BOOST_SP_TYPEID(D)); + return const_cast(static_cast(q)); +} + +#else + +template D * basic_get_deleter( shared_ptr const & p ) BOOST_NOEXCEPT +{ + return static_cast( p._internal_get_deleter(BOOST_SP_TYPEID(D)) ); +} + +#endif + +class esft2_deleter_wrapper +{ +private: + + shared_ptr deleter_; + +public: + + esft2_deleter_wrapper() + { + } + + template< class T > void set_deleter( shared_ptr const & deleter ) + { + deleter_ = deleter; + } + + template D* get_deleter() const BOOST_NOEXCEPT + { + return boost::detail::basic_get_deleter( deleter_ ); + } + + template< class T> void operator()( T* ) + { + BOOST_ASSERT( deleter_.use_count() <= 1 ); + deleter_.reset(); + } +}; + +} // namespace detail + +template D * get_deleter( shared_ptr const & p ) BOOST_NOEXCEPT +{ + D *del = boost::detail::basic_get_deleter(p); + + if(del == 0) + { + boost::detail::esft2_deleter_wrapper *del_wrapper = boost::detail::basic_get_deleter(p); +// The following get_deleter method call is fully qualified because +// older versions of gcc (2.95, 3.2.3) fail to compile it when written del_wrapper->get_deleter() + if(del_wrapper) del = del_wrapper->::boost::detail::esft2_deleter_wrapper::get_deleter(); + } + + return del; +} + +// atomic access + +#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) + +template inline bool atomic_is_lock_free( shared_ptr const * /*p*/ ) BOOST_NOEXCEPT +{ + return false; +} + +template shared_ptr atomic_load( shared_ptr const * p ) +{ + boost::detail::spinlock_pool<2>::scoped_lock lock( p ); + return *p; +} + +template inline shared_ptr atomic_load_explicit( shared_ptr const * p, /*memory_order mo*/ int ) +{ + return atomic_load( p ); +} + +template void atomic_store( shared_ptr * p, shared_ptr r ) +{ + boost::detail::spinlock_pool<2>::scoped_lock lock( p ); + p->swap( r ); +} + +template inline void atomic_store_explicit( shared_ptr * p, shared_ptr r, /*memory_order mo*/ int ) +{ + atomic_store( p, r ); // std::move( r ) +} + +template shared_ptr atomic_exchange( shared_ptr * p, shared_ptr r ) +{ + boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p ); + + sp.lock(); + p->swap( r ); + sp.unlock(); + + return r; // return std::move( r ) +} + +template shared_ptr atomic_exchange_explicit( shared_ptr * p, shared_ptr r, /*memory_order mo*/ int ) +{ + return atomic_exchange( p, r ); // std::move( r ) +} + +template bool atomic_compare_exchange( shared_ptr * p, shared_ptr * v, shared_ptr w ) +{ + boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( p ); + + sp.lock(); + + if( p->_internal_equiv( *v ) ) + { + p->swap( w ); + + sp.unlock(); + + return true; + } + else + { + shared_ptr tmp( *p ); + + sp.unlock(); + + tmp.swap( *v ); + return false; + } +} + +template inline bool atomic_compare_exchange_explicit( shared_ptr * p, shared_ptr * v, shared_ptr w, /*memory_order success*/ int, /*memory_order failure*/ int ) +{ + return atomic_compare_exchange( p, v, w ); // std::move( w ) +} + +#endif // !defined(BOOST_SP_NO_ATOMIC_ACCESS) + +// hash_value + +template< class T > struct hash; + +template< class T > std::size_t hash_value( boost::shared_ptr const & p ) BOOST_NOEXCEPT +{ + return boost::hash< T* >()( p.get() ); +} + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_SHARED_PTR_HPP_INCLUDED diff --git a/src/external/3rd/library/boost/boost/spirit/home/classic/core/non_terminal/impl/grammar.ipp b/src/external/3rd/library/boost/boost/spirit/home/classic/core/non_terminal/impl/grammar.ipp index faddd2f3a..b09043a40 100644 --- a/src/external/3rd/library/boost/boost/spirit/home/classic/core/non_terminal/impl/grammar.ipp +++ b/src/external/3rd/library/boost/boost/spirit/home/classic/core/non_terminal/impl/grammar.ipp @@ -1,370 +1,370 @@ -/*============================================================================= - Copyright (c) 2001-2003 Joel de Guzman - Copyright (c) 2002-2003 Martin Wille - Copyright (c) 2003 Hartmut Kaiser - http://spirit.sourceforge.net/ - - Use, modification and distribution is subject to the Boost Software - License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ -#if !defined BOOST_SPIRIT_GRAMMAR_IPP -#define BOOST_SPIRIT_GRAMMAR_IPP - -#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) -#include -#include -#include -#include // for std::unique_ptr -#include -#endif - -#ifdef BOOST_SPIRIT_THREADSAFE -#include -#include -#include -#endif - -/////////////////////////////////////////////////////////////////////////////// -namespace boost { namespace spirit { - -BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN - -template -struct grammar; - - -////////////////////////////////// -template -struct grammar_definition -{ - typedef typename GrammarT::template definition type; -}; - - - namespace impl - { - -#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) - struct grammar_tag {}; - - ////////////////////////////////// - template - struct grammar_helper_base - { - virtual int undefine(GrammarT *) = 0; - virtual ~grammar_helper_base() {} - }; - - ////////////////////////////////// - template - struct grammar_helper_list - { - typedef GrammarT grammar_t; - typedef grammar_helper_base helper_t; - typedef std::vector vector_t; - - grammar_helper_list() {} - grammar_helper_list(grammar_helper_list const& /*x*/) - { // Does _not_ copy the helpers member ! - } - - grammar_helper_list& operator=(grammar_helper_list const& x) - { // Does _not_ copy the helpers member ! - return *this; - } - - void push_back(helper_t *helper) - { helpers.push_back(helper); } - - void pop_back() - { helpers.pop_back(); } - - typename vector_t::size_type - size() const - { return helpers.size(); } - - typename vector_t::reverse_iterator - rbegin() - { return helpers.rbegin(); } - - typename vector_t::reverse_iterator - rend() - { return helpers.rend(); } - -#ifdef BOOST_SPIRIT_THREADSAFE - boost::mutex & mutex() - { return m; } -#endif - - private: - - vector_t helpers; -#ifdef BOOST_SPIRIT_THREADSAFE - boost::mutex m; -#endif - }; - - ////////////////////////////////// - struct grammartract_helper_list; - -#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) - - struct grammartract_helper_list - { - template - static grammar_helper_list& - do_(GrammarT const* g) - { - return g->helpers; - } - }; - -#endif - - ////////////////////////////////// - template - struct grammar_helper : private grammar_helper_base - { - typedef GrammarT grammar_t; - typedef ScannerT scanner_t; - typedef DerivedT derived_t; - typedef typename grammar_definition::type definition_t; - - typedef grammar_helper helper_t; - typedef boost::shared_ptr helper_ptr_t; - typedef boost::weak_ptr helper_weak_ptr_t; - - grammar_helper* - this_() { return this; } - - grammar_helper(helper_weak_ptr_t& p) - : definitions_cnt(0) - , self(this_()) - { p = self; } - - definition_t& - define(grammar_t const* target_grammar) - { - grammar_helper_list &helpers = - grammartract_helper_list::do_(target_grammar); - typename grammar_t::object_id id = target_grammar->get_object_id(); - - if (definitions.size()<=id) - definitions.resize(id*3/2+1); - if (definitions[id]!=0) - return *definitions[id]; - - std::unique_ptr - result(new definition_t(target_grammar->derived())); - -#ifdef BOOST_SPIRIT_THREADSAFE - boost::mutex::scoped_lock lock(helpers.mutex()); -#endif - helpers.push_back(this); - - ++definitions_cnt; - definitions[id] = result.get(); - return *(result.release()); - } - - int - undefine(grammar_t* target_grammar) - { - typename grammar_t::object_id id = target_grammar->get_object_id(); - - if (definitions.size()<=id) - return 0; - delete definitions[id]; - definitions[id] = 0; - if (--definitions_cnt==0) - self.reset(); - return 0; - } - - private: - - std::vector definitions; - unsigned long definitions_cnt; - helper_ptr_t self; - }; - -#endif /* defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) */ - -#ifdef BOOST_SPIRIT_THREADSAFE - class get_definition_static_data_tag - { - template - friend typename DerivedT::template definition & - get_definition(grammar const* self); - - get_definition_static_data_tag() {} - }; -#endif - - template - inline typename DerivedT::template definition & - get_definition(grammar const* self) - { -#if defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) - - typedef typename DerivedT::template definition definition_t; - static definition_t def(self->derived()); - return def; -#else - typedef grammar self_t; - typedef impl::grammar_helper helper_t; - typedef typename helper_t::helper_weak_ptr_t ptr_t; - -# ifdef BOOST_SPIRIT_THREADSAFE - boost::thread_specific_ptr & tld_helper - = static_, - get_definition_static_data_tag>(get_definition_static_data_tag()); - - if (!tld_helper.get()) - tld_helper.reset(new ptr_t); - ptr_t &helper = *tld_helper; -# else - static ptr_t helper; -# endif - if (helper.expired()) - new helper_t(helper); - return helper.lock()->define(self); -#endif - } - - template - struct call_helper { - - template - static void - do_ (RT &result, DefinitionT &def, ScannerT const &scan) - { - result = def.template get_start_parser()->parse(scan); - } - }; - - template <> - struct call_helper<0> { - - template - static void - do_ (RT &result, DefinitionT &def, ScannerT const &scan) - { - result = def.start().parse(scan); - } - }; - - ////////////////////////////////// - template - inline typename parser_result, ScannerT>::type - grammar_parser_parse( - grammar const* self, - ScannerT const &scan) - { - typedef - typename parser_result, ScannerT>::type - result_t; - typedef typename DerivedT::template definition definition_t; - - result_t result; - definition_t &def = get_definition(self); - - call_helper::do_(result, def, scan); - return result; - } - - ////////////////////////////////// - template - inline void - grammar_destruct(GrammarT* self) - { -#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) - typedef impl::grammar_helper_base helper_base_t; - typedef grammar_helper_list helper_list_t; - typedef typename helper_list_t::vector_t::reverse_iterator iterator_t; - - helper_list_t& helpers = - grammartract_helper_list::do_(self); - -# if defined(BOOST_INTEL_CXX_VERSION) - for (iterator_t i = helpers.rbegin(); i != helpers.rend(); ++i) - (*i)->undefine(self); -# else - std::for_each(helpers.rbegin(), helpers.rend(), - std::bind2nd(std::mem_fun(&helper_base_t::undefine), self)); -# endif - -#else - (void)self; -#endif - } - - /////////////////////////////////////////////////////////////////////////// - // - // entry_grammar class - // - /////////////////////////////////////////////////////////////////////////// - template - class entry_grammar - : public parser > - { - - public: - typedef entry_grammar self_t; - typedef self_t embed_t; - typedef typename ContextT::context_linker_t context_t; - typedef typename context_t::attr_t attr_t; - - template - struct result - { - typedef typename match_result::type type; - }; - - entry_grammar(DerivedT const &p) : target_grammar(p) {} - - template - typename parser_result::type - parse_main(ScannerT const& scan) const - { return impl::grammar_parser_parse(&target_grammar, scan); } - - template - typename parser_result::type - parse(ScannerT const& scan) const - { - typedef typename parser_result::type result_t; - typedef parser_scanner_linker scanner_t; - BOOST_SPIRIT_CONTEXT_PARSE(scan, target_grammar, scanner_t, - context_t, result_t) - } - - private: - DerivedT const &target_grammar; - }; - - } // namespace impl - -/////////////////////////////////////// -#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) -#define BOOST_SPIRIT_GRAMMAR_ID , public impl::object_with_id -#else -#define BOOST_SPIRIT_GRAMMAR_ID -#endif - -/////////////////////////////////////// -#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) -#define BOOST_SPIRIT_GRAMMAR_STATE \ - private: \ - friend struct impl::grammartract_helper_list; \ - mutable impl::grammar_helper_list helpers; -#else -#define BOOST_SPIRIT_GRAMMAR_STATE -#endif - -/////////////////////////////////////////////////////////////////////////////// -BOOST_SPIRIT_CLASSIC_NAMESPACE_END - -}} // namespace boost::spirit - -#endif +/*============================================================================= + Copyright (c) 2001-2003 Joel de Guzman + Copyright (c) 2002-2003 Martin Wille + Copyright (c) 2003 Hartmut Kaiser + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#if !defined BOOST_SPIRIT_GRAMMAR_IPP +#define BOOST_SPIRIT_GRAMMAR_IPP + +#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) +#include +#include +#include +#include // for std::unique_ptr +#include +#endif + +#ifdef BOOST_SPIRIT_THREADSAFE +#include +#include +#include +#endif + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace spirit { + +BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN + +template +struct grammar; + + +////////////////////////////////// +template +struct grammar_definition +{ + typedef typename GrammarT::template definition type; +}; + + + namespace impl + { + +#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) + struct grammar_tag {}; + + ////////////////////////////////// + template + struct grammar_helper_base + { + virtual int undefine(GrammarT *) = 0; + virtual ~grammar_helper_base() {} + }; + + ////////////////////////////////// + template + struct grammar_helper_list + { + typedef GrammarT grammar_t; + typedef grammar_helper_base helper_t; + typedef std::vector vector_t; + + grammar_helper_list() {} + grammar_helper_list(grammar_helper_list const& /*x*/) + { // Does _not_ copy the helpers member ! + } + + grammar_helper_list& operator=(grammar_helper_list const& x) + { // Does _not_ copy the helpers member ! + return *this; + } + + void push_back(helper_t *helper) + { helpers.push_back(helper); } + + void pop_back() + { helpers.pop_back(); } + + typename vector_t::size_type + size() const + { return helpers.size(); } + + typename vector_t::reverse_iterator + rbegin() + { return helpers.rbegin(); } + + typename vector_t::reverse_iterator + rend() + { return helpers.rend(); } + +#ifdef BOOST_SPIRIT_THREADSAFE + boost::mutex & mutex() + { return m; } +#endif + + private: + + vector_t helpers; +#ifdef BOOST_SPIRIT_THREADSAFE + boost::mutex m; +#endif + }; + + ////////////////////////////////// + struct grammartract_helper_list; + +#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) + + struct grammartract_helper_list + { + template + static grammar_helper_list& + do_(GrammarT const* g) + { + return g->helpers; + } + }; + +#endif + + ////////////////////////////////// + template + struct grammar_helper : private grammar_helper_base + { + typedef GrammarT grammar_t; + typedef ScannerT scanner_t; + typedef DerivedT derived_t; + typedef typename grammar_definition::type definition_t; + + typedef grammar_helper helper_t; + typedef boost::shared_ptr helper_ptr_t; + typedef boost::weak_ptr helper_weak_ptr_t; + + grammar_helper* + this_() { return this; } + + grammar_helper(helper_weak_ptr_t& p) + : definitions_cnt(0) + , self(this_()) + { p = self; } + + definition_t& + define(grammar_t const* target_grammar) + { + grammar_helper_list &helpers = + grammartract_helper_list::do_(target_grammar); + typename grammar_t::object_id id = target_grammar->get_object_id(); + + if (definitions.size()<=id) + definitions.resize(id*3/2+1); + if (definitions[id]!=0) + return *definitions[id]; + + std::unique_ptr + result(new definition_t(target_grammar->derived())); + +#ifdef BOOST_SPIRIT_THREADSAFE + boost::mutex::scoped_lock lock(helpers.mutex()); +#endif + helpers.push_back(this); + + ++definitions_cnt; + definitions[id] = result.get(); + return *(result.release()); + } + + int + undefine(grammar_t* target_grammar) + { + typename grammar_t::object_id id = target_grammar->get_object_id(); + + if (definitions.size()<=id) + return 0; + delete definitions[id]; + definitions[id] = 0; + if (--definitions_cnt==0) + self.reset(); + return 0; + } + + private: + + std::vector definitions; + unsigned long definitions_cnt; + helper_ptr_t self; + }; + +#endif /* defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) */ + +#ifdef BOOST_SPIRIT_THREADSAFE + class get_definition_static_data_tag + { + template + friend typename DerivedT::template definition & + get_definition(grammar const* self); + + get_definition_static_data_tag() {} + }; +#endif + + template + inline typename DerivedT::template definition & + get_definition(grammar const* self) + { +#if defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) + + typedef typename DerivedT::template definition definition_t; + static definition_t def(self->derived()); + return def; +#else + typedef grammar self_t; + typedef impl::grammar_helper helper_t; + typedef typename helper_t::helper_weak_ptr_t ptr_t; + +# ifdef BOOST_SPIRIT_THREADSAFE + boost::thread_specific_ptr & tld_helper + = static_, + get_definition_static_data_tag>(get_definition_static_data_tag()); + + if (!tld_helper.get()) + tld_helper.reset(new ptr_t); + ptr_t &helper = *tld_helper; +# else + static ptr_t helper; +# endif + if (helper.expired()) + new helper_t(helper); + return helper.lock()->define(self); +#endif + } + + template + struct call_helper { + + template + static void + do_ (RT &result, DefinitionT &def, ScannerT const &scan) + { + result = def.template get_start_parser()->parse(scan); + } + }; + + template <> + struct call_helper<0> { + + template + static void + do_ (RT &result, DefinitionT &def, ScannerT const &scan) + { + result = def.start().parse(scan); + } + }; + + ////////////////////////////////// + template + inline typename parser_result, ScannerT>::type + grammar_parser_parse( + grammar const* self, + ScannerT const &scan) + { + typedef + typename parser_result, ScannerT>::type + result_t; + typedef typename DerivedT::template definition definition_t; + + result_t result; + definition_t &def = get_definition(self); + + call_helper::do_(result, def, scan); + return result; + } + + ////////////////////////////////// + template + inline void + grammar_destruct(GrammarT* self) + { +#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) + typedef impl::grammar_helper_base helper_base_t; + typedef grammar_helper_list helper_list_t; + typedef typename helper_list_t::vector_t::reverse_iterator iterator_t; + + helper_list_t& helpers = + grammartract_helper_list::do_(self); + +# if defined(BOOST_INTEL_CXX_VERSION) + for (iterator_t i = helpers.rbegin(); i != helpers.rend(); ++i) + (*i)->undefine(self); +# else + std::for_each(helpers.rbegin(), helpers.rend(), + std::bind2nd(std::mem_fun(&helper_base_t::undefine), self)); +# endif + +#else + (void)self; +#endif + } + + /////////////////////////////////////////////////////////////////////////// + // + // entry_grammar class + // + /////////////////////////////////////////////////////////////////////////// + template + class entry_grammar + : public parser > + { + + public: + typedef entry_grammar self_t; + typedef self_t embed_t; + typedef typename ContextT::context_linker_t context_t; + typedef typename context_t::attr_t attr_t; + + template + struct result + { + typedef typename match_result::type type; + }; + + entry_grammar(DerivedT const &p) : target_grammar(p) {} + + template + typename parser_result::type + parse_main(ScannerT const& scan) const + { return impl::grammar_parser_parse(&target_grammar, scan); } + + template + typename parser_result::type + parse(ScannerT const& scan) const + { + typedef typename parser_result::type result_t; + typedef parser_scanner_linker scanner_t; + BOOST_SPIRIT_CONTEXT_PARSE(scan, target_grammar, scanner_t, + context_t, result_t) + } + + private: + DerivedT const &target_grammar; + }; + + } // namespace impl + +/////////////////////////////////////// +#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) +#define BOOST_SPIRIT_GRAMMAR_ID , public impl::object_with_id +#else +#define BOOST_SPIRIT_GRAMMAR_ID +#endif + +/////////////////////////////////////// +#if !defined(BOOST_SPIRIT_SINGLE_GRAMMAR_INSTANCE) +#define BOOST_SPIRIT_GRAMMAR_STATE \ + private: \ + friend struct impl::grammartract_helper_list; \ + mutable impl::grammar_helper_list helpers; +#else +#define BOOST_SPIRIT_GRAMMAR_STATE +#endif + +/////////////////////////////////////////////////////////////////////////////// +BOOST_SPIRIT_CLASSIC_NAMESPACE_END + +}} // namespace boost::spirit + +#endif diff --git a/src/external/3rd/library/boost/boost/spirit/home/classic/symbols/impl/tst.ipp b/src/external/3rd/library/boost/boost/spirit/home/classic/symbols/impl/tst.ipp index 5228fdb32..c7b9e0449 100644 --- a/src/external/3rd/library/boost/boost/spirit/home/classic/symbols/impl/tst.ipp +++ b/src/external/3rd/library/boost/boost/spirit/home/classic/symbols/impl/tst.ipp @@ -1,281 +1,281 @@ -/*============================================================================= - Copyright (c) 2001-2003 Joel de Guzman - http://spirit.sourceforge.net/ - - Use, modification and distribution is subject to the Boost Software - License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ -#ifndef BOOST_SPIRIT_TST_IPP -#define BOOST_SPIRIT_TST_IPP - -/////////////////////////////////////////////////////////////////////////////// -#include // for std::unique_ptr -#include - -/////////////////////////////////////////////////////////////////////////////// -namespace boost { namespace spirit { - -BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN - - namespace impl - { - -/////////////////////////////////////////////////////////////////////////////// -// -// tst class -// -// Ternary Search Tree implementation. The data structure is faster than -// hashing for many typical search problems especially when the search -// interface is iterator based. Searching for a string of length k in a -// ternary search tree with n strings will require at most O(log n+k) -// character comparisons. TSTs are many times faster than hash tables -// for unsuccessful searches since mismatches are discovered earlier -// after examining only a few characters. Hash tables always examine an -// entire key when searching. -// -// For details see http://www.cs.princeton.edu/~rs/strings/. -// -// *** This is a low level class and is -// not meant for public consumption *** -// -/////////////////////////////////////////////////////////////////////////////// - template - struct tst_node - { - tst_node(CharT value_) - : value(value_) - , left(0) - , right(0) - { middle.link = 0; } - - ~tst_node() - { - delete left; - delete right; - if (value) - delete middle.link; - else - delete middle.data; - } - - tst_node* - clone() const - { - std::unique_ptr copy(new tst_node(value)); - - if (left) - copy->left = left->clone(); - if (right) - copy->right = right->clone(); - - if (value && middle.link) - { - copy->middle.link = middle.link->clone(); - } - else - { - std::unique_ptr mid_data(new T(*middle.data)); - copy->middle.data = mid_data.release(); - } - - return copy.release(); - } - - union center { - - tst_node* link; - T* data; - }; - - CharT value; - tst_node* left; - center middle; - tst_node* right; - }; - - /////////////////////////////////////////////////////////////////////////// - template - class tst - { - public: - - struct search_info - { - T* data; - std::size_t length; - }; - - tst() - : root(0) {} - - tst(tst const& other) - : root(other.root ? other.root->clone() : 0) {} - - ~tst() - { delete root; } - - tst& - operator=(tst const& other) - { - if (this != &other) - { - node_t* new_root = other.root ? other.root->clone() : 0; - delete root; - root = new_root; - } - return *this; - } - - template - T* add(IteratorT first, IteratorT const& last, T const& data) - { - if (first == last) - return 0; - - node_t** np = &root; - CharT ch = *first; - - BOOST_SPIRIT_ASSERT((first == last || ch != 0) - && "Won't add string containing null character"); - - for (;;) - { - if (*np == 0 || ch == 0) - { - node_t* right = 0; - if (np != 0) - right = *np; - *np = new node_t(ch); - if (right) - (**np).right = right; - } - - if (ch < (**np).value) - { - np = &(**np).left; - } - else - { - if (ch == (**np).value) - { - if (ch == 0) - { - if ((**np).middle.data == 0) - { - (**np).middle.data = new T(data); - return (**np).middle.data; - } - else - { - // re-addition is disallowed - return 0; - } - } - ++first; - ch = (first == last) ? CharT(0) : *first; - BOOST_SPIRIT_ASSERT((first == last || ch != 0) - && "Won't add string containing null character"); - np = &(**np).middle.link; - } - else - { - np = &(**np).right; - } - } - } - } - - template - search_info find(ScannerT const& scan) const - { - search_info result = { 0, 0 }; - if (scan.at_end()) { - return result; - } - - typedef typename ScannerT::iterator_t iterator_t; - node_t* np = root; - CharT ch = *scan; - iterator_t save = scan.first; - iterator_t latest = scan.first; - std::size_t latest_len = 0; - - while (np) - { - - if (ch < np->value) // => go left! - { - if (np->value == 0) - { - result.data = np->middle.data; - if (result.data) - { - latest = scan.first; - latest_len = result.length; - } - } - - np = np->left; - } - else if (ch == np->value) // => go middle! - { - // Matching the null character is not allowed. - if (np->value == 0) - { - result.data = np->middle.data; - if (result.data) - { - latest = scan.first; - latest_len = result.length; - } - break; - } - - ++scan; - ch = scan.at_end() ? CharT(0) : *scan; - np = np->middle.link; - ++result.length; - } - else // (ch > np->value) => go right! - { - if (np->value == 0) - { - result.data = np->middle.data; - if (result.data) - { - latest = scan.first; - latest_len = result.length; - } - } - - np = np->right; - } - } - - if (result.data == 0) - { - scan.first = save; - } - else - { - scan.first = latest; - result.length = latest_len; - } - return result; - } - - private: - - typedef tst_node node_t; - node_t* root; - }; - -/////////////////////////////////////////////////////////////////////////////// - } // namespace impl - -BOOST_SPIRIT_CLASSIC_NAMESPACE_END - -}} // namespace boost::spirit - -#endif +/*============================================================================= + Copyright (c) 2001-2003 Joel de Guzman + http://spirit.sourceforge.net/ + + Use, modification and distribution is subject to the Boost Software + License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#ifndef BOOST_SPIRIT_TST_IPP +#define BOOST_SPIRIT_TST_IPP + +/////////////////////////////////////////////////////////////////////////////// +#include // for std::unique_ptr +#include + +/////////////////////////////////////////////////////////////////////////////// +namespace boost { namespace spirit { + +BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN + + namespace impl + { + +/////////////////////////////////////////////////////////////////////////////// +// +// tst class +// +// Ternary Search Tree implementation. The data structure is faster than +// hashing for many typical search problems especially when the search +// interface is iterator based. Searching for a string of length k in a +// ternary search tree with n strings will require at most O(log n+k) +// character comparisons. TSTs are many times faster than hash tables +// for unsuccessful searches since mismatches are discovered earlier +// after examining only a few characters. Hash tables always examine an +// entire key when searching. +// +// For details see http://www.cs.princeton.edu/~rs/strings/. +// +// *** This is a low level class and is +// not meant for public consumption *** +// +/////////////////////////////////////////////////////////////////////////////// + template + struct tst_node + { + tst_node(CharT value_) + : value(value_) + , left(0) + , right(0) + { middle.link = 0; } + + ~tst_node() + { + delete left; + delete right; + if (value) + delete middle.link; + else + delete middle.data; + } + + tst_node* + clone() const + { + std::unique_ptr copy(new tst_node(value)); + + if (left) + copy->left = left->clone(); + if (right) + copy->right = right->clone(); + + if (value && middle.link) + { + copy->middle.link = middle.link->clone(); + } + else + { + std::unique_ptr mid_data(new T(*middle.data)); + copy->middle.data = mid_data.release(); + } + + return copy.release(); + } + + union center { + + tst_node* link; + T* data; + }; + + CharT value; + tst_node* left; + center middle; + tst_node* right; + }; + + /////////////////////////////////////////////////////////////////////////// + template + class tst + { + public: + + struct search_info + { + T* data; + std::size_t length; + }; + + tst() + : root(0) {} + + tst(tst const& other) + : root(other.root ? other.root->clone() : 0) {} + + ~tst() + { delete root; } + + tst& + operator=(tst const& other) + { + if (this != &other) + { + node_t* new_root = other.root ? other.root->clone() : 0; + delete root; + root = new_root; + } + return *this; + } + + template + T* add(IteratorT first, IteratorT const& last, T const& data) + { + if (first == last) + return 0; + + node_t** np = &root; + CharT ch = *first; + + BOOST_SPIRIT_ASSERT((first == last || ch != 0) + && "Won't add string containing null character"); + + for (;;) + { + if (*np == 0 || ch == 0) + { + node_t* right = 0; + if (np != 0) + right = *np; + *np = new node_t(ch); + if (right) + (**np).right = right; + } + + if (ch < (**np).value) + { + np = &(**np).left; + } + else + { + if (ch == (**np).value) + { + if (ch == 0) + { + if ((**np).middle.data == 0) + { + (**np).middle.data = new T(data); + return (**np).middle.data; + } + else + { + // re-addition is disallowed + return 0; + } + } + ++first; + ch = (first == last) ? CharT(0) : *first; + BOOST_SPIRIT_ASSERT((first == last || ch != 0) + && "Won't add string containing null character"); + np = &(**np).middle.link; + } + else + { + np = &(**np).right; + } + } + } + } + + template + search_info find(ScannerT const& scan) const + { + search_info result = { 0, 0 }; + if (scan.at_end()) { + return result; + } + + typedef typename ScannerT::iterator_t iterator_t; + node_t* np = root; + CharT ch = *scan; + iterator_t save = scan.first; + iterator_t latest = scan.first; + std::size_t latest_len = 0; + + while (np) + { + + if (ch < np->value) // => go left! + { + if (np->value == 0) + { + result.data = np->middle.data; + if (result.data) + { + latest = scan.first; + latest_len = result.length; + } + } + + np = np->left; + } + else if (ch == np->value) // => go middle! + { + // Matching the null character is not allowed. + if (np->value == 0) + { + result.data = np->middle.data; + if (result.data) + { + latest = scan.first; + latest_len = result.length; + } + break; + } + + ++scan; + ch = scan.at_end() ? CharT(0) : *scan; + np = np->middle.link; + ++result.length; + } + else // (ch > np->value) => go right! + { + if (np->value == 0) + { + result.data = np->middle.data; + if (result.data) + { + latest = scan.first; + latest_len = result.length; + } + } + + np = np->right; + } + } + + if (result.data == 0) + { + scan.first = save; + } + else + { + scan.first = latest; + result.length = latest_len; + } + return result; + } + + private: + + typedef tst_node node_t; + node_t* root; + }; + +/////////////////////////////////////////////////////////////////////////////// + } // namespace impl + +BOOST_SPIRIT_CLASSIC_NAMESPACE_END + +}} // namespace boost::spirit + +#endif diff --git a/src/external/3rd/library/boost/boost/spirit/home/classic/tree/common.hpp b/src/external/3rd/library/boost/boost/spirit/home/classic/tree/common.hpp index 01cfa5353..509e3f56a 100644 --- a/src/external/3rd/library/boost/boost/spirit/home/classic/tree/common.hpp +++ b/src/external/3rd/library/boost/boost/spirit/home/classic/tree/common.hpp @@ -1,1585 +1,1585 @@ -/*============================================================================= - Copyright (c) 2001-2003 Daniel Nuffer - Copyright (c) 2001-2007 Hartmut Kaiser - Revised 2007, Copyright (c) Tobias Schwinger - http://spirit.sourceforge.net/ - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -=============================================================================*/ -#ifndef BOOST_SPIRIT_TREE_COMMON_HPP -#define BOOST_SPIRIT_TREE_COMMON_HPP - -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) -#include -#else -#include -#endif - -#if defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) -#include -#endif - -#include - -#include -#include -#include -#include -#include // for boost::detail::iterator_traits -#include - -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) -#include -#include -#endif - -#include - -namespace boost { namespace spirit { - -BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN - -template -void swap(tree_node& a, tree_node& b); - -template -void swap(node_iter_data& a, node_iter_data& b); - -namespace impl { - template - inline void cp_swap(T& t1, T& t2); -} - -template -struct tree_node -{ - typedef T parse_node_t; - -#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) - typedef std::allocator > allocator_type; -#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - typedef boost::pool_allocator > allocator_type; -#else - typedef boost::fast_pool_allocator > allocator_type; -#endif - -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - typedef std::vector, allocator_type> children_t; -#else - typedef std::list, allocator_type> children_t; -#endif // BOOST_SPIRIT_USE_LIST_FOR_TREES - - typedef typename children_t::iterator tree_iterator; - typedef typename children_t::const_iterator const_tree_iterator; - - T value; - children_t children; - - tree_node() - : value() - , children() - {} - - explicit tree_node(T const& v) - : value(v) - , children() - {} - - tree_node(T const& v, children_t const& c) - : value(v) - , children(c) - {} - - void swap(tree_node& x) - { - impl::cp_swap(value, x.value); - impl::cp_swap(children, x.children); - } - -// Intel V5.0.1 has a problem without this explicit operator= - tree_node &operator= (tree_node const &rhs) - { - tree_node(rhs).swap(*this); - return *this; - } -}; - -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) -template -inline std::ostream& -operator<<(std::ostream& o, tree_node const& n) -{ - static int depth = 0; - o << "\n"; - for (int i = 0; i <= depth; ++i) - { - o << "\t"; - } - o << "(depth = " << depth++ << " value = " << n.value; - int c = 0; - for (typename tree_node::children_t::const_iterator it = n.children.begin(); - it != n.children.end(); ++it) - { - o << " children[" << c++ << "] = " << *it; - } - o << ")"; - --depth; - return o; -} -#endif - -////////////////////////////////// -template -struct node_iter_data -{ - typedef IteratorT iterator_t; - typedef IteratorT /*const*/ const_iterator_t; - - node_iter_data() - : first(), last(), is_root_(false), parser_id_(), value_() - {} - - node_iter_data(IteratorT const& _first, IteratorT const& _last) - : first(_first), last(_last), is_root_(false), parser_id_(), value_() - {} - - void swap(node_iter_data& x) - { - impl::cp_swap(first, x.first); - impl::cp_swap(last, x.last); - impl::cp_swap(parser_id_, x.parser_id_); - impl::cp_swap(is_root_, x.is_root_); - impl::cp_swap(value_, x.value_); - } - - IteratorT begin() - { - return first; - } - - IteratorT const& begin() const - { - return first; - } - - IteratorT end() - { - return last; - } - - IteratorT const& end() const - { - return last; - } - - bool is_root() const - { - return is_root_; - } - - void is_root(bool b) - { - is_root_ = b; - } - - parser_id id() const - { - return parser_id_; - } - - void id(parser_id r) - { - parser_id_ = r; - } - - ValueT const& value() const - { - return value_; - } - - void value(ValueT const& v) - { - value_ = v; - } -private: - IteratorT first, last; - bool is_root_; - parser_id parser_id_; - ValueT value_; - -public: -}; - -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) -// value is default nil_t, so provide an operator<< for nil_t -inline std::ostream& -operator<<(std::ostream& o, nil_t const&) -{ - return o; -} - -template -inline std::ostream& -operator<<(std::ostream& o, node_iter_data const& n) -{ - o << "(id = " << n.id() << " text = \""; - typedef typename node_iter_data::const_iterator_t - iterator_t; - for (iterator_t it = n.begin(); it != n.end(); ++it) - impl::token_printer(o, *it); - o << "\" is_root = " << n.is_root() - << /*" value = " << n.value() << */")"; - return o; -} -#endif - -////////////////////////////////// -template -struct node_val_data -{ - typedef - typename boost::detail::iterator_traits::value_type - value_type; - -#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) - typedef std::allocator allocator_type; -#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - typedef boost::pool_allocator allocator_type; -#else - typedef boost::fast_pool_allocator allocator_type; -#endif - -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - typedef std::vector container_t; -#else - typedef std::list container_t; -#endif - - typedef typename container_t::iterator iterator_t; - typedef typename container_t::const_iterator const_iterator_t; - - node_val_data() - : text(), is_root_(false), parser_id_(), value_() - {} - -#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) - node_val_data(IteratorT const& _first, IteratorT const& _last) - : text(), is_root_(false), parser_id_(), value_() - { - std::copy(_first, _last, std::inserter(text, text.end())); - } - - // This constructor is for building text out of iterators - template - node_val_data(IteratorT2 const& _first, IteratorT2 const& _last) - : text(), is_root_(false), parser_id_(), value_() - { - std::copy(_first, _last, std::inserter(text, text.end())); - } -#else - node_val_data(IteratorT const& _first, IteratorT const& _last) - : text(_first, _last), is_root_(false), parser_id_(), value_() - {} - - // This constructor is for building text out of iterators - template - node_val_data(IteratorT2 const& _first, IteratorT2 const& _last) - : text(_first, _last), is_root_(false), parser_id_(), value_() - {} -#endif - - void swap(node_val_data& x) - { - impl::cp_swap(text, x.text); - impl::cp_swap(is_root_, x.is_root_); - impl::cp_swap(parser_id_, x.parser_id_); - impl::cp_swap(value_, x.value_); - } - - typename container_t::iterator begin() - { - return text.begin(); - } - - typename container_t::const_iterator begin() const - { - return text.begin(); - } - - typename container_t::iterator end() - { - return text.end(); - } - - typename container_t::const_iterator end() const - { - return text.end(); - } - - bool is_root() const - { - return is_root_; - } - - void is_root(bool b) - { - is_root_ = b; - } - - parser_id id() const - { - return parser_id_; - } - - void id(parser_id r) - { - parser_id_ = r; - } - - ValueT const& value() const - { - return value_; - } - - void value(ValueT const& v) - { - value_ = v; - } - -private: - container_t text; - bool is_root_; - parser_id parser_id_; - ValueT value_; -}; - -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) -template -inline std::ostream& -operator<<(std::ostream& o, node_val_data const& n) -{ - o << "(id = " << n.id() << " text = \""; - typedef typename node_val_data::const_iterator_t - iterator_t; - for (iterator_t it = n.begin(); it != n.end(); ++it) - impl::token_printer(o, *it); - o << "\" is_root = " << n.is_root() - << " value = " << n.value() << ")"; - return o; -} -#endif - -template -inline void -swap(tree_node& a, tree_node& b) -{ - a.swap(b); -} - -template -inline void -swap(node_iter_data& a, node_iter_data& b) -{ - a.swap(b); -} - -////////////////////////////////// -template -class node_iter_data_factory -{ -public: - // This inner class is so that node_iter_data_factory can simulate - // a template template parameter - template - class factory - { - public: - typedef IteratorT iterator_t; - typedef node_iter_data node_t; - - static node_t create_node(iterator_t const& first, iterator_t const& last, - bool /*is_leaf_node*/) - { - return node_t(first, last); - } - - static node_t empty_node() - { - return node_t(); - } - - // precondition: ContainerT contains a tree_node. And all - // iterators in the container point to the same sequence. - template - static node_t group_nodes(ContainerT const& nodes) - { - return node_t(nodes.begin()->value.begin(), - nodes.back().value.end()); - } - }; -}; - -////////////////////////////////// -template -class node_val_data_factory -{ -public: - // This inner class is so that node_val_data_factory can simulate - // a template template parameter - template - class factory - { - public: - typedef IteratorT iterator_t; - typedef node_val_data node_t; - - static node_t create_node(iterator_t const& first, iterator_t const& last, - bool is_leaf_node) - { - if (is_leaf_node) - return node_t(first, last); - else - return node_t(); - } - - static node_t empty_node() - { - return node_t(); - } - - template - static node_t group_nodes(ContainerT const& nodes) - { - typename node_t::container_t c; - typename ContainerT::const_iterator i_end = nodes.end(); - // copy all the nodes text into a new one - for (typename ContainerT::const_iterator i = nodes.begin(); - i != i_end; ++i) - { - // See docs: reduced_node_d cannot be used with a - // rule inside the []. - BOOST_ASSERT(i->children.size() == 0); - c.insert(c.end(), i->value.begin(), i->value.end()); - } - return node_t(c.begin(), c.end()); - } - }; -}; - -////////////////////////////////// -template -class node_all_val_data_factory -{ -public: - // This inner class is so that node_all_val_data_factory can simulate - // a template template parameter - template - class factory - { - public: - typedef IteratorT iterator_t; - typedef node_val_data node_t; - - static node_t create_node(iterator_t const& first, iterator_t const& last, - bool /*is_leaf_node*/) - { - return node_t(first, last); - } - - static node_t empty_node() - { - return node_t(); - } - - template - static node_t group_nodes(ContainerT const& nodes) - { - typename node_t::container_t c; - typename ContainerT::const_iterator i_end = nodes.end(); - // copy all the nodes text into a new one - for (typename ContainerT::const_iterator i = nodes.begin(); - i != i_end; ++i) - { - BOOST_ASSERT(i->children.size() == 0); - c.insert(c.end(), i->value.begin(), i->value.end()); - } - return node_t(c.begin(), c.end()); - } - }; -}; - -namespace impl { - - /////////////////////////////////////////////////////////////////////////// - // can't call unqualified swap from within classname::swap - // as Koenig lookup rules will find only the classname::swap - // member function not the global declaration, so use cp_swap - // as a forwarding function (JM): - template - inline void cp_swap(T& t1, T& t2) - { - using std::swap; - using BOOST_SPIRIT_CLASSIC_NS::swap; - using boost::swap; - swap(t1, t2); - } -} - -////////////////////////////////// -template -class tree_match : public match -{ -public: - - typedef typename NodeFactoryT::template factory node_factory_t; - typedef typename node_factory_t::node_t parse_node_t; - typedef tree_node node_t; - typedef typename node_t::children_t container_t; - typedef typename container_t::iterator tree_iterator; - typedef typename container_t::const_iterator const_tree_iterator; - - typedef T attr_t; - typedef typename boost::call_traits::param_type param_type; - typedef typename boost::call_traits::reference reference; - typedef typename boost::call_traits::const_reference const_reference; - - tree_match() - : match(), trees() - {} - - explicit - tree_match(std::size_t length_) - : match(length_), trees() - {} - - tree_match(std::size_t length_, parse_node_t const& n) - : match(length_), trees() - { - trees.push_back(node_t(n)); - } - - tree_match(std::size_t length_, param_type val, parse_node_t const& n) - : match(length_, val), trees() - { -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - trees.reserve(10); // this is more or less an arbitrary number... -#endif - trees.push_back(node_t(n)); - } - - // attention, these constructors will change the second parameter! - tree_match(std::size_t length_, container_t& c) - : match(length_), trees() - { - impl::cp_swap(trees, c); - } - - tree_match(std::size_t length_, param_type val, container_t& c) - : match(length_, val), trees() - { - impl::cp_swap(trees, c); - } - - template - tree_match(match const& other) - : match(other), trees() - {} - - template - tree_match(tree_match const& other) - : match(other), trees() - { impl::cp_swap(trees, other.trees); } - - template - tree_match& - operator=(match const& other) - { - match::operator=(other); - return *this; - } - - template - tree_match& - operator=(tree_match const& other) - { - match::operator=(other); - impl::cp_swap(trees, other.trees); - return *this; - } - - tree_match(tree_match const& x) - : match(x), trees() - { - // use unique_ptr like ownership for the trees data member - impl::cp_swap(trees, x.trees); - } - - tree_match& operator=(tree_match const& x) - { - tree_match tmp(x); - this->swap(tmp); - return *this; - } - - void swap(tree_match& x) - { - match::swap(x); - impl::cp_swap(trees, x.trees); - } - - mutable container_t trees; -}; - -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) -template -inline std::ostream& -operator<<(std::ostream& o, tree_match const& m) -{ - typedef - typename tree_match::container_t::iterator - iterator; - - o << "(length = " << (int)m.length(); - int c = 0; - for (iterator i = m.trees.begin(); i != m.trees.end(); ++i) - { - o << " trees[" << c++ << "] = " << *i; - } - o << "\n)"; - return o; -} -#endif - -////////////////////////////////// -struct tree_policy -{ - template - static void apply_op_to_match(FunctorT const& /*op*/, MatchT& /*m*/) - {} - - template - static void group_match(MatchT& /*m*/, parser_id const& /*id*/, - Iterator1T const& /*first*/, Iterator2T const& /*last*/) - {} - - template - static void concat(MatchT& /*a*/, MatchT const& /*b*/) - {} -}; - -////////////////////////////////// -template < - typename MatchPolicyT, - typename IteratorT, - typename NodeFactoryT, - typename TreePolicyT, - typename T -> -struct common_tree_match_policy : public match_policy -{ - common_tree_match_policy() - { - } - - template - common_tree_match_policy(PolicyT const & policies) - : match_policy((match_policy const &)policies) - { - } - - template - struct result { typedef tree_match type; }; - - typedef tree_match match_t; - typedef IteratorT iterator_t; - typedef TreePolicyT tree_policy_t; - typedef NodeFactoryT factory_t; - - static const match_t no_match() { return match_t(); } - static const match_t empty_match() - { return match_t(0, tree_policy_t::empty_node()); } - - template - static tree_match create_match( - std::size_t length, - AttrT const& val, - Iterator1T const& first, - Iterator2T const& last) - { -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) - - BOOST_SPIRIT_DEBUG_OUT << "\n>>> create_node(begin) <<<\n" - "creating node text: \""; - for (Iterator1T it = first; it != last; ++it) - impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it); - BOOST_SPIRIT_DEBUG_OUT << "\"\n"; - BOOST_SPIRIT_DEBUG_OUT << ">>> create_node(end) <<<\n\n"; -#endif - return tree_match(length, val, - tree_policy_t::create_node(length, first, last, true)); - } - - template - static void concat_match(Match1T& a, Match2T const& b) - { -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) - - BOOST_SPIRIT_DEBUG_OUT << "\n>>> concat_match(begin) <<<\n"; - BOOST_SPIRIT_DEBUG_OUT << "tree a:\n" << a << "\n"; - BOOST_SPIRIT_DEBUG_OUT << "tree b:\n" << b << "\n"; - BOOST_SPIRIT_DEBUG_OUT << ">>> concat_match(end) <<<\n\n"; -#endif - BOOST_SPIRIT_ASSERT(a && b); - if (a.length() == 0) - { - a = b; - return; - } - else if (b.length() == 0 -#ifdef BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING - && !b.trees.begin()->value.id().to_long() -#endif - ) - { - return; - } - a.concat(b); - tree_policy_t::concat(a, b); - } - - template - void - group_match( - MatchT& m, - parser_id const& id, - IteratorT2 const& first, - IteratorT2 const& last) const - { - if (!m) return; - -#if defined(BOOST_SPIRIT_DEBUG) && \ - (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_TREES) - - BOOST_SPIRIT_DEBUG_OUT << "\n>>> group_match(begin) <<<\n" - "new node(" << id << ") \""; - for (IteratorT2 it = first; it != last; ++it) - impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it); - BOOST_SPIRIT_DEBUG_OUT << "\"\n"; - BOOST_SPIRIT_DEBUG_OUT << "new child tree (before grouping):\n" << m << "\n"; - - tree_policy_t::group_match(m, id, first, last); - - BOOST_SPIRIT_DEBUG_OUT << "new child tree (after grouping):\n" << m << "\n"; - BOOST_SPIRIT_DEBUG_OUT << ">>> group_match(end) <<<\n\n"; -#else - tree_policy_t::group_match(m, id, first, last); -#endif - } -}; - -////////////////////////////////// -template -struct common_tree_tree_policy -{ - typedef typename MatchPolicyT::iterator_t iterator_t; - typedef typename MatchPolicyT::match_t match_t; - typedef typename NodeFactoryT::template factory factory_t; - typedef typename factory_t::node_t node_t; - - template - static node_t - create_node(std::size_t /*length*/, Iterator1T const& first, - Iterator2T const& last, bool leaf_node) - { - return factory_t::create_node(first, last, leaf_node); - } - - static node_t - empty_node() - { - return factory_t::empty_node(); - } - - template - static void apply_op_to_match(FunctorT const& op, match_t& m) - { - op(m); - } -}; - -////////////////////////////////// -// directives to modify how the parse tree is generated - -struct no_tree_gen_node_parser_gen; - -template -struct no_tree_gen_node_parser -: public unary > > -{ - typedef no_tree_gen_node_parser self_t; - typedef no_tree_gen_node_parser_gen parser_generator_t; - typedef unary_parser_category parser_category_t; - - no_tree_gen_node_parser(T const& a) - : unary > >(a) {} - - template - typename parser_result::type - parse(ScannerT const& scanner) const - { - typedef typename ScannerT::iteration_policy_t iteration_policy_t; - typedef match_policy match_policy_t; - typedef typename ScannerT::action_policy_t action_policy_t; - typedef scanner_policies< - iteration_policy_t, - match_policy_t, - action_policy_t - > policies_t; - - return this->subject().parse(scanner.change_policies(policies_t(scanner))); - } -}; - -struct no_tree_gen_node_parser_gen -{ - template - struct result { - - typedef no_tree_gen_node_parser type; - }; - - template - static no_tree_gen_node_parser - generate(parser const& s) - { - return no_tree_gen_node_parser(s.derived()); - } - - template - no_tree_gen_node_parser - operator[](parser const& s) const - { - return no_tree_gen_node_parser(s.derived()); - } -}; - -const no_tree_gen_node_parser_gen no_node_d = no_tree_gen_node_parser_gen(); - -////////////////////////////////// - -struct leaf_node_parser_gen; - -template -struct leaf_node_parser -: public unary > > -{ - typedef leaf_node_parser self_t; - typedef leaf_node_parser_gen parser_generator_t; - typedef unary_parser_category parser_category_t; - - leaf_node_parser(T const& a) - : unary > >(a) {} - - template - typename parser_result::type - parse(ScannerT const& scanner) const - { - typedef scanner_policies< typename ScannerT::iteration_policy_t, - match_policy, typename ScannerT::action_policy_t > policies_t; - - typedef typename ScannerT::iterator_t iterator_t; - typedef typename parser_result::type result_t; - typedef typename result_t::node_factory_t factory_t; - - iterator_t from = scanner.first; - result_t hit = impl::contiguous_parser_parse(this->subject(), - scanner.change_policies(policies_t(scanner,match_policy(),scanner)), - scanner); - - if (hit) - return result_t(hit.length(), - factory_t::create_node(from, scanner.first, true)); - else - return result_t(hit.length()); - } -}; - -struct leaf_node_parser_gen -{ - template - struct result { - - typedef leaf_node_parser type; - }; - - template - static leaf_node_parser - generate(parser const& s) - { - return leaf_node_parser(s.derived()); - } - - template - leaf_node_parser - operator[](parser const& s) const - { - return leaf_node_parser(s.derived()); - } -}; - -const leaf_node_parser_gen leaf_node_d = leaf_node_parser_gen(); -const leaf_node_parser_gen token_node_d = leaf_node_parser_gen(); - -////////////////////////////////// -namespace impl { - - template - struct tree_policy_selector - { - typedef tree_policy type; - }; - -} // namespace impl - -////////////////////////////////// -template -struct node_parser_gen; - -template -struct node_parser -: public unary > > -{ - typedef node_parser self_t; - typedef node_parser_gen parser_generator_t; - typedef unary_parser_category parser_category_t; - - node_parser(T const& a) - : unary > >(a) {} - - template - struct result - { - typedef typename parser_result::type type; - }; - - template - typename parser_result::type - parse(ScannerT const& scanner) const - { - typename parser_result::type hit = this->subject().parse(scanner); - if (hit) - { - impl::tree_policy_selector::type::apply_op_to_match(NodeParserT(), hit); - } - return hit; - } -}; - -template -struct node_parser_gen -{ - template - struct result { - - typedef node_parser type; - }; - - template - static node_parser - generate(parser const& s) - { - return node_parser(s.derived()); - } - - template - node_parser - operator[](parser const& s) const - { - return node_parser(s.derived()); - } -}; -////////////////////////////////// -struct reduced_node_op -{ - template - void operator()(MatchT& m) const - { - if (m.trees.size() == 1) - { - m.trees.begin()->children.clear(); - } - else if (m.trees.size() > 1) - { - typedef typename MatchT::node_factory_t node_factory_t; - m = MatchT(m.length(), node_factory_t::group_nodes(m.trees)); - } - } -}; - -const node_parser_gen reduced_node_d = - node_parser_gen(); - - -struct discard_node_op -{ - template - void operator()(MatchT& m) const - { - m.trees.clear(); - } -}; - -const node_parser_gen discard_node_d = - node_parser_gen(); - -struct infix_node_op -{ - template - void operator()(MatchT& m) const - { - typedef typename MatchT::container_t container_t; - typedef typename MatchT::container_t::iterator iter_t; - typedef typename MatchT::container_t::value_type value_t; - - using std::swap; - using boost::swap; - using BOOST_SPIRIT_CLASSIC_NS::swap; - - // copying the tree nodes is expensive, since it may copy a whole - // tree. swapping them is cheap, so swap the nodes we want into - // a new container of children. - container_t new_children; - std::size_t length = 0; - std::size_t tree_size = m.trees.size(); - - // the infix_node_d[] make no sense for nodes with no subnodes - BOOST_SPIRIT_ASSERT(tree_size >= 1); - - bool keep = true; -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - new_children.reserve((tree_size+1)/2); -#endif - iter_t i_end = m.trees.end(); - for (iter_t i = m.trees.begin(); i != i_end; ++i) - { - if (keep) { - // adjust the length - length += std::distance((*i).value.begin(), (*i).value.end()); - - // move the child node - new_children.push_back(value_t()); - swap(new_children.back(), *i); - keep = false; - } - else { - // ignore this child node - keep = true; - } - } - - m = MatchT(length, new_children); - } -}; - -const node_parser_gen infix_node_d = - node_parser_gen(); - -struct discard_first_node_op -{ - template - void operator()(MatchT& m) const - { - typedef typename MatchT::container_t container_t; - typedef typename MatchT::container_t::iterator iter_t; - typedef typename MatchT::container_t::value_type value_t; - - using std::swap; - using boost::swap; - using BOOST_SPIRIT_CLASSIC_NS::swap; - - // copying the tree nodes is expensive, since it may copy a whole - // tree. swapping them is cheap, so swap the nodes we want into - // a new container of children, instead of saying - // m.trees.erase(m.trees.begin()) because, on a container_t that will - // cause all the nodes afterwards to be copied into the previous - // position. - container_t new_children; - std::size_t length = 0; - std::size_t tree_size = m.trees.size(); - - // the discard_first_node_d[] make no sense for nodes with no subnodes - BOOST_SPIRIT_ASSERT(tree_size >= 1); - - if (tree_size > 1) { -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - new_children.reserve(tree_size - 1); -#endif - iter_t i = m.trees.begin(), i_end = m.trees.end(); - for (++i; i != i_end; ++i) - { - // adjust the length - length += std::distance((*i).value.begin(), (*i).value.end()); - - // move the child node - new_children.push_back(value_t()); - swap(new_children.back(), *i); - } - } - else { - // if there was a tree and now there isn't any, insert an empty node - iter_t i = m.trees.begin(); - - // This isn't entirely correct, since the empty node will reference - // the end of the discarded node, but I currently don't see any way to - // get at the begin of the node following this subnode. - // This should be safe anyway because the it shouldn't get dereferenced - // under any circumstances. - typedef typename value_t::parse_node_t::iterator_t iterator_type; - iterator_type it = (*i).value.end(); - - new_children.push_back( - value_t(typename value_t::parse_node_t(it, it))); - } - - m = MatchT(length, new_children); - } -}; - -const node_parser_gen discard_first_node_d = - node_parser_gen(); - -struct discard_last_node_op -{ - template - void operator()(MatchT& m) const - { - typedef typename MatchT::container_t container_t; - typedef typename MatchT::container_t::iterator iter_t; - typedef typename MatchT::container_t::value_type value_t; - - using std::swap; - using boost::swap; - using BOOST_SPIRIT_CLASSIC_NS::swap; - - // copying the tree nodes is expensive, since it may copy a whole - // tree. swapping them is cheap, so swap the nodes we want into - // a new container of children, instead of saying - // m.trees.erase(m.trees.begin()) because, on a container_t that will - // cause all the nodes afterwards to be copied into the previous - // position. - container_t new_children; - std::size_t length = 0; - std::size_t tree_size = m.trees.size(); - - // the discard_last_node_d[] make no sense for nodes with no subnodes - BOOST_SPIRIT_ASSERT(tree_size >= 1); - - if (tree_size > 1) { - m.trees.pop_back(); -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - new_children.reserve(tree_size - 1); -#endif - iter_t i_end = m.trees.end(); - for (iter_t i = m.trees.begin(); i != i_end; ++i) - { - // adjust the length - length += std::distance((*i).value.begin(), (*i).value.end()); - - // move the child node - new_children.push_back(value_t()); - swap(new_children.back(), *i); - } - } - else { - // if there was a tree and now there isn't any, insert an empty node - iter_t i = m.trees.begin(); - - typedef typename value_t::parse_node_t::iterator_t iterator_type; - iterator_type it = (*i).value.begin(); - - new_children.push_back( - value_t(typename value_t::parse_node_t(it, it))); - } - - m = MatchT(length, new_children); - } -}; - -const node_parser_gen discard_last_node_d = - node_parser_gen(); - -struct inner_node_op -{ - template - void operator()(MatchT& m) const - { - typedef typename MatchT::container_t container_t; - typedef typename MatchT::container_t::iterator iter_t; - typedef typename MatchT::container_t::value_type value_t; - - using std::swap; - using boost::swap; - using BOOST_SPIRIT_CLASSIC_NS::swap; - - // copying the tree nodes is expensive, since it may copy a whole - // tree. swapping them is cheap, so swap the nodes we want into - // a new container of children, instead of saying - // m.trees.erase(m.trees.begin()) because, on a container_t that will - // cause all the nodes afterwards to be copied into the previous - // position. - container_t new_children; - std::size_t length = 0; - std::size_t tree_size = m.trees.size(); - - // the inner_node_d[] make no sense for nodes with less then 2 subnodes - BOOST_SPIRIT_ASSERT(tree_size >= 2); - - if (tree_size > 2) { - m.trees.pop_back(); // erase the last element -#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) - new_children.reserve(tree_size - 1); -#endif - iter_t i = m.trees.begin(); // skip over the first element - iter_t i_end = m.trees.end(); - for (++i; i != i_end; ++i) - { - // adjust the length - length += std::distance((*i).value.begin(), (*i).value.end()); - - // move the child node - new_children.push_back(value_t()); - swap(new_children.back(), *i); - } - } - else { - // if there was a tree and now there isn't any, insert an empty node - iter_t i = m.trees.begin(); // skip over the first element - - typedef typename value_t::parse_node_t::iterator_t iterator_type; - iterator_type it = (*++i).value.begin(); - - new_children.push_back( - value_t(typename value_t::parse_node_t(it, it))); - } - - m = MatchT(length, new_children); - } -}; - -const node_parser_gen inner_node_d = - node_parser_gen(); - - -////////////////////////////////// -// action_directive_parser and action_directive_parser_gen -// are meant to be used as a template to create directives that -// generate action classes. For example access_match and -// access_node. The ActionParserT template parameter must be -// a class that has an innter class called action that is templated -// on the parser type and the action type. -template -struct action_directive_parser_gen; - -template -struct action_directive_parser -: public unary > > -{ - typedef action_directive_parser self_t; - typedef action_directive_parser_gen parser_generator_t; - typedef unary_parser_category parser_category_t; - - action_directive_parser(T const& a) - : unary > >(a) {} - - template - struct result - { - typedef typename parser_result::type type; - }; - - template - typename parser_result::type - parse(ScannerT const& scanner) const - { - return this->subject().parse(scanner); - } - - template - typename ActionParserT::template action, ActionT> - operator[](ActionT const& actor) const - { - typedef typename - ActionParserT::template action - action_t; - return action_t(*this, actor); - } -}; - -////////////////////////////////// -template -struct action_directive_parser_gen -{ - template - struct result { - - typedef action_directive_parser type; - }; - - template - static action_directive_parser - generate(parser const& s) - { - return action_directive_parser(s.derived()); - } - - template - action_directive_parser - operator[](parser const& s) const - { - return action_directive_parser(s.derived()); - } -}; - -////////////////////////////////// -// Calls the attached action passing it the match from the parser -// and the first and last iterators. -// The inner template class is used to simulate template-template parameters -// (declared in common_fwd.hpp). -template -struct access_match_action::action -: public unary > > -{ - typedef action_parser_category parser_category; - typedef action self_t; - - template - struct result - { - typedef typename parser_result::type type; - }; - - action( ParserT const& subject, - ActionT const& actor_); - - template - typename parser_result::type - parse(ScannerT const& scanner) const; - - ActionT const &predicate() const; - - private: - ActionT actor; -}; - -////////////////////////////////// -template -access_match_action::action::action( - ParserT const& subject, - ActionT const& actor_) -: unary > >(subject) -, actor(actor_) -{} - -////////////////////////////////// -template -template -typename parser_result, ScannerT>::type -access_match_action::action:: -parse(ScannerT const& scan) const -{ - typedef typename ScannerT::iterator_t iterator_t; - typedef typename parser_result::type result_t; - if (!scan.at_end()) - { - iterator_t save = scan.first; - result_t hit = this->subject().parse(scan); - actor(hit, save, scan.first); - return hit; - } - return scan.no_match(); -} - -////////////////////////////////// -template -ActionT const &access_match_action::action::predicate() const -{ - return actor; -} - -////////////////////////////////// -const action_directive_parser_gen access_match_d - = action_directive_parser_gen(); - - - -////////////////////////////////// -// Calls the attached action passing it the node from the parser -// and the first and last iterators -// The inner template class is used to simulate template-template parameters -// (declared in common_fwd.hpp). -template -struct access_node_action::action -: public unary > > -{ - typedef action_parser_category parser_category; - typedef action self_t; - - template - struct result - { - typedef typename parser_result::type type; - }; - - action( ParserT const& subject, - ActionT const& actor_); - - template - typename parser_result::type - parse(ScannerT const& scanner) const; - - ActionT const &predicate() const; - - private: - ActionT actor; -}; - -////////////////////////////////// -template -access_node_action::action::action( - ParserT const& subject, - ActionT const& actor_) -: unary > >(subject) -, actor(actor_) -{} - -////////////////////////////////// -template -template -typename parser_result, ScannerT>::type -access_node_action::action:: -parse(ScannerT const& scan) const -{ - typedef typename ScannerT::iterator_t iterator_t; - typedef typename parser_result::type result_t; - if (!scan.at_end()) - { - iterator_t save = scan.first; - result_t hit = this->subject().parse(scan); - if (hit && hit.trees.size() > 0) - actor(*hit.trees.begin(), save, scan.first); - return hit; - } - return scan.no_match(); -} - -////////////////////////////////// -template -ActionT const &access_node_action::action::predicate() const -{ - return actor; -} - -////////////////////////////////// -const action_directive_parser_gen access_node_d - = action_directive_parser_gen(); - - - -////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// -// tree_parse_info -// -// Results returned by the tree parse functions: -// -// stop: points to the final parse position (i.e parsing -// processed the input up to this point). -// -// match: true if parsing is successful. This may be full: -// the parser consumed all the input, or partial: -// the parser consumed only a portion of the input. -// -// full: true when we have a full match (i.e the parser -// consumed all the input. -// -// length: The number of characters consumed by the parser. -// This is valid only if we have a successful match -// (either partial or full). A negative value means -// that the match is unsucessful. -// -// trees: Contains the root node(s) of the tree. -// -/////////////////////////////////////////////////////////////////////////////// -template < - typename IteratorT, - typename NodeFactoryT, - typename T -> -struct tree_parse_info -{ - IteratorT stop; - bool match; - bool full; - std::size_t length; - typename tree_match::container_t trees; - - tree_parse_info() - : stop() - , match(false) - , full(false) - , length(0) - , trees() - {} - - template - tree_parse_info(tree_parse_info const& pi) - : stop(pi.stop) - , match(pi.match) - , full(pi.full) - , length(pi.length) - , trees() - { - using std::swap; - using boost::swap; - using BOOST_SPIRIT_CLASSIC_NS::swap; - - // use unique_ptr like ownership for the trees data member - swap(trees, pi.trees); - } - - tree_parse_info( - IteratorT stop_, - bool match_, - bool full_, - std::size_t length_, - typename tree_match::container_t trees_) - : stop(stop_) - , match(match_) - , full(full_) - , length(length_) - , trees() - { - using std::swap; - using boost::swap; - using BOOST_SPIRIT_CLASSIC_NS::swap; - - // use unique_ptr like ownership for the trees data member - swap(trees, trees_); - } -}; - -BOOST_SPIRIT_CLASSIC_NAMESPACE_END - -}} // namespace BOOST_SPIRIT_CLASSIC_NS - -#endif - +/*============================================================================= + Copyright (c) 2001-2003 Daniel Nuffer + Copyright (c) 2001-2007 Hartmut Kaiser + Revised 2007, Copyright (c) Tobias Schwinger + http://spirit.sourceforge.net/ + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +=============================================================================*/ +#ifndef BOOST_SPIRIT_TREE_COMMON_HPP +#define BOOST_SPIRIT_TREE_COMMON_HPP + +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) +#include +#else +#include +#endif + +#if defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) +#include +#endif + +#include + +#include +#include +#include +#include +#include // for boost::detail::iterator_traits +#include + +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) +#include +#include +#endif + +#include + +namespace boost { namespace spirit { + +BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN + +template +void swap(tree_node& a, tree_node& b); + +template +void swap(node_iter_data& a, node_iter_data& b); + +namespace impl { + template + inline void cp_swap(T& t1, T& t2); +} + +template +struct tree_node +{ + typedef T parse_node_t; + +#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) + typedef std::allocator > allocator_type; +#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + typedef boost::pool_allocator > allocator_type; +#else + typedef boost::fast_pool_allocator > allocator_type; +#endif + +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + typedef std::vector, allocator_type> children_t; +#else + typedef std::list, allocator_type> children_t; +#endif // BOOST_SPIRIT_USE_LIST_FOR_TREES + + typedef typename children_t::iterator tree_iterator; + typedef typename children_t::const_iterator const_tree_iterator; + + T value; + children_t children; + + tree_node() + : value() + , children() + {} + + explicit tree_node(T const& v) + : value(v) + , children() + {} + + tree_node(T const& v, children_t const& c) + : value(v) + , children(c) + {} + + void swap(tree_node& x) + { + impl::cp_swap(value, x.value); + impl::cp_swap(children, x.children); + } + +// Intel V5.0.1 has a problem without this explicit operator= + tree_node &operator= (tree_node const &rhs) + { + tree_node(rhs).swap(*this); + return *this; + } +}; + +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) +template +inline std::ostream& +operator<<(std::ostream& o, tree_node const& n) +{ + static int depth = 0; + o << "\n"; + for (int i = 0; i <= depth; ++i) + { + o << "\t"; + } + o << "(depth = " << depth++ << " value = " << n.value; + int c = 0; + for (typename tree_node::children_t::const_iterator it = n.children.begin(); + it != n.children.end(); ++it) + { + o << " children[" << c++ << "] = " << *it; + } + o << ")"; + --depth; + return o; +} +#endif + +////////////////////////////////// +template +struct node_iter_data +{ + typedef IteratorT iterator_t; + typedef IteratorT /*const*/ const_iterator_t; + + node_iter_data() + : first(), last(), is_root_(false), parser_id_(), value_() + {} + + node_iter_data(IteratorT const& _first, IteratorT const& _last) + : first(_first), last(_last), is_root_(false), parser_id_(), value_() + {} + + void swap(node_iter_data& x) + { + impl::cp_swap(first, x.first); + impl::cp_swap(last, x.last); + impl::cp_swap(parser_id_, x.parser_id_); + impl::cp_swap(is_root_, x.is_root_); + impl::cp_swap(value_, x.value_); + } + + IteratorT begin() + { + return first; + } + + IteratorT const& begin() const + { + return first; + } + + IteratorT end() + { + return last; + } + + IteratorT const& end() const + { + return last; + } + + bool is_root() const + { + return is_root_; + } + + void is_root(bool b) + { + is_root_ = b; + } + + parser_id id() const + { + return parser_id_; + } + + void id(parser_id r) + { + parser_id_ = r; + } + + ValueT const& value() const + { + return value_; + } + + void value(ValueT const& v) + { + value_ = v; + } +private: + IteratorT first, last; + bool is_root_; + parser_id parser_id_; + ValueT value_; + +public: +}; + +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) +// value is default nil_t, so provide an operator<< for nil_t +inline std::ostream& +operator<<(std::ostream& o, nil_t const&) +{ + return o; +} + +template +inline std::ostream& +operator<<(std::ostream& o, node_iter_data const& n) +{ + o << "(id = " << n.id() << " text = \""; + typedef typename node_iter_data::const_iterator_t + iterator_t; + for (iterator_t it = n.begin(); it != n.end(); ++it) + impl::token_printer(o, *it); + o << "\" is_root = " << n.is_root() + << /*" value = " << n.value() << */")"; + return o; +} +#endif + +////////////////////////////////// +template +struct node_val_data +{ + typedef + typename boost::detail::iterator_traits::value_type + value_type; + +#if !defined(BOOST_SPIRIT_USE_BOOST_ALLOCATOR_FOR_TREES) + typedef std::allocator allocator_type; +#elif !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + typedef boost::pool_allocator allocator_type; +#else + typedef boost::fast_pool_allocator allocator_type; +#endif + +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + typedef std::vector container_t; +#else + typedef std::list container_t; +#endif + + typedef typename container_t::iterator iterator_t; + typedef typename container_t::const_iterator const_iterator_t; + + node_val_data() + : text(), is_root_(false), parser_id_(), value_() + {} + +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + node_val_data(IteratorT const& _first, IteratorT const& _last) + : text(), is_root_(false), parser_id_(), value_() + { + std::copy(_first, _last, std::inserter(text, text.end())); + } + + // This constructor is for building text out of iterators + template + node_val_data(IteratorT2 const& _first, IteratorT2 const& _last) + : text(), is_root_(false), parser_id_(), value_() + { + std::copy(_first, _last, std::inserter(text, text.end())); + } +#else + node_val_data(IteratorT const& _first, IteratorT const& _last) + : text(_first, _last), is_root_(false), parser_id_(), value_() + {} + + // This constructor is for building text out of iterators + template + node_val_data(IteratorT2 const& _first, IteratorT2 const& _last) + : text(_first, _last), is_root_(false), parser_id_(), value_() + {} +#endif + + void swap(node_val_data& x) + { + impl::cp_swap(text, x.text); + impl::cp_swap(is_root_, x.is_root_); + impl::cp_swap(parser_id_, x.parser_id_); + impl::cp_swap(value_, x.value_); + } + + typename container_t::iterator begin() + { + return text.begin(); + } + + typename container_t::const_iterator begin() const + { + return text.begin(); + } + + typename container_t::iterator end() + { + return text.end(); + } + + typename container_t::const_iterator end() const + { + return text.end(); + } + + bool is_root() const + { + return is_root_; + } + + void is_root(bool b) + { + is_root_ = b; + } + + parser_id id() const + { + return parser_id_; + } + + void id(parser_id r) + { + parser_id_ = r; + } + + ValueT const& value() const + { + return value_; + } + + void value(ValueT const& v) + { + value_ = v; + } + +private: + container_t text; + bool is_root_; + parser_id parser_id_; + ValueT value_; +}; + +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) +template +inline std::ostream& +operator<<(std::ostream& o, node_val_data const& n) +{ + o << "(id = " << n.id() << " text = \""; + typedef typename node_val_data::const_iterator_t + iterator_t; + for (iterator_t it = n.begin(); it != n.end(); ++it) + impl::token_printer(o, *it); + o << "\" is_root = " << n.is_root() + << " value = " << n.value() << ")"; + return o; +} +#endif + +template +inline void +swap(tree_node& a, tree_node& b) +{ + a.swap(b); +} + +template +inline void +swap(node_iter_data& a, node_iter_data& b) +{ + a.swap(b); +} + +////////////////////////////////// +template +class node_iter_data_factory +{ +public: + // This inner class is so that node_iter_data_factory can simulate + // a template template parameter + template + class factory + { + public: + typedef IteratorT iterator_t; + typedef node_iter_data node_t; + + static node_t create_node(iterator_t const& first, iterator_t const& last, + bool /*is_leaf_node*/) + { + return node_t(first, last); + } + + static node_t empty_node() + { + return node_t(); + } + + // precondition: ContainerT contains a tree_node. And all + // iterators in the container point to the same sequence. + template + static node_t group_nodes(ContainerT const& nodes) + { + return node_t(nodes.begin()->value.begin(), + nodes.back().value.end()); + } + }; +}; + +////////////////////////////////// +template +class node_val_data_factory +{ +public: + // This inner class is so that node_val_data_factory can simulate + // a template template parameter + template + class factory + { + public: + typedef IteratorT iterator_t; + typedef node_val_data node_t; + + static node_t create_node(iterator_t const& first, iterator_t const& last, + bool is_leaf_node) + { + if (is_leaf_node) + return node_t(first, last); + else + return node_t(); + } + + static node_t empty_node() + { + return node_t(); + } + + template + static node_t group_nodes(ContainerT const& nodes) + { + typename node_t::container_t c; + typename ContainerT::const_iterator i_end = nodes.end(); + // copy all the nodes text into a new one + for (typename ContainerT::const_iterator i = nodes.begin(); + i != i_end; ++i) + { + // See docs: reduced_node_d cannot be used with a + // rule inside the []. + BOOST_ASSERT(i->children.size() == 0); + c.insert(c.end(), i->value.begin(), i->value.end()); + } + return node_t(c.begin(), c.end()); + } + }; +}; + +////////////////////////////////// +template +class node_all_val_data_factory +{ +public: + // This inner class is so that node_all_val_data_factory can simulate + // a template template parameter + template + class factory + { + public: + typedef IteratorT iterator_t; + typedef node_val_data node_t; + + static node_t create_node(iterator_t const& first, iterator_t const& last, + bool /*is_leaf_node*/) + { + return node_t(first, last); + } + + static node_t empty_node() + { + return node_t(); + } + + template + static node_t group_nodes(ContainerT const& nodes) + { + typename node_t::container_t c; + typename ContainerT::const_iterator i_end = nodes.end(); + // copy all the nodes text into a new one + for (typename ContainerT::const_iterator i = nodes.begin(); + i != i_end; ++i) + { + BOOST_ASSERT(i->children.size() == 0); + c.insert(c.end(), i->value.begin(), i->value.end()); + } + return node_t(c.begin(), c.end()); + } + }; +}; + +namespace impl { + + /////////////////////////////////////////////////////////////////////////// + // can't call unqualified swap from within classname::swap + // as Koenig lookup rules will find only the classname::swap + // member function not the global declaration, so use cp_swap + // as a forwarding function (JM): + template + inline void cp_swap(T& t1, T& t2) + { + using std::swap; + using BOOST_SPIRIT_CLASSIC_NS::swap; + using boost::swap; + swap(t1, t2); + } +} + +////////////////////////////////// +template +class tree_match : public match +{ +public: + + typedef typename NodeFactoryT::template factory node_factory_t; + typedef typename node_factory_t::node_t parse_node_t; + typedef tree_node node_t; + typedef typename node_t::children_t container_t; + typedef typename container_t::iterator tree_iterator; + typedef typename container_t::const_iterator const_tree_iterator; + + typedef T attr_t; + typedef typename boost::call_traits::param_type param_type; + typedef typename boost::call_traits::reference reference; + typedef typename boost::call_traits::const_reference const_reference; + + tree_match() + : match(), trees() + {} + + explicit + tree_match(std::size_t length_) + : match(length_), trees() + {} + + tree_match(std::size_t length_, parse_node_t const& n) + : match(length_), trees() + { + trees.push_back(node_t(n)); + } + + tree_match(std::size_t length_, param_type val, parse_node_t const& n) + : match(length_, val), trees() + { +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + trees.reserve(10); // this is more or less an arbitrary number... +#endif + trees.push_back(node_t(n)); + } + + // attention, these constructors will change the second parameter! + tree_match(std::size_t length_, container_t& c) + : match(length_), trees() + { + impl::cp_swap(trees, c); + } + + tree_match(std::size_t length_, param_type val, container_t& c) + : match(length_, val), trees() + { + impl::cp_swap(trees, c); + } + + template + tree_match(match const& other) + : match(other), trees() + {} + + template + tree_match(tree_match const& other) + : match(other), trees() + { impl::cp_swap(trees, other.trees); } + + template + tree_match& + operator=(match const& other) + { + match::operator=(other); + return *this; + } + + template + tree_match& + operator=(tree_match const& other) + { + match::operator=(other); + impl::cp_swap(trees, other.trees); + return *this; + } + + tree_match(tree_match const& x) + : match(x), trees() + { + // use unique_ptr like ownership for the trees data member + impl::cp_swap(trees, x.trees); + } + + tree_match& operator=(tree_match const& x) + { + tree_match tmp(x); + this->swap(tmp); + return *this; + } + + void swap(tree_match& x) + { + match::swap(x); + impl::cp_swap(trees, x.trees); + } + + mutable container_t trees; +}; + +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) +template +inline std::ostream& +operator<<(std::ostream& o, tree_match const& m) +{ + typedef + typename tree_match::container_t::iterator + iterator; + + o << "(length = " << (int)m.length(); + int c = 0; + for (iterator i = m.trees.begin(); i != m.trees.end(); ++i) + { + o << " trees[" << c++ << "] = " << *i; + } + o << "\n)"; + return o; +} +#endif + +////////////////////////////////// +struct tree_policy +{ + template + static void apply_op_to_match(FunctorT const& /*op*/, MatchT& /*m*/) + {} + + template + static void group_match(MatchT& /*m*/, parser_id const& /*id*/, + Iterator1T const& /*first*/, Iterator2T const& /*last*/) + {} + + template + static void concat(MatchT& /*a*/, MatchT const& /*b*/) + {} +}; + +////////////////////////////////// +template < + typename MatchPolicyT, + typename IteratorT, + typename NodeFactoryT, + typename TreePolicyT, + typename T +> +struct common_tree_match_policy : public match_policy +{ + common_tree_match_policy() + { + } + + template + common_tree_match_policy(PolicyT const & policies) + : match_policy((match_policy const &)policies) + { + } + + template + struct result { typedef tree_match type; }; + + typedef tree_match match_t; + typedef IteratorT iterator_t; + typedef TreePolicyT tree_policy_t; + typedef NodeFactoryT factory_t; + + static const match_t no_match() { return match_t(); } + static const match_t empty_match() + { return match_t(0, tree_policy_t::empty_node()); } + + template + static tree_match create_match( + std::size_t length, + AttrT const& val, + Iterator1T const& first, + Iterator2T const& last) + { +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) + + BOOST_SPIRIT_DEBUG_OUT << "\n>>> create_node(begin) <<<\n" + "creating node text: \""; + for (Iterator1T it = first; it != last; ++it) + impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it); + BOOST_SPIRIT_DEBUG_OUT << "\"\n"; + BOOST_SPIRIT_DEBUG_OUT << ">>> create_node(end) <<<\n\n"; +#endif + return tree_match(length, val, + tree_policy_t::create_node(length, first, last, true)); + } + + template + static void concat_match(Match1T& a, Match2T const& b) + { +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_NODES) + + BOOST_SPIRIT_DEBUG_OUT << "\n>>> concat_match(begin) <<<\n"; + BOOST_SPIRIT_DEBUG_OUT << "tree a:\n" << a << "\n"; + BOOST_SPIRIT_DEBUG_OUT << "tree b:\n" << b << "\n"; + BOOST_SPIRIT_DEBUG_OUT << ">>> concat_match(end) <<<\n\n"; +#endif + BOOST_SPIRIT_ASSERT(a && b); + if (a.length() == 0) + { + a = b; + return; + } + else if (b.length() == 0 +#ifdef BOOST_SPIRIT_NO_TREE_NODE_COLLAPSING + && !b.trees.begin()->value.id().to_long() +#endif + ) + { + return; + } + a.concat(b); + tree_policy_t::concat(a, b); + } + + template + void + group_match( + MatchT& m, + parser_id const& id, + IteratorT2 const& first, + IteratorT2 const& last) const + { + if (!m) return; + +#if defined(BOOST_SPIRIT_DEBUG) && \ + (BOOST_SPIRIT_DEBUG_FLAGS & BOOST_SPIRIT_DEBUG_FLAGS_TREES) + + BOOST_SPIRIT_DEBUG_OUT << "\n>>> group_match(begin) <<<\n" + "new node(" << id << ") \""; + for (IteratorT2 it = first; it != last; ++it) + impl::token_printer(BOOST_SPIRIT_DEBUG_OUT, *it); + BOOST_SPIRIT_DEBUG_OUT << "\"\n"; + BOOST_SPIRIT_DEBUG_OUT << "new child tree (before grouping):\n" << m << "\n"; + + tree_policy_t::group_match(m, id, first, last); + + BOOST_SPIRIT_DEBUG_OUT << "new child tree (after grouping):\n" << m << "\n"; + BOOST_SPIRIT_DEBUG_OUT << ">>> group_match(end) <<<\n\n"; +#else + tree_policy_t::group_match(m, id, first, last); +#endif + } +}; + +////////////////////////////////// +template +struct common_tree_tree_policy +{ + typedef typename MatchPolicyT::iterator_t iterator_t; + typedef typename MatchPolicyT::match_t match_t; + typedef typename NodeFactoryT::template factory factory_t; + typedef typename factory_t::node_t node_t; + + template + static node_t + create_node(std::size_t /*length*/, Iterator1T const& first, + Iterator2T const& last, bool leaf_node) + { + return factory_t::create_node(first, last, leaf_node); + } + + static node_t + empty_node() + { + return factory_t::empty_node(); + } + + template + static void apply_op_to_match(FunctorT const& op, match_t& m) + { + op(m); + } +}; + +////////////////////////////////// +// directives to modify how the parse tree is generated + +struct no_tree_gen_node_parser_gen; + +template +struct no_tree_gen_node_parser +: public unary > > +{ + typedef no_tree_gen_node_parser self_t; + typedef no_tree_gen_node_parser_gen parser_generator_t; + typedef unary_parser_category parser_category_t; + + no_tree_gen_node_parser(T const& a) + : unary > >(a) {} + + template + typename parser_result::type + parse(ScannerT const& scanner) const + { + typedef typename ScannerT::iteration_policy_t iteration_policy_t; + typedef match_policy match_policy_t; + typedef typename ScannerT::action_policy_t action_policy_t; + typedef scanner_policies< + iteration_policy_t, + match_policy_t, + action_policy_t + > policies_t; + + return this->subject().parse(scanner.change_policies(policies_t(scanner))); + } +}; + +struct no_tree_gen_node_parser_gen +{ + template + struct result { + + typedef no_tree_gen_node_parser type; + }; + + template + static no_tree_gen_node_parser + generate(parser const& s) + { + return no_tree_gen_node_parser(s.derived()); + } + + template + no_tree_gen_node_parser + operator[](parser const& s) const + { + return no_tree_gen_node_parser(s.derived()); + } +}; + +const no_tree_gen_node_parser_gen no_node_d = no_tree_gen_node_parser_gen(); + +////////////////////////////////// + +struct leaf_node_parser_gen; + +template +struct leaf_node_parser +: public unary > > +{ + typedef leaf_node_parser self_t; + typedef leaf_node_parser_gen parser_generator_t; + typedef unary_parser_category parser_category_t; + + leaf_node_parser(T const& a) + : unary > >(a) {} + + template + typename parser_result::type + parse(ScannerT const& scanner) const + { + typedef scanner_policies< typename ScannerT::iteration_policy_t, + match_policy, typename ScannerT::action_policy_t > policies_t; + + typedef typename ScannerT::iterator_t iterator_t; + typedef typename parser_result::type result_t; + typedef typename result_t::node_factory_t factory_t; + + iterator_t from = scanner.first; + result_t hit = impl::contiguous_parser_parse(this->subject(), + scanner.change_policies(policies_t(scanner,match_policy(),scanner)), + scanner); + + if (hit) + return result_t(hit.length(), + factory_t::create_node(from, scanner.first, true)); + else + return result_t(hit.length()); + } +}; + +struct leaf_node_parser_gen +{ + template + struct result { + + typedef leaf_node_parser type; + }; + + template + static leaf_node_parser + generate(parser const& s) + { + return leaf_node_parser(s.derived()); + } + + template + leaf_node_parser + operator[](parser const& s) const + { + return leaf_node_parser(s.derived()); + } +}; + +const leaf_node_parser_gen leaf_node_d = leaf_node_parser_gen(); +const leaf_node_parser_gen token_node_d = leaf_node_parser_gen(); + +////////////////////////////////// +namespace impl { + + template + struct tree_policy_selector + { + typedef tree_policy type; + }; + +} // namespace impl + +////////////////////////////////// +template +struct node_parser_gen; + +template +struct node_parser +: public unary > > +{ + typedef node_parser self_t; + typedef node_parser_gen parser_generator_t; + typedef unary_parser_category parser_category_t; + + node_parser(T const& a) + : unary > >(a) {} + + template + struct result + { + typedef typename parser_result::type type; + }; + + template + typename parser_result::type + parse(ScannerT const& scanner) const + { + typename parser_result::type hit = this->subject().parse(scanner); + if (hit) + { + impl::tree_policy_selector::type::apply_op_to_match(NodeParserT(), hit); + } + return hit; + } +}; + +template +struct node_parser_gen +{ + template + struct result { + + typedef node_parser type; + }; + + template + static node_parser + generate(parser const& s) + { + return node_parser(s.derived()); + } + + template + node_parser + operator[](parser const& s) const + { + return node_parser(s.derived()); + } +}; +////////////////////////////////// +struct reduced_node_op +{ + template + void operator()(MatchT& m) const + { + if (m.trees.size() == 1) + { + m.trees.begin()->children.clear(); + } + else if (m.trees.size() > 1) + { + typedef typename MatchT::node_factory_t node_factory_t; + m = MatchT(m.length(), node_factory_t::group_nodes(m.trees)); + } + } +}; + +const node_parser_gen reduced_node_d = + node_parser_gen(); + + +struct discard_node_op +{ + template + void operator()(MatchT& m) const + { + m.trees.clear(); + } +}; + +const node_parser_gen discard_node_d = + node_parser_gen(); + +struct infix_node_op +{ + template + void operator()(MatchT& m) const + { + typedef typename MatchT::container_t container_t; + typedef typename MatchT::container_t::iterator iter_t; + typedef typename MatchT::container_t::value_type value_t; + + using std::swap; + using boost::swap; + using BOOST_SPIRIT_CLASSIC_NS::swap; + + // copying the tree nodes is expensive, since it may copy a whole + // tree. swapping them is cheap, so swap the nodes we want into + // a new container of children. + container_t new_children; + std::size_t length = 0; + std::size_t tree_size = m.trees.size(); + + // the infix_node_d[] make no sense for nodes with no subnodes + BOOST_SPIRIT_ASSERT(tree_size >= 1); + + bool keep = true; +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + new_children.reserve((tree_size+1)/2); +#endif + iter_t i_end = m.trees.end(); + for (iter_t i = m.trees.begin(); i != i_end; ++i) + { + if (keep) { + // adjust the length + length += std::distance((*i).value.begin(), (*i).value.end()); + + // move the child node + new_children.push_back(value_t()); + swap(new_children.back(), *i); + keep = false; + } + else { + // ignore this child node + keep = true; + } + } + + m = MatchT(length, new_children); + } +}; + +const node_parser_gen infix_node_d = + node_parser_gen(); + +struct discard_first_node_op +{ + template + void operator()(MatchT& m) const + { + typedef typename MatchT::container_t container_t; + typedef typename MatchT::container_t::iterator iter_t; + typedef typename MatchT::container_t::value_type value_t; + + using std::swap; + using boost::swap; + using BOOST_SPIRIT_CLASSIC_NS::swap; + + // copying the tree nodes is expensive, since it may copy a whole + // tree. swapping them is cheap, so swap the nodes we want into + // a new container of children, instead of saying + // m.trees.erase(m.trees.begin()) because, on a container_t that will + // cause all the nodes afterwards to be copied into the previous + // position. + container_t new_children; + std::size_t length = 0; + std::size_t tree_size = m.trees.size(); + + // the discard_first_node_d[] make no sense for nodes with no subnodes + BOOST_SPIRIT_ASSERT(tree_size >= 1); + + if (tree_size > 1) { +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + new_children.reserve(tree_size - 1); +#endif + iter_t i = m.trees.begin(), i_end = m.trees.end(); + for (++i; i != i_end; ++i) + { + // adjust the length + length += std::distance((*i).value.begin(), (*i).value.end()); + + // move the child node + new_children.push_back(value_t()); + swap(new_children.back(), *i); + } + } + else { + // if there was a tree and now there isn't any, insert an empty node + iter_t i = m.trees.begin(); + + // This isn't entirely correct, since the empty node will reference + // the end of the discarded node, but I currently don't see any way to + // get at the begin of the node following this subnode. + // This should be safe anyway because the it shouldn't get dereferenced + // under any circumstances. + typedef typename value_t::parse_node_t::iterator_t iterator_type; + iterator_type it = (*i).value.end(); + + new_children.push_back( + value_t(typename value_t::parse_node_t(it, it))); + } + + m = MatchT(length, new_children); + } +}; + +const node_parser_gen discard_first_node_d = + node_parser_gen(); + +struct discard_last_node_op +{ + template + void operator()(MatchT& m) const + { + typedef typename MatchT::container_t container_t; + typedef typename MatchT::container_t::iterator iter_t; + typedef typename MatchT::container_t::value_type value_t; + + using std::swap; + using boost::swap; + using BOOST_SPIRIT_CLASSIC_NS::swap; + + // copying the tree nodes is expensive, since it may copy a whole + // tree. swapping them is cheap, so swap the nodes we want into + // a new container of children, instead of saying + // m.trees.erase(m.trees.begin()) because, on a container_t that will + // cause all the nodes afterwards to be copied into the previous + // position. + container_t new_children; + std::size_t length = 0; + std::size_t tree_size = m.trees.size(); + + // the discard_last_node_d[] make no sense for nodes with no subnodes + BOOST_SPIRIT_ASSERT(tree_size >= 1); + + if (tree_size > 1) { + m.trees.pop_back(); +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + new_children.reserve(tree_size - 1); +#endif + iter_t i_end = m.trees.end(); + for (iter_t i = m.trees.begin(); i != i_end; ++i) + { + // adjust the length + length += std::distance((*i).value.begin(), (*i).value.end()); + + // move the child node + new_children.push_back(value_t()); + swap(new_children.back(), *i); + } + } + else { + // if there was a tree and now there isn't any, insert an empty node + iter_t i = m.trees.begin(); + + typedef typename value_t::parse_node_t::iterator_t iterator_type; + iterator_type it = (*i).value.begin(); + + new_children.push_back( + value_t(typename value_t::parse_node_t(it, it))); + } + + m = MatchT(length, new_children); + } +}; + +const node_parser_gen discard_last_node_d = + node_parser_gen(); + +struct inner_node_op +{ + template + void operator()(MatchT& m) const + { + typedef typename MatchT::container_t container_t; + typedef typename MatchT::container_t::iterator iter_t; + typedef typename MatchT::container_t::value_type value_t; + + using std::swap; + using boost::swap; + using BOOST_SPIRIT_CLASSIC_NS::swap; + + // copying the tree nodes is expensive, since it may copy a whole + // tree. swapping them is cheap, so swap the nodes we want into + // a new container of children, instead of saying + // m.trees.erase(m.trees.begin()) because, on a container_t that will + // cause all the nodes afterwards to be copied into the previous + // position. + container_t new_children; + std::size_t length = 0; + std::size_t tree_size = m.trees.size(); + + // the inner_node_d[] make no sense for nodes with less then 2 subnodes + BOOST_SPIRIT_ASSERT(tree_size >= 2); + + if (tree_size > 2) { + m.trees.pop_back(); // erase the last element +#if !defined(BOOST_SPIRIT_USE_LIST_FOR_TREES) + new_children.reserve(tree_size - 1); +#endif + iter_t i = m.trees.begin(); // skip over the first element + iter_t i_end = m.trees.end(); + for (++i; i != i_end; ++i) + { + // adjust the length + length += std::distance((*i).value.begin(), (*i).value.end()); + + // move the child node + new_children.push_back(value_t()); + swap(new_children.back(), *i); + } + } + else { + // if there was a tree and now there isn't any, insert an empty node + iter_t i = m.trees.begin(); // skip over the first element + + typedef typename value_t::parse_node_t::iterator_t iterator_type; + iterator_type it = (*++i).value.begin(); + + new_children.push_back( + value_t(typename value_t::parse_node_t(it, it))); + } + + m = MatchT(length, new_children); + } +}; + +const node_parser_gen inner_node_d = + node_parser_gen(); + + +////////////////////////////////// +// action_directive_parser and action_directive_parser_gen +// are meant to be used as a template to create directives that +// generate action classes. For example access_match and +// access_node. The ActionParserT template parameter must be +// a class that has an innter class called action that is templated +// on the parser type and the action type. +template +struct action_directive_parser_gen; + +template +struct action_directive_parser +: public unary > > +{ + typedef action_directive_parser self_t; + typedef action_directive_parser_gen parser_generator_t; + typedef unary_parser_category parser_category_t; + + action_directive_parser(T const& a) + : unary > >(a) {} + + template + struct result + { + typedef typename parser_result::type type; + }; + + template + typename parser_result::type + parse(ScannerT const& scanner) const + { + return this->subject().parse(scanner); + } + + template + typename ActionParserT::template action, ActionT> + operator[](ActionT const& actor) const + { + typedef typename + ActionParserT::template action + action_t; + return action_t(*this, actor); + } +}; + +////////////////////////////////// +template +struct action_directive_parser_gen +{ + template + struct result { + + typedef action_directive_parser type; + }; + + template + static action_directive_parser + generate(parser const& s) + { + return action_directive_parser(s.derived()); + } + + template + action_directive_parser + operator[](parser const& s) const + { + return action_directive_parser(s.derived()); + } +}; + +////////////////////////////////// +// Calls the attached action passing it the match from the parser +// and the first and last iterators. +// The inner template class is used to simulate template-template parameters +// (declared in common_fwd.hpp). +template +struct access_match_action::action +: public unary > > +{ + typedef action_parser_category parser_category; + typedef action self_t; + + template + struct result + { + typedef typename parser_result::type type; + }; + + action( ParserT const& subject, + ActionT const& actor_); + + template + typename parser_result::type + parse(ScannerT const& scanner) const; + + ActionT const &predicate() const; + + private: + ActionT actor; +}; + +////////////////////////////////// +template +access_match_action::action::action( + ParserT const& subject, + ActionT const& actor_) +: unary > >(subject) +, actor(actor_) +{} + +////////////////////////////////// +template +template +typename parser_result, ScannerT>::type +access_match_action::action:: +parse(ScannerT const& scan) const +{ + typedef typename ScannerT::iterator_t iterator_t; + typedef typename parser_result::type result_t; + if (!scan.at_end()) + { + iterator_t save = scan.first; + result_t hit = this->subject().parse(scan); + actor(hit, save, scan.first); + return hit; + } + return scan.no_match(); +} + +////////////////////////////////// +template +ActionT const &access_match_action::action::predicate() const +{ + return actor; +} + +////////////////////////////////// +const action_directive_parser_gen access_match_d + = action_directive_parser_gen(); + + + +////////////////////////////////// +// Calls the attached action passing it the node from the parser +// and the first and last iterators +// The inner template class is used to simulate template-template parameters +// (declared in common_fwd.hpp). +template +struct access_node_action::action +: public unary > > +{ + typedef action_parser_category parser_category; + typedef action self_t; + + template + struct result + { + typedef typename parser_result::type type; + }; + + action( ParserT const& subject, + ActionT const& actor_); + + template + typename parser_result::type + parse(ScannerT const& scanner) const; + + ActionT const &predicate() const; + + private: + ActionT actor; +}; + +////////////////////////////////// +template +access_node_action::action::action( + ParserT const& subject, + ActionT const& actor_) +: unary > >(subject) +, actor(actor_) +{} + +////////////////////////////////// +template +template +typename parser_result, ScannerT>::type +access_node_action::action:: +parse(ScannerT const& scan) const +{ + typedef typename ScannerT::iterator_t iterator_t; + typedef typename parser_result::type result_t; + if (!scan.at_end()) + { + iterator_t save = scan.first; + result_t hit = this->subject().parse(scan); + if (hit && hit.trees.size() > 0) + actor(*hit.trees.begin(), save, scan.first); + return hit; + } + return scan.no_match(); +} + +////////////////////////////////// +template +ActionT const &access_node_action::action::predicate() const +{ + return actor; +} + +////////////////////////////////// +const action_directive_parser_gen access_node_d + = action_directive_parser_gen(); + + + +////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// +// tree_parse_info +// +// Results returned by the tree parse functions: +// +// stop: points to the final parse position (i.e parsing +// processed the input up to this point). +// +// match: true if parsing is successful. This may be full: +// the parser consumed all the input, or partial: +// the parser consumed only a portion of the input. +// +// full: true when we have a full match (i.e the parser +// consumed all the input. +// +// length: The number of characters consumed by the parser. +// This is valid only if we have a successful match +// (either partial or full). A negative value means +// that the match is unsucessful. +// +// trees: Contains the root node(s) of the tree. +// +/////////////////////////////////////////////////////////////////////////////// +template < + typename IteratorT, + typename NodeFactoryT, + typename T +> +struct tree_parse_info +{ + IteratorT stop; + bool match; + bool full; + std::size_t length; + typename tree_match::container_t trees; + + tree_parse_info() + : stop() + , match(false) + , full(false) + , length(0) + , trees() + {} + + template + tree_parse_info(tree_parse_info const& pi) + : stop(pi.stop) + , match(pi.match) + , full(pi.full) + , length(pi.length) + , trees() + { + using std::swap; + using boost::swap; + using BOOST_SPIRIT_CLASSIC_NS::swap; + + // use unique_ptr like ownership for the trees data member + swap(trees, pi.trees); + } + + tree_parse_info( + IteratorT stop_, + bool match_, + bool full_, + std::size_t length_, + typename tree_match::container_t trees_) + : stop(stop_) + , match(match_) + , full(full_) + , length(length_) + , trees() + { + using std::swap; + using boost::swap; + using BOOST_SPIRIT_CLASSIC_NS::swap; + + // use unique_ptr like ownership for the trees data member + swap(trees, trees_); + } +}; + +BOOST_SPIRIT_CLASSIC_NAMESPACE_END + +}} // namespace BOOST_SPIRIT_CLASSIC_NS + +#endif + diff --git a/src/external/3rd/library/boost/boost/spirit/home/support/detail/lexer/generator.hpp b/src/external/3rd/library/boost/boost/spirit/home/support/detail/lexer/generator.hpp index 158ef4d26..29f3e89c5 100644 --- a/src/external/3rd/library/boost/boost/spirit/home/support/detail/lexer/generator.hpp +++ b/src/external/3rd/library/boost/boost/spirit/home/support/detail/lexer/generator.hpp @@ -1,864 +1,864 @@ -// generator.hpp -// Copyright (c) 2007-2009 Ben Hanson (http://www.benhanson.net/) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_LEXER_GENERATOR_HPP -#define BOOST_LEXER_GENERATOR_HPP - -#include "char_traits.hpp" -// memcmp() -#include -#include "partition/charset.hpp" -#include "partition/equivset.hpp" -#include -#include -#include "parser/tree/node.hpp" -#include "parser/parser.hpp" -#include "containers/ptr_list.hpp" -#include "rules.hpp" -#include "state_machine.hpp" - -namespace boost -{ -namespace lexer -{ -template > -class basic_generator -{ -public: - typedef typename detail::internals::size_t_vector size_t_vector; - typedef basic_rules rules; - - static void build (const rules &rules_, - basic_state_machine &state_machine_) - { - std::size_t index_ = 0; - std::size_t size_ = rules_.statemap ().size (); - node_ptr_vector node_ptr_vector_; - detail::internals &internals_ = const_cast - (state_machine_.data ()); - bool seen_BOL_assertion_ = false; - bool seen_EOL_assertion_ = false; - - state_machine_.clear (); - - for (; index_ < size_; ++index_) - { - internals_._lookup->push_back (static_cast(0)); - internals_._lookup->back () = new size_t_vector; - internals_._dfa_alphabet.push_back (0); - internals_._dfa->push_back (static_cast(0)); - internals_._dfa->back () = new size_t_vector; - } - - for (index_ = 0, size_ = internals_._lookup->size (); - index_ < size_; ++index_) - { - internals_._lookup[index_]->resize (sizeof (CharT) == 1 ? - num_chars : num_wchar_ts, dead_state_index); - - if (!rules_.regexes ()[index_].empty ()) - { - // vector mapping token indexes to partitioned token index sets - index_set_vector set_mapping_; - // syntax tree - detail::node *root_ = build_tree (rules_, index_, - node_ptr_vector_, internals_, set_mapping_); - - build_dfa (root_, set_mapping_, - internals_._dfa_alphabet[index_], - *internals_._dfa[index_]); - - if (internals_._seen_BOL_assertion) - { - seen_BOL_assertion_ = true; - } - - if (internals_._seen_EOL_assertion) - { - seen_EOL_assertion_ = true; - } - - internals_._seen_BOL_assertion = false; - internals_._seen_EOL_assertion = false; - } - } - - internals_._seen_BOL_assertion = seen_BOL_assertion_; - internals_._seen_EOL_assertion = seen_EOL_assertion_; - } - - static void minimise (basic_state_machine &state_machine_) - { - detail::internals &internals_ = const_cast - (state_machine_.data ()); - const std::size_t machines_ = internals_._dfa->size (); - - for (std::size_t i_ = 0; i_ < machines_; ++i_) - { - const std::size_t dfa_alphabet_ = internals_._dfa_alphabet[i_]; - size_t_vector *dfa_ = internals_._dfa[i_]; - - if (dfa_alphabet_ != 0) - { - std::size_t size_ = 0; - - do - { - size_ = dfa_->size (); - minimise_dfa (dfa_alphabet_, *dfa_, size_); - } while (dfa_->size () != size_); - } - } - } - -protected: - typedef detail::basic_charset charset; - typedef detail::ptr_list charset_list; - typedef std::unique_ptr charset_ptr; - typedef detail::equivset equivset; - typedef detail::ptr_list equivset_list; - typedef std::unique_ptr equivset_ptr; - typedef typename charset::index_set index_set; - typedef std::vector index_set_vector; - typedef detail::basic_parser parser; - typedef typename parser::node_ptr_vector node_ptr_vector; - typedef std::set node_set; - typedef detail::ptr_vector node_set_vector; - typedef std::vector node_vector; - typedef detail::ptr_vector node_vector_vector; - typedef typename parser::string string; - typedef std::pair string_pair; - typedef typename parser::tokeniser::string_token string_token; - typedef std::deque macro_deque; - typedef std::pair macro_pair; - typedef typename parser::macro_map::iterator macro_iter; - typedef std::pair macro_iter_pair; - typedef typename parser::tokeniser::token_map token_map; - - static detail::node *build_tree (const rules &rules_, - const std::size_t state_, node_ptr_vector &node_ptr_vector_, - detail::internals &internals_, index_set_vector &set_mapping_) - { - size_t_vector *lookup_ = internals_._lookup[state_]; - const typename rules::string_deque_deque ®exes_ = - rules_.regexes (); - const typename rules::id_vector_deque &ids_ = rules_.ids (); - const typename rules::id_vector_deque &unique_ids_ = - rules_.unique_ids (); - const typename rules::id_vector_deque &states_ = rules_.states (); - typename rules::string_deque::const_iterator regex_iter_ = - regexes_[state_].begin (); - typename rules::string_deque::const_iterator regex_iter_end_ = - regexes_[state_].end (); - typename rules::id_vector::const_iterator ids_iter_ = - ids_[state_].begin (); - typename rules::id_vector::const_iterator unique_ids_iter_ = - unique_ids_[state_].begin (); - typename rules::id_vector::const_iterator states_iter_ = - states_[state_].begin (); - const typename rules::string ®ex_ = *regex_iter_; - // map of regex charset tokens (strings) to index - token_map token_map_; - const typename rules::string_pair_deque ¯odeque_ = - rules_.macrodeque (); - typename parser::macro_map macromap_; - typename detail::node::node_vector tree_vector_; - - build_macros (token_map_, macrodeque_, macromap_, - rules_.flags (), rules_.locale (), node_ptr_vector_, - internals_._seen_BOL_assertion, internals_._seen_EOL_assertion); - - detail::node *root_ = parser::parse (regex_.c_str (), - regex_.c_str () + regex_.size (), *ids_iter_, *unique_ids_iter_, - *states_iter_, rules_.flags (), rules_.locale (), node_ptr_vector_, - macromap_, token_map_, internals_._seen_BOL_assertion, - internals_._seen_EOL_assertion); - - ++regex_iter_; - ++ids_iter_; - ++unique_ids_iter_; - ++states_iter_; - tree_vector_.push_back (root_); - - // build syntax trees - while (regex_iter_ != regex_iter_end_) - { - // re-declare var, otherwise we perform an assignment..! - const typename rules::string ®ex2_ = *regex_iter_; - - root_ = parser::parse (regex2_.c_str (), - regex2_.c_str () + regex2_.size (), *ids_iter_, - *unique_ids_iter_, *states_iter_, rules_.flags (), - rules_.locale (), node_ptr_vector_, macromap_, token_map_, - internals_._seen_BOL_assertion, - internals_._seen_EOL_assertion); - tree_vector_.push_back (root_); - ++regex_iter_; - ++ids_iter_; - ++unique_ids_iter_; - ++states_iter_; - } - - if (internals_._seen_BOL_assertion) - { - // Fixup BOLs - typename detail::node::node_vector::iterator iter_ = - tree_vector_.begin (); - typename detail::node::node_vector::iterator end_ = - tree_vector_.end (); - - for (; iter_ != end_; ++iter_) - { - fixup_bol (*iter_, node_ptr_vector_); - } - } - - // join trees - { - typename detail::node::node_vector::iterator iter_ = - tree_vector_.begin (); - typename detail::node::node_vector::iterator end_ = - tree_vector_.end (); - - if (iter_ != end_) - { - root_ = *iter_; - ++iter_; - } - - for (; iter_ != end_; ++iter_) - { - node_ptr_vector_->push_back (static_cast(0)); - node_ptr_vector_->back () = new detail::selection_node - (root_, *iter_); - root_ = node_ptr_vector_->back (); - } - } - - // partitioned token list - charset_list token_list_; - - set_mapping_.resize (token_map_.size ()); - partition_tokens (token_map_, token_list_); - - typename charset_list::list::const_iterator iter_ = - token_list_->begin (); - typename charset_list::list::const_iterator end_ = - token_list_->end (); - std::size_t index_ = 0; - - for (; iter_ != end_; ++iter_, ++index_) - { - const charset *cs_ = *iter_; - typename charset::index_set::const_iterator set_iter_ = - cs_->_index_set.begin (); - typename charset::index_set::const_iterator set_end_ = - cs_->_index_set.end (); - - fill_lookup (cs_->_token, lookup_, index_); - - for (; set_iter_ != set_end_; ++set_iter_) - { - set_mapping_[*set_iter_].insert (index_); - } - } - - internals_._dfa_alphabet[state_] = token_list_->size () + dfa_offset; - return root_; - } - - static void build_macros (token_map &token_map_, - const macro_deque ¯odeque_, - typename parser::macro_map ¯omap_, const regex_flags flags_, - const std::locale &locale_, node_ptr_vector &node_ptr_vector_, - bool &seen_BOL_assertion_, bool &seen_EOL_assertion_) - { - for (typename macro_deque::const_iterator iter_ = - macrodeque_.begin (), end_ = macrodeque_.end (); - iter_ != end_; ++iter_) - { - const typename rules::string &name_ = iter_->first; - const typename rules::string ®ex_ = iter_->second; - detail::node *node_ = parser::parse (regex_.c_str (), - regex_.c_str () + regex_.size (), 0, 0, 0, flags_, - locale_, node_ptr_vector_, macromap_, token_map_, - seen_BOL_assertion_, seen_EOL_assertion_); - macro_iter_pair map_iter_ = macromap_. - insert (macro_pair (name_, static_cast - (0))); - - map_iter_.first->second = node_; - } - } - - static void build_dfa (detail::node *root_, - const index_set_vector &set_mapping_, const std::size_t dfa_alphabet_, - size_t_vector &dfa_) - { - typename detail::node::node_vector *followpos_ = - &root_->firstpos (); - node_set_vector seen_sets_; - node_vector_vector seen_vectors_; - size_t_vector hash_vector_; - - // 'jam' state - dfa_.resize (dfa_alphabet_, 0); - closure (followpos_, seen_sets_, seen_vectors_, - hash_vector_, dfa_alphabet_, dfa_); - - std::size_t *ptr_ = 0; - - for (std::size_t index_ = 0; index_ < seen_vectors_->size (); ++index_) - { - equivset_list equiv_list_; - - build_equiv_list (seen_vectors_[index_], set_mapping_, equiv_list_); - - for (typename equivset_list::list::const_iterator iter_ = - equiv_list_->begin (), end_ = equiv_list_->end (); - iter_ != end_; ++iter_) - { - equivset *equivset_ = *iter_; - const std::size_t transition_ = closure - (&equivset_->_followpos, seen_sets_, seen_vectors_, - hash_vector_, dfa_alphabet_, dfa_); - - if (transition_ != npos) - { - ptr_ = &dfa_.front () + ((index_ + 1) * dfa_alphabet_); - - // Prune abstemious transitions from end states. - if (*ptr_ && !equivset_->_greedy) continue; - - for (typename detail::equivset::index_vector::const_iterator - equiv_iter_ = equivset_->_index_vector.begin (), - equiv_end_ = equivset_->_index_vector.end (); - equiv_iter_ != equiv_end_; ++equiv_iter_) - { - const std::size_t equiv_index_ = *equiv_iter_; - - if (equiv_index_ == bol_token) - { - if (ptr_[eol_index] == 0) - { - ptr_[bol_index] = transition_; - } - } - else if (equiv_index_ == eol_token) - { - if (ptr_[bol_index] == 0) - { - ptr_[eol_index] = transition_; - } - } - else - { - ptr_[equiv_index_ + dfa_offset] = transition_; - } - } - } - } - } - } - - static std::size_t closure (typename detail::node::node_vector *followpos_, - node_set_vector &seen_sets_, node_vector_vector &seen_vectors_, - size_t_vector &hash_vector_, const std::size_t size_, - size_t_vector &dfa_) - { - bool end_state_ = false; - std::size_t id_ = 0; - std::size_t unique_id_ = npos; - std::size_t state_ = 0; - std::size_t hash_ = 0; - - if (followpos_->empty ()) return npos; - - std::size_t index_ = 0; - std::unique_ptr set_ptr_ (new node_set); - std::unique_ptr vector_ptr_ (new node_vector); - - for (typename detail::node::node_vector::const_iterator iter_ = - followpos_->begin (), end_ = followpos_->end (); - iter_ != end_; ++iter_) - { - closure_ex (*iter_, end_state_, id_, unique_id_, state_, - set_ptr_.get (), vector_ptr_.get (), hash_); - } - - bool found_ = false; - typename size_t_vector::const_iterator hash_iter_ = - hash_vector_.begin (); - typename size_t_vector::const_iterator hash_end_ = - hash_vector_.end (); - typename node_set_vector::vector::const_iterator set_iter_ = - seen_sets_->begin (); - - for (; hash_iter_ != hash_end_; ++hash_iter_, ++set_iter_) - { - found_ = *hash_iter_ == hash_ && *(*set_iter_) == *set_ptr_; - ++index_; - - if (found_) break; - } - - if (!found_) - { - seen_sets_->push_back (static_cast(0)); - seen_sets_->back () = set_ptr_.release (); - seen_vectors_->push_back (static_cast(0)); - seen_vectors_->back () = vector_ptr_.release (); - hash_vector_.push_back (hash_); - // State 0 is the jam state... - index_ = seen_sets_->size (); - - const std::size_t old_size_ = dfa_.size (); - - dfa_.resize (old_size_ + size_, 0); - - if (end_state_) - { - dfa_[old_size_] |= end_state; - dfa_[old_size_ + id_index] = id_; - dfa_[old_size_ + unique_id_index] = unique_id_; - dfa_[old_size_ + state_index] = state_; - } - } - - return index_; - } - - static void closure_ex (detail::node *node_, bool &end_state_, - std::size_t &id_, std::size_t &unique_id_, std::size_t &state_, - node_set *set_ptr_, node_vector *vector_ptr_, std::size_t &hash_) - { - const bool temp_end_state_ = node_->end_state (); - - if (temp_end_state_) - { - if (!end_state_) - { - end_state_ = true; - id_ = node_->id (); - unique_id_ = node_->unique_id (); - state_ = node_->lexer_state (); - } - } - - if (set_ptr_->insert (node_).second) - { - vector_ptr_->push_back (node_); - hash_ += reinterpret_cast (node_); - } - } - - static void partition_tokens (const token_map &map_, - charset_list &lhs_) - { - charset_list rhs_; - - fill_rhs_list (map_, rhs_); - - if (!rhs_->empty ()) - { - typename charset_list::list::iterator iter_; - typename charset_list::list::iterator end_; - charset_ptr overlap_ (new charset); - - lhs_->push_back (static_cast(0)); - lhs_->back () = rhs_->front (); - rhs_->pop_front (); - - while (!rhs_->empty ()) - { - charset_ptr r_ (rhs_->front ()); - - rhs_->pop_front (); - iter_ = lhs_->begin (); - end_ = lhs_->end (); - - while (!r_->empty () && iter_ != end_) - { - typename charset_list::list::iterator l_iter_ = iter_; - - (*l_iter_)->intersect (*r_.get (), *overlap_.get ()); - - if (overlap_->empty ()) - { - ++iter_; - } - else if ((*l_iter_)->empty ()) - { - delete *l_iter_; - *l_iter_ = overlap_.release (); - - // VC++ 6 Hack: - charset_ptr temp_overlap_ (new charset); - - overlap_ = temp_overlap_; - ++iter_; - } - else if (r_->empty ()) - { - delete r_.release (); - r_ = overlap_; - - // VC++ 6 Hack: - charset_ptr temp_overlap_ (new charset); - - overlap_ = temp_overlap_; - break; - } - else - { - iter_ = lhs_->insert (++iter_, - static_cast(0)); - *iter_ = overlap_.release (); - - // VC++ 6 Hack: - charset_ptr temp_overlap_ (new charset); - - overlap_ = temp_overlap_; - ++iter_; - end_ = lhs_->end (); - } - } - - if (!r_->empty ()) - { - lhs_->push_back (static_cast(0)); - lhs_->back () = r_.release (); - } - } - } - } - - static void fill_rhs_list (const token_map &map_, - charset_list &list_) - { - typename parser::tokeniser::token_map::const_iterator iter_ = - map_.begin (); - typename parser::tokeniser::token_map::const_iterator end_ = - map_.end (); - - for (; iter_ != end_; ++iter_) - { - list_->push_back (static_cast(0)); - list_->back () = new charset (iter_->first, iter_->second); - } - } - - static void fill_lookup (const string_token &token_, - size_t_vector *lookup_, const std::size_t index_) - { - const CharT *curr_ = token_._charset.c_str (); - const CharT *chars_end_ = curr_ + token_._charset.size (); - std::size_t *ptr_ = &lookup_->front (); - const std::size_t max_ = sizeof (CharT) == 1 ? - num_chars : num_wchar_ts; - - if (token_._negated) - { - // $$$ FIXME JDG July 2014 $$$ - // this code is problematic on platforms where wchar_t is signed - // with min generating negative numbers. This crashes with BAD_ACCESS - // because of the vector index below: - // ptr_[static_cast(curr_char_)] - CharT curr_char_ = 0; // (std::numeric_limits::min)(); - std::size_t i_ = 0; - - while (curr_ < chars_end_) - { - while (*curr_ > curr_char_) - { - ptr_[static_cast - (curr_char_)] = index_ + dfa_offset; - ++curr_char_; - ++i_; - } - - ++curr_char_; - ++curr_; - ++i_; - } - - for (; i_ < max_; ++i_) - { - ptr_[static_cast(curr_char_)] = - index_ + dfa_offset; - ++curr_char_; - } - } - else - { - while (curr_ < chars_end_) - { - ptr_[static_cast(*curr_)] = - index_ + dfa_offset; - ++curr_; - } - } - } - - static void build_equiv_list (const node_vector *vector_, - const index_set_vector &set_mapping_, equivset_list &lhs_) - { - equivset_list rhs_; - - fill_rhs_list (vector_, set_mapping_, rhs_); - - if (!rhs_->empty ()) - { - typename equivset_list::list::iterator iter_; - typename equivset_list::list::iterator end_; - equivset_ptr overlap_ (new equivset); - - lhs_->push_back (static_cast(0)); - lhs_->back () = rhs_->front (); - rhs_->pop_front (); - - while (!rhs_->empty ()) - { - equivset_ptr r_ (rhs_->front ()); - - rhs_->pop_front (); - iter_ = lhs_->begin (); - end_ = lhs_->end (); - - while (!r_->empty () && iter_ != end_) - { - typename equivset_list::list::iterator l_iter_ = iter_; - - (*l_iter_)->intersect (*r_.get (), *overlap_.get ()); - - if (overlap_->empty ()) - { - ++iter_; - } - else if ((*l_iter_)->empty ()) - { - delete *l_iter_; - *l_iter_ = overlap_.release (); - - // VC++ 6 Hack: - equivset_ptr temp_overlap_ (new equivset); - - overlap_ = temp_overlap_; - ++iter_; - } - else if (r_->empty ()) - { - delete r_.release (); - r_ = overlap_; - - // VC++ 6 Hack: - equivset_ptr temp_overlap_ (new equivset); - - overlap_ = temp_overlap_; - break; - } - else - { - iter_ = lhs_->insert (++iter_, - static_cast(0)); - *iter_ = overlap_.release (); - - // VC++ 6 Hack: - equivset_ptr temp_overlap_ (new equivset); - - overlap_ = temp_overlap_; - ++iter_; - end_ = lhs_->end (); - } - } - - if (!r_->empty ()) - { - lhs_->push_back (static_cast(0)); - lhs_->back () = r_.release (); - } - } - } - } - - static void fill_rhs_list (const node_vector *vector_, - const index_set_vector &set_mapping_, equivset_list &list_) - { - typename node_vector::const_iterator iter_ = - vector_->begin (); - typename node_vector::const_iterator end_ = - vector_->end (); - - for (; iter_ != end_; ++iter_) - { - const detail::node *node_ = *iter_; - - if (!node_->end_state ()) - { - const std::size_t token_ = node_->token (); - - if (token_ != null_token) - { - list_->push_back (static_cast(0)); - - if (token_ == bol_token || token_ == eol_token) - { - std::set index_set_; - - index_set_.insert (token_); - list_->back () = new equivset (index_set_, - node_->greedy (), token_, node_->followpos ()); - } - else - { - list_->back () = new equivset (set_mapping_[token_], - node_->greedy (), token_, node_->followpos ()); - } - } - } - } - } - - static void fixup_bol (detail::node * &root_, - node_ptr_vector &node_ptr_vector_) - { - typename detail::node::node_vector *first_ = &root_->firstpos (); - bool found_ = false; - typename detail::node::node_vector::const_iterator iter_ = - first_->begin (); - typename detail::node::node_vector::const_iterator end_ = - first_->end (); - - for (; iter_ != end_; ++iter_) - { - const detail::node *node_ = *iter_; - - found_ = !node_->end_state () && node_->token () == bol_token; - - if (found_) break; - } - - if (!found_) - { - node_ptr_vector_->push_back (static_cast(0)); - node_ptr_vector_->back () = new detail::leaf_node - (bol_token, true); - - detail::node *lhs_ = node_ptr_vector_->back (); - - node_ptr_vector_->push_back (static_cast(0)); - node_ptr_vector_->back () = new detail::leaf_node - (null_token, true); - - detail::node *rhs_ = node_ptr_vector_->back (); - - node_ptr_vector_->push_back - (static_cast(0)); - node_ptr_vector_->back () = - new detail::selection_node (lhs_, rhs_); - lhs_ = node_ptr_vector_->back (); - - node_ptr_vector_->push_back - (static_cast(0)); - node_ptr_vector_->back () = - new detail::sequence_node (lhs_, root_); - root_ = node_ptr_vector_->back (); - } - } - - static void minimise_dfa (const std::size_t dfa_alphabet_, - size_t_vector &dfa_, std::size_t size_) - { - const std::size_t *first_ = &dfa_.front (); - const std::size_t *second_ = 0; - const std::size_t *end_ = first_ + size_; - std::size_t index_ = 1; - std::size_t new_index_ = 1; - std::size_t curr_index_ = 0; - index_set index_set_; - size_t_vector lookup_; - std::size_t *lookup_ptr_ = 0; - - lookup_.resize (size_ / dfa_alphabet_, null_token); - lookup_ptr_ = &lookup_.front (); - *lookup_ptr_ = 0; - // Only one 'jam' state, so skip it. - first_ += dfa_alphabet_; - - for (; first_ < end_; first_ += dfa_alphabet_, ++index_) - { - for (second_ = first_ + dfa_alphabet_, curr_index_ = index_ + 1; - second_ < end_; second_ += dfa_alphabet_, ++curr_index_) - { - if (index_set_.find (curr_index_) != index_set_.end ()) - { - continue; - } - - // Some systems have memcmp in namespace std. - using namespace std; - - if (memcmp (first_, second_, sizeof (std::size_t) * - dfa_alphabet_) == 0) - { - index_set_.insert (curr_index_); - lookup_ptr_[curr_index_] = new_index_; - } - } - - if (lookup_ptr_[index_] == null_token) - { - lookup_ptr_[index_] = new_index_; - ++new_index_; - } - } - - if (!index_set_.empty ()) - { - const std::size_t *front_ = &dfa_.front (); - size_t_vector new_dfa_ (front_, front_ + dfa_alphabet_); - typename index_set::iterator set_end_ = - index_set_.end (); - const std::size_t *ptr_ = front_ + dfa_alphabet_; - std::size_t *new_ptr_ = 0; - - new_dfa_.resize (size_ - index_set_.size () * dfa_alphabet_, 0); - new_ptr_ = &new_dfa_.front () + dfa_alphabet_; - size_ /= dfa_alphabet_; - - for (index_ = 1; index_ < size_; ++index_) - { - if (index_set_.find (index_) != set_end_) - { - ptr_ += dfa_alphabet_; - continue; - } - - new_ptr_[end_state_index] = ptr_[end_state_index]; - new_ptr_[id_index] = ptr_[id_index]; - new_ptr_[unique_id_index] = ptr_[unique_id_index]; - new_ptr_[state_index] = ptr_[state_index]; - new_ptr_[bol_index] = lookup_ptr_[ptr_[bol_index]]; - new_ptr_[eol_index] = lookup_ptr_[ptr_[eol_index]]; - new_ptr_ += dfa_offset; - ptr_ += dfa_offset; - - for (std::size_t i_ = dfa_offset; i_ < dfa_alphabet_; ++i_) - { - *new_ptr_++ = lookup_ptr_[*ptr_++]; - } - } - - dfa_.swap (new_dfa_); - } - } -}; - -typedef basic_generator generator; -typedef basic_generator wgenerator; -} -} - -#endif +// generator.hpp +// Copyright (c) 2007-2009 Ben Hanson (http://www.benhanson.net/) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file licence_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_LEXER_GENERATOR_HPP +#define BOOST_LEXER_GENERATOR_HPP + +#include "char_traits.hpp" +// memcmp() +#include +#include "partition/charset.hpp" +#include "partition/equivset.hpp" +#include +#include +#include "parser/tree/node.hpp" +#include "parser/parser.hpp" +#include "containers/ptr_list.hpp" +#include "rules.hpp" +#include "state_machine.hpp" + +namespace boost +{ +namespace lexer +{ +template > +class basic_generator +{ +public: + typedef typename detail::internals::size_t_vector size_t_vector; + typedef basic_rules rules; + + static void build (const rules &rules_, + basic_state_machine &state_machine_) + { + std::size_t index_ = 0; + std::size_t size_ = rules_.statemap ().size (); + node_ptr_vector node_ptr_vector_; + detail::internals &internals_ = const_cast + (state_machine_.data ()); + bool seen_BOL_assertion_ = false; + bool seen_EOL_assertion_ = false; + + state_machine_.clear (); + + for (; index_ < size_; ++index_) + { + internals_._lookup->push_back (static_cast(0)); + internals_._lookup->back () = new size_t_vector; + internals_._dfa_alphabet.push_back (0); + internals_._dfa->push_back (static_cast(0)); + internals_._dfa->back () = new size_t_vector; + } + + for (index_ = 0, size_ = internals_._lookup->size (); + index_ < size_; ++index_) + { + internals_._lookup[index_]->resize (sizeof (CharT) == 1 ? + num_chars : num_wchar_ts, dead_state_index); + + if (!rules_.regexes ()[index_].empty ()) + { + // vector mapping token indexes to partitioned token index sets + index_set_vector set_mapping_; + // syntax tree + detail::node *root_ = build_tree (rules_, index_, + node_ptr_vector_, internals_, set_mapping_); + + build_dfa (root_, set_mapping_, + internals_._dfa_alphabet[index_], + *internals_._dfa[index_]); + + if (internals_._seen_BOL_assertion) + { + seen_BOL_assertion_ = true; + } + + if (internals_._seen_EOL_assertion) + { + seen_EOL_assertion_ = true; + } + + internals_._seen_BOL_assertion = false; + internals_._seen_EOL_assertion = false; + } + } + + internals_._seen_BOL_assertion = seen_BOL_assertion_; + internals_._seen_EOL_assertion = seen_EOL_assertion_; + } + + static void minimise (basic_state_machine &state_machine_) + { + detail::internals &internals_ = const_cast + (state_machine_.data ()); + const std::size_t machines_ = internals_._dfa->size (); + + for (std::size_t i_ = 0; i_ < machines_; ++i_) + { + const std::size_t dfa_alphabet_ = internals_._dfa_alphabet[i_]; + size_t_vector *dfa_ = internals_._dfa[i_]; + + if (dfa_alphabet_ != 0) + { + std::size_t size_ = 0; + + do + { + size_ = dfa_->size (); + minimise_dfa (dfa_alphabet_, *dfa_, size_); + } while (dfa_->size () != size_); + } + } + } + +protected: + typedef detail::basic_charset charset; + typedef detail::ptr_list charset_list; + typedef std::unique_ptr charset_ptr; + typedef detail::equivset equivset; + typedef detail::ptr_list equivset_list; + typedef std::unique_ptr equivset_ptr; + typedef typename charset::index_set index_set; + typedef std::vector index_set_vector; + typedef detail::basic_parser parser; + typedef typename parser::node_ptr_vector node_ptr_vector; + typedef std::set node_set; + typedef detail::ptr_vector node_set_vector; + typedef std::vector node_vector; + typedef detail::ptr_vector node_vector_vector; + typedef typename parser::string string; + typedef std::pair string_pair; + typedef typename parser::tokeniser::string_token string_token; + typedef std::deque macro_deque; + typedef std::pair macro_pair; + typedef typename parser::macro_map::iterator macro_iter; + typedef std::pair macro_iter_pair; + typedef typename parser::tokeniser::token_map token_map; + + static detail::node *build_tree (const rules &rules_, + const std::size_t state_, node_ptr_vector &node_ptr_vector_, + detail::internals &internals_, index_set_vector &set_mapping_) + { + size_t_vector *lookup_ = internals_._lookup[state_]; + const typename rules::string_deque_deque ®exes_ = + rules_.regexes (); + const typename rules::id_vector_deque &ids_ = rules_.ids (); + const typename rules::id_vector_deque &unique_ids_ = + rules_.unique_ids (); + const typename rules::id_vector_deque &states_ = rules_.states (); + typename rules::string_deque::const_iterator regex_iter_ = + regexes_[state_].begin (); + typename rules::string_deque::const_iterator regex_iter_end_ = + regexes_[state_].end (); + typename rules::id_vector::const_iterator ids_iter_ = + ids_[state_].begin (); + typename rules::id_vector::const_iterator unique_ids_iter_ = + unique_ids_[state_].begin (); + typename rules::id_vector::const_iterator states_iter_ = + states_[state_].begin (); + const typename rules::string ®ex_ = *regex_iter_; + // map of regex charset tokens (strings) to index + token_map token_map_; + const typename rules::string_pair_deque ¯odeque_ = + rules_.macrodeque (); + typename parser::macro_map macromap_; + typename detail::node::node_vector tree_vector_; + + build_macros (token_map_, macrodeque_, macromap_, + rules_.flags (), rules_.locale (), node_ptr_vector_, + internals_._seen_BOL_assertion, internals_._seen_EOL_assertion); + + detail::node *root_ = parser::parse (regex_.c_str (), + regex_.c_str () + regex_.size (), *ids_iter_, *unique_ids_iter_, + *states_iter_, rules_.flags (), rules_.locale (), node_ptr_vector_, + macromap_, token_map_, internals_._seen_BOL_assertion, + internals_._seen_EOL_assertion); + + ++regex_iter_; + ++ids_iter_; + ++unique_ids_iter_; + ++states_iter_; + tree_vector_.push_back (root_); + + // build syntax trees + while (regex_iter_ != regex_iter_end_) + { + // re-declare var, otherwise we perform an assignment..! + const typename rules::string ®ex2_ = *regex_iter_; + + root_ = parser::parse (regex2_.c_str (), + regex2_.c_str () + regex2_.size (), *ids_iter_, + *unique_ids_iter_, *states_iter_, rules_.flags (), + rules_.locale (), node_ptr_vector_, macromap_, token_map_, + internals_._seen_BOL_assertion, + internals_._seen_EOL_assertion); + tree_vector_.push_back (root_); + ++regex_iter_; + ++ids_iter_; + ++unique_ids_iter_; + ++states_iter_; + } + + if (internals_._seen_BOL_assertion) + { + // Fixup BOLs + typename detail::node::node_vector::iterator iter_ = + tree_vector_.begin (); + typename detail::node::node_vector::iterator end_ = + tree_vector_.end (); + + for (; iter_ != end_; ++iter_) + { + fixup_bol (*iter_, node_ptr_vector_); + } + } + + // join trees + { + typename detail::node::node_vector::iterator iter_ = + tree_vector_.begin (); + typename detail::node::node_vector::iterator end_ = + tree_vector_.end (); + + if (iter_ != end_) + { + root_ = *iter_; + ++iter_; + } + + for (; iter_ != end_; ++iter_) + { + node_ptr_vector_->push_back (static_cast(0)); + node_ptr_vector_->back () = new detail::selection_node + (root_, *iter_); + root_ = node_ptr_vector_->back (); + } + } + + // partitioned token list + charset_list token_list_; + + set_mapping_.resize (token_map_.size ()); + partition_tokens (token_map_, token_list_); + + typename charset_list::list::const_iterator iter_ = + token_list_->begin (); + typename charset_list::list::const_iterator end_ = + token_list_->end (); + std::size_t index_ = 0; + + for (; iter_ != end_; ++iter_, ++index_) + { + const charset *cs_ = *iter_; + typename charset::index_set::const_iterator set_iter_ = + cs_->_index_set.begin (); + typename charset::index_set::const_iterator set_end_ = + cs_->_index_set.end (); + + fill_lookup (cs_->_token, lookup_, index_); + + for (; set_iter_ != set_end_; ++set_iter_) + { + set_mapping_[*set_iter_].insert (index_); + } + } + + internals_._dfa_alphabet[state_] = token_list_->size () + dfa_offset; + return root_; + } + + static void build_macros (token_map &token_map_, + const macro_deque ¯odeque_, + typename parser::macro_map ¯omap_, const regex_flags flags_, + const std::locale &locale_, node_ptr_vector &node_ptr_vector_, + bool &seen_BOL_assertion_, bool &seen_EOL_assertion_) + { + for (typename macro_deque::const_iterator iter_ = + macrodeque_.begin (), end_ = macrodeque_.end (); + iter_ != end_; ++iter_) + { + const typename rules::string &name_ = iter_->first; + const typename rules::string ®ex_ = iter_->second; + detail::node *node_ = parser::parse (regex_.c_str (), + regex_.c_str () + regex_.size (), 0, 0, 0, flags_, + locale_, node_ptr_vector_, macromap_, token_map_, + seen_BOL_assertion_, seen_EOL_assertion_); + macro_iter_pair map_iter_ = macromap_. + insert (macro_pair (name_, static_cast + (0))); + + map_iter_.first->second = node_; + } + } + + static void build_dfa (detail::node *root_, + const index_set_vector &set_mapping_, const std::size_t dfa_alphabet_, + size_t_vector &dfa_) + { + typename detail::node::node_vector *followpos_ = + &root_->firstpos (); + node_set_vector seen_sets_; + node_vector_vector seen_vectors_; + size_t_vector hash_vector_; + + // 'jam' state + dfa_.resize (dfa_alphabet_, 0); + closure (followpos_, seen_sets_, seen_vectors_, + hash_vector_, dfa_alphabet_, dfa_); + + std::size_t *ptr_ = 0; + + for (std::size_t index_ = 0; index_ < seen_vectors_->size (); ++index_) + { + equivset_list equiv_list_; + + build_equiv_list (seen_vectors_[index_], set_mapping_, equiv_list_); + + for (typename equivset_list::list::const_iterator iter_ = + equiv_list_->begin (), end_ = equiv_list_->end (); + iter_ != end_; ++iter_) + { + equivset *equivset_ = *iter_; + const std::size_t transition_ = closure + (&equivset_->_followpos, seen_sets_, seen_vectors_, + hash_vector_, dfa_alphabet_, dfa_); + + if (transition_ != npos) + { + ptr_ = &dfa_.front () + ((index_ + 1) * dfa_alphabet_); + + // Prune abstemious transitions from end states. + if (*ptr_ && !equivset_->_greedy) continue; + + for (typename detail::equivset::index_vector::const_iterator + equiv_iter_ = equivset_->_index_vector.begin (), + equiv_end_ = equivset_->_index_vector.end (); + equiv_iter_ != equiv_end_; ++equiv_iter_) + { + const std::size_t equiv_index_ = *equiv_iter_; + + if (equiv_index_ == bol_token) + { + if (ptr_[eol_index] == 0) + { + ptr_[bol_index] = transition_; + } + } + else if (equiv_index_ == eol_token) + { + if (ptr_[bol_index] == 0) + { + ptr_[eol_index] = transition_; + } + } + else + { + ptr_[equiv_index_ + dfa_offset] = transition_; + } + } + } + } + } + } + + static std::size_t closure (typename detail::node::node_vector *followpos_, + node_set_vector &seen_sets_, node_vector_vector &seen_vectors_, + size_t_vector &hash_vector_, const std::size_t size_, + size_t_vector &dfa_) + { + bool end_state_ = false; + std::size_t id_ = 0; + std::size_t unique_id_ = npos; + std::size_t state_ = 0; + std::size_t hash_ = 0; + + if (followpos_->empty ()) return npos; + + std::size_t index_ = 0; + std::unique_ptr set_ptr_ (new node_set); + std::unique_ptr vector_ptr_ (new node_vector); + + for (typename detail::node::node_vector::const_iterator iter_ = + followpos_->begin (), end_ = followpos_->end (); + iter_ != end_; ++iter_) + { + closure_ex (*iter_, end_state_, id_, unique_id_, state_, + set_ptr_.get (), vector_ptr_.get (), hash_); + } + + bool found_ = false; + typename size_t_vector::const_iterator hash_iter_ = + hash_vector_.begin (); + typename size_t_vector::const_iterator hash_end_ = + hash_vector_.end (); + typename node_set_vector::vector::const_iterator set_iter_ = + seen_sets_->begin (); + + for (; hash_iter_ != hash_end_; ++hash_iter_, ++set_iter_) + { + found_ = *hash_iter_ == hash_ && *(*set_iter_) == *set_ptr_; + ++index_; + + if (found_) break; + } + + if (!found_) + { + seen_sets_->push_back (static_cast(0)); + seen_sets_->back () = set_ptr_.release (); + seen_vectors_->push_back (static_cast(0)); + seen_vectors_->back () = vector_ptr_.release (); + hash_vector_.push_back (hash_); + // State 0 is the jam state... + index_ = seen_sets_->size (); + + const std::size_t old_size_ = dfa_.size (); + + dfa_.resize (old_size_ + size_, 0); + + if (end_state_) + { + dfa_[old_size_] |= end_state; + dfa_[old_size_ + id_index] = id_; + dfa_[old_size_ + unique_id_index] = unique_id_; + dfa_[old_size_ + state_index] = state_; + } + } + + return index_; + } + + static void closure_ex (detail::node *node_, bool &end_state_, + std::size_t &id_, std::size_t &unique_id_, std::size_t &state_, + node_set *set_ptr_, node_vector *vector_ptr_, std::size_t &hash_) + { + const bool temp_end_state_ = node_->end_state (); + + if (temp_end_state_) + { + if (!end_state_) + { + end_state_ = true; + id_ = node_->id (); + unique_id_ = node_->unique_id (); + state_ = node_->lexer_state (); + } + } + + if (set_ptr_->insert (node_).second) + { + vector_ptr_->push_back (node_); + hash_ += reinterpret_cast (node_); + } + } + + static void partition_tokens (const token_map &map_, + charset_list &lhs_) + { + charset_list rhs_; + + fill_rhs_list (map_, rhs_); + + if (!rhs_->empty ()) + { + typename charset_list::list::iterator iter_; + typename charset_list::list::iterator end_; + charset_ptr overlap_ (new charset); + + lhs_->push_back (static_cast(0)); + lhs_->back () = rhs_->front (); + rhs_->pop_front (); + + while (!rhs_->empty ()) + { + charset_ptr r_ (rhs_->front ()); + + rhs_->pop_front (); + iter_ = lhs_->begin (); + end_ = lhs_->end (); + + while (!r_->empty () && iter_ != end_) + { + typename charset_list::list::iterator l_iter_ = iter_; + + (*l_iter_)->intersect (*r_.get (), *overlap_.get ()); + + if (overlap_->empty ()) + { + ++iter_; + } + else if ((*l_iter_)->empty ()) + { + delete *l_iter_; + *l_iter_ = overlap_.release (); + + // VC++ 6 Hack: + charset_ptr temp_overlap_ (new charset); + + overlap_ = temp_overlap_; + ++iter_; + } + else if (r_->empty ()) + { + delete r_.release (); + r_ = overlap_; + + // VC++ 6 Hack: + charset_ptr temp_overlap_ (new charset); + + overlap_ = temp_overlap_; + break; + } + else + { + iter_ = lhs_->insert (++iter_, + static_cast(0)); + *iter_ = overlap_.release (); + + // VC++ 6 Hack: + charset_ptr temp_overlap_ (new charset); + + overlap_ = temp_overlap_; + ++iter_; + end_ = lhs_->end (); + } + } + + if (!r_->empty ()) + { + lhs_->push_back (static_cast(0)); + lhs_->back () = r_.release (); + } + } + } + } + + static void fill_rhs_list (const token_map &map_, + charset_list &list_) + { + typename parser::tokeniser::token_map::const_iterator iter_ = + map_.begin (); + typename parser::tokeniser::token_map::const_iterator end_ = + map_.end (); + + for (; iter_ != end_; ++iter_) + { + list_->push_back (static_cast(0)); + list_->back () = new charset (iter_->first, iter_->second); + } + } + + static void fill_lookup (const string_token &token_, + size_t_vector *lookup_, const std::size_t index_) + { + const CharT *curr_ = token_._charset.c_str (); + const CharT *chars_end_ = curr_ + token_._charset.size (); + std::size_t *ptr_ = &lookup_->front (); + const std::size_t max_ = sizeof (CharT) == 1 ? + num_chars : num_wchar_ts; + + if (token_._negated) + { + // $$$ FIXME JDG July 2014 $$$ + // this code is problematic on platforms where wchar_t is signed + // with min generating negative numbers. This crashes with BAD_ACCESS + // because of the vector index below: + // ptr_[static_cast(curr_char_)] + CharT curr_char_ = 0; // (std::numeric_limits::min)(); + std::size_t i_ = 0; + + while (curr_ < chars_end_) + { + while (*curr_ > curr_char_) + { + ptr_[static_cast + (curr_char_)] = index_ + dfa_offset; + ++curr_char_; + ++i_; + } + + ++curr_char_; + ++curr_; + ++i_; + } + + for (; i_ < max_; ++i_) + { + ptr_[static_cast(curr_char_)] = + index_ + dfa_offset; + ++curr_char_; + } + } + else + { + while (curr_ < chars_end_) + { + ptr_[static_cast(*curr_)] = + index_ + dfa_offset; + ++curr_; + } + } + } + + static void build_equiv_list (const node_vector *vector_, + const index_set_vector &set_mapping_, equivset_list &lhs_) + { + equivset_list rhs_; + + fill_rhs_list (vector_, set_mapping_, rhs_); + + if (!rhs_->empty ()) + { + typename equivset_list::list::iterator iter_; + typename equivset_list::list::iterator end_; + equivset_ptr overlap_ (new equivset); + + lhs_->push_back (static_cast(0)); + lhs_->back () = rhs_->front (); + rhs_->pop_front (); + + while (!rhs_->empty ()) + { + equivset_ptr r_ (rhs_->front ()); + + rhs_->pop_front (); + iter_ = lhs_->begin (); + end_ = lhs_->end (); + + while (!r_->empty () && iter_ != end_) + { + typename equivset_list::list::iterator l_iter_ = iter_; + + (*l_iter_)->intersect (*r_.get (), *overlap_.get ()); + + if (overlap_->empty ()) + { + ++iter_; + } + else if ((*l_iter_)->empty ()) + { + delete *l_iter_; + *l_iter_ = overlap_.release (); + + // VC++ 6 Hack: + equivset_ptr temp_overlap_ (new equivset); + + overlap_ = temp_overlap_; + ++iter_; + } + else if (r_->empty ()) + { + delete r_.release (); + r_ = overlap_; + + // VC++ 6 Hack: + equivset_ptr temp_overlap_ (new equivset); + + overlap_ = temp_overlap_; + break; + } + else + { + iter_ = lhs_->insert (++iter_, + static_cast(0)); + *iter_ = overlap_.release (); + + // VC++ 6 Hack: + equivset_ptr temp_overlap_ (new equivset); + + overlap_ = temp_overlap_; + ++iter_; + end_ = lhs_->end (); + } + } + + if (!r_->empty ()) + { + lhs_->push_back (static_cast(0)); + lhs_->back () = r_.release (); + } + } + } + } + + static void fill_rhs_list (const node_vector *vector_, + const index_set_vector &set_mapping_, equivset_list &list_) + { + typename node_vector::const_iterator iter_ = + vector_->begin (); + typename node_vector::const_iterator end_ = + vector_->end (); + + for (; iter_ != end_; ++iter_) + { + const detail::node *node_ = *iter_; + + if (!node_->end_state ()) + { + const std::size_t token_ = node_->token (); + + if (token_ != null_token) + { + list_->push_back (static_cast(0)); + + if (token_ == bol_token || token_ == eol_token) + { + std::set index_set_; + + index_set_.insert (token_); + list_->back () = new equivset (index_set_, + node_->greedy (), token_, node_->followpos ()); + } + else + { + list_->back () = new equivset (set_mapping_[token_], + node_->greedy (), token_, node_->followpos ()); + } + } + } + } + } + + static void fixup_bol (detail::node * &root_, + node_ptr_vector &node_ptr_vector_) + { + typename detail::node::node_vector *first_ = &root_->firstpos (); + bool found_ = false; + typename detail::node::node_vector::const_iterator iter_ = + first_->begin (); + typename detail::node::node_vector::const_iterator end_ = + first_->end (); + + for (; iter_ != end_; ++iter_) + { + const detail::node *node_ = *iter_; + + found_ = !node_->end_state () && node_->token () == bol_token; + + if (found_) break; + } + + if (!found_) + { + node_ptr_vector_->push_back (static_cast(0)); + node_ptr_vector_->back () = new detail::leaf_node + (bol_token, true); + + detail::node *lhs_ = node_ptr_vector_->back (); + + node_ptr_vector_->push_back (static_cast(0)); + node_ptr_vector_->back () = new detail::leaf_node + (null_token, true); + + detail::node *rhs_ = node_ptr_vector_->back (); + + node_ptr_vector_->push_back + (static_cast(0)); + node_ptr_vector_->back () = + new detail::selection_node (lhs_, rhs_); + lhs_ = node_ptr_vector_->back (); + + node_ptr_vector_->push_back + (static_cast(0)); + node_ptr_vector_->back () = + new detail::sequence_node (lhs_, root_); + root_ = node_ptr_vector_->back (); + } + } + + static void minimise_dfa (const std::size_t dfa_alphabet_, + size_t_vector &dfa_, std::size_t size_) + { + const std::size_t *first_ = &dfa_.front (); + const std::size_t *second_ = 0; + const std::size_t *end_ = first_ + size_; + std::size_t index_ = 1; + std::size_t new_index_ = 1; + std::size_t curr_index_ = 0; + index_set index_set_; + size_t_vector lookup_; + std::size_t *lookup_ptr_ = 0; + + lookup_.resize (size_ / dfa_alphabet_, null_token); + lookup_ptr_ = &lookup_.front (); + *lookup_ptr_ = 0; + // Only one 'jam' state, so skip it. + first_ += dfa_alphabet_; + + for (; first_ < end_; first_ += dfa_alphabet_, ++index_) + { + for (second_ = first_ + dfa_alphabet_, curr_index_ = index_ + 1; + second_ < end_; second_ += dfa_alphabet_, ++curr_index_) + { + if (index_set_.find (curr_index_) != index_set_.end ()) + { + continue; + } + + // Some systems have memcmp in namespace std. + using namespace std; + + if (memcmp (first_, second_, sizeof (std::size_t) * + dfa_alphabet_) == 0) + { + index_set_.insert (curr_index_); + lookup_ptr_[curr_index_] = new_index_; + } + } + + if (lookup_ptr_[index_] == null_token) + { + lookup_ptr_[index_] = new_index_; + ++new_index_; + } + } + + if (!index_set_.empty ()) + { + const std::size_t *front_ = &dfa_.front (); + size_t_vector new_dfa_ (front_, front_ + dfa_alphabet_); + typename index_set::iterator set_end_ = + index_set_.end (); + const std::size_t *ptr_ = front_ + dfa_alphabet_; + std::size_t *new_ptr_ = 0; + + new_dfa_.resize (size_ - index_set_.size () * dfa_alphabet_, 0); + new_ptr_ = &new_dfa_.front () + dfa_alphabet_; + size_ /= dfa_alphabet_; + + for (index_ = 1; index_ < size_; ++index_) + { + if (index_set_.find (index_) != set_end_) + { + ptr_ += dfa_alphabet_; + continue; + } + + new_ptr_[end_state_index] = ptr_[end_state_index]; + new_ptr_[id_index] = ptr_[id_index]; + new_ptr_[unique_id_index] = ptr_[unique_id_index]; + new_ptr_[state_index] = ptr_[state_index]; + new_ptr_[bol_index] = lookup_ptr_[ptr_[bol_index]]; + new_ptr_[eol_index] = lookup_ptr_[ptr_[eol_index]]; + new_ptr_ += dfa_offset; + ptr_ += dfa_offset; + + for (std::size_t i_ = dfa_offset; i_ < dfa_alphabet_; ++i_) + { + *new_ptr_++ = lookup_ptr_[*ptr_++]; + } + } + + dfa_.swap (new_dfa_); + } + } +}; + +typedef basic_generator generator; +typedef basic_generator wgenerator; +} +} + +#endif diff --git a/src/external/3rd/library/boost/boost/statechart/processor_container.hpp b/src/external/3rd/library/boost/boost/statechart/processor_container.hpp index 6ed920901..8c8ffe02e 100644 --- a/src/external/3rd/library/boost/boost/statechart/processor_container.hpp +++ b/src/external/3rd/library/boost/boost/statechart/processor_container.hpp @@ -1,445 +1,445 @@ -#ifndef BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED -#define BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED -////////////////////////////////////////////////////////////////////////////// -// Copyright 2002-2008 Andreas Huber Doenni -// Distributed under the Boost Software License, Version 1.0. (See accompany- -// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -////////////////////////////////////////////////////////////////////////////// - - - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include // BOOST_INTEL - -#include -#include - -#include -#include // std::allocator, std::unique_ptr - - - -namespace boost -{ -namespace statechart -{ -namespace detail -{ - template - struct unwrap_impl - { - template< typename T > - struct apply { typedef T type; }; - }; - - template<> - struct unwrap_impl - { - template< typename T > - struct apply { typedef typename T::type & type; }; - }; - - template - struct unwrap - { - typedef typename unwrap_impl< - is_reference_wrapper< T >::value >::template apply< T >::type type; - }; -} - - -template< - class Scheduler, - class WorkItem, - class Allocator = std::allocator< void > > -class processor_container : noncopyable -{ - typedef event_processor< Scheduler > processor_base_type; - typedef std::unique_ptr< processor_base_type > processor_holder_type; - typedef shared_ptr< processor_holder_type > processor_holder_ptr_type; - - public: - ////////////////////////////////////////////////////////////////////////// - typedef weak_ptr< processor_holder_type > processor_handle; - - class processor_context - { - processor_context( - Scheduler & scheduler, const processor_handle & handle - ) : - scheduler_( scheduler ), - handle_( handle ) - { - } - - #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) ) - public: - // for some reason Intel 8.0 seems to think that the following functions - // are inaccessible from event_processor<>::event_processor - #endif - - Scheduler & my_scheduler() const { return scheduler_; } - const processor_handle & my_handle() const { return handle_; } - - #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) ) - private: - #endif - - // avoids C4512 (assignment operator could not be generated) - processor_context & operator=( const processor_context & ); - - Scheduler & scheduler_; - const processor_handle handle_; - - friend class processor_container; - friend class event_processor< Scheduler >; - }; - - template< class Processor > - WorkItem create_processor( processor_handle & handle, Scheduler & scheduler ) - { - processor_holder_ptr_type pProcessor = make_processor_holder(); - handle = pProcessor; - typedef void ( processor_container::*impl_fun_ptr )( - const processor_holder_ptr_type &, const processor_context & ); - impl_fun_ptr pImpl = - &processor_container::template create_processor_impl0< Processor >; - return WorkItem( - boost::bind( pImpl, this, pProcessor, - processor_context( scheduler, handle ) ), - Allocator() ); - } - - template< class Processor, typename Arg1 > - WorkItem create_processor( - processor_handle & handle, Scheduler & scheduler, Arg1 arg1 ) - { - processor_holder_ptr_type pProcessor = make_processor_holder(); - handle = pProcessor; - typedef typename detail::unwrap< Arg1 >::type arg1_type; - typedef void ( processor_container::*impl_fun_ptr )( - const processor_holder_ptr_type &, const processor_context &, - arg1_type ); - impl_fun_ptr pImpl = - &processor_container::template create_processor_impl1< - Processor, arg1_type >; - return WorkItem( - boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), - arg1 ), - Allocator() ); - } - - template< class Processor, typename Arg1, typename Arg2 > - WorkItem create_processor( - processor_handle & handle, Scheduler & scheduler, Arg1 arg1, Arg2 arg2 ) - { - processor_holder_ptr_type pProcessor = make_processor_holder(); - handle = pProcessor; - typedef typename detail::unwrap< Arg1 >::type arg1_type; - typedef typename detail::unwrap< Arg2 >::type arg2_type; - typedef void ( processor_container::*impl_fun_ptr )( - const processor_holder_ptr_type &, const processor_context &, - arg1_type, arg2_type ); - impl_fun_ptr pImpl = - &processor_container::template create_processor_impl2< - Processor, arg1_type, arg2_type >; - return WorkItem( - boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), - arg1, arg2 ), - Allocator() ); - } - - template< class Processor, typename Arg1, typename Arg2, typename Arg3 > - WorkItem create_processor( - processor_handle & handle, Scheduler & scheduler, - Arg1 arg1, Arg2 arg2, Arg3 arg3 ) - { - processor_holder_ptr_type pProcessor = make_processor_holder(); - handle = pProcessor; - typedef typename detail::unwrap< Arg1 >::type arg1_type; - typedef typename detail::unwrap< Arg2 >::type arg2_type; - typedef typename detail::unwrap< Arg3 >::type arg3_type; - typedef void ( processor_container::*impl_fun_ptr )( - const processor_holder_ptr_type &, const processor_context &, - arg1_type, arg2_type, arg3_type ); - impl_fun_ptr pImpl = - &processor_container::template create_processor_impl3< - Processor, arg1_type, arg2_type, arg3_type >; - return WorkItem( - boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), - arg1, arg2, arg3 ), - Allocator() ); - } - - template< - class Processor, typename Arg1, typename Arg2, - typename Arg3, typename Arg4 > - WorkItem create_processor( - processor_handle & handle, Scheduler & scheduler, - Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 ) - { - processor_holder_ptr_type pProcessor = make_processor_holder(); - handle = pProcessor; - typedef typename detail::unwrap< Arg1 >::type arg1_type; - typedef typename detail::unwrap< Arg2 >::type arg2_type; - typedef typename detail::unwrap< Arg3 >::type arg3_type; - typedef typename detail::unwrap< Arg4 >::type arg4_type; - typedef void ( processor_container::*impl_fun_ptr )( - const processor_holder_ptr_type &, const processor_context &, - arg1_type, arg2_type, arg3_type, arg4_type ); - impl_fun_ptr pImpl = - &processor_container::template create_processor_impl4< - Processor, arg1_type, arg2_type, arg3_type, arg4_type >; - return WorkItem( - boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), - arg1, arg2, arg3, arg4 ), - Allocator() ); - } - - template< - class Processor, typename Arg1, typename Arg2, - typename Arg3, typename Arg4, typename Arg5 > - WorkItem create_processor( - processor_handle & handle, Scheduler & scheduler, - Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 ) - { - processor_holder_ptr_type pProcessor = make_processor_holder(); - handle = pProcessor; - typedef typename detail::unwrap< Arg1 >::type arg1_type; - typedef typename detail::unwrap< Arg2 >::type arg2_type; - typedef typename detail::unwrap< Arg3 >::type arg3_type; - typedef typename detail::unwrap< Arg4 >::type arg4_type; - typedef typename detail::unwrap< Arg5 >::type arg5_type; - typedef void ( processor_container::*impl_fun_ptr )( - const processor_holder_ptr_type &, const processor_context &, - arg1_type, arg2_type, arg3_type, arg4_type, arg5_type ); - impl_fun_ptr pImpl = - &processor_container::template create_processor_impl5< - Processor, arg1_type, arg2_type, arg3_type, arg4_type, arg5_type >; - return WorkItem( - boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), - arg1, arg2, arg3, arg4, arg5 ), - Allocator() ); - } - - template< - class Processor, typename Arg1, typename Arg2, - typename Arg3, typename Arg4, typename Arg5, typename Arg6 > - WorkItem create_processor( - processor_handle & handle, Scheduler & scheduler, - Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 ) - { - processor_holder_ptr_type pProcessor = make_processor_holder(); - handle = pProcessor; - typedef typename detail::unwrap< Arg1 >::type arg1_type; - typedef typename detail::unwrap< Arg2 >::type arg2_type; - typedef typename detail::unwrap< Arg3 >::type arg3_type; - typedef typename detail::unwrap< Arg4 >::type arg4_type; - typedef typename detail::unwrap< Arg5 >::type arg5_type; - typedef typename detail::unwrap< Arg6 >::type arg6_type; - typedef void ( processor_container::*impl_fun_ptr )( - const processor_holder_ptr_type &, const processor_context &, - arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type ); - impl_fun_ptr pImpl = - &processor_container::template create_processor_impl6< - Processor, - arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type >; - return WorkItem( - boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), - arg1, arg2, arg3, arg4, arg5, arg6 ), - Allocator() ); - } - - WorkItem destroy_processor( const processor_handle & processor ) - { - return WorkItem( - boost::bind( &processor_container::destroy_processor_impl, this, processor ), - Allocator() ); - } - - WorkItem initiate_processor( const processor_handle & processor ) - { - return WorkItem( - boost::bind( &processor_container::initiate_processor_impl, this, - processor ), - Allocator() ); - } - - WorkItem terminate_processor( const processor_handle & processor ) - { - return WorkItem( - boost::bind( &processor_container::terminate_processor_impl, this, - processor ), - Allocator() ); - } - - typedef intrusive_ptr< const event_base > event_ptr_type; - - WorkItem queue_event( - const processor_handle & processor, const event_ptr_type & pEvent ) - { - BOOST_ASSERT( pEvent.get() != 0 ); - - return WorkItem( - boost::bind( &processor_container::queue_event_impl, this, processor, - pEvent ), - Allocator() ); - } - - private: - ////////////////////////////////////////////////////////////////////////// - processor_holder_ptr_type make_processor_holder() - { - return processor_holder_ptr_type( new processor_holder_type() ); - } - - template< class Processor > - void create_processor_impl0( - const processor_holder_ptr_type & pProcessor, - const processor_context & context ) - { - processorSet_.insert( pProcessor ); - processor_holder_type holder( new Processor( context ) ); - *pProcessor = holder; - } - - template< class Processor, typename Arg1 > - void create_processor_impl1( - const processor_holder_ptr_type & pProcessor, - const processor_context & context, Arg1 arg1 ) - { - processorSet_.insert( pProcessor ); - processor_holder_type holder( new Processor( context, arg1 ) ); - *pProcessor = holder; - } - - template< class Processor, typename Arg1, typename Arg2 > - void create_processor_impl2( - const processor_holder_ptr_type & pProcessor, - const processor_context & context, Arg1 arg1, Arg2 arg2 ) - { - processorSet_.insert( pProcessor ); - processor_holder_type holder( new Processor( context, arg1, arg2 ) ); - *pProcessor = holder; - } - - template< class Processor, typename Arg1, typename Arg2, typename Arg3 > - void create_processor_impl3( - const processor_holder_ptr_type & pProcessor, - const processor_context & context, Arg1 arg1, Arg2 arg2, Arg3 arg3 ) - { - processorSet_.insert( pProcessor ); - processor_holder_type holder( - new Processor( context, arg1, arg2, arg3 ) ); - *pProcessor = holder; - } - - template< - class Processor, typename Arg1, typename Arg2, - typename Arg3, typename Arg4 > - void create_processor_impl4( - const processor_holder_ptr_type & pProcessor, - const processor_context & context, - Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 ) - { - processorSet_.insert( pProcessor ); - processor_holder_type holder( - new Processor( context, arg1, arg2, arg3, arg4 ) ); - *pProcessor = holder; - } - - template< - class Processor, typename Arg1, typename Arg2, - typename Arg3, typename Arg4, typename Arg5 > - void create_processor_impl5( - const processor_holder_ptr_type & pProcessor, - const processor_context & context, - Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 ) - { - processorSet_.insert( pProcessor ); - processor_holder_type holder( - new Processor( context, arg1, arg2, arg3, arg4, arg5 ) ); - *pProcessor = holder; - } - - template< - class Processor, typename Arg1, typename Arg2, - typename Arg3, typename Arg4, typename Arg5, typename Arg6 > - void create_processor_impl6( - const processor_holder_ptr_type & pProcessor, - const processor_context & context, - Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 ) - { - processorSet_.insert( pProcessor ); - processor_holder_type holder( - new Processor( context, arg1, arg2, arg3, arg4, arg5, arg6 ) ); - *pProcessor = holder; - } - - void destroy_processor_impl( const processor_handle & processor ) - { - const processor_holder_ptr_type pProcessor = processor.lock(); - - if ( pProcessor != 0 ) - { - processorSet_.erase( pProcessor ); - } - } - - void initiate_processor_impl( const processor_handle & processor ) - { - const processor_holder_ptr_type pProcessor = processor.lock(); - - if ( pProcessor != 0 ) - { - ( *pProcessor )->initiate(); - } - } - - void terminate_processor_impl( const processor_handle & processor ) - { - const processor_holder_ptr_type pProcessor = processor.lock(); - - if ( pProcessor != 0 ) - { - ( *pProcessor )->terminate(); - } - } - - void queue_event_impl( - const processor_handle & processor, const event_ptr_type & pEvent ) - { - const processor_holder_ptr_type pProcessor = processor.lock(); - - if ( pProcessor != 0 ) - { - ( *pProcessor )->process_event( *pEvent ); - } - } - - typedef std::set< - processor_holder_ptr_type, - std::less< processor_holder_ptr_type >, - typename boost::detail::allocator::rebind_to< - Allocator, processor_holder_ptr_type >::type - > event_processor_set_type; - - event_processor_set_type processorSet_; -}; - - -} // namespace statechart -} // namespace boost - - - -#endif +#ifndef BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED +#define BOOST_STATECHART_PROCESSOR_CONTAINER_HPP_INCLUDED +////////////////////////////////////////////////////////////////////////////// +// Copyright 2002-2008 Andreas Huber Doenni +// Distributed under the Boost Software License, Version 1.0. (See accompany- +// ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +////////////////////////////////////////////////////////////////////////////// + + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include // BOOST_INTEL + +#include +#include + +#include +#include // std::allocator, std::unique_ptr + + + +namespace boost +{ +namespace statechart +{ +namespace detail +{ + template + struct unwrap_impl + { + template< typename T > + struct apply { typedef T type; }; + }; + + template<> + struct unwrap_impl + { + template< typename T > + struct apply { typedef typename T::type & type; }; + }; + + template + struct unwrap + { + typedef typename unwrap_impl< + is_reference_wrapper< T >::value >::template apply< T >::type type; + }; +} + + +template< + class Scheduler, + class WorkItem, + class Allocator = std::allocator< void > > +class processor_container : noncopyable +{ + typedef event_processor< Scheduler > processor_base_type; + typedef std::unique_ptr< processor_base_type > processor_holder_type; + typedef shared_ptr< processor_holder_type > processor_holder_ptr_type; + + public: + ////////////////////////////////////////////////////////////////////////// + typedef weak_ptr< processor_holder_type > processor_handle; + + class processor_context + { + processor_context( + Scheduler & scheduler, const processor_handle & handle + ) : + scheduler_( scheduler ), + handle_( handle ) + { + } + + #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) ) + public: + // for some reason Intel 8.0 seems to think that the following functions + // are inaccessible from event_processor<>::event_processor + #endif + + Scheduler & my_scheduler() const { return scheduler_; } + const processor_handle & my_handle() const { return handle_; } + + #if BOOST_WORKAROUND( BOOST_INTEL, BOOST_TESTED_AT( 800 ) ) + private: + #endif + + // avoids C4512 (assignment operator could not be generated) + processor_context & operator=( const processor_context & ); + + Scheduler & scheduler_; + const processor_handle handle_; + + friend class processor_container; + friend class event_processor< Scheduler >; + }; + + template< class Processor > + WorkItem create_processor( processor_handle & handle, Scheduler & scheduler ) + { + processor_holder_ptr_type pProcessor = make_processor_holder(); + handle = pProcessor; + typedef void ( processor_container::*impl_fun_ptr )( + const processor_holder_ptr_type &, const processor_context & ); + impl_fun_ptr pImpl = + &processor_container::template create_processor_impl0< Processor >; + return WorkItem( + boost::bind( pImpl, this, pProcessor, + processor_context( scheduler, handle ) ), + Allocator() ); + } + + template< class Processor, typename Arg1 > + WorkItem create_processor( + processor_handle & handle, Scheduler & scheduler, Arg1 arg1 ) + { + processor_holder_ptr_type pProcessor = make_processor_holder(); + handle = pProcessor; + typedef typename detail::unwrap< Arg1 >::type arg1_type; + typedef void ( processor_container::*impl_fun_ptr )( + const processor_holder_ptr_type &, const processor_context &, + arg1_type ); + impl_fun_ptr pImpl = + &processor_container::template create_processor_impl1< + Processor, arg1_type >; + return WorkItem( + boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), + arg1 ), + Allocator() ); + } + + template< class Processor, typename Arg1, typename Arg2 > + WorkItem create_processor( + processor_handle & handle, Scheduler & scheduler, Arg1 arg1, Arg2 arg2 ) + { + processor_holder_ptr_type pProcessor = make_processor_holder(); + handle = pProcessor; + typedef typename detail::unwrap< Arg1 >::type arg1_type; + typedef typename detail::unwrap< Arg2 >::type arg2_type; + typedef void ( processor_container::*impl_fun_ptr )( + const processor_holder_ptr_type &, const processor_context &, + arg1_type, arg2_type ); + impl_fun_ptr pImpl = + &processor_container::template create_processor_impl2< + Processor, arg1_type, arg2_type >; + return WorkItem( + boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), + arg1, arg2 ), + Allocator() ); + } + + template< class Processor, typename Arg1, typename Arg2, typename Arg3 > + WorkItem create_processor( + processor_handle & handle, Scheduler & scheduler, + Arg1 arg1, Arg2 arg2, Arg3 arg3 ) + { + processor_holder_ptr_type pProcessor = make_processor_holder(); + handle = pProcessor; + typedef typename detail::unwrap< Arg1 >::type arg1_type; + typedef typename detail::unwrap< Arg2 >::type arg2_type; + typedef typename detail::unwrap< Arg3 >::type arg3_type; + typedef void ( processor_container::*impl_fun_ptr )( + const processor_holder_ptr_type &, const processor_context &, + arg1_type, arg2_type, arg3_type ); + impl_fun_ptr pImpl = + &processor_container::template create_processor_impl3< + Processor, arg1_type, arg2_type, arg3_type >; + return WorkItem( + boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), + arg1, arg2, arg3 ), + Allocator() ); + } + + template< + class Processor, typename Arg1, typename Arg2, + typename Arg3, typename Arg4 > + WorkItem create_processor( + processor_handle & handle, Scheduler & scheduler, + Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 ) + { + processor_holder_ptr_type pProcessor = make_processor_holder(); + handle = pProcessor; + typedef typename detail::unwrap< Arg1 >::type arg1_type; + typedef typename detail::unwrap< Arg2 >::type arg2_type; + typedef typename detail::unwrap< Arg3 >::type arg3_type; + typedef typename detail::unwrap< Arg4 >::type arg4_type; + typedef void ( processor_container::*impl_fun_ptr )( + const processor_holder_ptr_type &, const processor_context &, + arg1_type, arg2_type, arg3_type, arg4_type ); + impl_fun_ptr pImpl = + &processor_container::template create_processor_impl4< + Processor, arg1_type, arg2_type, arg3_type, arg4_type >; + return WorkItem( + boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), + arg1, arg2, arg3, arg4 ), + Allocator() ); + } + + template< + class Processor, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5 > + WorkItem create_processor( + processor_handle & handle, Scheduler & scheduler, + Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 ) + { + processor_holder_ptr_type pProcessor = make_processor_holder(); + handle = pProcessor; + typedef typename detail::unwrap< Arg1 >::type arg1_type; + typedef typename detail::unwrap< Arg2 >::type arg2_type; + typedef typename detail::unwrap< Arg3 >::type arg3_type; + typedef typename detail::unwrap< Arg4 >::type arg4_type; + typedef typename detail::unwrap< Arg5 >::type arg5_type; + typedef void ( processor_container::*impl_fun_ptr )( + const processor_holder_ptr_type &, const processor_context &, + arg1_type, arg2_type, arg3_type, arg4_type, arg5_type ); + impl_fun_ptr pImpl = + &processor_container::template create_processor_impl5< + Processor, arg1_type, arg2_type, arg3_type, arg4_type, arg5_type >; + return WorkItem( + boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), + arg1, arg2, arg3, arg4, arg5 ), + Allocator() ); + } + + template< + class Processor, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5, typename Arg6 > + WorkItem create_processor( + processor_handle & handle, Scheduler & scheduler, + Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 ) + { + processor_holder_ptr_type pProcessor = make_processor_holder(); + handle = pProcessor; + typedef typename detail::unwrap< Arg1 >::type arg1_type; + typedef typename detail::unwrap< Arg2 >::type arg2_type; + typedef typename detail::unwrap< Arg3 >::type arg3_type; + typedef typename detail::unwrap< Arg4 >::type arg4_type; + typedef typename detail::unwrap< Arg5 >::type arg5_type; + typedef typename detail::unwrap< Arg6 >::type arg6_type; + typedef void ( processor_container::*impl_fun_ptr )( + const processor_holder_ptr_type &, const processor_context &, + arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type ); + impl_fun_ptr pImpl = + &processor_container::template create_processor_impl6< + Processor, + arg1_type, arg2_type, arg3_type, arg4_type, arg5_type, arg6_type >; + return WorkItem( + boost::bind( pImpl, this, pProcessor, processor_context( scheduler, handle ), + arg1, arg2, arg3, arg4, arg5, arg6 ), + Allocator() ); + } + + WorkItem destroy_processor( const processor_handle & processor ) + { + return WorkItem( + boost::bind( &processor_container::destroy_processor_impl, this, processor ), + Allocator() ); + } + + WorkItem initiate_processor( const processor_handle & processor ) + { + return WorkItem( + boost::bind( &processor_container::initiate_processor_impl, this, + processor ), + Allocator() ); + } + + WorkItem terminate_processor( const processor_handle & processor ) + { + return WorkItem( + boost::bind( &processor_container::terminate_processor_impl, this, + processor ), + Allocator() ); + } + + typedef intrusive_ptr< const event_base > event_ptr_type; + + WorkItem queue_event( + const processor_handle & processor, const event_ptr_type & pEvent ) + { + BOOST_ASSERT( pEvent.get() != 0 ); + + return WorkItem( + boost::bind( &processor_container::queue_event_impl, this, processor, + pEvent ), + Allocator() ); + } + + private: + ////////////////////////////////////////////////////////////////////////// + processor_holder_ptr_type make_processor_holder() + { + return processor_holder_ptr_type( new processor_holder_type() ); + } + + template< class Processor > + void create_processor_impl0( + const processor_holder_ptr_type & pProcessor, + const processor_context & context ) + { + processorSet_.insert( pProcessor ); + processor_holder_type holder( new Processor( context ) ); + *pProcessor = holder; + } + + template< class Processor, typename Arg1 > + void create_processor_impl1( + const processor_holder_ptr_type & pProcessor, + const processor_context & context, Arg1 arg1 ) + { + processorSet_.insert( pProcessor ); + processor_holder_type holder( new Processor( context, arg1 ) ); + *pProcessor = holder; + } + + template< class Processor, typename Arg1, typename Arg2 > + void create_processor_impl2( + const processor_holder_ptr_type & pProcessor, + const processor_context & context, Arg1 arg1, Arg2 arg2 ) + { + processorSet_.insert( pProcessor ); + processor_holder_type holder( new Processor( context, arg1, arg2 ) ); + *pProcessor = holder; + } + + template< class Processor, typename Arg1, typename Arg2, typename Arg3 > + void create_processor_impl3( + const processor_holder_ptr_type & pProcessor, + const processor_context & context, Arg1 arg1, Arg2 arg2, Arg3 arg3 ) + { + processorSet_.insert( pProcessor ); + processor_holder_type holder( + new Processor( context, arg1, arg2, arg3 ) ); + *pProcessor = holder; + } + + template< + class Processor, typename Arg1, typename Arg2, + typename Arg3, typename Arg4 > + void create_processor_impl4( + const processor_holder_ptr_type & pProcessor, + const processor_context & context, + Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4 ) + { + processorSet_.insert( pProcessor ); + processor_holder_type holder( + new Processor( context, arg1, arg2, arg3, arg4 ) ); + *pProcessor = holder; + } + + template< + class Processor, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5 > + void create_processor_impl5( + const processor_holder_ptr_type & pProcessor, + const processor_context & context, + Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5 ) + { + processorSet_.insert( pProcessor ); + processor_holder_type holder( + new Processor( context, arg1, arg2, arg3, arg4, arg5 ) ); + *pProcessor = holder; + } + + template< + class Processor, typename Arg1, typename Arg2, + typename Arg3, typename Arg4, typename Arg5, typename Arg6 > + void create_processor_impl6( + const processor_holder_ptr_type & pProcessor, + const processor_context & context, + Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6 ) + { + processorSet_.insert( pProcessor ); + processor_holder_type holder( + new Processor( context, arg1, arg2, arg3, arg4, arg5, arg6 ) ); + *pProcessor = holder; + } + + void destroy_processor_impl( const processor_handle & processor ) + { + const processor_holder_ptr_type pProcessor = processor.lock(); + + if ( pProcessor != 0 ) + { + processorSet_.erase( pProcessor ); + } + } + + void initiate_processor_impl( const processor_handle & processor ) + { + const processor_holder_ptr_type pProcessor = processor.lock(); + + if ( pProcessor != 0 ) + { + ( *pProcessor )->initiate(); + } + } + + void terminate_processor_impl( const processor_handle & processor ) + { + const processor_holder_ptr_type pProcessor = processor.lock(); + + if ( pProcessor != 0 ) + { + ( *pProcessor )->terminate(); + } + } + + void queue_event_impl( + const processor_handle & processor, const event_ptr_type & pEvent ) + { + const processor_holder_ptr_type pProcessor = processor.lock(); + + if ( pProcessor != 0 ) + { + ( *pProcessor )->process_event( *pEvent ); + } + } + + typedef std::set< + processor_holder_ptr_type, + std::less< processor_holder_ptr_type >, + typename boost::detail::allocator::rebind_to< + Allocator, processor_holder_ptr_type >::type + > event_processor_set_type; + + event_processor_set_type processorSet_; +}; + + +} // namespace statechart +} // namespace boost + + + +#endif diff --git a/src/external/3rd/library/boost/boost/test/utils/runtime/file/config_file_iterator.cpp b/src/external/3rd/library/boost/boost/test/utils/runtime/file/config_file_iterator.cpp index 7f29458eb..df3b48368 100644 --- a/src/external/3rd/library/boost/boost/test/utils/runtime/file/config_file_iterator.cpp +++ b/src/external/3rd/library/boost/boost/test/utils/runtime/file/config_file_iterator.cpp @@ -1,685 +1,685 @@ -// (C) Copyright Gennadiy Rozental 2005-2008. -// Use, modification, and distribution are subject to the -// Boost Software License, Version 1.0. (See accompanying file -// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See http://www.boost.org/libs/test for the library home page. -// -// File : $RCSfile$ -// -// Version : $Revision$ -// -// Description : flexible configuration file iterator implementation -// *************************************************************************** - -// Boost.Runtime.Parameter -#include - -#include -#include - -#ifndef UNDER_CE -#include -#endif - - -// Boost -#include -#include -#include - -// Boost.Test -#include -#include -#include -#include - -// STL -#include -#include -#include -#include -#include -#include -#include - -namespace boost { - -namespace BOOST_RT_PARAM_NAMESPACE { - -namespace file { - -// ************************************************************************** // -// ************** symbol_to_value_map ************** // -// ************************************************************************** // - -template -struct symbol_to_value_map : std::map { - template - void add( cstring name, ParamType const& value ) - { - using namespace unit_test; - - m_name_store.push_back( dstring() ); - - assign_op( m_name_store.back(), name, 0 ); - assign_op( (*this)[m_name_store.back()], value, 0 ); - } - void remove( cstring name ) - { - std::list::iterator it = std::find( m_name_store.begin(), m_name_store.end(), name ); - - m_name_store.erase( it ); - - erase( name ); - } - -private: - std::list m_name_store; -}; - -// ************************************************************************** // -// ************** symbol_table_t ************** // -// ************************************************************************** // - -typedef symbol_to_value_map symbol_table_t; - -// ************************************************************************** // -// ************** command_handler_map ************** // -// ************************************************************************** // - -typedef symbol_to_value_map command_handler_map; - -// ************************************************************************** // -// ************** is_valid_identifier ************** // -// ************************************************************************** // - -static bool -is_valid_identifier( cstring const& source ) -{ - if( source.is_empty() ) - return false; - - cstring::const_iterator it = source.begin(); - - if( !std::isalpha( *it ) ) - return false; - - while( ++it < source.end() ) { - if( !std::isalnum( *it ) && *it != BOOST_RT_PARAM_LITERAL( '_' ) && *it != BOOST_RT_PARAM_LITERAL( '-' ) ) - return false; - } - - return true; -} - -// ************************************************************************** // -// ************** include_level ************** // -// ************************************************************************** // - -struct include_level; -typedef std::unique_ptr include_level_ptr; - -struct include_level : noncopyable -{ - // Constructor - explicit include_level( cstring file_name, cstring path_separators, include_level* parent = 0 ); - - // Data members - std::ifstream m_stream; - location m_curr_location; - include_level_ptr m_parent; -}; - -//____________________________________________________________________________// - -include_level::include_level( cstring file_name, cstring path_separators, include_level* parent_ ) -: m_parent( parent_ ) -{ - if( file_name.is_empty() ) - return; - - assign_op( m_curr_location.first, file_name, 0 ); - m_curr_location.second = 0; - - m_stream.open( m_curr_location.first.c_str() ); - - if( !m_stream.is_open() && !!m_parent.get() ) { - cstring parent_path = m_parent->m_curr_location.first; - cstring::iterator it = unit_test::find_last_of( parent_path.begin(), parent_path.end(), - path_separators.begin(), - path_separators.end() ); - - if( it != parent_path.end() ) { - assign_op( m_curr_location.first, cstring( parent_path.begin(), it+1 ), 0 ); - m_curr_location.first.append( file_name.begin(), file_name.end() ); - m_stream.clear(); - m_stream.open( m_curr_location.first.c_str() ); - } - } - - BOOST_RT_PARAM_VALIDATE_LOGIC( m_stream.is_open(), BOOST_RT_PARAM_LITERAL( "can't open file " ) << file_name ); -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** config_file_iterator::Impl ************** // -// ************************************************************************** // - -struct config_file_iterator::Impl : noncopyable { - // Constructor - Impl(); - - bool get_next_line( cstring& next_line ); - - void process_command_line( cstring line ); - void process_include( cstring line ); - void process_define( cstring line ); - void process_undef( cstring line ); - void process_ifdef( cstring line ); - void process_ifndef( cstring line ); - void process_else( cstring line ); - void process_endif( cstring line ); - - boost::optional - get_macro_value( cstring macro_name, bool ignore_missing = true ); - void substitute_macros( cstring& where ); - - bool is_active_line() { return m_inactive_ifdef_level == 0; } - - static bool match_front( cstring str, cstring pattern ) - { - return str.size() >= pattern.size() && str.substr( 0, pattern.size() ) == pattern; - } - static bool match_back( cstring str, cstring pattern ) - { - return str.size() >= pattern.size() && str.substr( str.size() - pattern.size() ) == pattern; - } - - // Configurable parameters - dstring m_path_separators; - char_type m_line_delimeter; - dstring m_sl_comment_delimeter; - dstring m_command_delimeter; - dstring m_line_beak; - dstring m_macro_ref_begin; - dstring m_macro_ref_end; - - dstring m_include_kw; - dstring m_define_kw; - dstring m_undef_kw; - dstring m_ifdef_kw; - dstring m_ifndef_kw; - dstring m_else_kw; - dstring m_endif_kw; - - std::size_t m_buffer_size; - - bool m_trim_trailing_spaces; - bool m_trim_leading_spaces; - bool m_skip_empty_lines; - bool m_detect_missing_macro; - - // Data members - dstring m_post_subst_line; - scoped_array m_buffer; - include_level_ptr m_curr_level; - symbol_table_t m_symbols_table; - std::vector m_conditional_states; - std::size_t m_inactive_ifdef_level; - command_handler_map m_command_handler_map; -}; - -//____________________________________________________________________________// - -config_file_iterator::Impl::Impl() -: m_path_separators( BOOST_RT_PARAM_LITERAL( "/\\" ) ) -, m_line_delimeter( BOOST_RT_PARAM_LITERAL( '\n' ) ) -, m_sl_comment_delimeter( BOOST_RT_PARAM_LITERAL( "#" ) ) -, m_command_delimeter( BOOST_RT_PARAM_LITERAL( "$" ) ) -, m_line_beak( BOOST_RT_PARAM_LITERAL( "\\" ) ) -, m_macro_ref_begin( BOOST_RT_PARAM_LITERAL( "$" ) ) -, m_macro_ref_end( BOOST_RT_PARAM_LITERAL( "$" ) ) - -, m_include_kw( BOOST_RT_PARAM_LITERAL( "include" ) ) -, m_define_kw( BOOST_RT_PARAM_LITERAL( "define" ) ) -, m_undef_kw( BOOST_RT_PARAM_LITERAL( "undef" ) ) -, m_ifdef_kw( BOOST_RT_PARAM_LITERAL( "ifdef" ) ) -, m_ifndef_kw( BOOST_RT_PARAM_LITERAL( "ifndef" ) ) -, m_else_kw( BOOST_RT_PARAM_LITERAL( "else" ) ) -, m_endif_kw( BOOST_RT_PARAM_LITERAL( "endif" ) ) - -, m_buffer_size( 8192 ) - -, m_trim_trailing_spaces( true ) -, m_trim_leading_spaces( false ) -, m_skip_empty_lines( true ) -, m_detect_missing_macro( true ) - -, m_inactive_ifdef_level( 0 ) -{} - -//____________________________________________________________________________// - -bool -config_file_iterator::Impl::get_next_line( cstring& line ) -{ - bool broken_line = false; - - line.clear(); - - while( !m_curr_level->m_stream.eof() || !!m_curr_level->m_parent.get() ) { - // 10. Switch to upper include level if current one is finished - // 20. Read/append next file line - // 30. Increment line number - // 40. Remove comments - // 50. Remove trailing and leading spaces - // 60. Skip empty string - // 70. Concatenate broken lines if needed. Put the result into line - // 80. If line is not completed, try to finish it by reading the next line - // 90. Process command line - // 100. Substitute macros references with their definitions - // 110. Next line found. - - if( m_curr_level->m_stream.eof() ) { // 10 // - m_curr_level = m_curr_level->m_parent; - continue; - } - - std::ifstream& input = m_curr_level->m_stream; - char_type* buffer_insert_pos = broken_line ? m_buffer.get() + line.size() : m_buffer.get(); - - input.getline( buffer_insert_pos, (std::streamsize)(m_buffer_size - line.size()), // 20 // - m_line_delimeter ); - - cstring next_line( buffer_insert_pos, - input.gcount() > 0 - ? buffer_insert_pos + (input.eof() ? input.gcount() : (input.gcount()-1)) - : buffer_insert_pos ); - - - m_curr_level->m_curr_location.second++; // 30 // - - cstring::size_type comment_pos = next_line.find( m_sl_comment_delimeter ); - if( comment_pos != cstring::npos ) - next_line.trim_right( next_line.begin()+comment_pos ); // 40 // - - if( m_trim_trailing_spaces ) // 50 // - next_line.trim_right(); - if( m_trim_leading_spaces && !broken_line ) - next_line.trim_left(); - - if( next_line.is_empty() ) { // 60 // - if( m_skip_empty_lines ) - continue; - else - next_line.assign( buffer_insert_pos, buffer_insert_pos ); - } - - line = broken_line ? cstring( line.begin(), next_line.end() ) : next_line; // 70 // - - broken_line = match_back( line, m_line_beak ); - if( broken_line ) { // 80 // - line.trim_right( 1 ); - continue; - } - - if( match_front( line, m_command_delimeter ) ) { // 90 // - process_command_line( line ); - continue; - } - - if( !is_active_line() ) - continue; - - substitute_macros( line ); // 100 // - - return true; // 110 // - } - - BOOST_RT_PARAM_VALIDATE_LOGIC( !broken_line, BOOST_RT_PARAM_LITERAL( "broken line is not completed" ) ); - BOOST_RT_PARAM_VALIDATE_LOGIC( m_conditional_states.size() == 0, - BOOST_RT_PARAM_LITERAL( "matching endif command is missing" ) ); - - return false; -} - -//____________________________________________________________________________// - -boost::optional -config_file_iterator::Impl::get_macro_value( cstring macro_name, bool ignore_missing ) -{ - symbol_table_t::const_iterator it = m_symbols_table.find( macro_name ); - - if( it == m_symbols_table.end() ) { - boost::optional macro_value; // !! variable actually may have different type - - #ifndef UNDER_CE - env::get( macro_name, macro_value ); - #endif - - BOOST_RT_PARAM_VALIDATE_LOGIC( macro_value || ignore_missing || !m_detect_missing_macro, - BOOST_RT_PARAM_LITERAL( "Unknown macro \"" ) << macro_name << BOOST_RT_PARAM_LITERAL( "\"" ) ); - - if( !macro_value ) { - if( !ignore_missing ) - macro_value = cstring(); - } - else - m_symbols_table.add( macro_name, *macro_value ); - - return macro_value; - } - - return boost::optional( cstring( it->second ) ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_command_line( cstring line ) -{ - line.trim_left( m_command_delimeter.size() ); - - unit_test::string_token_iterator tit( line, unit_test::max_tokens = 2 ); - - command_handler_map::const_iterator it = m_command_handler_map.find( *tit ); - - BOOST_RT_PARAM_VALIDATE_LOGIC( it != m_command_handler_map.end(), BOOST_RT_PARAM_LITERAL( "Invalid command " ) << *tit ); - - ++tit; - - (it->second)( *tit ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_include( cstring line ) -{ - using namespace unit_test; - - if( !is_active_line() ) - return; - - string_token_iterator tit( line, kept_delimeters = dt_none ); - - BOOST_RT_PARAM_VALIDATE_LOGIC( tit != string_token_iterator(), - BOOST_RT_PARAM_LITERAL( "include file name missing" ) ); - - cstring include_file_name = *tit; - - BOOST_RT_PARAM_VALIDATE_LOGIC( ++tit == string_token_iterator(), - BOOST_RT_PARAM_LITERAL( "unexpected tokens at the end of include command" ) ); - - substitute_macros( include_file_name ); - - m_curr_level.reset( new include_level( include_file_name, m_path_separators, m_curr_level.release() ) ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_define( cstring line ) -{ - using namespace unit_test; - - if( !is_active_line() ) - return; - - string_token_iterator tit( line, (kept_delimeters = dt_none, max_tokens = 2 )); - - cstring macro_name = *tit; - BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), - BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); - - cstring macro_value = *(++tit); - substitute_macros( macro_value ); - - m_symbols_table.add( macro_name, macro_value ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_undef( cstring line ) -{ - if( !is_active_line() ) - return; - - cstring macro_name = line; - BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), - BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); - - m_symbols_table.remove( macro_name ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_ifdef( cstring line ) -{ - m_conditional_states.push_back( true ); - if( !is_active_line() ) - return; - - cstring macro_name = line; - BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), - BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); - - if( !get_macro_value( macro_name ) ) - m_inactive_ifdef_level = m_conditional_states.size(); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_ifndef( cstring line ) -{ - m_conditional_states.push_back( true ); - if( !is_active_line() ) - return; - - cstring macro_name = line; - BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), - BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); - - if( get_macro_value( macro_name ) ) - m_inactive_ifdef_level = m_conditional_states.size(); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_else( cstring line ) -{ - BOOST_RT_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0 && m_conditional_states.back(), - BOOST_RT_PARAM_LITERAL( "else without matching if" ) ); - - m_inactive_ifdef_level = m_conditional_states.size() == m_inactive_ifdef_level ? 0 : m_conditional_states.size(); - - BOOST_RT_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_RT_PARAM_LITERAL( "unexpected tokens at the end of else command" ) ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::process_endif( cstring line ) -{ - BOOST_RT_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0, BOOST_RT_PARAM_LITERAL( "endif without matching if" ) ); - - if( m_conditional_states.size() == m_inactive_ifdef_level ) - m_inactive_ifdef_level = 0; - - m_conditional_states.pop_back(); - BOOST_RT_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_RT_PARAM_LITERAL( "unexpected tokens at the end of endif command" ) ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::Impl::substitute_macros( cstring& where ) -{ - m_post_subst_line.clear(); - cstring::size_type pos; - - while( (pos = where.find( m_macro_ref_begin )) != cstring::npos ) { - m_post_subst_line.append( where.begin(), pos ); - - where.trim_left( where.begin() + pos + m_macro_ref_begin.size() ); - - pos = where.find( m_macro_ref_end ); - - BOOST_RT_PARAM_VALIDATE_LOGIC( pos != cstring::npos, BOOST_RT_PARAM_LITERAL( "incomplete macro reference" ) ); - - cstring value = *get_macro_value( where.substr( 0, pos ), false ); - m_post_subst_line.append( value.begin(), value.size() ); - - where.trim_left( where.begin() + pos + m_macro_ref_end.size() ); - } - - if( !m_post_subst_line.empty() ) { - m_post_subst_line.append( where.begin(), where.size() ); - where = m_post_subst_line; - } -} - -//____________________________________________________________________________// - -// ************************************************************************** // -// ************** runtime::file::config_file_iterator ************** // -// ************************************************************************** // - -void -config_file_iterator::construct() -{ - m_pimpl.reset( new Impl ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::load( cstring file_name ) -{ - m_pimpl->m_curr_level.reset( new include_level( file_name, m_pimpl->m_path_separators ) ); - m_pimpl->m_buffer.reset( new char[m_pimpl->m_buffer_size] ); - - register_command_handler( m_pimpl->m_include_kw, bind( &Impl::process_include, m_pimpl.get(), _1 ) ); - register_command_handler( m_pimpl->m_define_kw, bind( &Impl::process_define, m_pimpl.get(), _1 ) ); - register_command_handler( m_pimpl->m_undef_kw, bind( &Impl::process_undef, m_pimpl.get(), _1 ) ); - register_command_handler( m_pimpl->m_ifdef_kw, bind( &Impl::process_ifdef, m_pimpl.get(), _1 ) ); - register_command_handler( m_pimpl->m_ifndef_kw, bind( &Impl::process_ifndef, m_pimpl.get(), _1 ) ); - register_command_handler( m_pimpl->m_else_kw, bind( &Impl::process_else, m_pimpl.get(), _1 ) ); - register_command_handler( m_pimpl->m_endif_kw, bind( &Impl::process_endif, m_pimpl.get(), _1 ) ); - - init(); -} - -//____________________________________________________________________________// - -location const& -config_file_iterator::curr_location() -{ - return m_pimpl->m_curr_level->m_curr_location; -} - -//____________________________________________________________________________// - -void -config_file_iterator::register_command_handler( cstring command_kw, command_handler const& ch ) -{ - m_pimpl->m_command_handler_map.add( command_kw, ch ); -} - -//____________________________________________________________________________// - -bool -config_file_iterator::get() -{ - return m_pimpl->get_next_line( m_value ); -} - -//____________________________________________________________________________// - -void -config_file_iterator::set_parameter( rtti::id_t id, cstring value ) -{ - BOOST_RTTI_SWITCH( id ) { - BOOST_RTTI_CASE( cfg_detail::path_separators_t ) - assign_op( m_pimpl->m_path_separators , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::sl_comment_delimeter_t ) - assign_op( m_pimpl->m_sl_comment_delimeter , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::command_delimeter_t ) - assign_op( m_pimpl->m_command_delimeter , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::line_beak_t ) - assign_op( m_pimpl->m_line_beak , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::macro_ref_begin_t ) - assign_op( m_pimpl->m_macro_ref_begin , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::macro_ref_end_t ) - assign_op( m_pimpl->m_macro_ref_end , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::include_kw_t ) - assign_op( m_pimpl->m_include_kw , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::define_kw_t ) - assign_op( m_pimpl->m_define_kw , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::undef_kw_t ) - assign_op( m_pimpl->m_undef_kw , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::ifdef_kw_t ) - assign_op( m_pimpl->m_ifdef_kw , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::ifndef_kw_t ) - assign_op( m_pimpl->m_ifndef_kw , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::else_kw_t ) - assign_op( m_pimpl->m_else_kw , value, 0 ); - BOOST_RTTI_CASE( cfg_detail::endif_kw_t ) - assign_op( m_pimpl->m_endif_kw , value, 0 ); - } -} - -//____________________________________________________________________________// - -void -config_file_iterator::set_parameter( rtti::id_t id, bool value ) -{ - BOOST_RTTI_SWITCH( id ) { - BOOST_RTTI_CASE( cfg_detail::trim_leading_spaces_t ) - m_pimpl->m_trim_leading_spaces = value; - BOOST_RTTI_CASE( cfg_detail::trim_trailing_spaces_t ) - m_pimpl->m_trim_trailing_spaces = value; - BOOST_RTTI_CASE( cfg_detail::skip_empty_lines_t ) - m_pimpl->m_skip_empty_lines = value; - BOOST_RTTI_CASE( cfg_detail::detect_missing_macro_t ) - m_pimpl->m_detect_missing_macro = value; - } -} - -//____________________________________________________________________________// - -void -config_file_iterator::set_parameter( rtti::id_t id, char_type value ) -{ - BOOST_RTTI_SWITCH( id ) { - BOOST_RTTI_CASE( cfg_detail::line_delimeter_t ) - m_pimpl->m_line_delimeter = value; - } -} - -//____________________________________________________________________________// - -void -config_file_iterator::set_parameter( rtti::id_t id, std::size_t value ) -{ - BOOST_RTTI_SWITCH( id ) { - BOOST_RTTI_CASE( cfg_detail::buffer_size_t ) - m_pimpl->m_buffer_size = value; - } -} - -//____________________________________________________________________________// - -} // namespace file - -} // namespace BOOST_RT_PARAM_NAMESPACE - -} // namespace boost - -// EOF +// (C) Copyright Gennadiy Rozental 2005-2008. +// Use, modification, and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/test for the library home page. +// +// File : $RCSfile$ +// +// Version : $Revision$ +// +// Description : flexible configuration file iterator implementation +// *************************************************************************** + +// Boost.Runtime.Parameter +#include + +#include +#include + +#ifndef UNDER_CE +#include +#endif + + +// Boost +#include +#include +#include + +// Boost.Test +#include +#include +#include +#include + +// STL +#include +#include +#include +#include +#include +#include +#include + +namespace boost { + +namespace BOOST_RT_PARAM_NAMESPACE { + +namespace file { + +// ************************************************************************** // +// ************** symbol_to_value_map ************** // +// ************************************************************************** // + +template +struct symbol_to_value_map : std::map { + template + void add( cstring name, ParamType const& value ) + { + using namespace unit_test; + + m_name_store.push_back( dstring() ); + + assign_op( m_name_store.back(), name, 0 ); + assign_op( (*this)[m_name_store.back()], value, 0 ); + } + void remove( cstring name ) + { + std::list::iterator it = std::find( m_name_store.begin(), m_name_store.end(), name ); + + m_name_store.erase( it ); + + erase( name ); + } + +private: + std::list m_name_store; +}; + +// ************************************************************************** // +// ************** symbol_table_t ************** // +// ************************************************************************** // + +typedef symbol_to_value_map symbol_table_t; + +// ************************************************************************** // +// ************** command_handler_map ************** // +// ************************************************************************** // + +typedef symbol_to_value_map command_handler_map; + +// ************************************************************************** // +// ************** is_valid_identifier ************** // +// ************************************************************************** // + +static bool +is_valid_identifier( cstring const& source ) +{ + if( source.is_empty() ) + return false; + + cstring::const_iterator it = source.begin(); + + if( !std::isalpha( *it ) ) + return false; + + while( ++it < source.end() ) { + if( !std::isalnum( *it ) && *it != BOOST_RT_PARAM_LITERAL( '_' ) && *it != BOOST_RT_PARAM_LITERAL( '-' ) ) + return false; + } + + return true; +} + +// ************************************************************************** // +// ************** include_level ************** // +// ************************************************************************** // + +struct include_level; +typedef std::unique_ptr include_level_ptr; + +struct include_level : noncopyable +{ + // Constructor + explicit include_level( cstring file_name, cstring path_separators, include_level* parent = 0 ); + + // Data members + std::ifstream m_stream; + location m_curr_location; + include_level_ptr m_parent; +}; + +//____________________________________________________________________________// + +include_level::include_level( cstring file_name, cstring path_separators, include_level* parent_ ) +: m_parent( parent_ ) +{ + if( file_name.is_empty() ) + return; + + assign_op( m_curr_location.first, file_name, 0 ); + m_curr_location.second = 0; + + m_stream.open( m_curr_location.first.c_str() ); + + if( !m_stream.is_open() && !!m_parent.get() ) { + cstring parent_path = m_parent->m_curr_location.first; + cstring::iterator it = unit_test::find_last_of( parent_path.begin(), parent_path.end(), + path_separators.begin(), + path_separators.end() ); + + if( it != parent_path.end() ) { + assign_op( m_curr_location.first, cstring( parent_path.begin(), it+1 ), 0 ); + m_curr_location.first.append( file_name.begin(), file_name.end() ); + m_stream.clear(); + m_stream.open( m_curr_location.first.c_str() ); + } + } + + BOOST_RT_PARAM_VALIDATE_LOGIC( m_stream.is_open(), BOOST_RT_PARAM_LITERAL( "can't open file " ) << file_name ); +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** config_file_iterator::Impl ************** // +// ************************************************************************** // + +struct config_file_iterator::Impl : noncopyable { + // Constructor + Impl(); + + bool get_next_line( cstring& next_line ); + + void process_command_line( cstring line ); + void process_include( cstring line ); + void process_define( cstring line ); + void process_undef( cstring line ); + void process_ifdef( cstring line ); + void process_ifndef( cstring line ); + void process_else( cstring line ); + void process_endif( cstring line ); + + boost::optional + get_macro_value( cstring macro_name, bool ignore_missing = true ); + void substitute_macros( cstring& where ); + + bool is_active_line() { return m_inactive_ifdef_level == 0; } + + static bool match_front( cstring str, cstring pattern ) + { + return str.size() >= pattern.size() && str.substr( 0, pattern.size() ) == pattern; + } + static bool match_back( cstring str, cstring pattern ) + { + return str.size() >= pattern.size() && str.substr( str.size() - pattern.size() ) == pattern; + } + + // Configurable parameters + dstring m_path_separators; + char_type m_line_delimeter; + dstring m_sl_comment_delimeter; + dstring m_command_delimeter; + dstring m_line_beak; + dstring m_macro_ref_begin; + dstring m_macro_ref_end; + + dstring m_include_kw; + dstring m_define_kw; + dstring m_undef_kw; + dstring m_ifdef_kw; + dstring m_ifndef_kw; + dstring m_else_kw; + dstring m_endif_kw; + + std::size_t m_buffer_size; + + bool m_trim_trailing_spaces; + bool m_trim_leading_spaces; + bool m_skip_empty_lines; + bool m_detect_missing_macro; + + // Data members + dstring m_post_subst_line; + scoped_array m_buffer; + include_level_ptr m_curr_level; + symbol_table_t m_symbols_table; + std::vector m_conditional_states; + std::size_t m_inactive_ifdef_level; + command_handler_map m_command_handler_map; +}; + +//____________________________________________________________________________// + +config_file_iterator::Impl::Impl() +: m_path_separators( BOOST_RT_PARAM_LITERAL( "/\\" ) ) +, m_line_delimeter( BOOST_RT_PARAM_LITERAL( '\n' ) ) +, m_sl_comment_delimeter( BOOST_RT_PARAM_LITERAL( "#" ) ) +, m_command_delimeter( BOOST_RT_PARAM_LITERAL( "$" ) ) +, m_line_beak( BOOST_RT_PARAM_LITERAL( "\\" ) ) +, m_macro_ref_begin( BOOST_RT_PARAM_LITERAL( "$" ) ) +, m_macro_ref_end( BOOST_RT_PARAM_LITERAL( "$" ) ) + +, m_include_kw( BOOST_RT_PARAM_LITERAL( "include" ) ) +, m_define_kw( BOOST_RT_PARAM_LITERAL( "define" ) ) +, m_undef_kw( BOOST_RT_PARAM_LITERAL( "undef" ) ) +, m_ifdef_kw( BOOST_RT_PARAM_LITERAL( "ifdef" ) ) +, m_ifndef_kw( BOOST_RT_PARAM_LITERAL( "ifndef" ) ) +, m_else_kw( BOOST_RT_PARAM_LITERAL( "else" ) ) +, m_endif_kw( BOOST_RT_PARAM_LITERAL( "endif" ) ) + +, m_buffer_size( 8192 ) + +, m_trim_trailing_spaces( true ) +, m_trim_leading_spaces( false ) +, m_skip_empty_lines( true ) +, m_detect_missing_macro( true ) + +, m_inactive_ifdef_level( 0 ) +{} + +//____________________________________________________________________________// + +bool +config_file_iterator::Impl::get_next_line( cstring& line ) +{ + bool broken_line = false; + + line.clear(); + + while( !m_curr_level->m_stream.eof() || !!m_curr_level->m_parent.get() ) { + // 10. Switch to upper include level if current one is finished + // 20. Read/append next file line + // 30. Increment line number + // 40. Remove comments + // 50. Remove trailing and leading spaces + // 60. Skip empty string + // 70. Concatenate broken lines if needed. Put the result into line + // 80. If line is not completed, try to finish it by reading the next line + // 90. Process command line + // 100. Substitute macros references with their definitions + // 110. Next line found. + + if( m_curr_level->m_stream.eof() ) { // 10 // + m_curr_level = m_curr_level->m_parent; + continue; + } + + std::ifstream& input = m_curr_level->m_stream; + char_type* buffer_insert_pos = broken_line ? m_buffer.get() + line.size() : m_buffer.get(); + + input.getline( buffer_insert_pos, (std::streamsize)(m_buffer_size - line.size()), // 20 // + m_line_delimeter ); + + cstring next_line( buffer_insert_pos, + input.gcount() > 0 + ? buffer_insert_pos + (input.eof() ? input.gcount() : (input.gcount()-1)) + : buffer_insert_pos ); + + + m_curr_level->m_curr_location.second++; // 30 // + + cstring::size_type comment_pos = next_line.find( m_sl_comment_delimeter ); + if( comment_pos != cstring::npos ) + next_line.trim_right( next_line.begin()+comment_pos ); // 40 // + + if( m_trim_trailing_spaces ) // 50 // + next_line.trim_right(); + if( m_trim_leading_spaces && !broken_line ) + next_line.trim_left(); + + if( next_line.is_empty() ) { // 60 // + if( m_skip_empty_lines ) + continue; + else + next_line.assign( buffer_insert_pos, buffer_insert_pos ); + } + + line = broken_line ? cstring( line.begin(), next_line.end() ) : next_line; // 70 // + + broken_line = match_back( line, m_line_beak ); + if( broken_line ) { // 80 // + line.trim_right( 1 ); + continue; + } + + if( match_front( line, m_command_delimeter ) ) { // 90 // + process_command_line( line ); + continue; + } + + if( !is_active_line() ) + continue; + + substitute_macros( line ); // 100 // + + return true; // 110 // + } + + BOOST_RT_PARAM_VALIDATE_LOGIC( !broken_line, BOOST_RT_PARAM_LITERAL( "broken line is not completed" ) ); + BOOST_RT_PARAM_VALIDATE_LOGIC( m_conditional_states.size() == 0, + BOOST_RT_PARAM_LITERAL( "matching endif command is missing" ) ); + + return false; +} + +//____________________________________________________________________________// + +boost::optional +config_file_iterator::Impl::get_macro_value( cstring macro_name, bool ignore_missing ) +{ + symbol_table_t::const_iterator it = m_symbols_table.find( macro_name ); + + if( it == m_symbols_table.end() ) { + boost::optional macro_value; // !! variable actually may have different type + + #ifndef UNDER_CE + env::get( macro_name, macro_value ); + #endif + + BOOST_RT_PARAM_VALIDATE_LOGIC( macro_value || ignore_missing || !m_detect_missing_macro, + BOOST_RT_PARAM_LITERAL( "Unknown macro \"" ) << macro_name << BOOST_RT_PARAM_LITERAL( "\"" ) ); + + if( !macro_value ) { + if( !ignore_missing ) + macro_value = cstring(); + } + else + m_symbols_table.add( macro_name, *macro_value ); + + return macro_value; + } + + return boost::optional( cstring( it->second ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_command_line( cstring line ) +{ + line.trim_left( m_command_delimeter.size() ); + + unit_test::string_token_iterator tit( line, unit_test::max_tokens = 2 ); + + command_handler_map::const_iterator it = m_command_handler_map.find( *tit ); + + BOOST_RT_PARAM_VALIDATE_LOGIC( it != m_command_handler_map.end(), BOOST_RT_PARAM_LITERAL( "Invalid command " ) << *tit ); + + ++tit; + + (it->second)( *tit ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_include( cstring line ) +{ + using namespace unit_test; + + if( !is_active_line() ) + return; + + string_token_iterator tit( line, kept_delimeters = dt_none ); + + BOOST_RT_PARAM_VALIDATE_LOGIC( tit != string_token_iterator(), + BOOST_RT_PARAM_LITERAL( "include file name missing" ) ); + + cstring include_file_name = *tit; + + BOOST_RT_PARAM_VALIDATE_LOGIC( ++tit == string_token_iterator(), + BOOST_RT_PARAM_LITERAL( "unexpected tokens at the end of include command" ) ); + + substitute_macros( include_file_name ); + + m_curr_level.reset( new include_level( include_file_name, m_path_separators, m_curr_level.release() ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_define( cstring line ) +{ + using namespace unit_test; + + if( !is_active_line() ) + return; + + string_token_iterator tit( line, (kept_delimeters = dt_none, max_tokens = 2 )); + + cstring macro_name = *tit; + BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); + + cstring macro_value = *(++tit); + substitute_macros( macro_value ); + + m_symbols_table.add( macro_name, macro_value ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_undef( cstring line ) +{ + if( !is_active_line() ) + return; + + cstring macro_name = line; + BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); + + m_symbols_table.remove( macro_name ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_ifdef( cstring line ) +{ + m_conditional_states.push_back( true ); + if( !is_active_line() ) + return; + + cstring macro_name = line; + BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); + + if( !get_macro_value( macro_name ) ) + m_inactive_ifdef_level = m_conditional_states.size(); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_ifndef( cstring line ) +{ + m_conditional_states.push_back( true ); + if( !is_active_line() ) + return; + + cstring macro_name = line; + BOOST_RT_PARAM_VALIDATE_LOGIC( is_valid_identifier( macro_name ), + BOOST_RT_PARAM_LITERAL( "invalid macro name" ) ); + + if( get_macro_value( macro_name ) ) + m_inactive_ifdef_level = m_conditional_states.size(); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_else( cstring line ) +{ + BOOST_RT_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0 && m_conditional_states.back(), + BOOST_RT_PARAM_LITERAL( "else without matching if" ) ); + + m_inactive_ifdef_level = m_conditional_states.size() == m_inactive_ifdef_level ? 0 : m_conditional_states.size(); + + BOOST_RT_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_RT_PARAM_LITERAL( "unexpected tokens at the end of else command" ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::process_endif( cstring line ) +{ + BOOST_RT_PARAM_VALIDATE_LOGIC( m_conditional_states.size() > 0, BOOST_RT_PARAM_LITERAL( "endif without matching if" ) ); + + if( m_conditional_states.size() == m_inactive_ifdef_level ) + m_inactive_ifdef_level = 0; + + m_conditional_states.pop_back(); + BOOST_RT_PARAM_VALIDATE_LOGIC( line.is_empty(), BOOST_RT_PARAM_LITERAL( "unexpected tokens at the end of endif command" ) ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::Impl::substitute_macros( cstring& where ) +{ + m_post_subst_line.clear(); + cstring::size_type pos; + + while( (pos = where.find( m_macro_ref_begin )) != cstring::npos ) { + m_post_subst_line.append( where.begin(), pos ); + + where.trim_left( where.begin() + pos + m_macro_ref_begin.size() ); + + pos = where.find( m_macro_ref_end ); + + BOOST_RT_PARAM_VALIDATE_LOGIC( pos != cstring::npos, BOOST_RT_PARAM_LITERAL( "incomplete macro reference" ) ); + + cstring value = *get_macro_value( where.substr( 0, pos ), false ); + m_post_subst_line.append( value.begin(), value.size() ); + + where.trim_left( where.begin() + pos + m_macro_ref_end.size() ); + } + + if( !m_post_subst_line.empty() ) { + m_post_subst_line.append( where.begin(), where.size() ); + where = m_post_subst_line; + } +} + +//____________________________________________________________________________// + +// ************************************************************************** // +// ************** runtime::file::config_file_iterator ************** // +// ************************************************************************** // + +void +config_file_iterator::construct() +{ + m_pimpl.reset( new Impl ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::load( cstring file_name ) +{ + m_pimpl->m_curr_level.reset( new include_level( file_name, m_pimpl->m_path_separators ) ); + m_pimpl->m_buffer.reset( new char[m_pimpl->m_buffer_size] ); + + register_command_handler( m_pimpl->m_include_kw, bind( &Impl::process_include, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_define_kw, bind( &Impl::process_define, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_undef_kw, bind( &Impl::process_undef, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_ifdef_kw, bind( &Impl::process_ifdef, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_ifndef_kw, bind( &Impl::process_ifndef, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_else_kw, bind( &Impl::process_else, m_pimpl.get(), _1 ) ); + register_command_handler( m_pimpl->m_endif_kw, bind( &Impl::process_endif, m_pimpl.get(), _1 ) ); + + init(); +} + +//____________________________________________________________________________// + +location const& +config_file_iterator::curr_location() +{ + return m_pimpl->m_curr_level->m_curr_location; +} + +//____________________________________________________________________________// + +void +config_file_iterator::register_command_handler( cstring command_kw, command_handler const& ch ) +{ + m_pimpl->m_command_handler_map.add( command_kw, ch ); +} + +//____________________________________________________________________________// + +bool +config_file_iterator::get() +{ + return m_pimpl->get_next_line( m_value ); +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, cstring value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::path_separators_t ) + assign_op( m_pimpl->m_path_separators , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::sl_comment_delimeter_t ) + assign_op( m_pimpl->m_sl_comment_delimeter , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::command_delimeter_t ) + assign_op( m_pimpl->m_command_delimeter , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::line_beak_t ) + assign_op( m_pimpl->m_line_beak , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::macro_ref_begin_t ) + assign_op( m_pimpl->m_macro_ref_begin , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::macro_ref_end_t ) + assign_op( m_pimpl->m_macro_ref_end , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::include_kw_t ) + assign_op( m_pimpl->m_include_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::define_kw_t ) + assign_op( m_pimpl->m_define_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::undef_kw_t ) + assign_op( m_pimpl->m_undef_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::ifdef_kw_t ) + assign_op( m_pimpl->m_ifdef_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::ifndef_kw_t ) + assign_op( m_pimpl->m_ifndef_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::else_kw_t ) + assign_op( m_pimpl->m_else_kw , value, 0 ); + BOOST_RTTI_CASE( cfg_detail::endif_kw_t ) + assign_op( m_pimpl->m_endif_kw , value, 0 ); + } +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, bool value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::trim_leading_spaces_t ) + m_pimpl->m_trim_leading_spaces = value; + BOOST_RTTI_CASE( cfg_detail::trim_trailing_spaces_t ) + m_pimpl->m_trim_trailing_spaces = value; + BOOST_RTTI_CASE( cfg_detail::skip_empty_lines_t ) + m_pimpl->m_skip_empty_lines = value; + BOOST_RTTI_CASE( cfg_detail::detect_missing_macro_t ) + m_pimpl->m_detect_missing_macro = value; + } +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, char_type value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::line_delimeter_t ) + m_pimpl->m_line_delimeter = value; + } +} + +//____________________________________________________________________________// + +void +config_file_iterator::set_parameter( rtti::id_t id, std::size_t value ) +{ + BOOST_RTTI_SWITCH( id ) { + BOOST_RTTI_CASE( cfg_detail::buffer_size_t ) + m_pimpl->m_buffer_size = value; + } +} + +//____________________________________________________________________________// + +} // namespace file + +} // namespace BOOST_RT_PARAM_NAMESPACE + +} // namespace boost + +// EOF diff --git a/src/external/3rd/library/boost/boost/thread/detail/thread_group.hpp b/src/external/3rd/library/boost/boost/thread/detail/thread_group.hpp index 4acdfe586..240f8d27d 100644 --- a/src/external/3rd/library/boost/boost/thread/detail/thread_group.hpp +++ b/src/external/3rd/library/boost/boost/thread/detail/thread_group.hpp @@ -1,154 +1,154 @@ -#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP -#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP -// Distributed under the Boost Software License, Version 1.0. (See -// accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// (C) Copyright 2007-9 Anthony Williams - -#include -#include -#include -#include - -#include - -#ifdef BOOST_MSVC -#pragma warning(push) -#pragma warning(disable:4251) -#endif - -namespace boost -{ - class thread_group - { - private: - thread_group(thread_group const&); - thread_group& operator=(thread_group const&); - public: - thread_group() {} - ~thread_group() - { - for(std::list::iterator it=threads.begin(),end=threads.end(); - it!=end; - ++it) - { - delete *it; - } - } - - bool is_this_thread_in() - { - thread::id id = this_thread::get_id(); - boost::shared_lock guard(m); - for(std::list::iterator it=threads.begin(),end=threads.end(); - it!=end; - ++it) - { - if ((*it)->get_id() == id) - return true; - } - return false; - } - - bool is_thread_in(thread* thrd) - { - if(thrd) - { - thread::id id = thrd->get_id(); - boost::shared_lock guard(m); - for(std::list::iterator it=threads.begin(),end=threads.end(); - it!=end; - ++it) - { - if ((*it)->get_id() == id) - return true; - } - return false; - } - else - { - return false; - } - } - - template - thread* create_thread(F threadfunc) - { - boost::lock_guard guard(m); - std::unique_ptr new_thread(new thread(threadfunc)); - threads.push_back(new_thread.get()); - return new_thread.release(); - } - - void add_thread(thread* thrd) - { - if(thrd) - { - BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) , - thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying to add a duplicated thread") - ); - - boost::lock_guard guard(m); - threads.push_back(thrd); - } - } - - void remove_thread(thread* thrd) - { - boost::lock_guard guard(m); - std::list::iterator const it=std::find(threads.begin(),threads.end(),thrd); - if(it!=threads.end()) - { - threads.erase(it); - } - } - - void join_all() - { - BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() , - thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying joining itself") - ); - boost::shared_lock guard(m); - - for(std::list::iterator it=threads.begin(),end=threads.end(); - it!=end; - ++it) - { - if ((*it)->joinable()) - (*it)->join(); - } - } - -#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS - void interrupt_all() - { - boost::shared_lock guard(m); - - for(std::list::iterator it=threads.begin(),end=threads.end(); - it!=end; - ++it) - { - (*it)->interrupt(); - } - } -#endif - - size_t size() const - { - boost::shared_lock guard(m); - return threads.size(); - } - - private: - std::list threads; - mutable shared_mutex m; - }; -} - -#ifdef BOOST_MSVC -#pragma warning(pop) -#endif - -#include - -#endif +#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP +#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007-9 Anthony Williams + +#include +#include +#include +#include + +#include + +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + +namespace boost +{ + class thread_group + { + private: + thread_group(thread_group const&); + thread_group& operator=(thread_group const&); + public: + thread_group() {} + ~thread_group() + { + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + delete *it; + } + } + + bool is_this_thread_in() + { + thread::id id = this_thread::get_id(); + boost::shared_lock guard(m); + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + + bool is_thread_in(thread* thrd) + { + if(thrd) + { + thread::id id = thrd->get_id(); + boost::shared_lock guard(m); + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + else + { + return false; + } + } + + template + thread* create_thread(F threadfunc) + { + boost::lock_guard guard(m); + std::unique_ptr new_thread(new thread(threadfunc)); + threads.push_back(new_thread.get()); + return new_thread.release(); + } + + void add_thread(thread* thrd) + { + if(thrd) + { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) , + thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying to add a duplicated thread") + ); + + boost::lock_guard guard(m); + threads.push_back(thrd); + } + } + + void remove_thread(thread* thrd) + { + boost::lock_guard guard(m); + std::list::iterator const it=std::find(threads.begin(),threads.end(),thrd); + if(it!=threads.end()) + { + threads.erase(it); + } + } + + void join_all() + { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() , + thread_resource_error(static_cast(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying joining itself") + ); + boost::shared_lock guard(m); + + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->joinable()) + (*it)->join(); + } + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void interrupt_all() + { + boost::shared_lock guard(m); + + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + (*it)->interrupt(); + } + } +#endif + + size_t size() const + { + boost::shared_lock guard(m); + return threads.size(); + } + + private: + std::list threads; + mutable shared_mutex m; + }; +} + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +#include + +#endif diff --git a/src/external/3rd/library/boost/boost/typeof/std/memory.hpp b/src/external/3rd/library/boost/boost/typeof/std/memory.hpp index a4c703dca..04b086d59 100644 --- a/src/external/3rd/library/boost/boost/typeof/std/memory.hpp +++ b/src/external/3rd/library/boost/boost/typeof/std/memory.hpp @@ -1,17 +1,17 @@ -// Copyright (C) 2005 Arkadiy Vertleyb, Peder Holt. -// Use, modification and distribution is subject to the Boost Software -// License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_TYPEOF_STD_memory_hpp_INCLUDED -#define BOOST_TYPEOF_STD_memory_hpp_INCLUDED - -#include -#include - -#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() - -BOOST_TYPEOF_REGISTER_TEMPLATE(std::allocator, 1) -BOOST_TYPEOF_REGISTER_TEMPLATE(std::raw_storage_iterator, 2) -BOOST_TYPEOF_REGISTER_TEMPLATE(std::unique_ptr, 1) - -#endif//BOOST_TYPEOF_STD_memory_hpp_INCLUDED +// Copyright (C) 2005 Arkadiy Vertleyb, Peder Holt. +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_TYPEOF_STD_memory_hpp_INCLUDED +#define BOOST_TYPEOF_STD_memory_hpp_INCLUDED + +#include +#include + +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +BOOST_TYPEOF_REGISTER_TEMPLATE(std::allocator, 1) +BOOST_TYPEOF_REGISTER_TEMPLATE(std::raw_storage_iterator, 2) +BOOST_TYPEOF_REGISTER_TEMPLATE(std::unique_ptr, 1) + +#endif//BOOST_TYPEOF_STD_memory_hpp_INCLUDED diff --git a/src/external/3rd/library/platform/projects/Session/CommonAPI/CommonAPIStrings.h b/src/external/3rd/library/platform/projects/Session/CommonAPI/CommonAPIStrings.h index 2e9380a48..df836c968 100644 --- a/src/external/3rd/library/platform/projects/Session/CommonAPI/CommonAPIStrings.h +++ b/src/external/3rd/library/platform/projects/Session/CommonAPI/CommonAPIStrings.h @@ -1,252 +1,252 @@ -#ifndef COMMON_API_STRINGS_H -#define COMMON_API_STRINGS_H - -#include -#include -#include "CommonAPI.h" - -#define result_text std::pair -#define gamecode_text std::pair -#define text_gamecode std::pair - -static const int _ResultCount = 38; -static const result_text _resultString[_ResultCount] = -{ - result_text(RESULT_SUCCESS, "RESULT_SUCCESS"), - result_text(RESULT_CANCELLED, "RESULT_CANCELLED"), - result_text(RESULT_TIMEOUT, "RESULT_TIMEOUT"), - result_text(RESULT_FUNCTION_DEPRICATED, "RESULT_FUNCTION_DEPRICATED"), - result_text(RESULT_FUNCTION_NOT_SUPPORTED, "RESULT_FUNCTION_NOT_SUPPORTED"), - result_text(RESULT_INVALID_NAME_OR_PASSWORD, "RESULT_INVALID_NAME_OR_PASSWORD"), - result_text(RESULT_INVALID_ACCOUNT_ID, "RESULT_INVALID_USER_ID"), - result_text(RESULT_INVALID_SESSION, "RESULT_INVALID_SESSION"), - result_text(RESULT_INVALID_PARENT_SESSION, "RESULT_INVALID_PARENT_SESSION"), - result_text(RESULT_INVALID_SESSION_TYPE, "RESULT_INVALID_SESSION_TYPE"), - result_text(RESULT_INVALID_GAMECODE, "RESULT_INVALID_GAMECODE"), - result_text(RESULT_REQUIRES_VALID_SUBSCRIPTION, "RESULT_REQUIRES_VALID_SUBSCRIPTION"), - result_text(RESULT_REQUIRES_ACTIVE_ACCOUNT, "RESULT_REQUIRES_ACTIVE_ACCOUNT"), - result_text(RESULT_REQUIRES_CLIENT_LOGOUT, "RESULT_REQUIRES_CLIENT_LOGOUT"), - result_text(RESULT_SESSION_ALREADY_CONSUMED, "RESULT_SESSION_ALREADY_CONSUMED"), - result_text(RESULT_REQUIRES_SECURE_ID_NEXT_CODE, "RESULT_REQUIRES_SECURE_ID_NEXT_CODE"), - result_text(RESULT_REQUIRES_SECURE_ID_NEW_PIN, "RESULT_REQUIRES_SECURE_ID_NEW_PIN"), - result_text(RESULT_SECURE_ID_PIN_ACCEPTED, "RESULT_SECURE_ID_PIN_ACCEPTED"), - result_text(RESULT_SECURE_ID_PIN_REJECTED, "RESULT_SECURE_ID_PIN_REJECTED"), - result_text(RESULT_USAGE_LIMIT_DENIED_LOGIN, "RESULT_USAGE_LIMIT_DENIED_LOGIN"), - result_text(RESULT_INVALID_FEATURE, "RESULT_INVALID_FEATURE"), - result_text(RESULT_INVALID_AVATAR, "RESULT_INVALID_AVATAR"), - result_text(RESULT_INVALID_CHATROOM, "RESULT_INVALID_CHATROOM"), - result_text(RESULT_INVALID_MESSAGE, "RESULT_INVALID_MESSAGE"), - result_text(RESULT_INVALID_FANCLUB, "RESULT_INVALID_FANCLUB"), - result_text(RESULT_INVALID_ROOM_BANNER, "RESULT_INVALID_ROOM_BANNER"), - result_text(RESULT_REQUIRES_FANCLUB_MEMBERSHIP, "RESULT_REQUIRES_FANCLUB_MEMBERSHIP"), - result_text(RESULT_REQUIRES_ONLINE_AVATAR, "RESULT_REQUIRES_ONLINE_AVATAR"), - result_text(RESULT_REQUIRES_MODERATOR_PRIVILEGES, "RESULT_REQUIRES_MODERATOR_PRIVILEGES"), - result_text(RESULT_REQUIRES_VALID_MODERATION_STATE, "RESULT_REQUIRES_VALID_MODERATION_STATE"), - result_text(RESULT_BANNED_FROM_ROOM, "RESULT_BANNED_FROM_ROOM"), - result_text(RESULT_INVALID_NAMESPACE, "RESULT_INVALID_NAMESPACE"), - result_text(RESULT_INVALID_CLIENT_IP, "RESULT_INVALID_CLIENT_IP"), - result_text(RESULT_USER_LOCKOUT, "RESULT_USER_LOCKOUT"), - result_text(RESULT_INVALID_KICK_REASON, "RESULT_INVALID_KICK_REASON"), - result_text(RESULT_INVALID_PLAN_ID, "RESULT_INVALID_PLAN_ID"), - result_text(RESULT_INVALID_FEATURE_MATCH, "RESULT_INVALID_FEATURE_MATCH"), - result_text(RESULT_INVALID_SUBSCRIPTION, "RESULT_INVALID_SUBSCRIPTION"), - -}; -static std::map ResultString((const std::map::value_type *)&_resultString[0],(const std::map::value_type *)&_resultString[_ResultCount]); - -static const result_text _resultText[_ResultCount] = -{ - result_text(RESULT_SUCCESS, "The operation completed successfully."), - result_text(RESULT_CANCELLED, "The operation was cancelled by the requestor."), - result_text(RESULT_TIMEOUT, "The operation could not be processed within a reasonable time. Please try again."), - result_text(RESULT_FUNCTION_DEPRICATED, "This operation is no longer supported."), - result_text(RESULT_FUNCTION_NOT_SUPPORTED, "This operation is not supported yet."), - result_text(RESULT_INVALID_NAME_OR_PASSWORD, "The sepecifed user name or password is invalid."), - result_text(RESULT_INVALID_ACCOUNT_ID, "The sepecifed account identifier is invalid."), - result_text(RESULT_INVALID_SESSION, "The sepecifed session identifier is invalid."), - result_text(RESULT_INVALID_PARENT_SESSION, "The sepecifed parent session identifier is invalid."), - result_text(RESULT_INVALID_SESSION_TYPE, "The sepecifed session type is invalid."), - result_text(RESULT_INVALID_GAMECODE, "The specified gamecode is invalid."), - result_text(RESULT_REQUIRES_VALID_SUBSCRIPTION, "This operation requires a valid subscription to complete."), - result_text(RESULT_REQUIRES_ACTIVE_ACCOUNT, "RESULT_REQUIRES_ACTIVE_ACCOUNT"), - result_text(RESULT_REQUIRES_CLIENT_LOGOUT, "RESULT_REQUIRES_CLIENT_LOGOUT"), - result_text(RESULT_SESSION_ALREADY_CONSUMED, "RESULT_SESSION_ALREADY_CONSUMED"), - result_text(RESULT_REQUIRES_SECURE_ID_NEXT_CODE,"RESULT_REQUIRES_SECURE_ID_NEXT_CODE"), - result_text(RESULT_REQUIRES_SECURE_ID_NEW_PIN, "RESULT_REQUIRES_SECURE_ID_NEW_PIN"), - result_text(RESULT_SECURE_ID_PIN_ACCEPTED, "RESULT_SECURE_ID_PIN_ACCEPTED"), - result_text(RESULT_SECURE_ID_PIN_REJECTED, "RESULT_SECURE_ID_PIN_REJECTED"), - result_text(RESULT_USAGE_LIMIT_DENIED_LOGIN, "RESULT_USAGE_LIMIT_DENIED_LOGIN"), - result_text(RESULT_INVALID_FEATURE, "RESULT_INVALID_FEATURE"), - result_text(RESULT_INVALID_AVATAR, "The specified chat avatar name is invalid."), - result_text(RESULT_INVALID_CHATROOM, "The specified chat room name is invalid."), - result_text(RESULT_INVALID_MESSAGE, "The specified chat message is invalid."), - result_text(RESULT_INVALID_FANCLUB, "The specified fan club is invalid."), - result_text(RESULT_INVALID_ROOM_BANNER, "RESULT_INVALID_ROOM_BANNER"), - result_text(RESULT_REQUIRES_FANCLUB_MEMBERSHIP, "This operation requires membership inb the specified fan club."), - result_text(RESULT_REQUIRES_ONLINE_AVATAR, "RESULT_REQUIRES_ONLINE_AVATAR"), - result_text(RESULT_REQUIRES_MODERATOR_PRIVILEGES, "RESULT_REQUIRES_MODERATOR_PRIVILEGES"), - result_text(RESULT_REQUIRES_VALID_MODERATION_STATE, "RESULT_REQUIRES_VALID_MODERATION_STATE"), - result_text(RESULT_BANNED_FROM_ROOM, "RESULT_BANNED_FROM_ROOM"), - result_text(RESULT_INVALID_NAMESPACE, "RESULT_INVALID_NAMESPACE"), - result_text(RESULT_INVALID_PLAN_ID, "RESULT_INVALID_PLAN_ID"), - result_text(RESULT_INVALID_FEATURE_MATCH, "RESULT_INVALID_FEATURE_MATCH"), - result_text(RESULT_INVALID_SUBSCRIPTION, "RESULT_INVALID_SUBSCRIPTION"), -}; -static std::map ResultText((const std::map::value_type *)&_resultText[0],(const std::map::value_type *)&_resultText[_ResultCount]); - -static const char * AccountStatusString[ACCOUNT_STATUS_END] = -{ - "ACCOUNT_STATUS_NULL", - "ACCOUNT_STATUS_ACTIVE", - "ACCOUNT_STATUS_CLOSED" -}; - -static const char * SessionTypeString[SESSION_TYPE_END] = -{ - "SESSION_TYPE_NULL", - "SESSION_TYPE_LAUNCH_PAD", - "SESSION_TYPE_STATION_UNSECURE", - "SESSION_TYPE_STATION_SECURE", - "SESSION_TYPE_TANARUS", - "SESSION_TYPE_INFANTRY", - "SESSION_TYPE_COSMIC_RIFT", - "SESSION_TYPE_EVERQUEST", - "SESSION_TYPE_EVERQUEST_2", - "SESSION_TYPE_STARWARS", - "SESSION_TYPE_PLANETSIDE", - "SESSION_TYPE_EVERQUEST_ONLINE_ADVENTURES_BETA", - "SESSION_TYPE_EVERQUEST_ONLINE_ADVENTURES", - "SESSION_TYPE_EVERQUEST_INSTANT_MESSENGER", - "SESSION_TYPE_REALM_SERVER", - "SESSION_TYPE_EVERQUEST_MACINTOSH", - "SESSION_TYPE_MATRIX_ONLINE", - "SESSION_TYPE_HARRY_POTTER", - "SESSION_TYPE_NEO_PETS", - "SESSION_TYPE_GOODLIFE", - "SESSION_TYPE_EQ2_GUILDS", - "SESSION_TYPE_SWG_JP_BETA", - "SESSION_TYPE_MARVEL", - "SESSION_TYPE_EQ2_JAPAN", - "SESSION_TYPE_EQ2_TAIWAN", - "SESSION_TYPE_EQ2_CHINA", - "SESSION_TYPE_EQ2_KOREA", - "SESSION_TYPE_VGD", - "SESSION_TYPE_PIRATE", - "SESSION_TYPE_STAR_CHAMBER", - "SESSION_TYPE_STARGATE", - "SESSION_TYPE_DCU_ONLINE", - "SESSION_TYPE_NORRATH_CSG", -}; - -static const char * GamecodeString[GAMECODE_END] = -{ - "GAMECODE_NULL", - "GAMECODE_STATION_PASS", - "GAMECODE_EVERQUEST", - "GAMECODE_EVERQUEST_2", - "GAMECODE_STARWARS", - "GAMECODE_PLANETSIDE", - "GAMECODE_EVERQUEST_ONLINE_ADVENTURES_BETA", - "GAMECODE_EVERQUEST_ONLINE_ADVENTURES", - "GAMECODE_EVERQUEST_INSTANT_MESSENGER", - "GAMECODE_EVERQUEST_MACINTOSH", - "GAMECODE_MATRIX_ONLINE", - "GAMECODE_HARRY_POTTER", - "GAMECODE_NEO_PETS", - "GAMECODE_GOODLIFE", - "GAMECODE_SWG_JP_BETA", - "GAMECODE_MARVEL", - "GAMECODE_EQ2_JAPAN", - "GAMECODE_EQ2_TAIWAN", - "GAMECODE_EQ2_CHINA", - "GAMECODE_EQ2_KOREA", - "GAMECODE_VGD", - "GAMECODE_PIRATE", - "GAMECODE_STAR_CHAMBER", - "GAMECODE_STARGATE", - "GAMECODE_DCU_ONLINE", - "GAMECODE_NORRATH_CSG" -}; - -static const char * SubscriptionStatusString[SUBSCRIPTION_STATUS_END] = -{ - "SUBSCRIPTION_STATUS_NULL", - "SUBSCRIPTION_STATUS_NO_ACCOUNT", - "SUBSCRIPTION_STATUS_ACTIVE", - "SUBSCRIPTION_STATUS_PENDING", - "SUBSCRIPTION_STATUS_CANCEL", - "SUBSCRIPTION_STATUS_TRIAL_ACTIVE", - "SUBSCRIPTION_STATUS_TRIAL_EXPIRED", - "SUBSCRIPTION_STATUS_SUSPENDED", - "SUBSCRIPTION_STATUS_BANNED", - "SUBSCRIPTION_STATUS_RENTAL_ACTIVE", - "SUBSCRIPTION_STATUS_RENTAL_CLOSED" - "SUBSCRIPTION_STATUS_ACTIVE_COMBO", - "SUBSCRIPTION_STATUS_BANNED_CHARGEBACK", -}; - -#ifdef UNIX -const std::pair _gamecodeID[GAMECODE_END] = -{ - text_gamecode(std::string("SP"), GAMECODE_STATION_PASS), - text_gamecode(std::string("EQ"), GAMECODE_EVERQUEST), - text_gamecode(std::string("EQ2"), GAMECODE_EVERQUEST_2), - text_gamecode(std::string("SWG"), GAMECODE_STARWARS), - text_gamecode(std::string("PS"), GAMECODE_PLANETSIDE), - text_gamecode(std::string("EQOA-beta"), GAMECODE_EVERQUEST_ONLINE_ADVENTURES_BETA), - text_gamecode(std::string("EQOA"), GAMECODE_EVERQUEST_ONLINE_ADVENTURES), - text_gamecode(std::string("EQIM"), GAMECODE_EVERQUEST_INSTANT_MESSENGER), - text_gamecode(std::string("EQM"), GAMECODE_EVERQUEST_MACINTOSH), - text_gamecode(std::string("MXO"), GAMECODE_MATRIX_ONLINE), - text_gamecode(std::string("HPO"), GAMECODE_HARRY_POTTER), - text_gamecode(std::string("NP"), GAMECODE_NEO_PETS), - text_gamecode(std::string("GL"), GAMECODE_GOODLIFE), - text_gamecode(std::string("SWG-JP"), GAMECODE_SWG_JP_BETA), - text_gamecode(std::string("MRVL"), GAMECODE_MARVEL), - text_gamecode(std::string("EQ2-JP"), GAMECODE_EQ2_JAPAN), - text_gamecode(std::string("EQ2-TW"), GAMECODE_EQ2_TAIWAN), - text_gamecode(std::string("EQ2-CN"), GAMECODE_EQ2_CHINA), - text_gamecode(std::string("EQ2-KR"), GAMECODE_EQ2_KOREA), - text_gamecode(std::string("VGD"), GAMECODE_VGD), - text_gamecode(std::string("POCSG"), GAMECODE_PIRATE), - text_gamecode(std::string("StarChamber"), GAMECODE_STAR_CHAMBER), - text_gamecode(std::string("Stargate"), GAMECODE_STARGATE), - text_gamecode(std::string("DCO"), GAMECODE_DCU_ONLINE), - text_gamecode(std::string("NCSG"), GAMECODE_NORRATH_CSG) -}; -static std::map GamecodeID((const std::map::value_type *)&_gamecodeID[0],(const std::map::value_type *)&_gamecodeID[GAMECODE_END]); - -const gamecode_text _gamecodeName[GAMECODE_END] = -{ - gamecode_text(GAMECODE_NULL, ""), - gamecode_text(GAMECODE_STATION_PASS, "SP"), - gamecode_text(GAMECODE_EVERQUEST, "EQ"), - gamecode_text(GAMECODE_EVERQUEST_2, "EQ2"), - gamecode_text(GAMECODE_STARWARS, "SWG"), - gamecode_text(GAMECODE_PLANETSIDE, "PS"), - gamecode_text(GAMECODE_EVERQUEST_ONLINE_ADVENTURES_BETA, "EQOA-beta"), - gamecode_text(GAMECODE_EVERQUEST_ONLINE_ADVENTURES, "EQOA"), - gamecode_text(GAMECODE_EVERQUEST_INSTANT_MESSENGER, "EQIM"), - gamecode_text(GAMECODE_EVERQUEST_MACINTOSH, "EQM"), - gamecode_text(GAMECODE_MATRIX_ONLINE, "MXO"), - gamecode_text(GAMECODE_HARRY_POTTER, "HPO"), - gamecode_text(GAMECODE_NEO_PETS, "NP"), - gamecode_text(GAMECODE_GOODLIFE, "GL"), - gamecode_text(GAMECODE_SWG_JP_BETA, "SWG-JP"), - gamecode_text(GAMECODE_MARVEL, "MRVL"), - gamecode_text(GAMECODE_EQ2_JAPAN, "EQ2-JP"), - gamecode_text(GAMECODE_EQ2_TAIWAN, "EQ2-TW"), - gamecode_text(GAMECODE_EQ2_CHINA, "EQ2-CN"), - gamecode_text(GAMECODE_EQ2_KOREA, "EQ2-KR"), - gamecode_text(GAMECODE_VGD, "VGD"), - gamecode_text(GAMECODE_PIRATE, "POCSG"), - gamecode_text(GAMECODE_STAR_CHAMBER, "StarChamber"), - gamecode_text(GAMECODE_STARGATE, "Stargate"), - gamecode_text(GAMECODE_DCU_ONLINE, "DCO"), - gamecode_text(GAMECODE_NORRATH_CSG, "NCSG") -}; -static std::map GamecodeName((const std::map::value_type *)&_gamecodeName[0],(const std::map::value_type *)&_gamecodeName[GAMECODE_END]); - -#endif UNIX -#endif - +#ifndef COMMON_API_STRINGS_H +#define COMMON_API_STRINGS_H + +#include +#include +#include "CommonAPI.h" + +#define result_text std::pair +#define gamecode_text std::pair +#define text_gamecode std::pair + +static const int _ResultCount = 38; +static const result_text _resultString[_ResultCount] = +{ + result_text(RESULT_SUCCESS, "RESULT_SUCCESS"), + result_text(RESULT_CANCELLED, "RESULT_CANCELLED"), + result_text(RESULT_TIMEOUT, "RESULT_TIMEOUT"), + result_text(RESULT_FUNCTION_DEPRICATED, "RESULT_FUNCTION_DEPRICATED"), + result_text(RESULT_FUNCTION_NOT_SUPPORTED, "RESULT_FUNCTION_NOT_SUPPORTED"), + result_text(RESULT_INVALID_NAME_OR_PASSWORD, "RESULT_INVALID_NAME_OR_PASSWORD"), + result_text(RESULT_INVALID_ACCOUNT_ID, "RESULT_INVALID_USER_ID"), + result_text(RESULT_INVALID_SESSION, "RESULT_INVALID_SESSION"), + result_text(RESULT_INVALID_PARENT_SESSION, "RESULT_INVALID_PARENT_SESSION"), + result_text(RESULT_INVALID_SESSION_TYPE, "RESULT_INVALID_SESSION_TYPE"), + result_text(RESULT_INVALID_GAMECODE, "RESULT_INVALID_GAMECODE"), + result_text(RESULT_REQUIRES_VALID_SUBSCRIPTION, "RESULT_REQUIRES_VALID_SUBSCRIPTION"), + result_text(RESULT_REQUIRES_ACTIVE_ACCOUNT, "RESULT_REQUIRES_ACTIVE_ACCOUNT"), + result_text(RESULT_REQUIRES_CLIENT_LOGOUT, "RESULT_REQUIRES_CLIENT_LOGOUT"), + result_text(RESULT_SESSION_ALREADY_CONSUMED, "RESULT_SESSION_ALREADY_CONSUMED"), + result_text(RESULT_REQUIRES_SECURE_ID_NEXT_CODE, "RESULT_REQUIRES_SECURE_ID_NEXT_CODE"), + result_text(RESULT_REQUIRES_SECURE_ID_NEW_PIN, "RESULT_REQUIRES_SECURE_ID_NEW_PIN"), + result_text(RESULT_SECURE_ID_PIN_ACCEPTED, "RESULT_SECURE_ID_PIN_ACCEPTED"), + result_text(RESULT_SECURE_ID_PIN_REJECTED, "RESULT_SECURE_ID_PIN_REJECTED"), + result_text(RESULT_USAGE_LIMIT_DENIED_LOGIN, "RESULT_USAGE_LIMIT_DENIED_LOGIN"), + result_text(RESULT_INVALID_FEATURE, "RESULT_INVALID_FEATURE"), + result_text(RESULT_INVALID_AVATAR, "RESULT_INVALID_AVATAR"), + result_text(RESULT_INVALID_CHATROOM, "RESULT_INVALID_CHATROOM"), + result_text(RESULT_INVALID_MESSAGE, "RESULT_INVALID_MESSAGE"), + result_text(RESULT_INVALID_FANCLUB, "RESULT_INVALID_FANCLUB"), + result_text(RESULT_INVALID_ROOM_BANNER, "RESULT_INVALID_ROOM_BANNER"), + result_text(RESULT_REQUIRES_FANCLUB_MEMBERSHIP, "RESULT_REQUIRES_FANCLUB_MEMBERSHIP"), + result_text(RESULT_REQUIRES_ONLINE_AVATAR, "RESULT_REQUIRES_ONLINE_AVATAR"), + result_text(RESULT_REQUIRES_MODERATOR_PRIVILEGES, "RESULT_REQUIRES_MODERATOR_PRIVILEGES"), + result_text(RESULT_REQUIRES_VALID_MODERATION_STATE, "RESULT_REQUIRES_VALID_MODERATION_STATE"), + result_text(RESULT_BANNED_FROM_ROOM, "RESULT_BANNED_FROM_ROOM"), + result_text(RESULT_INVALID_NAMESPACE, "RESULT_INVALID_NAMESPACE"), + result_text(RESULT_INVALID_CLIENT_IP, "RESULT_INVALID_CLIENT_IP"), + result_text(RESULT_USER_LOCKOUT, "RESULT_USER_LOCKOUT"), + result_text(RESULT_INVALID_KICK_REASON, "RESULT_INVALID_KICK_REASON"), + result_text(RESULT_INVALID_PLAN_ID, "RESULT_INVALID_PLAN_ID"), + result_text(RESULT_INVALID_FEATURE_MATCH, "RESULT_INVALID_FEATURE_MATCH"), + result_text(RESULT_INVALID_SUBSCRIPTION, "RESULT_INVALID_SUBSCRIPTION"), + +}; +static std::map ResultString((const std::map::value_type *)&_resultString[0],(const std::map::value_type *)&_resultString[_ResultCount]); + +static const result_text _resultText[_ResultCount] = +{ + result_text(RESULT_SUCCESS, "The operation completed successfully."), + result_text(RESULT_CANCELLED, "The operation was cancelled by the requestor."), + result_text(RESULT_TIMEOUT, "The operation could not be processed within a reasonable time. Please try again."), + result_text(RESULT_FUNCTION_DEPRICATED, "This operation is no longer supported."), + result_text(RESULT_FUNCTION_NOT_SUPPORTED, "This operation is not supported yet."), + result_text(RESULT_INVALID_NAME_OR_PASSWORD, "The sepecifed user name or password is invalid."), + result_text(RESULT_INVALID_ACCOUNT_ID, "The sepecifed account identifier is invalid."), + result_text(RESULT_INVALID_SESSION, "The sepecifed session identifier is invalid."), + result_text(RESULT_INVALID_PARENT_SESSION, "The sepecifed parent session identifier is invalid."), + result_text(RESULT_INVALID_SESSION_TYPE, "The sepecifed session type is invalid."), + result_text(RESULT_INVALID_GAMECODE, "The specified gamecode is invalid."), + result_text(RESULT_REQUIRES_VALID_SUBSCRIPTION, "This operation requires a valid subscription to complete."), + result_text(RESULT_REQUIRES_ACTIVE_ACCOUNT, "RESULT_REQUIRES_ACTIVE_ACCOUNT"), + result_text(RESULT_REQUIRES_CLIENT_LOGOUT, "RESULT_REQUIRES_CLIENT_LOGOUT"), + result_text(RESULT_SESSION_ALREADY_CONSUMED, "RESULT_SESSION_ALREADY_CONSUMED"), + result_text(RESULT_REQUIRES_SECURE_ID_NEXT_CODE,"RESULT_REQUIRES_SECURE_ID_NEXT_CODE"), + result_text(RESULT_REQUIRES_SECURE_ID_NEW_PIN, "RESULT_REQUIRES_SECURE_ID_NEW_PIN"), + result_text(RESULT_SECURE_ID_PIN_ACCEPTED, "RESULT_SECURE_ID_PIN_ACCEPTED"), + result_text(RESULT_SECURE_ID_PIN_REJECTED, "RESULT_SECURE_ID_PIN_REJECTED"), + result_text(RESULT_USAGE_LIMIT_DENIED_LOGIN, "RESULT_USAGE_LIMIT_DENIED_LOGIN"), + result_text(RESULT_INVALID_FEATURE, "RESULT_INVALID_FEATURE"), + result_text(RESULT_INVALID_AVATAR, "The specified chat avatar name is invalid."), + result_text(RESULT_INVALID_CHATROOM, "The specified chat room name is invalid."), + result_text(RESULT_INVALID_MESSAGE, "The specified chat message is invalid."), + result_text(RESULT_INVALID_FANCLUB, "The specified fan club is invalid."), + result_text(RESULT_INVALID_ROOM_BANNER, "RESULT_INVALID_ROOM_BANNER"), + result_text(RESULT_REQUIRES_FANCLUB_MEMBERSHIP, "This operation requires membership inb the specified fan club."), + result_text(RESULT_REQUIRES_ONLINE_AVATAR, "RESULT_REQUIRES_ONLINE_AVATAR"), + result_text(RESULT_REQUIRES_MODERATOR_PRIVILEGES, "RESULT_REQUIRES_MODERATOR_PRIVILEGES"), + result_text(RESULT_REQUIRES_VALID_MODERATION_STATE, "RESULT_REQUIRES_VALID_MODERATION_STATE"), + result_text(RESULT_BANNED_FROM_ROOM, "RESULT_BANNED_FROM_ROOM"), + result_text(RESULT_INVALID_NAMESPACE, "RESULT_INVALID_NAMESPACE"), + result_text(RESULT_INVALID_PLAN_ID, "RESULT_INVALID_PLAN_ID"), + result_text(RESULT_INVALID_FEATURE_MATCH, "RESULT_INVALID_FEATURE_MATCH"), + result_text(RESULT_INVALID_SUBSCRIPTION, "RESULT_INVALID_SUBSCRIPTION"), +}; +static std::map ResultText((const std::map::value_type *)&_resultText[0],(const std::map::value_type *)&_resultText[_ResultCount]); + +static const char * AccountStatusString[ACCOUNT_STATUS_END] = +{ + "ACCOUNT_STATUS_NULL", + "ACCOUNT_STATUS_ACTIVE", + "ACCOUNT_STATUS_CLOSED" +}; + +static const char * SessionTypeString[SESSION_TYPE_END] = +{ + "SESSION_TYPE_NULL", + "SESSION_TYPE_LAUNCH_PAD", + "SESSION_TYPE_STATION_UNSECURE", + "SESSION_TYPE_STATION_SECURE", + "SESSION_TYPE_TANARUS", + "SESSION_TYPE_INFANTRY", + "SESSION_TYPE_COSMIC_RIFT", + "SESSION_TYPE_EVERQUEST", + "SESSION_TYPE_EVERQUEST_2", + "SESSION_TYPE_STARWARS", + "SESSION_TYPE_PLANETSIDE", + "SESSION_TYPE_EVERQUEST_ONLINE_ADVENTURES_BETA", + "SESSION_TYPE_EVERQUEST_ONLINE_ADVENTURES", + "SESSION_TYPE_EVERQUEST_INSTANT_MESSENGER", + "SESSION_TYPE_REALM_SERVER", + "SESSION_TYPE_EVERQUEST_MACINTOSH", + "SESSION_TYPE_MATRIX_ONLINE", + "SESSION_TYPE_HARRY_POTTER", + "SESSION_TYPE_NEO_PETS", + "SESSION_TYPE_GOODLIFE", + "SESSION_TYPE_EQ2_GUILDS", + "SESSION_TYPE_SWG_JP_BETA", + "SESSION_TYPE_MARVEL", + "SESSION_TYPE_EQ2_JAPAN", + "SESSION_TYPE_EQ2_TAIWAN", + "SESSION_TYPE_EQ2_CHINA", + "SESSION_TYPE_EQ2_KOREA", + "SESSION_TYPE_VGD", + "SESSION_TYPE_PIRATE", + "SESSION_TYPE_STAR_CHAMBER", + "SESSION_TYPE_STARGATE", + "SESSION_TYPE_DCU_ONLINE", + "SESSION_TYPE_NORRATH_CSG", +}; + +static const char * GamecodeString[GAMECODE_END] = +{ + "GAMECODE_NULL", + "GAMECODE_STATION_PASS", + "GAMECODE_EVERQUEST", + "GAMECODE_EVERQUEST_2", + "GAMECODE_STARWARS", + "GAMECODE_PLANETSIDE", + "GAMECODE_EVERQUEST_ONLINE_ADVENTURES_BETA", + "GAMECODE_EVERQUEST_ONLINE_ADVENTURES", + "GAMECODE_EVERQUEST_INSTANT_MESSENGER", + "GAMECODE_EVERQUEST_MACINTOSH", + "GAMECODE_MATRIX_ONLINE", + "GAMECODE_HARRY_POTTER", + "GAMECODE_NEO_PETS", + "GAMECODE_GOODLIFE", + "GAMECODE_SWG_JP_BETA", + "GAMECODE_MARVEL", + "GAMECODE_EQ2_JAPAN", + "GAMECODE_EQ2_TAIWAN", + "GAMECODE_EQ2_CHINA", + "GAMECODE_EQ2_KOREA", + "GAMECODE_VGD", + "GAMECODE_PIRATE", + "GAMECODE_STAR_CHAMBER", + "GAMECODE_STARGATE", + "GAMECODE_DCU_ONLINE", + "GAMECODE_NORRATH_CSG" +}; + +static const char * SubscriptionStatusString[SUBSCRIPTION_STATUS_END] = +{ + "SUBSCRIPTION_STATUS_NULL", + "SUBSCRIPTION_STATUS_NO_ACCOUNT", + "SUBSCRIPTION_STATUS_ACTIVE", + "SUBSCRIPTION_STATUS_PENDING", + "SUBSCRIPTION_STATUS_CANCEL", + "SUBSCRIPTION_STATUS_TRIAL_ACTIVE", + "SUBSCRIPTION_STATUS_TRIAL_EXPIRED", + "SUBSCRIPTION_STATUS_SUSPENDED", + "SUBSCRIPTION_STATUS_BANNED", + "SUBSCRIPTION_STATUS_RENTAL_ACTIVE", + "SUBSCRIPTION_STATUS_RENTAL_CLOSED" + "SUBSCRIPTION_STATUS_ACTIVE_COMBO", + "SUBSCRIPTION_STATUS_BANNED_CHARGEBACK", +}; + +#ifdef UNIX +const std::pair _gamecodeID[GAMECODE_END] = +{ + text_gamecode(std::string("SP"), GAMECODE_STATION_PASS), + text_gamecode(std::string("EQ"), GAMECODE_EVERQUEST), + text_gamecode(std::string("EQ2"), GAMECODE_EVERQUEST_2), + text_gamecode(std::string("SWG"), GAMECODE_STARWARS), + text_gamecode(std::string("PS"), GAMECODE_PLANETSIDE), + text_gamecode(std::string("EQOA-beta"), GAMECODE_EVERQUEST_ONLINE_ADVENTURES_BETA), + text_gamecode(std::string("EQOA"), GAMECODE_EVERQUEST_ONLINE_ADVENTURES), + text_gamecode(std::string("EQIM"), GAMECODE_EVERQUEST_INSTANT_MESSENGER), + text_gamecode(std::string("EQM"), GAMECODE_EVERQUEST_MACINTOSH), + text_gamecode(std::string("MXO"), GAMECODE_MATRIX_ONLINE), + text_gamecode(std::string("HPO"), GAMECODE_HARRY_POTTER), + text_gamecode(std::string("NP"), GAMECODE_NEO_PETS), + text_gamecode(std::string("GL"), GAMECODE_GOODLIFE), + text_gamecode(std::string("SWG-JP"), GAMECODE_SWG_JP_BETA), + text_gamecode(std::string("MRVL"), GAMECODE_MARVEL), + text_gamecode(std::string("EQ2-JP"), GAMECODE_EQ2_JAPAN), + text_gamecode(std::string("EQ2-TW"), GAMECODE_EQ2_TAIWAN), + text_gamecode(std::string("EQ2-CN"), GAMECODE_EQ2_CHINA), + text_gamecode(std::string("EQ2-KR"), GAMECODE_EQ2_KOREA), + text_gamecode(std::string("VGD"), GAMECODE_VGD), + text_gamecode(std::string("POCSG"), GAMECODE_PIRATE), + text_gamecode(std::string("StarChamber"), GAMECODE_STAR_CHAMBER), + text_gamecode(std::string("Stargate"), GAMECODE_STARGATE), + text_gamecode(std::string("DCO"), GAMECODE_DCU_ONLINE), + text_gamecode(std::string("NCSG"), GAMECODE_NORRATH_CSG) +}; +static std::map GamecodeID((const std::map::value_type *)&_gamecodeID[0],(const std::map::value_type *)&_gamecodeID[GAMECODE_END]); + +const gamecode_text _gamecodeName[GAMECODE_END] = +{ + gamecode_text(GAMECODE_NULL, ""), + gamecode_text(GAMECODE_STATION_PASS, "SP"), + gamecode_text(GAMECODE_EVERQUEST, "EQ"), + gamecode_text(GAMECODE_EVERQUEST_2, "EQ2"), + gamecode_text(GAMECODE_STARWARS, "SWG"), + gamecode_text(GAMECODE_PLANETSIDE, "PS"), + gamecode_text(GAMECODE_EVERQUEST_ONLINE_ADVENTURES_BETA, "EQOA-beta"), + gamecode_text(GAMECODE_EVERQUEST_ONLINE_ADVENTURES, "EQOA"), + gamecode_text(GAMECODE_EVERQUEST_INSTANT_MESSENGER, "EQIM"), + gamecode_text(GAMECODE_EVERQUEST_MACINTOSH, "EQM"), + gamecode_text(GAMECODE_MATRIX_ONLINE, "MXO"), + gamecode_text(GAMECODE_HARRY_POTTER, "HPO"), + gamecode_text(GAMECODE_NEO_PETS, "NP"), + gamecode_text(GAMECODE_GOODLIFE, "GL"), + gamecode_text(GAMECODE_SWG_JP_BETA, "SWG-JP"), + gamecode_text(GAMECODE_MARVEL, "MRVL"), + gamecode_text(GAMECODE_EQ2_JAPAN, "EQ2-JP"), + gamecode_text(GAMECODE_EQ2_TAIWAN, "EQ2-TW"), + gamecode_text(GAMECODE_EQ2_CHINA, "EQ2-CN"), + gamecode_text(GAMECODE_EQ2_KOREA, "EQ2-KR"), + gamecode_text(GAMECODE_VGD, "VGD"), + gamecode_text(GAMECODE_PIRATE, "POCSG"), + gamecode_text(GAMECODE_STAR_CHAMBER, "StarChamber"), + gamecode_text(GAMECODE_STARGATE, "Stargate"), + gamecode_text(GAMECODE_DCU_ONLINE, "DCO"), + gamecode_text(GAMECODE_NORRATH_CSG, "NCSG") +}; +static std::map GamecodeName((const std::map::value_type *)&_gamecodeName[0],(const std::map::value_type *)&_gamecodeName[GAMECODE_END]); + +#endif +#endif + diff --git a/src/external/3rd/library/platform/utils/Base/Config.cpp b/src/external/3rd/library/platform/utils/Base/Config.cpp index 91b1d052a..6dbe93b93 100644 --- a/src/external/3rd/library/platform/utils/Base/Config.cpp +++ b/src/external/3rd/library/platform/utils/Base/Config.cpp @@ -1,180 +1,180 @@ -#include "Config.h" - -//#include -//#include -//#include -#include - -#include "Platform.h" - -#ifdef EXTERNAL_DISTRO -namespace NAMESPACE -{ - -#endif -namespace Base -{ - -//----------------------------------- -/// Read the config file into memory -/// Returns true for success -bool CConfig::LoadFile(char * file) -//----------------------------------- -{ - char ch; - FILE * fp; - - UnloadFile(); - - // open file - fp = fopen(file, "r"); - if (fp == NULL || fp == (FILE *)-1) - { - //fprintf(stderr,"Failed to open config file %s!",file); - delete fp; - return false; - } - - // get length of file - fseek(fp,0,SEEK_END); - long length = ftell(fp); - rewind(fp); - - // allocate buffer - pConfig = new char[length + 1]; - - if (pConfig == NULL) - { - fclose(fp); - fprintf(stderr,"Failed to alloc config buffer length %d",(int32)length); - return false; - } - memset(pConfig,0,length); - - // read data, stripping comments - int i = 0; - while (i < length) - { - ch = fgetc(fp); - if (feof(fp)) - break; - if (ch == '#') - { - while (ch != 10 && !feof (fp)) - { - ch = fgetc(fp); - } - } - pConfig[i++] = ch; - } - pConfig[i] = 0; // mark end of file buffer - - fclose(fp); - return true; -} - -//----------------------------------- -/// remove the config file from memory -void CConfig::UnloadFile(void) -//----------------------------------- -{ - if (pConfig) - delete[] pConfig; - pConfig = NULL; -} - -//----------------------------------- -/// finds a key of the config in memory -// key argument is case-insensitive, but must be upper case in config file -// Returns true for success (passing NULL is a special case returned as success) -bool CConfig::FindKey(char *key) -//----------------------------------- -{ - if (pConfig == NULL) - return false; - - // special case...continue with existing key - if (key == NULL) - return true; - - // form the search key - strcpy(strBuffer, "["); - strcat(strBuffer, key); - strcat(strBuffer,"]"); - _strupr(strBuffer); // keywords must be upper case - - // find the key heading - pCursor = strstr(pConfig,strBuffer); - if (pCursor==NULL) - return false; - - // find the closing bracket of key heading - pCursor = strchr(pCursor,']'); - if (pCursor==NULL) - return false; - pCursor++; - - return true; -} - -//----------------------------------- -/// extract a number from the config string -// pass the key to find the first number in the list, else NULL to find the next number in the list -// returns 0 if no number is found, else returns the number -long CConfig::GetLong(char *key) -//----------------------------------- -{ - if (!FindKey(key)) - return 0; - - - // look for start of number or end of key - while (*pCursor && !isdigit(*pCursor) && *pCursor != '[') - pCursor++; - - int c = 0; - while (*pCursor && isdigit(*pCursor) && c < (int)sizeof(strBuffer)) - strBuffer[c++] = *(pCursor++); - strBuffer[c] = '\0'; - - return atol(strBuffer); -} - -//----------------------------------- -/// extract string (in double-quotes) from the list. -// pass the key to find the first string in the list, else NULL to find the next string in the list -// returns NULL if no string found, else returns a temporary copy of the string (without quotes) -char * CConfig::GetString(char *key) -//----------------------------------- -{ - if (!FindKey(key)) - return NULL; - - - // look for start of string or end of key - while (*pCursor && *pCursor != '"' && *pCursor != '[') - pCursor++; - if (*(pCursor++) != '"') - return NULL; - - // until closing quote - int c = 0; - while (*pCursor && c < (int)sizeof(strBuffer)) - { - strBuffer[c++] = *pCursor; // extract string - if (*pCursor++ == '"') - { - strBuffer[--c] = '\0'; - return strBuffer; - } - } - - return NULL; -} - - -}; -#ifdef EXTERNAL_DISTRO -}; -#endif - +#include "Config.h" + +//#include +//#include +//#include +#include + +#include "Platform.h" + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + +//----------------------------------- +/// Read the config file into memory +/// Returns true for success +bool CConfig::LoadFile(char * file) +//----------------------------------- +{ + char ch; + FILE * fp; + + UnloadFile(); + + // open file + fp = fopen(file, "r"); + if (fp == NULL || fp == (FILE *)-1) + { + //fprintf(stderr,"Failed to open config file %s!",file); + delete fp; + return false; + } + + // get length of file + fseek(fp,0,SEEK_END); + long length = ftell(fp); + rewind(fp); + + // allocate buffer + pConfig = new char[length + 1]; + + if (pConfig == NULL) + { + fclose(fp); + fprintf(stderr,"Failed to alloc config buffer length %d",(int32)length); + return false; + } + memset(pConfig,0,length); + + // read data, stripping comments + int i = 0; + while (i < length) + { + ch = fgetc(fp); + if (feof(fp)) + break; + if (ch == '#') + { + while (ch != 10 && !feof (fp)) + { + ch = fgetc(fp); + } + } + pConfig[i++] = ch; + } + pConfig[i] = 0; // mark end of file buffer + + fclose(fp); + return true; +} + +//----------------------------------- +/// remove the config file from memory +void CConfig::UnloadFile(void) +//----------------------------------- +{ + if (pConfig) + delete[] pConfig; + pConfig = NULL; +} + +//----------------------------------- +/// finds a key of the config in memory +// key argument is case-insensitive, but must be upper case in config file +// Returns true for success (passing NULL is a special case returned as success) +bool CConfig::FindKey(char *key) +//----------------------------------- +{ + if (pConfig == NULL) + return false; + + // special case...continue with existing key + if (key == NULL) + return true; + + // form the search key + strcpy(strBuffer, "["); + strcat(strBuffer, key); + strcat(strBuffer,"]"); + _strupr(strBuffer); // keywords must be upper case + + // find the key heading + pCursor = strstr(pConfig,strBuffer); + if (pCursor==NULL) + return false; + + // find the closing bracket of key heading + pCursor = strchr(pCursor,']'); + if (pCursor==NULL) + return false; + pCursor++; + + return true; +} + +//----------------------------------- +/// extract a number from the config string +// pass the key to find the first number in the list, else NULL to find the next number in the list +// returns 0 if no number is found, else returns the number +long CConfig::GetLong(char *key) +//----------------------------------- +{ + if (!FindKey(key)) + return 0; + + + // look for start of number or end of key + while (*pCursor && !isdigit(*pCursor) && *pCursor != '[') + pCursor++; + + int c = 0; + while (*pCursor && isdigit(*pCursor) && c < (int)sizeof(strBuffer)) + strBuffer[c++] = *(pCursor++); + strBuffer[c] = '\0'; + + return atol(strBuffer); +} + +//----------------------------------- +/// extract string (in double-quotes) from the list. +// pass the key to find the first string in the list, else NULL to find the next string in the list +// returns NULL if no string found, else returns a temporary copy of the string (without quotes) +char * CConfig::GetString(char *key) +//----------------------------------- +{ + if (!FindKey(key)) + return NULL; + + + // look for start of string or end of key + while (*pCursor && *pCursor != '"' && *pCursor != '[') + pCursor++; + if (*(pCursor++) != '"') + return NULL; + + // until closing quote + int c = 0; + while (*pCursor && c < (int)sizeof(strBuffer)) + { + strBuffer[c++] = *pCursor; // extract string + if (*pCursor++ == '"') + { + strBuffer[--c] = '\0'; + return strBuffer; + } + } + + return NULL; +} + + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + diff --git a/src/external/3rd/library/platform/utils/Base/MD5.cpp b/src/external/3rd/library/platform/utils/Base/MD5.cpp index a988f46b3..7fa9f8063 100644 --- a/src/external/3rd/library/platform/utils/Base/MD5.cpp +++ b/src/external/3rd/library/platform/utils/Base/MD5.cpp @@ -59,7 +59,7 @@ namespace Base int k = l = 0; for(; l < i; l += 4) { - ai[k] = achar0[l + j] & 0xff | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; + ai[k] = (achar0[l + j] & 0xff) | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; k++; } @@ -84,7 +84,7 @@ namespace Base int MD5::FF(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & k | ~j & l, i1, k1); + i = uadd(i, (j & k) | (~j & l), i1, k1); return uadd(rotate_left(i, j1), j); } @@ -106,7 +106,7 @@ namespace Base int MD5::GG(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & l | k & ~l, i1, k1); + i = uadd(i, (j & l) | (k & ~l), i1, k1); return uadd(rotate_left(i, j1), j); } @@ -128,7 +128,7 @@ namespace Base { padding.resize(64,0); padding[0] = -128; - } + } finalsNull = true; } diff --git a/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistStressTest/test.cpp b/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistStressTest/test.cpp index 2c6d697b0..c9d48ca34 100644 --- a/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistStressTest/test.cpp +++ b/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistStressTest/test.cpp @@ -1,732 +1,732 @@ -#include "test.h" -#include "Base/Base.h" -#include "Unicode/UnicodeUtils.h" -#include "request.h" - -#include -#include -#include -#ifdef WIN32 -#include -#endif -#include - -//#define WARP_SPEED true // set this for BRIEF std::cout printing -#define AUTO_RUN true - -using namespace std; -using namespace CSAssist; -using namespace Plat_Unicode; - -apiTest *api; -int received = 0; -int submitted = 0; -unsigned packetsRx = 0; -bool ready = false; -bool createdTicket = false; -bool loginFailed = true; -unsigned firstTicketID = 0; -unsigned lastTicketID = 0; -unsigned uid = 0; -unsigned testUID = 623259672;//99709401; -unsigned track(0); -int numberFunctionsToRun(0); -bool doBug(false); - -std::queue register_list; -Plat_Unicode::String game; -Plat_Unicode::String server; -Plat_Unicode::String character; -Plat_Unicode::String lang; -Plat_Unicode::String comment; -Plat_Unicode::String id; -Plat_Unicode::String search; -Plat_Unicode::String hierarchy = narrowToWide("test"); - -unsigned numberFunctions = 16; -unsigned functionCount[16]; -unsigned functionID[] = -{ - CSASSIST_CALL_NEWTICKETACTIVITY, // 2 - CSASSIST_CALL_REGISTERCHARACTER, // 3 - CSASSIST_CALL_GETISSUEHIERARCHY, // 6 - CSASSIST_CALL_CREATETICKET, // 7 - CSASSIST_CALL_APPENDCOMMENT, // 8 - CSASSIST_CALL_GETTICKETBYID, // 9 - CSASSIST_CALL_GETTICKETCOMMENTS, // 10 - CSASSIST_CALL_GETTICKET, // 11 - CSASSIST_CALL_MARKREAD, // 12 - CSASSIST_CALL_CANCELTICKET, // 13 - CSASSIST_CALL_COMMENTCOUNT, // 14 - CSASSIST_CALL_GETDOCUMENTLIST, // 16 - CSASSIST_CALL_GETDOCUMENT, // 17 - CSASSIST_CALL_GETTICKETXMLBLOCK, // 18 - CSASSIST_CALL_GETKBARTICLE, // 19 - CSASSIST_CALL_SEARCHKB // 20 -}; -char *functionName[] = -{ - "CSASSIST_CALL_NEWTICKETACTIVITY", // 2 - "CSASSIST_CALL_REGISTERCHARACTER", // 3 - "CSASSIST_CALL_GETISSUEHIERARCHY", // 6 - "CSASSIST_CALL_CREATETICKET", // 7 - "CSASSIST_CALL_APPENDCOMMENT", // 8 - "CSASSIST_CALL_GETTICKETBYID", // 9 - "CSASSIST_CALL_GETTICKETCOMMENTS", // 10 - "CSASSIST_CALL_GETTICKET", // 11 - "CSASSIST_CALL_MARKREAD", // 12 - "CSASSIST_CALL_CANCELTICKET", // 13 - "CSASSIST_CALL_COMMENTCOUNT", // 14 - "CSASSIST_CALL_GETDOCUMENTLIST", // 16 - "CSASSIST_CALL_GETDOCUMENT", // 17 - "CSASSIST_CALL_GETTICKETXMLBLOCK", // 18 - "CSASSIST_CALL_GETKBARTICLE", // 19 - "CSASSIST_CALL_SEARCHKB" // 20 -}; - -void ResetGlobals() -{ - received = 0; - submitted = 0; - packetsRx = 0; - ready = false; - createdTicket = false; - loginFailed = true; - firstTicketID = 0; - lastTicketID = 0; - uid = 0; - - float max = 500.0; - //srand(time(0)); - //numberFunctionsToRun = 2+(int) (max*rand()/(RAND_MAX+1.0)); - numberFunctionsToRun = 2000; -} - -//--------------------------------------------- -apiTest::apiTest(const char *host, const unsigned port, const unsigned timeout = 0, const unsigned flags = 0) -: CSAssistGameAPI(host, port, timeout, flags) -//--------------------------------------------- -{ -} - -//--------------------------------------------- -apiTest::~apiTest() -//--------------------------------------------- -{ -} - -//--------------------------------------------- -void apiTest::OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nConnect: " << result; -#endif - if (result == CSASSIST_RESULT_SUCCESS) - ready = true; - else - loginFailed = true; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nDisConnect: " << result; -#endif - received++; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nRegister: " << result; -#endif - received++; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nUnRegister: " << result; -#endif - received++; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nMark Read: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nUCancel: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nComment Count: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nGame Location: " << uid; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nDoc List: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nDocument: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nGet XML Block: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nSearch KB: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nGet KB Article: " << result; -#endif - received++; - packetsRx++; -} -//--------------------------------------------- -void apiTest::OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nHierarchy Changed"; -#endif - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nNewActivity: " << result << " " << HasTickets; -#endif - received++; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nHierarchy: " << result; -#endif - received++; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nCreate Ticket: " << result << " "< lastTicketID) - lastTicketID = ticket; - received++; - packetsRx++; - createdTicket = true; -} -//--------------------------------------------- -void apiTest::OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nAppend Comment: " << result; -#endif - received++; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nGet Ticket: " << result; -#endif - received++; - packetsRx++; -} - -//--------------------------------------------- -void apiTest::OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nGet Ticket Comments: " << result; - if (comments == 0) - std::cout << "\nNo Comment data"; -#endif - received++; - packetsRx += numberRead; -} - -//--------------------------------------------- -void apiTest::OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *tickets) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nGet Ticket: " << result; - if (tickets == 0) - std::cout << "\nNo Ticket data"; -#endif - received++; - packetsRx += NumberReturned; -} - -//--------------------------------------------- -void apiTest::OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character) -//--------------------------------------------- -{ -#ifndef WARP_SPEED - std::cout << "\nTicket Change: " << ticketID; -#endif - packetsRx++; -} - -//--------------------------------------------- -void createTicket() -//--------------------------------------------- -{ - CSAssistGameAPITicket t; - t.setUID(testUID); - t.setGame(game.c_str()); - t.setServer(server.c_str()); - t.setCharacter(character.c_str()); - t.setCategory(0,4000); - t.setCategory(1,4001); - t.setCategory(2,2); - t.setCategory(3,1); - if (doBug) t.setBug(); - Plat_Unicode::String details = narrowToWide("Stress Test Ticket details here."); - Plat_Unicode::String location = narrowToWide("Stress Test Location"); - Plat_Unicode::String xml = narrowToWide("Stress Test XML here"); - t.setDetails(details.c_str()); - t.setLocation(location.c_str()); - track = api->requestCreateTicket(NULL, &t, NULL, t.uid); - //track = api->requestCreateTicket(NULL, &t, xml.c_str(), t.uid); - submitted++; - - printf("creating ticket\n"); - createdTicket = false; - if (firstTicketID ==0) // if no tickets created yet, wait for one - { - while (!createdTicket) // wait for create ticket to return, so we know ticket number we created - { - Base::sleep(50); - api->Update(); - } - } -} - -//--------------------------------------------- -unsigned randomTicketID() -//--------------------------------------------- -{ - if (firstTicketID == 0) - createTicket(); // create at least one ticket first - - unsigned r = firstTicketID; - if (r != lastTicketID) - r += rand() % (lastTicketID - firstTicketID); -#ifndef WARP_SPEED - printf(" (%d) ", r); -#endif - return r; -} - -//----------------------------------------------- -std::string GetHostName(unsigned port) -//----------------------------------------------- -{ - const short hostLen(512); - char hostName[hostLen] = {0}; - char hostAndPort[hostLen+10] = {0}; - std::string serverID; -#ifdef WIN32 - WSADATA wsaData; - WSAStartup(MAKEWORD(1,1), &wsaData); -#endif - if (gethostname(hostName, hostLen) < 0) - { - // Bad error - the serverID must be unique between CSA servers. - // Attempt to use IP Address ?. // TODO:rlsmith - sprintf(hostName,"localhost-%u", port); - } -//#endif - std::string shortName = hostName; - unsigned dot = shortName.find_first_of("."); - if (dot != std::string::npos) - { - shortName = shortName.substr(0,dot); - } -#ifdef WIN32 - _snprintf(hostAndPort, hostLen+10, "%s", shortName.c_str()); -#else - snprintf(hostAndPort, hostLen+10, "%s", shortName.c_str()); -#endif - return (std::string)hostAndPort; -} - -//--------------------------------------------- -int main(int argc, char **argv) -//--------------------------------------------- -{ - unsigned i = 0; - unsigned tid = 0; - - // ----- validate and strip command line parameters ----- - - char *serverhost; - int serverport; - char *gamep; - char *gameserver; - -#ifdef AUTO_RUN - ResetGlobals(); - serverhost = "localhost"; - serverport = 3009; - if (argc > 1) - gamep = argv[1]; - else - gamep = "PS"; - if (argc> 2 && !strcmp(argv[2],"bug")) doBug=true; - std::string gs = GetHostName(numberFunctionsToRun); - gameserver = (char*)gs.c_str(); -#else - if (argc < 6) - { - std::cout << "CSAssistStressTest Game Version: Syntax:\nCSAssistStressTest \n"; - return 0; - } - serverhost = argv[1]; - serverport = atoi(argv[2]); - numberFunctionsToRun = atoi(argv[3]); - gamep = argv[4]; - gameserver = argv[5]; - - if (serverhost == NULL || strlen(serverhost) == 0) - { - std::cout << "Missing hostname!\n"; - return 0; - } - if (serverport < 3000 || serverport > 3020) - { - std::cout << "Missing or invalid serverport!\n"; - return 0; - } - if (numberFunctionsToRun <= 0) - { - std::cout << "Missing or invalid number of functions to run!\n"; - return 0; - } - if (gamep == NULL || strlen(gamep) == 0) - { - std::cout << "Missing game name!\n"; - return 0; - } - if (gameserver == NULL || strlen(gameserver) == 0) - { - std::cout << "Missing game server name!\n"; - return 0; - } -#endif - - game = narrowToWide(gamep); - server = narrowToWide(gameserver); - character = narrowToWide("Sabinia"); - - // ----- connect to API ----- -while(1) -{ - ResetGlobals(); - unsigned updateDelay(100); - unsigned loginWait(500); - unsigned loginAttempts(0); - //api = new apiTest(serverhost, serverport, 60, CSASSIST_APIFLAG_ASSUME_RECONNECT); //, 0, CSASSIST_APIFLAG_ASSUME_RECONNECT); - //api->connectCSAssist(NULL, game.c_str(), server.c_str()); - //while (!ready) - // api->Update(); - - cerr<<"numberFunctionsToRun="<< numberFunctionsToRun <connectCSAssist(NULL, game.c_str(), server.c_str()); - loginFailed = false; - std::cout <<"Trying to connect..."< 5000) loginWait=500; - } - if (loginAttempts++ > 30) - { - loginAttempts = 0; - loginFailed = true; - delete api; - api = NULL; - continue; - } - std::cout <<"Waiting for login: track:" << track<<" ..."<Update(); - } - - for (i=0; i < numberFunctions; i++) - functionCount[i] = 0; - - createTicket(); // works better if we do this before timing starts - - time_t now = time(0); - srand(now); - - // ----- submit random packets ----- - - for (i=0; i < (unsigned)numberFunctionsToRun; i++) - { - //unsigned randomFunction = 3; // to generate dummy tickets use this line - unsigned randomFunction = 3;//rand() % numberFunctions; - functionCount[randomFunction]++; -#ifndef WARP_SPEED - std::cout << " " << i << " "; -#endif - std::cout << " calling: "<requestNewTicketActivity(NULL, testUID, 0); - else - track = api->requestNewTicketActivity(NULL, testUID, character.c_str()); - submitted++; - - break; - case CSASSIST_CALL_REGISTERCHARACTER: - uid = rand(); - track = api->requestRegisterCharacter(NULL, uid, 0, 0); - register_list.push(uid); - submitted++; - break; - case CSASSIST_CALL_GETISSUEHIERARCHY: - lang = narrowToWide("en"); - track = api->requestGetIssueHierarchy(NULL, hierarchy.c_str(), lang.c_str()); - submitted++; - break; - case CSASSIST_CALL_CREATETICKET: - createTicket(); - break; - case CSASSIST_CALL_APPENDCOMMENT: - comment = narrowToWide("Unicode comment by player."); - tid = randomTicketID(); - track = api->requestAppendTicketComment(NULL, tid, testUID, character.c_str(), comment.c_str()); - submitted++; - break; - case CSASSIST_CALL_GETTICKETBYID: - tid = randomTicketID(); - track = api->requestGetTicketByID(NULL, tid, 1); - submitted++; - break; - case CSASSIST_CALL_GETTICKETCOMMENTS: - tid = randomTicketID(); - track = api->requestGetTicketComments(NULL, tid, 0, (rand() % 100)+1, CSASSIST_OFFSET_START); - submitted++; - break; - case CSASSIST_CALL_GETTICKET: - track = api->requestGetTicketByCharacter(NULL, testUID, character.c_str(), 0, (rand() % 100)+1, 1); - submitted++; - break; - case CSASSIST_CALL_MARKREAD: - tid = randomTicketID(); - track = api->requestMarkTicketRead(NULL, tid); - submitted++; - break; - case CSASSIST_CALL_CANCELTICKET: - if (firstTicketID != 0) - { - comment = narrowToWide("Ticket closed by player"); - track = api->requestCancelTicket(NULL, firstTicketID, testUID, comment.c_str()); - if (++firstTicketID > lastTicketID) - { - firstTicketID = 0; - lastTicketID = 0; - } - submitted++; - } - break; - case CSASSIST_CALL_COMMENTCOUNT: - tid = randomTicketID(); - track = api->requestGetTicketCommentsCount(NULL, tid); - submitted++; - break; - case CSASSIST_CALL_GETDOCUMENTLIST: -// lang = narrowToWide("en"); -// track = api->requestGetDocumentList(NULL, hierarchy.c_str(), lang.c_str()); -// submitted++; - break; - case CSASSIST_CALL_GETDOCUMENT: -// track = api->requestGetDocument(NULL, 1); -// submitted++; - break; - case CSASSIST_CALL_GETTICKETXMLBLOCK: - tid = randomTicketID(); - track = api->requestGetTicketXMLBlock(NULL, tid); - submitted++; - break; - case CSASSIST_CALL_GETKBARTICLE: - /*id = narrowToWide("soe1401"); - lang = narrowToWide("en"); - track = api->requestGetKBArticle(NULL, id.c_str(), lang.c_str()); - submitted++; - */break; - case CSASSIST_CALL_SEARCHKB: - /*Plat_Unicode::String searchStr = narrowToWide("video drivers"); - lang = narrowToWide("en"); - track = api->requestSearchKB(NULL, searchStr.c_str(), lang.c_str()); - submitted++; - */break; - } - Base::sleep(5); - //api->Update(); - if (track) - std::cout << "called: "<< functionName[randomFunction] << ": " << functionCount[randomFunction] << " track:" < 50) - { - while (submitted > received) - { - Base::sleep(50); - api->Update(); - } - } - } - - // ----- Wait for final packet ----- - cout<<"Waiting for last packet..."< received) // make sure everything is complete before disconnecting - { - Base::sleep(50); - api->Update(); - } - - // ----- unregister any registered characters ---- - - while (register_list.size()) - { - uid = register_list.front(); - register_list.pop(); - api->requestUnRegisterCharacter(NULL, uid, 0); - submitted++; - } - cout<<"Waiting for unregisters..."< received) // make sure everything is complete before disconnecting - { - Base::sleep(50); - api->Update(); - } - - // ----- and clean up ----- - - time_t elapsed = time(0) - now; - if (elapsed == 0) - elapsed = 1; - cout<<"Going to disconnect now."<disconnectCSAssist(NULL); - submitted++; - - while (submitted > received) - { - api->Update(); - } - - cout<<"Going to delete API now."< +#include +#include +#ifdef WIN32 +#include +#endif +#include + +//#define WARP_SPEED true // set this for BRIEF std::cout printing +#define AUTO_RUN true + +using namespace std; +using namespace CSAssist; +using namespace Plat_Unicode; + +apiTest *api; +int received = 0; +int submitted = 0; +unsigned packetsRx = 0; +bool ready = false; +bool createdTicket = false; +bool loginFailed = true; +unsigned firstTicketID = 0; +unsigned lastTicketID = 0; +unsigned uid = 0; +unsigned testUID = 623259672;//99709401; +unsigned track(0); +int numberFunctionsToRun(0); +bool doBug(false); + +std::queue register_list; +Plat_Unicode::String game; +Plat_Unicode::String server; +Plat_Unicode::String character; +Plat_Unicode::String lang; +Plat_Unicode::String comment; +Plat_Unicode::String id; +Plat_Unicode::String search; +Plat_Unicode::String hierarchy = narrowToWide("test"); + +unsigned numberFunctions = 16; +unsigned functionCount[16]; +unsigned functionID[] = +{ + CSASSIST_CALL_NEWTICKETACTIVITY, // 2 + CSASSIST_CALL_REGISTERCHARACTER, // 3 + CSASSIST_CALL_GETISSUEHIERARCHY, // 6 + CSASSIST_CALL_CREATETICKET, // 7 + CSASSIST_CALL_APPENDCOMMENT, // 8 + CSASSIST_CALL_GETTICKETBYID, // 9 + CSASSIST_CALL_GETTICKETCOMMENTS, // 10 + CSASSIST_CALL_GETTICKET, // 11 + CSASSIST_CALL_MARKREAD, // 12 + CSASSIST_CALL_CANCELTICKET, // 13 + CSASSIST_CALL_COMMENTCOUNT, // 14 + CSASSIST_CALL_GETDOCUMENTLIST, // 16 + CSASSIST_CALL_GETDOCUMENT, // 17 + CSASSIST_CALL_GETTICKETXMLBLOCK, // 18 + CSASSIST_CALL_GETKBARTICLE, // 19 + CSASSIST_CALL_SEARCHKB // 20 +}; +char *functionName[] = +{ + "CSASSIST_CALL_NEWTICKETACTIVITY", // 2 + "CSASSIST_CALL_REGISTERCHARACTER", // 3 + "CSASSIST_CALL_GETISSUEHIERARCHY", // 6 + "CSASSIST_CALL_CREATETICKET", // 7 + "CSASSIST_CALL_APPENDCOMMENT", // 8 + "CSASSIST_CALL_GETTICKETBYID", // 9 + "CSASSIST_CALL_GETTICKETCOMMENTS", // 10 + "CSASSIST_CALL_GETTICKET", // 11 + "CSASSIST_CALL_MARKREAD", // 12 + "CSASSIST_CALL_CANCELTICKET", // 13 + "CSASSIST_CALL_COMMENTCOUNT", // 14 + "CSASSIST_CALL_GETDOCUMENTLIST", // 16 + "CSASSIST_CALL_GETDOCUMENT", // 17 + "CSASSIST_CALL_GETTICKETXMLBLOCK", // 18 + "CSASSIST_CALL_GETKBARTICLE", // 19 + "CSASSIST_CALL_SEARCHKB" // 20 +}; + +void ResetGlobals() +{ + received = 0; + submitted = 0; + packetsRx = 0; + ready = false; + createdTicket = false; + loginFailed = true; + firstTicketID = 0; + lastTicketID = 0; + uid = 0; + + float max = 500.0; + //srand(time(0)); + //numberFunctionsToRun = 2+(int) (max*rand()/(RAND_MAX+1.0)); + numberFunctionsToRun = 2000; +} + +//--------------------------------------------- +apiTest::apiTest(const char *host, const unsigned port, const unsigned timeout = 0, const unsigned flags = 0) +: CSAssistGameAPI(host, port, timeout, flags) +//--------------------------------------------- +{ +} + +//--------------------------------------------- +apiTest::~apiTest() +//--------------------------------------------- +{ +} + +//--------------------------------------------- +void apiTest::OnConnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nConnect: " << result; +#endif + if (result == CSASSIST_RESULT_SUCCESS) + ready = true; + else + loginFailed = true; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnDisconnectCSAssist(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nDisConnect: " << result; +#endif + received++; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nRegister: " << result; +#endif + received++; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnUnRegisterCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nUnRegister: " << result; +#endif + received++; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnMarkTicketRead(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nMark Read: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnCancelTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nUCancel: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnGetTicketCommentsCount(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket, const unsigned count) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nComment Count: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnRequestGameLocation(const CSAssistGameAPITrack sourceTrack, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character, const CSAssistGameAPIUID CSRUID) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nGame Location: " << uid; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnGetDocumentList(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIDocumentHeader *docList, const unsigned numberRead) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nDoc List: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnGetDocument(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistUnicodeChar *documentBody) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nDocument: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnGetTicketXMLBlock(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML XMLBody) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nGet XML Block: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnSearchKB(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPISearchResult *results, const unsigned numberRead) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nSearch KB: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnGetKBArticle(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML articleBody) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nGet KB Article: " << result; +#endif + received++; + packetsRx++; +} +//--------------------------------------------- +void apiTest::OnIssueHierarchyChanged(const CSAssistUnicodeChar *version, const CSAssistUnicodeChar *language) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nHierarchy Changed"; +#endif + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnNewTicketActivity(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NewActivityFlag, const unsigned HasTickets) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nNewActivity: " << result << " " << HasTickets; +#endif + received++; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnGetIssueHierarchy(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPIXML hierarchyBody, const unsigned modifyDate) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nHierarchy: " << result; +#endif + received++; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnCreateTicket(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nCreate Ticket: " << result << " "< lastTicketID) + lastTicketID = ticket; + received++; + packetsRx++; + createdTicket = true; +} +//--------------------------------------------- +void apiTest::OnAppendTicketComment(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketID ticket) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nAppend Comment: " << result; +#endif + received++; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnGetTicketByID(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicket *ticketBody) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nGet Ticket: " << result; +#endif + received++; + packetsRx++; +} + +//--------------------------------------------- +void apiTest::OnGetTicketComments(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const CSAssistGameAPITicketComment *comments, const unsigned numberRead) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nGet Ticket Comments: " << result; + if (comments == 0) + std::cout << "\nNo Comment data"; +#endif + received++; + packetsRx += numberRead; +} + +//--------------------------------------------- +void apiTest::OnGetTicketByCharacter(const CSAssistGameAPITrack track, const CSAssistGameAPIResult result, const void *userData, const unsigned NumberReturned, const unsigned TotalNumber, const CSAssistGameAPITicket *tickets) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nGet Ticket: " << result; + if (tickets == 0) + std::cout << "\nNo Ticket data"; +#endif + received++; + packetsRx += NumberReturned; +} + +//--------------------------------------------- +void apiTest::OnTicketChange(const CSAssistGameAPITicketID ticketID, const CSAssistGameAPIUID uid, const CSAssistUnicodeChar *character) +//--------------------------------------------- +{ +#ifndef WARP_SPEED + std::cout << "\nTicket Change: " << ticketID; +#endif + packetsRx++; +} + +//--------------------------------------------- +void createTicket() +//--------------------------------------------- +{ + CSAssistGameAPITicket t; + t.setUID(testUID); + t.setGame(game.c_str()); + t.setServer(server.c_str()); + t.setCharacter(character.c_str()); + t.setCategory(0,4000); + t.setCategory(1,4001); + t.setCategory(2,2); + t.setCategory(3,1); + if (doBug) t.setBug(); + Plat_Unicode::String details = narrowToWide("Stress Test Ticket details here."); + Plat_Unicode::String location = narrowToWide("Stress Test Location"); + Plat_Unicode::String xml = narrowToWide("Stress Test XML here"); + t.setDetails(details.c_str()); + t.setLocation(location.c_str()); + track = api->requestCreateTicket(NULL, &t, NULL, t.uid); + //track = api->requestCreateTicket(NULL, &t, xml.c_str(), t.uid); + submitted++; + + printf("creating ticket\n"); + createdTicket = false; + if (firstTicketID ==0) // if no tickets created yet, wait for one + { + while (!createdTicket) // wait for create ticket to return, so we know ticket number we created + { + Base::sleep(50); + api->Update(); + } + } +} + +//--------------------------------------------- +unsigned randomTicketID() +//--------------------------------------------- +{ + if (firstTicketID == 0) + createTicket(); // create at least one ticket first + + unsigned r = firstTicketID; + if (r != lastTicketID) + r += rand() % (lastTicketID - firstTicketID); +#ifndef WARP_SPEED + printf(" (%d) ", r); +#endif + return r; +} + +//----------------------------------------------- +std::string GetHostName(unsigned port) +//----------------------------------------------- +{ + const short hostLen(512); + char hostName[hostLen] = {0}; + char hostAndPort[hostLen+10] = {0}; + std::string serverID; +#ifdef WIN32 + WSADATA wsaData; + WSAStartup(MAKEWORD(1,1), &wsaData); +#endif + if (gethostname(hostName, hostLen) < 0) + { + // Bad error - the serverID must be unique between CSA servers. + // Attempt to use IP Address ?. // TODO:rlsmith + sprintf(hostName,"localhost-%u", port); + } +//#endif + std::string shortName = hostName; + unsigned dot = shortName.find_first_of("."); + if (dot != std::string::npos) + { + shortName = shortName.substr(0,dot); + } +#ifdef WIN32 + _snprintf(hostAndPort, hostLen+10, "%s", shortName.c_str()); +#else + snprintf(hostAndPort, hostLen+10, "%s", shortName.c_str()); +#endif + return (std::string)hostAndPort; +} + +//--------------------------------------------- +int main(int argc, char **argv) +//--------------------------------------------- +{ + unsigned i = 0; + unsigned tid = 0; + + // ----- validate and strip command line parameters ----- + + char *serverhost; + int serverport; + char *gamep; + char *gameserver; + +#ifdef AUTO_RUN + ResetGlobals(); + serverhost = "localhost"; + serverport = 3009; + if (argc > 1) + gamep = argv[1]; + else + gamep = "PS"; + if (argc> 2 && !strcmp(argv[2],"bug")) doBug=true; + std::string gs = GetHostName(numberFunctionsToRun); + gameserver = (char*)gs.c_str(); +#else + if (argc < 6) + { + std::cout << "CSAssistStressTest Game Version: Syntax:\nCSAssistStressTest \n"; + return 0; + } + serverhost = argv[1]; + serverport = atoi(argv[2]); + numberFunctionsToRun = atoi(argv[3]); + gamep = argv[4]; + gameserver = argv[5]; + + if (serverhost == NULL || strlen(serverhost) == 0) + { + std::cout << "Missing hostname!\n"; + return 0; + } + if (serverport < 3000 || serverport > 3020) + { + std::cout << "Missing or invalid serverport!\n"; + return 0; + } + if (numberFunctionsToRun <= 0) + { + std::cout << "Missing or invalid number of functions to run!\n"; + return 0; + } + if (gamep == NULL || strlen(gamep) == 0) + { + std::cout << "Missing game name!\n"; + return 0; + } + if (gameserver == NULL || strlen(gameserver) == 0) + { + std::cout << "Missing game server name!\n"; + return 0; + } +#endif + + game = narrowToWide(gamep); + server = narrowToWide(gameserver); + character = narrowToWide("Sabinia"); + + // ----- connect to API ----- +while(1) +{ + ResetGlobals(); + unsigned updateDelay(100); + unsigned loginWait(500); + unsigned loginAttempts(0); + //api = new apiTest(serverhost, serverport, 60, CSASSIST_APIFLAG_ASSUME_RECONNECT); //, 0, CSASSIST_APIFLAG_ASSUME_RECONNECT); + //api->connectCSAssist(NULL, game.c_str(), server.c_str()); + //while (!ready) + // api->Update(); + + cerr<<"numberFunctionsToRun="<< numberFunctionsToRun <connectCSAssist(NULL, game.c_str(), server.c_str()); + loginFailed = false; + std::cout <<"Trying to connect..."< 5000) loginWait=500; + } + if (loginAttempts++ > 30) + { + loginAttempts = 0; + loginFailed = true; + delete api; + api = NULL; + continue; + } + std::cout <<"Waiting for login: track:" << track<<" ..."<Update(); + } + + for (i=0; i < numberFunctions; i++) + functionCount[i] = 0; + + createTicket(); // works better if we do this before timing starts + + time_t now = time(0); + srand(now); + + // ----- submit random packets ----- + + for (i=0; i < (unsigned)numberFunctionsToRun; i++) + { + //unsigned randomFunction = 3; // to generate dummy tickets use this line + unsigned randomFunction = 3;//rand() % numberFunctions; + functionCount[randomFunction]++; +#ifndef WARP_SPEED + std::cout << " " << i << " "; +#endif + std::cout << " calling: "<requestNewTicketActivity(NULL, testUID, 0); + else + track = api->requestNewTicketActivity(NULL, testUID, character.c_str()); + submitted++; + + break; + case CSASSIST_CALL_REGISTERCHARACTER: + uid = rand(); + track = api->requestRegisterCharacter(NULL, uid, 0, 0); + register_list.push(uid); + submitted++; + break; + case CSASSIST_CALL_GETISSUEHIERARCHY: + lang = narrowToWide("en"); + track = api->requestGetIssueHierarchy(NULL, hierarchy.c_str(), lang.c_str()); + submitted++; + break; + case CSASSIST_CALL_CREATETICKET: + createTicket(); + break; + case CSASSIST_CALL_APPENDCOMMENT: + comment = narrowToWide("Unicode comment by player."); + tid = randomTicketID(); + track = api->requestAppendTicketComment(NULL, tid, testUID, character.c_str(), comment.c_str()); + submitted++; + break; + case CSASSIST_CALL_GETTICKETBYID: + tid = randomTicketID(); + track = api->requestGetTicketByID(NULL, tid, 1); + submitted++; + break; + case CSASSIST_CALL_GETTICKETCOMMENTS: + tid = randomTicketID(); + track = api->requestGetTicketComments(NULL, tid, 0, (rand() % 100)+1, CSASSIST_OFFSET_START); + submitted++; + break; + case CSASSIST_CALL_GETTICKET: + track = api->requestGetTicketByCharacter(NULL, testUID, character.c_str(), 0, (rand() % 100)+1, 1); + submitted++; + break; + case CSASSIST_CALL_MARKREAD: + tid = randomTicketID(); + track = api->requestMarkTicketRead(NULL, tid); + submitted++; + break; + case CSASSIST_CALL_CANCELTICKET: + if (firstTicketID != 0) + { + comment = narrowToWide("Ticket closed by player"); + track = api->requestCancelTicket(NULL, firstTicketID, testUID, comment.c_str()); + if (++firstTicketID > lastTicketID) + { + firstTicketID = 0; + lastTicketID = 0; + } + submitted++; + } + break; + case CSASSIST_CALL_COMMENTCOUNT: + tid = randomTicketID(); + track = api->requestGetTicketCommentsCount(NULL, tid); + submitted++; + break; + case CSASSIST_CALL_GETDOCUMENTLIST: +// lang = narrowToWide("en"); +// track = api->requestGetDocumentList(NULL, hierarchy.c_str(), lang.c_str()); +// submitted++; + break; + case CSASSIST_CALL_GETDOCUMENT: +// track = api->requestGetDocument(NULL, 1); +// submitted++; + break; + case CSASSIST_CALL_GETTICKETXMLBLOCK: + tid = randomTicketID(); + track = api->requestGetTicketXMLBlock(NULL, tid); + submitted++; + break; + case CSASSIST_CALL_GETKBARTICLE: + /*id = narrowToWide("soe1401"); + lang = narrowToWide("en"); + track = api->requestGetKBArticle(NULL, id.c_str(), lang.c_str()); + submitted++; + */break; + case CSASSIST_CALL_SEARCHKB: + /*Plat_Unicode::String searchStr = narrowToWide("video drivers"); + lang = narrowToWide("en"); + track = api->requestSearchKB(NULL, searchStr.c_str(), lang.c_str()); + submitted++; + */break; + } + Base::sleep(5); + //api->Update(); + if (track) + std::cout << "called: "<< functionName[randomFunction] << ": " << functionCount[randomFunction] << " track:" < 50) + { + while (submitted > received) + { + Base::sleep(50); + api->Update(); + } + } + } + + // ----- Wait for final packet ----- + cout<<"Waiting for last packet..."< received) // make sure everything is complete before disconnecting + { + Base::sleep(50); + api->Update(); + } + + // ----- unregister any registered characters ---- + + while (register_list.size()) + { + uid = register_list.front(); + register_list.pop(); + api->requestUnRegisterCharacter(NULL, uid, 0); + submitted++; + } + cout<<"Waiting for unregisters..."< received) // make sure everything is complete before disconnecting + { + Base::sleep(50); + api->Update(); + } + + // ----- and clean up ----- + + time_t elapsed = time(0) - now; + if (elapsed == 0) + elapsed = 1; + cout<<"Going to disconnect now."<disconnectCSAssist(NULL); + submitted++; + + while (submitted > received) + { + api->Update(); + } + + cout<<"Going to delete API now."<= (short)CSASSIST_NUM_CATEGORIES) diff --git a/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistgameobjects.h b/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistgameobjects.h index e1fdeda7d..b65353507 100644 --- a/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistgameobjects.h +++ b/src/external/3rd/library/soePlatform/CSAssist/projects/CSAssist/CSAssistgameapi/CSAssistgameobjects.h @@ -33,7 +33,7 @@ public: CSAssistGameAPIResult setDetails(const CSAssistUnicodeChar *string); CSAssistGameAPIResult setLanguage(const CSAssistUnicodeChar *string); CSAssistGameAPIResult setLocation(const CSAssistUnicodeChar *string); - CSAssistGameAPIResult setCategory(unsigned index, unsigned value); + CSAssistGameAPIResult setCategory(int index, unsigned value); CSAssistGameAPITicketID ticketID; // unique ID CSAssistGameAPIUID uid; // station UID diff --git a/src/external/3rd/library/soePlatform/CSAssist/utils/Base/Config.h b/src/external/3rd/library/soePlatform/CSAssist/utils/Base/Config.h index 99483832c..864506f32 100644 --- a/src/external/3rd/library/soePlatform/CSAssist/utils/Base/Config.h +++ b/src/external/3rd/library/soePlatform/CSAssist/utils/Base/Config.h @@ -1,111 +1,111 @@ -/* -; Example syntax of a config file. -# This is a comment to end of line. -; This is a comment too....both comments are to end of line -[KEYWORD] ; all keywords must be upper case to be recognized - -; single number, with code example -# long number = config.GetLong("PORT"); -[PORT] 5999 ; common single-value case - -; list of strings, with code example -# config.FindKey("NUMBERS"); -# while (number = config.GetLong(NULL)) -# YourHandleNumber(number); -[NUMBERS] 100 - 200, 300 ; formatting is very flexible as long as numbers are delimited by non-numbers - 400 500 - 600 ; This is badly formatted for example purposes only - -; single string, with code example -# strcpy(mystring, config.GetString("STRING")); -[STRING] "This is a string" - -; list of strings, with code example -# config.FindKey("HOSTS"); -# while (string = config.GetString(NULL)) -# YourHandleString(string); -[HOSTS] - "127.0.0.1:5999" - "127.0.0.1:5998" - "127.0.0.1:2000" - -*/ - -#ifndef _CONFIG_H -#define _CONFIG_H - -#include - -#ifdef EXTERNAL_DISTRO -namespace NAMESPACE -{ - -#endif -namespace Base -{ - - class CConfig - { - public: - // constructor, no file loaded - CConfig(); - - // version of constructor that calls LoadFile(file) - CConfig(char * file); - - // destructor, will delete all buffers - ~CConfig(); - - // copy text config file into memory. Required to use extraction methods. - // if called with a different filename, existing file will be discarded. - bool LoadFile(char * file); - - // delete memory buffer of file - void UnloadFile(); - - // set cursor in file based on key name. Alternate way to select first key when extracting lists. - // returns TRUE if key is found. - bool FindKey(char *key); - - // extract string from config. If key is NULL, extract next string in list, else extract first string. - // if key was not found, returns NULL - char * GetString(char *key = NULL); - - // extract number from config. If key is NULL, extract next number in list, else extract first number. - // if key was not found, returns 0 - long GetLong(char *key = NULL); // extract number from config. - - // indicate if config file has been loaded - inline bool FileLoaded() { return pConfig == NULL ? false : true; } - - private: - char * pConfig; // pointer to file memory - char * pCursor; // current cursor into file memory - char strBuffer[8196]; // buffer for GetString return pointer -- reused - }; - - inline CConfig::CConfig() - { - pConfig = NULL; - pCursor = NULL; - } - - inline CConfig::CConfig(char * file) - { - pConfig = NULL; - pCursor = NULL; - LoadFile(file); - } - - inline CConfig::~CConfig() - { - UnloadFile(); - } - -}; -#ifdef EXTERNAL_DISTRO -}; -#endif - -#endif +/* +; Example syntax of a config file. +# This is a comment to end of line. +; This is a comment too....both comments are to end of line +[KEYWORD] ; all keywords must be upper case to be recognized + +; single number, with code example +# long number = config.GetLong("PORT"); +[PORT] 5999 ; common single-value case + +; list of strings, with code example +# config.FindKey("NUMBERS"); +# while (number = config.GetLong(NULL)) +# YourHandleNumber(number); +[NUMBERS] 100 + 200, 300 ; formatting is very flexible as long as numbers are delimited by non-numbers + 400 500 + 600 ; This is badly formatted for example purposes only + +; single string, with code example +# strcpy(mystring, config.GetString("STRING")); +[STRING] "This is a string" + +; list of strings, with code example +# config.FindKey("HOSTS"); +# while (string = config.GetString(NULL)) +# YourHandleString(string); +[HOSTS] + "127.0.0.1:5999" + "127.0.0.1:5998" + "127.0.0.1:2000" + +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif +namespace Base +{ + + class CConfig + { + public: + // constructor, no file loaded + CConfig(); + + // version of constructor that calls LoadFile(file) + CConfig(char * file); + + // destructor, will delete all buffers + ~CConfig(); + + // copy text config file into memory. Required to use extraction methods. + // if called with a different filename, existing file will be discarded. + bool LoadFile(char * file); + + // delete memory buffer of file + void UnloadFile(); + + // set cursor in file based on key name. Alternate way to select first key when extracting lists. + // returns TRUE if key is found. + bool FindKey(char *key); + + // extract string from config. If key is NULL, extract next string in list, else extract first string. + // if key was not found, returns NULL + char * GetString(char *key = NULL); + + // extract number from config. If key is NULL, extract next number in list, else extract first number. + // if key was not found, returns 0 + long GetLong(char *key = NULL); // extract number from config. + + // indicate if config file has been loaded + inline bool FileLoaded() { return pConfig == NULL ? false : true; } + + private: + char * pConfig; // pointer to file memory + char * pCursor; // current cursor into file memory + char strBuffer[8196]; // buffer for GetString return pointer -- reused + }; + + inline CConfig::CConfig() + { + pConfig = NULL; + pCursor = NULL; + } + + inline CConfig::CConfig(char * file) + { + pConfig = NULL; + pCursor = NULL; + LoadFile(file); + } + + inline CConfig::~CConfig() + { + UnloadFile(); + } + +}; +#ifdef EXTERNAL_DISTRO +}; +#endif + +#endif diff --git a/src/external/3rd/library/soePlatform/CSAssist/utils/Base/MD5.cpp b/src/external/3rd/library/soePlatform/CSAssist/utils/Base/MD5.cpp index a988f46b3..31d75dcb8 100644 --- a/src/external/3rd/library/soePlatform/CSAssist/utils/Base/MD5.cpp +++ b/src/external/3rd/library/soePlatform/CSAssist/utils/Base/MD5.cpp @@ -59,7 +59,7 @@ namespace Base int k = l = 0; for(; l < i; l += 4) { - ai[k] = achar0[l + j] & 0xff | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; + ai[k] = (achar0[l + j] & 0xff) | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; k++; } @@ -84,7 +84,7 @@ namespace Base int MD5::FF(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & k | ~j & l, i1, k1); + i = uadd(i, (j & k) | (~j & l), i1, k1); return uadd(rotate_left(i, j1), j); } @@ -106,7 +106,7 @@ namespace Base int MD5::GG(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & l | k & ~l, i1, k1); + i = uadd(i, (j & l) | (k & ~l), i1, k1); return uadd(rotate_left(i, j1), j); } diff --git a/src/external/3rd/library/soePlatform/CSAssist/utils/Base/linux/Types.h b/src/external/3rd/library/soePlatform/CSAssist/utils/Base/linux/Types.h index 4ff7adc36..69419a0fc 100644 --- a/src/external/3rd/library/soePlatform/CSAssist/utils/Base/linux/Types.h +++ b/src/external/3rd/library/soePlatform/CSAssist/utils/Base/linux/Types.h @@ -1,45 +1,45 @@ -//////////////////////////////////////// -// Types.h -// -// Purpose: -// 1. Define integer types that are unambiguous with respect to size -// -// Revisions: -// 07/10/2001 Created -// - -#ifndef BASE_LINUX_TYPES_H -#define BASE_LINUX_TYPES_H - -#include - -#ifdef EXTERNAL_DISTRO -namespace NAMESPACE -{ - -#endif - -namespace Base -{ - -#ifndef INT32_MAX -#define INT32_MAX 0x7FFFFFFF -#define INT32_MIN 0x80000000 -#define UINT32_MAX 0xFFFFFFFF -#endif - -typedef signed char int8; -typedef unsigned char uint8; -typedef signed short int16; -typedef unsigned short uint16; - -typedef int32_t int32; -typedef u_int32_t uint32; -typedef int64_t int64; -typedef u_int64_t uint64; -} -#ifdef EXTERNAL_DISTRO -}; -#endif -#endif // BASE_LINUX_TYPES_H - +//////////////////////////////////////// +// Types.h +// +// Purpose: +// 1. Define integer types that are unambiguous with respect to size +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_TYPES_H +#define BASE_LINUX_TYPES_H + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif + +namespace Base +{ + +#ifndef INT32_MAX +#define INT32_MAX 0x7FFFFFFF +#define INT32_MIN 0x80000000 +#define UINT32_MAX 0xFFFFFFFF +#endif + +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; + +typedef int32_t int32; +typedef u_int32_t uint32; +typedef int64_t int64; +typedef u_int64_t uint64; +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // BASE_LINUX_TYPES_H + diff --git a/src/external/3rd/library/soePlatform/CSAssist/utils/TcpLibrary/Clock.cpp b/src/external/3rd/library/soePlatform/CSAssist/utils/TcpLibrary/Clock.cpp index 2f5f47b4c..2b7265bc2 100644 --- a/src/external/3rd/library/soePlatform/CSAssist/utils/TcpLibrary/Clock.cpp +++ b/src/external/3rd/library/soePlatform/CSAssist/utils/TcpLibrary/Clock.cpp @@ -46,8 +46,6 @@ ClockStamp Clock::getCurTime() return ret; #else struct timeval tv; - int err; - err = gettimeofday(&tv, NULL); return (static_cast(tv.tv_sec) * 1000 + static_cast(tv.tv_usec / 1000)); #endif } diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/Base/linux/Types.h b/src/external/3rd/library/soePlatform/CTServiceGameAPI/Base/linux/Types.h index 4ff7adc36..69419a0fc 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/Base/linux/Types.h +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/Base/linux/Types.h @@ -1,45 +1,45 @@ -//////////////////////////////////////// -// Types.h -// -// Purpose: -// 1. Define integer types that are unambiguous with respect to size -// -// Revisions: -// 07/10/2001 Created -// - -#ifndef BASE_LINUX_TYPES_H -#define BASE_LINUX_TYPES_H - -#include - -#ifdef EXTERNAL_DISTRO -namespace NAMESPACE -{ - -#endif - -namespace Base -{ - -#ifndef INT32_MAX -#define INT32_MAX 0x7FFFFFFF -#define INT32_MIN 0x80000000 -#define UINT32_MAX 0xFFFFFFFF -#endif - -typedef signed char int8; -typedef unsigned char uint8; -typedef signed short int16; -typedef unsigned short uint16; - -typedef int32_t int32; -typedef u_int32_t uint32; -typedef int64_t int64; -typedef u_int64_t uint64; -} -#ifdef EXTERNAL_DISTRO -}; -#endif -#endif // BASE_LINUX_TYPES_H - +//////////////////////////////////////// +// Types.h +// +// Purpose: +// 1. Define integer types that are unambiguous with respect to size +// +// Revisions: +// 07/10/2001 Created +// + +#ifndef BASE_LINUX_TYPES_H +#define BASE_LINUX_TYPES_H + +#include + +#ifdef EXTERNAL_DISTRO +namespace NAMESPACE +{ + +#endif + +namespace Base +{ + +#ifndef INT32_MAX +#define INT32_MAX 0x7FFFFFFF +#define INT32_MIN 0x80000000 +#define UINT32_MAX 0xFFFFFFFF +#endif + +typedef signed char int8; +typedef unsigned char uint8; +typedef signed short int16; +typedef unsigned short uint16; + +typedef int32_t int32; +typedef u_int32_t uint32; +typedef int64_t int64; +typedef u_int64_t uint64; +} +#ifdef EXTERNAL_DISTRO +}; +#endif +#endif // BASE_LINUX_TYPES_H + diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCharacter.h b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCharacter.h index c9582d982..b880941a0 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCharacter.h +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCharacter.h @@ -18,9 +18,12 @@ class CTServiceCharacter target[0] = 0; return; } + int offset = 0; - while (offset < length && (target[offset++] = source[offset])); - target[length-1] = 0; + while (offset < length && (target[(offset+1)] = source[offset])) { + target[length-1] = 0; + offset++; + } } public: enum { CHARACTER_SIZE=64, CHARACTER_BUFFER, REASON_SIZE=4096, REASON_BUFFER }; diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCustomer.h b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCustomer.h index e8a580d03..cf5d2f276 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCustomer.h +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceCustomer.h @@ -19,10 +19,14 @@ class CTServiceCustomer target[0] = 0; return; } + int offset = 0; - while (offset < length && (target[offset++] = source[offset])); - target[length-1] = 0; + while (offset < length && (target[(offset+1)] = source[offset])){ + target[length-1] = 0; + offset++; + } } + public: enum { SHORT_NAME_SIZE=64, SHORT_NAME_BUFFER, PHONE_SIZE=32, PHONE_BUFFER, diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBOrder.h b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBOrder.h index c10f6890e..cbd79ad8d 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBOrder.h +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBOrder.h @@ -22,9 +22,12 @@ class CTServiceDBOrder target[0] = 0; return; } + int offset = 0; - while (offset < length && (target[offset++] = source[offset])); - target[length-1] = 0; + while (offset < length && (target[(offset+1)] = source[offset])){ + target[length-1] = 0; + offset++; + } } public: diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBTransaction.h b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBTransaction.h index 21dace6c0..b96efe7f0 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBTransaction.h +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceDBTransaction.h @@ -21,9 +21,12 @@ class CTServiceTransaction target[0] = 0; return; } + int offset = 0; - while (offset < length && (target[offset++] = source[offset])); - target[length-1] = 0; + while (offset < length && (target[(offset+1)] = source[offset])){ + target[length-1] = 0; + offset++; + } } public: diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceServer.h b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceServer.h index 7d76ddff7..5cef4bde0 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceServer.h +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceServer.h @@ -17,9 +17,12 @@ class CTServiceServer target[0] = 0; return; } + int offset = 0; - while (offset < length && (target[offset++] = source[offset])); - target[length-1] = 0; + while (offset < length && (target[(offset+1)] = source[offset])) { + target[length-1] = 0; + offset++; + } } public: enum { SERVER_SIZE=64, SERVER_BUFFER, REASON_SIZE=4096, REASON_BUFFER }; diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceWebAPITransaction.h b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceWebAPITransaction.h index b51fe366f..47005521b 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceWebAPITransaction.h +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/CTCommon/CTServiceWebAPITransaction.h @@ -21,9 +21,12 @@ class CTServiceWebAPITransaction target[0] = 0; return; } + int offset = 0; - while (offset < length && (target[offset++] = source[offset])); - target[length-1] = 0; + while (offset < length && (target[(offset+1)] = source[offset])) { + target[length-1] = 0; + offset++; + } } typedef unsigned short uchar_t; diff --git a/src/external/3rd/library/soePlatform/CTServiceGameAPI/TcpLibrary/Clock.cpp b/src/external/3rd/library/soePlatform/CTServiceGameAPI/TcpLibrary/Clock.cpp index 2f5f47b4c..9b317d05a 100644 --- a/src/external/3rd/library/soePlatform/CTServiceGameAPI/TcpLibrary/Clock.cpp +++ b/src/external/3rd/library/soePlatform/CTServiceGameAPI/TcpLibrary/Clock.cpp @@ -45,10 +45,11 @@ ClockStamp Clock::getCurTime() return ret; #else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wuninitialized" struct timeval tv; - int err; - err = gettimeofday(&tv, NULL); return (static_cast(tv.tv_sec) * 1000 + static_cast(tv.tv_usec / 1000)); +#pragma clang diagnostic pop #endif } diff --git a/src/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.cpp b/src/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.cpp index 7e88557a4..25d587fc8 100644 --- a/src/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.cpp +++ b/src/external/3rd/library/soePlatform/ChatAPI/projects/ChatAPI/Response.cpp @@ -28,7 +28,7 @@ ResLoginAvatar::ResLoginAvatar(void *user, int avatarLoginPriority) void ResLoginAvatar::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + Plat_Unicode::String email; unsigned inboxLimit = 0; @@ -69,7 +69,7 @@ ResTemporaryAvatar::ResTemporaryAvatar(void *user) void ResTemporaryAvatar::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -88,7 +88,7 @@ ResLogoutAvatar::ResLogoutAvatar(void *user, unsigned avatarID) void ResLogoutAvatar::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -102,7 +102,7 @@ ResDestroyAvatar::ResDestroyAvatar(void *user, unsigned avatarID) void ResDestroyAvatar::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -116,7 +116,7 @@ ResGetAvatar::ResGetAvatar(void *user) void ResGetAvatar::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -150,7 +150,7 @@ ResGetAnyAvatar::ResGetAnyAvatar(void* user) void ResGetAnyAvatar::unpack(Base::ByteStream::ReadIterator& iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -194,7 +194,7 @@ ResAvatarList::~ResAvatarList() void ResAvatarList::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -220,7 +220,7 @@ ResSetAvatarAttributes::ResSetAvatarAttributes(void *user) void ResSetAvatarAttributes::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -254,7 +254,7 @@ m_avatar(NULL) void ResSetAvatarStatusMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -291,7 +291,7 @@ ResSetAvatarForwardingEmail::ResSetAvatarForwardingEmail(void *user) void ResSetAvatarForwardingEmail::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -318,7 +318,7 @@ ResSetAvatarInboxLimit::ResSetAvatarInboxLimit(void *user) void ResSetAvatarInboxLimit::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -346,7 +346,7 @@ ResSearchAvatarKeywords::ResSearchAvatarKeywords(void *user) void ResSearchAvatarKeywords::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -379,7 +379,7 @@ ResSetAvatarKeywords::ResSetAvatarKeywords(void *user, unsigned avatarID) void ResSetAvatarKeywords::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -401,7 +401,7 @@ ResGetAvatarKeywords::~ResGetAvatarKeywords() void ResGetAvatarKeywords::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -427,7 +427,7 @@ ResGetRoom::ResGetRoom(void *user) void ResGetRoom::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -455,7 +455,7 @@ ResCreateRoom::ResCreateRoom(void *user, unsigned avatarID) void ResCreateRoom::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -481,7 +481,7 @@ ResDestroyRoom::ResDestroyRoom(void *user, unsigned avatarID) void ResDestroyRoom::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -498,7 +498,7 @@ ResSendInstantMessage::ResSendInstantMessage(void *user, unsigned avatarID, cons void ResSendInstantMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -513,7 +513,7 @@ ResSendRoomMessage::ResSendRoomMessage(void *user, unsigned avatarID) void ResSendRoomMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -529,7 +529,7 @@ ResSendBroadcastMessage::ResSendBroadcastMessage(void *user, unsigned avatarID, void ResSendBroadcastMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -543,7 +543,7 @@ ResFilterMessage::ResFilterMessage(void *user, unsigned version) void ResFilterMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -561,7 +561,7 @@ ResAddFriend::ResAddFriend(void *user, unsigned avatarID, const ChatUnicodeStrin void ResAddFriend::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -578,7 +578,7 @@ m_comment(comment.string_data, comment.string_length) void ResAddFriendReciprocate::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -596,7 +596,7 @@ ResSetFriendComment::ResSetFriendComment(void *user, unsigned avatarID, const Ch void ResSetFriendComment::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -612,7 +612,7 @@ ResRemoveFriend::ResRemoveFriend(void *user, unsigned avatarID, const ChatUnicod void ResRemoveFriend::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -627,7 +627,7 @@ m_address(address.string_data, address.string_length) void ResRemoveFriendReciprocate::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -650,7 +650,7 @@ ResFriendStatus::~ResFriendStatus() void ResFriendStatus::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -678,7 +678,7 @@ ResAddIgnore::ResAddIgnore(void *user, unsigned avatarID, const ChatUnicodeStrin void ResAddIgnore::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -694,7 +694,7 @@ ResRemoveIgnore::ResRemoveIgnore(void *user, unsigned avatarID, const ChatUnicod void ResRemoveIgnore::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -717,7 +717,7 @@ ResIgnoreStatus::~ResIgnoreStatus() void ResIgnoreStatus::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -747,7 +747,7 @@ ResEnterRoom::ResEnterRoom(void *user, unsigned avatarID, const ChatUnicodeStrin void ResEnterRoom::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -778,7 +778,7 @@ ResAllowRoomEntry::ResAllowRoomEntry(void *user, unsigned srcAvatarID, const Cha void ResAllowRoomEntry::unpack(Base::ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -794,7 +794,7 @@ ResLeaveRoom::ResLeaveRoom(void *user, unsigned avatarID, const ChatUnicodeStrin void ResLeaveRoom::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -810,7 +810,7 @@ ResAddModerator::ResAddModerator(void *user, unsigned srcAvatarID) void ResAddModerator::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -826,7 +826,7 @@ ResRemoveModerator::ResRemoveModerator(void *user, unsigned srcAvatarID) void ResRemoveModerator::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -842,7 +842,7 @@ ResAddTemporaryModerator::ResAddTemporaryModerator(void *user, unsigned srcAvata void ResAddTemporaryModerator::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -858,7 +858,7 @@ ResRemoveTemporaryModerator::ResRemoveTemporaryModerator(void *user, unsigned sr void ResRemoveTemporaryModerator::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -874,7 +874,7 @@ ResAddBan::ResAddBan(void *user, unsigned srcAvatarID) void ResAddBan::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -890,7 +890,7 @@ ResRemoveBan::ResRemoveBan(void *user, unsigned srcAvatarID) void ResRemoveBan::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -906,7 +906,7 @@ ResAddInvite::ResAddInvite(void *user, unsigned srcAvatarID) void ResAddInvite::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -922,7 +922,7 @@ ResRemoveInvite::ResRemoveInvite(void *user, unsigned srcAvatarID) void ResRemoveInvite::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -938,7 +938,7 @@ ResGrantVoice::ResGrantVoice(void *user, unsigned srcAvatarID) void ResGrantVoice::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -954,7 +954,7 @@ ResRevokeVoice::ResRevokeVoice(void *user, unsigned srcAvatarID) void ResRevokeVoice::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -970,7 +970,7 @@ ResKickAvatar::ResKickAvatar(void *user, unsigned srcAvatarID) void ResKickAvatar::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -986,7 +986,7 @@ ResSetRoomParams::ResSetRoomParams(void *user, unsigned srcAvatarID) void ResSetRoomParams::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1002,7 +1002,7 @@ ResChangeRoomOwner::ResChangeRoomOwner(void *user, unsigned srcAvatarID) void ResChangeRoomOwner::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1023,7 +1023,7 @@ ResGetRoomSummaries::~ResGetRoomSummaries() void ResGetRoomSummaries::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1062,7 +1062,7 @@ ResSendPersistentMessage::ResSendPersistentMessage(void *user, unsigned srcAvata void ResSendPersistentMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1082,7 +1082,7 @@ ResSendMultiplePersistentMessages::ResSendMultiplePersistentMessages(void *user, void ResSendMultiplePersistentMessages::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + unsigned resultIndex; get(iter, m_type); @@ -1122,7 +1122,7 @@ ResAlterPersistentMessage::~ResAlterPersistentMessage() void ResAlterPersistentMessage::unpack(Base::ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1144,7 +1144,7 @@ ResGetPersistentMessage::~ResGetPersistentMessage() } void ResGetPersistentMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1193,7 +1193,7 @@ PersistentMessage ** const ResGetMultiplePersistentMessages::getList() const void ResGetMultiplePersistentMessages::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1230,7 +1230,7 @@ ResGetPersistentHeaders::~ResGetPersistentHeaders() void ResGetPersistentHeaders::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1276,7 +1276,7 @@ ResGetPartialPersistentHeaders::~ResGetPartialPersistentHeaders() void ResGetPartialPersistentHeaders::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1315,7 +1315,7 @@ ResCountPersistentMessages::ResCountPersistentMessages(void *user, const ChatUni void ResCountPersistentMessages::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1331,7 +1331,7 @@ ResUpdatePersistentMessage::ResUpdatePersistentMessage(void *user, unsigned srcA void ResUpdatePersistentMessage::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1358,7 +1358,7 @@ ResClassifyPersistentMessages::ResClassifyPersistentMessages(void *user, unsigne void ResClassifyPersistentMessages::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1374,7 +1374,7 @@ ResDeleteAllPersistentMessages::ResDeleteAllPersistentMessages(void *user, const void ResDeleteAllPersistentMessages::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1468,7 +1468,7 @@ ResGetFanClubHandle::ResGetFanClubHandle(unsigned stationID, unsigned fanClubCod void ResGetFanClubHandle::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1494,7 +1494,7 @@ ResFindAvatarByUID::~ResFindAvatarByUID() void ResFindAvatarByUID::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1518,7 +1518,7 @@ ResRegistrarGetChatServer::ResRegistrarGetChatServer() void ResRegistrarGetChatServer::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); @@ -1622,7 +1622,7 @@ ResGetSnoopList::~ResGetSnoopList() void ResGetSnoopList::unpack(ByteStream::ReadIterator &iter) { - unsigned numRead = 0; + get(iter, m_type); get(iter, m_track); get(iter, m_result); diff --git a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.cpp b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.cpp index f8d7d1ccc..cfa250070 100644 --- a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.cpp +++ b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.cpp @@ -170,7 +170,7 @@ namespace Base return bytes; } - bool Base64::UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen) + bool Base64::UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, int *destLen) { unsigned char q[3]; unsigned index; diff --git a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.h b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.h index 735424957..6f1d08589 100644 --- a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.h +++ b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/Base64.h @@ -15,7 +15,7 @@ namespace Base public: static bool UUEncode(const unsigned char *source, unsigned sourceLen, char *dest, unsigned destLen); static bool UUEncode(const unsigned char *source, unsigned sourceLen, std::string &destString); - static bool UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen); + static bool UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, int *destLen); static bool UUDecode(const char *source, unsigned sourceLen, std::string &destString); // these don't *exactly* belong here, but it's a convenient place for them diff --git a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.cpp b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.cpp index a988f46b3..31d75dcb8 100644 --- a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.cpp +++ b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/MD5.cpp @@ -59,7 +59,7 @@ namespace Base int k = l = 0; for(; l < i; l += 4) { - ai[k] = achar0[l + j] & 0xff | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; + ai[k] = (achar0[l + j] & 0xff) | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; k++; } @@ -84,7 +84,7 @@ namespace Base int MD5::FF(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & k | ~j & l, i1, k1); + i = uadd(i, (j & k) | (~j & l), i1, k1); return uadd(rotate_left(i, j1), j); } @@ -106,7 +106,7 @@ namespace Base int MD5::GG(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & l | k & ~l, i1, k1); + i = uadd(i, (j & l) | (k & ~l), i1, k1); return uadd(rotate_left(i, j1), j); } diff --git a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.cpp b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.cpp index 287812738..8d97c1850 100644 --- a/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.cpp +++ b/src/external/3rd/library/soePlatform/ChatAPI/utils/Base/ccspanutil.cpp @@ -73,7 +73,6 @@ char * CSpanUtil::getDescriptionFromCardNum(const char *cardNum) char temp[8]; memcpy(temp, cardNum, 7); temp[7] = 0; - int value7 = atoi(temp); temp[6] = 0; int value6 = atoi(temp); temp[5] = 0; diff --git a/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHashTable.h b/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHashTable.h index ba9f17481..10af003da 100644 --- a/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHashTable.h +++ b/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpHashTable.h @@ -614,7 +614,7 @@ inline int UpperHashString(const char *string) int h = 0; while (*string != 0) { - h = ((31 * h) + (*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26); + h = ((31 * h) + (((*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26))); string++; } return(h); diff --git a/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpPriority.h b/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpPriority.h index 6b4f5968f..c50dee629 100644 --- a/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpPriority.h +++ b/src/external/3rd/library/soePlatform/ChatAPI/utils/UdpLibrary/UdpPriority.h @@ -83,7 +83,7 @@ template PriorityQueue::PriorityQueue(int queueSiz mQueueEnd = 0; mQueueSize = queueSize; mQueue = new QueueEntry[mQueueSize]; - memset(mQueue, 0, sizeof(mQueue)); + memset(mQueue, 0, mQueueSize); } template PriorityQueue::~PriorityQueue() diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.cpp b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.cpp index 3aba1fb2d..efc420f3f 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.cpp +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.cpp @@ -168,7 +168,7 @@ namespace soe return bytes; } - bool Base64::UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen) + bool Base64::UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, int *destLen) { unsigned char q[3]; unsigned index; @@ -315,7 +315,7 @@ namespace soe UUEncodeTripleToQuadPtr(source + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z)); destLen -= strlen(quad); if (destLen > 0) { - dest += snprintf(dest, sizeof(dest), quad); + dest += snprintf(dest, sourceLen, quad); } else { noErrors = false; } @@ -355,7 +355,7 @@ namespace soe { UUEncodeTripleToQuadRef(source.begin() + z,quad,(z + 3 < sourceLen) ? 3 : (sourceLen - z)); if (destLen > 0) { - dest += snprintf(dest, sizeof(dest), quad); + dest += snprintf(dest, sourceLen, quad); } else { noErrors = false; } @@ -389,7 +389,7 @@ namespace soe for (; sourceLen > 0; sourceLen--, source++) { if (destLen >= 2) { - destLen -= snprintf(dest, sizeof(dest), format, *source); + destLen -= snprintf(dest, sourceLen, format, *source); } else { noErrors = false; } diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.h b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.h index ac450794a..3a8635879 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.h +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/Base64.h @@ -13,7 +13,7 @@ namespace soe static bool UUEncode(const unsigned char *source, unsigned sourceLen, std::string &destString); static bool UUEncode(const std::vector &source, char *dest, unsigned destLen); static bool UUEncode(const std::vector &source, std::string &destString); - static bool UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, unsigned *destLen); + static bool UUDecode(const char *source, unsigned sourceLen, unsigned char *dest, int *destLen); static bool UUDecode(const char *source, unsigned sourceLen, std::vector &destVector); static bool UUDecode(const char *source, unsigned sourceLen, std::string &destString); diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/MD5.cpp b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/MD5.cpp index 50f3887d0..54e7e9fa1 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/MD5.cpp +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/MD5.cpp @@ -54,7 +54,7 @@ namespace soe int k = l = 0; for(; l < i; l += 4) { - ai[k] = achar0[l + j] & 0xff | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; + ai[k] = (achar0[l + j] & 0xff) | (achar0[l + 1 + j] & 0xff) << 8 | (achar0[l + 2 + j] & 0xff) << 16 | (achar0[l + 3 + j] & 0xff) << 24; k++; } @@ -79,7 +79,7 @@ namespace soe int MD5::FF(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & k | ~j & l, i1, k1); + i = uadd(i, (j & k) | (~j & l), i1, k1); return uadd(rotate_left(i, j1), j); } @@ -101,7 +101,7 @@ namespace soe int MD5::GG(int i, int j, int k, int l, int i1, int j1, int k1) { - i = uadd(i, j & l | k & ~l, i1, k1); + i = uadd(i, (j & l) | (k & ~l), i1, k1); return uadd(rotate_left(i, j1), j); } diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/hashtable.hpp b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/hashtable.hpp index 0256f2978..00f9cd759 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/hashtable.hpp +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/hashtable.hpp @@ -155,7 +155,7 @@ inline int UpperHashString(char *string) int h = 0; while (*string != 0) { - h = ((31 * h) + (*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26); + h = ((31 * h) + (((*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26))); string++; } return(h); diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/pid.cpp b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/pid.cpp index 6097fd7b3..6a1d7b564 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/pid.cpp +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/pid.cpp @@ -44,13 +44,7 @@ std::string soegethostname() char res[NAME_SIZE]; memset(res, 0, NAME_SIZE); std::string retVal; - int error = gethostname(res, NAME_SIZE-1); - int errdetail; - if(error !=0) - { - errdetail = errno; - } retVal = res; return retVal; } diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/priority.hpp b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/priority.hpp index 82751efa2..19f34ab3f 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/priority.hpp +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/priority.hpp @@ -77,7 +77,7 @@ template PriorityQueue::PriorityQueue(int queueSiz mQueueEnd = 0; mQueueSize = queueSize; mQueue = new QueueEntry[mQueueSize]; - memset(mQueue, 0, sizeof(mQueue)); + memset(mQueue, 0, mQueueSize); } template PriorityQueue::~PriorityQueue() diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeStringVector.h b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeStringVector.h index f27f37ad9..7beccb4dc 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeStringVector.h +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeStringVector.h @@ -221,9 +221,6 @@ namespace soe return bytes; } - operator stringVector_t () { return *this; } - - //unsigned Read(const unsigned char * stream, unsigned size); //DECLARE_SCRIBE_MEMBERS }; diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeTemplates.h b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeTemplates.h index 4af421bbc..c2f745ed7 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeTemplates.h +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/serializeTemplates.h @@ -719,9 +719,10 @@ namespace soe int ClassScribe::Print(char * stream, unsigned size, const ClassType & data, unsigned maxDepth) const { int bytesTotal = 0; - int bytes = 0; #ifdef PRINTABLE_MESSAGES + int bytes = 0; + if (maxDepth == 0) { bytes = snprintf(stream, size, "%s{mMembers(%u)}", ClassName(), mMemberScribes.size()); return bytes; diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/utf8.cpp b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/utf8.cpp index 9cc64b437..ce6b8f167 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/utf8.cpp +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/Base/utf8.cpp @@ -264,7 +264,7 @@ namespace soe { int wchar_length=0; //number of utf-8 characters int code_size; //number of bytes each wchar - int cur_bytes_count = 0; + unsigned cur_bytes_count = 0; unsigned char byte; char *pout = output; diff --git a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/TcpLibrary/Clock.cpp b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/TcpLibrary/Clock.cpp index 2f5f47b4c..2b7265bc2 100644 --- a/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/TcpLibrary/Clock.cpp +++ b/src/external/3rd/library/soePlatform/VChatAPI/utils2.0/utils/TcpLibrary/Clock.cpp @@ -46,8 +46,6 @@ ClockStamp Clock::getCurTime() return ret; #else struct timeval tv; - int err; - err = gettimeofday(&tv, NULL); return (static_cast(tv.tv_sec) * 1000 + static_cast(tv.tv_usec / 1000)); #endif } diff --git a/src/external/3rd/library/udplibrary/hashtable.hpp b/src/external/3rd/library/udplibrary/hashtable.hpp index 8d9e80b7e..8c7340bce 100644 --- a/src/external/3rd/library/udplibrary/hashtable.hpp +++ b/src/external/3rd/library/udplibrary/hashtable.hpp @@ -148,7 +148,7 @@ inline int UpperHashString(char *string) int h = 0; while (*string != 0) { - h = ((31 * h) + (*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26); + h = ((31 * h) + (((*string >= 'a' && *string <= 'z') ? (*string - 0x20) : *string) ^ (h >> 26))); string++; } return(h); diff --git a/src/external/3rd/library/udplibrary/priority.hpp b/src/external/3rd/library/udplibrary/priority.hpp index 82751efa2..19f34ab3f 100644 --- a/src/external/3rd/library/udplibrary/priority.hpp +++ b/src/external/3rd/library/udplibrary/priority.hpp @@ -77,7 +77,7 @@ template PriorityQueue::PriorityQueue(int queueSiz mQueueEnd = 0; mQueueSize = queueSize; mQueue = new QueueEntry[mQueueSize]; - memset(mQueue, 0, sizeof(mQueue)); + memset(mQueue, 0, mQueueSize); } template PriorityQueue::~PriorityQueue() diff --git a/src/external/ours/library/crypto/src/shared/original/cryptlib.cpp b/src/external/ours/library/crypto/src/shared/original/cryptlib.cpp index c3c1df06c..86e2d4d36 100644 --- a/src/external/ours/library/crypto/src/shared/original/cryptlib.cpp +++ b/src/external/ours/library/crypto/src/shared/original/cryptlib.cpp @@ -50,8 +50,10 @@ void StreamCipher::ProcessString(byte *outString, const byte *inString, unsigned void StreamCipher::ProcessString(byte *inoutString, unsigned int length) { - while(length--) - *inoutString++ = ProcessByte(*inoutString); //TODO: order of operations issue here, per the warning + while(length--) { + (*inoutString)++; + *inoutString = ProcessByte(*inoutString); + } } bool HashModule::Verify(const byte *digestIn) diff --git a/src/external/ours/library/crypto/src/shared/original/filters.cpp b/src/external/ours/library/crypto/src/shared/original/filters.cpp index b7c462f8d..7caaf21db 100644 --- a/src/external/ours/library/crypto/src/shared/original/filters.cpp +++ b/src/external/ours/library/crypto/src/shared/original/filters.cpp @@ -1,424 +1,424 @@ -// filters.cpp - written and placed in the public domain by Wei Dai - -#include "FirstCrypto.h" -#include "filters.h" -#include "mqueue.h" -#include - -NAMESPACE_BEGIN(CryptoPP) - -BitBucket g_bitBucket; - -Filter::Filter(BufferedTransformation *outQ) - : m_outQueue(outQ ? outQ : new MessageQueue) -{ -} - -void Filter::Detach(BufferedTransformation *newOut) -{ - m_outQueue.reset(newOut ? newOut : new MessageQueue); - NotifyAttachmentChange(); -} - -void Filter::Insert(Filter *filter) -{ - filter->m_outQueue.reset(m_outQueue.release()); - m_outQueue.reset(filter); - NotifyAttachmentChange(); -} - -// ************************************************************* - -FilterWithBufferedInput::BlockQueue::BlockQueue(unsigned int blockSize, unsigned int maxBlocks) - : m_buffer(blockSize * maxBlocks) -{ - ResetQueue(blockSize, maxBlocks); -} - -void FilterWithBufferedInput::BlockQueue::ResetQueue(unsigned int blockSize, unsigned int maxBlocks) -{ - m_buffer.Resize(blockSize * maxBlocks); - m_blockSize = blockSize; - m_maxBlocks = maxBlocks; - m_size = 0; - m_begin = m_buffer; -} - -const byte *FilterWithBufferedInput::BlockQueue::GetBlock() -{ - if (m_size >= m_blockSize) - { - const byte *ptr = m_begin; - if ((m_begin+=m_blockSize) == m_buffer.End()) - m_begin = m_buffer; - m_size -= m_blockSize; - return ptr; - } - else - return NULL; -} - -const byte *FilterWithBufferedInput::BlockQueue::GetContigousBlocks(unsigned int &numberOfBlocks) -{ - numberOfBlocks = STDMIN(numberOfBlocks, STDMIN((unsigned int)(m_buffer.End()-m_begin), m_size)/m_blockSize); - const byte *ptr = m_begin; - if ((m_begin+=m_blockSize*numberOfBlocks) == m_buffer.End()) - m_begin = m_buffer; - m_size -= m_blockSize*numberOfBlocks; - return ptr; -} - -unsigned int FilterWithBufferedInput::BlockQueue::GetAll(byte *outString) -{ - unsigned int size = m_size; - unsigned int numberOfBlocks = m_maxBlocks; - const byte *ptr = GetContigousBlocks(numberOfBlocks); - memcpy(outString, ptr, numberOfBlocks*m_blockSize); - memcpy(outString+numberOfBlocks*m_blockSize, m_begin, m_size); - m_size = 0; - return size; -} - -void FilterWithBufferedInput::BlockQueue::Put(const byte *inString, unsigned int length) -{ - assert(m_size + length <= m_buffer.size); - byte *end = (m_size < m_buffer+m_buffer.size-m_begin) ? m_begin + m_size : m_begin + m_size - m_buffer.size; - unsigned int len = STDMIN(length, (unsigned int)(m_buffer+m_buffer.size-end)); - memcpy(end, inString, len); - if (len < length) - memcpy(m_buffer, inString+len, length-len); - m_size += length; -} - -FilterWithBufferedInput::FilterWithBufferedInput(unsigned int firstSize, unsigned int blockSize, unsigned int lastSize, BufferedTransformation *outQ) - : Filter(outQ), m_firstSize(firstSize), m_blockSize(blockSize), m_lastSize(lastSize) - , m_firstInputDone(false) - , m_queue(1, m_firstSize) -{ -} - -void FilterWithBufferedInput::Put(byte inByte) -{ - Put(&inByte, 1); -} - -void FilterWithBufferedInput::Put(const byte *inString, unsigned int length) -{ - if (length == 0) - return; - - unsigned int newLength = m_queue.CurrentSize() + length; - - if (!m_firstInputDone && newLength >= m_firstSize) - { - unsigned int len = m_firstSize - m_queue.CurrentSize(); - m_queue.Put(inString, len); - FirstPut(m_queue.GetContigousBlocks(m_firstSize)); - assert(m_queue.CurrentSize() == 0); - m_queue.ResetQueue(m_blockSize, (2*m_blockSize+m_lastSize-2)/m_blockSize); - - inString += len; - newLength -= m_firstSize; - m_firstInputDone = true; - } - - if (m_firstInputDone) - { - if (m_blockSize == 1) - { - while (newLength > m_lastSize && m_queue.CurrentSize() > 0) - { - unsigned int len = newLength - m_lastSize; - const byte *ptr = m_queue.GetContigousBlocks(len); - NextPut(ptr, len); - newLength -= len; - } - - if (newLength > m_lastSize) - { - unsigned int len = newLength - m_lastSize; - NextPut(inString, len); - inString += len; - newLength -= len; - } - } - else - { - while (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() >= m_blockSize) - { - NextPut(m_queue.GetBlock(), m_blockSize); - newLength -= m_blockSize; - } - - if (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() > 0) - { - assert(m_queue.CurrentSize() < m_blockSize); - unsigned int len = m_blockSize - m_queue.CurrentSize(); - m_queue.Put(inString, len); - inString += len; - NextPut(m_queue.GetBlock(), m_blockSize); - newLength -= m_blockSize; - } - - while (newLength >= m_blockSize + m_lastSize) - { - NextPut(inString, m_blockSize); - inString += m_blockSize; - newLength -= m_blockSize; - } - } - } - - m_queue.Put(inString, newLength - m_queue.CurrentSize()); -} - -void FilterWithBufferedInput::MessageEnd(int propagation) -{ - if (!m_firstInputDone && m_firstSize==0) - FirstPut(NULL); - - SecByteBlock temp(m_queue.CurrentSize()); - m_queue.GetAll(temp); - LastPut(temp, temp.size); - - m_firstInputDone = false; - m_queue.ResetQueue(1, m_firstSize); - - Filter::MessageEnd(propagation); -} - -void FilterWithBufferedInput::ForceNextPut() -{ - if (m_firstInputDone && m_queue.CurrentSize() >= m_blockSize) - NextPut(m_queue.GetBlock(), m_blockSize); -} - -// ************************************************************* - - - -// ************************************************************* - -ProxyFilter::ProxyFilter(Filter *filter, unsigned int firstSize, unsigned int lastSize, BufferedTransformation *outQ) - : FilterWithBufferedInput(firstSize, 1, lastSize, outQ), m_filter(filter), m_proxy(NULL) -{ - if (m_filter.get()) - m_filter->Attach(m_proxy = new OutputProxy(*this, false)); -} - -void ProxyFilter::Flush(bool completeFlush, int propagation) -{ - if (m_filter.get()) - { - bool passSignal = m_proxy->GetPassSignal(); - m_proxy->SetPassSignal(false); - m_filter->Flush(completeFlush, -1); - m_proxy->SetPassSignal(passSignal); - } - Filter::Flush(completeFlush, propagation); -} - -void ProxyFilter::SetFilter(Filter *filter) -{ - bool passSignal = m_proxy ? m_proxy->GetPassSignal() : false; - m_filter.reset(filter); - if (filter) - { - std::unique_ptr temp(m_proxy = new OutputProxy(*this, passSignal)); - m_filter->TransferAllTo(*m_proxy); - m_filter->Attach(temp.release()); - } - else - m_proxy=NULL; -} - -void ProxyFilter::NextPut(const byte *s, unsigned int len) -{ - if (m_filter.get()) - m_filter->Put(s, len); -} - -// ************************************************************* - -void StreamCipherFilter::Put(const byte *inString, unsigned int length) -{ - SecByteBlock temp(length); - cipher.ProcessString(temp, inString, length); - AttachedTransformation()->Put(temp, length); -} - -void HashFilter::Put(byte inByte) -{ - m_hashModule.Update(&inByte, 1); - if (m_putMessage) - AttachedTransformation()->Put(inByte); -} - -void HashFilter::Put(const byte *inString, unsigned int length) -{ - m_hashModule.Update(inString, length); - if (m_putMessage) - AttachedTransformation()->Put(inString, length); -} - -void HashFilter::MessageEnd(int propagation) -{ - SecByteBlock buf(m_hashModule.DigestSize()); - m_hashModule.Final(buf); - AttachedTransformation()->Put(buf, buf.size); - Filter::MessageEnd(propagation); -} - -// ************************************************************* - -HashVerifier::HashVerifier(HashModule &hm, BufferedTransformation *outQueue, word32 flags) - : FilterWithBufferedInput(flags & HASH_AT_BEGIN ? hm.DigestSize() : 0, 1, flags & HASH_AT_BEGIN ? 0 : hm.DigestSize(), outQueue) - , m_hashModule(hm), m_flags(flags) - , m_expectedHash(flags & HASH_AT_BEGIN ? hm.DigestSize() : 0), m_verified(false) -{ -} - -void HashVerifier::FirstPut(const byte *inString) -{ - if (m_flags & HASH_AT_BEGIN) - { - memcpy(m_expectedHash, inString, m_expectedHash.size); - if (m_flags & PUT_HASH) - AttachedTransformation()->Put(inString, m_expectedHash.size); - } -} - -void HashVerifier::NextPut(const byte *inString, unsigned int length) -{ - m_hashModule.Update(inString, length); - if (m_flags & PUT_MESSAGE) - AttachedTransformation()->Put(inString, length); -} - -void HashVerifier::LastPut(const byte *inString, unsigned int length) -{ - if (m_flags & HASH_AT_BEGIN) - { - assert(length == 0); - m_verified = m_hashModule.Verify(m_expectedHash); - } - else - { - m_verified = (length==m_hashModule.DigestSize() && m_hashModule.Verify(inString)); - if (m_flags & PUT_HASH) - AttachedTransformation()->Put(inString, length); - } - - if (m_flags & PUT_RESULT) - AttachedTransformation()->Put(m_verified); - - if ((m_flags & THROW_EXCEPTION) && !m_verified) - throw HashVerificationFailed(); -} - -// ************************************************************* - -void SignerFilter::MessageEnd(int propagation) -{ - SecByteBlock buf(m_signer.SignatureLength()); - m_signer.Sign(m_rng, m_messageAccumulator.release(), buf); - AttachedTransformation()->Put(buf, buf.size); - Filter::MessageEnd(propagation); - m_messageAccumulator.reset(m_signer.NewMessageAccumulator()); -} - -void VerifierFilter::PutSignature(const byte *sig) -{ - memcpy(m_signature.ptr, sig, m_signature.size); -} - -void VerifierFilter::MessageEnd(int propagation) -{ - AttachedTransformation()->Put((byte)m_verifier.Verify(m_messageAccumulator.release(), m_signature)); - Filter::MessageEnd(propagation); - m_messageAccumulator.reset(m_verifier.NewMessageAccumulator()); -} - -// ************************************************************* - -void Source::PumpAll() -{ - while (PumpMessages()) {} - while (Pump()) {} -} - -StringSource::StringSource(const char *string, bool pumpAll, BufferedTransformation *outQueue) - : Source(outQueue), m_store(string) -{ - if (pumpAll) - PumpAll(); -} - -StringSource::StringSource(const byte *string, unsigned int length, bool pumpAll, BufferedTransformation *outQueue) - : Source(outQueue), m_store(string, length) -{ - if (pumpAll) - PumpAll(); -} - -bool Store::GetNextMessage() -{ - if (!m_messageEnd && !AnyRetrievable()) - { - m_messageEnd=true; - return true; - } - else - return false; -} - -unsigned int Store::CopyMessagesTo(BufferedTransformation &target, unsigned int count) const -{ - if (m_messageEnd || count == 0) - return 0; - else - { - CopyTo(target); - if (GetAutoSignalPropagation()) - target.MessageEnd(GetAutoSignalPropagation()-1); - return 1; - } -} - -unsigned long StringStore::TransferTo(BufferedTransformation &target, unsigned long transferMax) -{ - unsigned long result = CopyTo(target, transferMax); - m_count += result; - return result; -} - -unsigned long StringStore::CopyTo(BufferedTransformation &target, unsigned long copyMax) const -{ - unsigned int len = (unsigned int)STDMIN((unsigned long)(m_length-m_count), copyMax); - target.Put(m_store+m_count, len); - return len; -} - -unsigned long RandomNumberStore::CopyTo(BufferedTransformation &target, unsigned long copyMax) const -{ - unsigned int len = (unsigned int)STDMIN((unsigned long)(m_length-m_count), copyMax); - for (unsigned int i=0; i + +NAMESPACE_BEGIN(CryptoPP) + +BitBucket g_bitBucket; + +Filter::Filter(BufferedTransformation *outQ) + : m_outQueue(outQ ? outQ : new MessageQueue) +{ +} + +void Filter::Detach(BufferedTransformation *newOut) +{ + m_outQueue.reset(newOut ? newOut : new MessageQueue); + NotifyAttachmentChange(); +} + +void Filter::Insert(Filter *filter) +{ + filter->m_outQueue.reset(m_outQueue.release()); + m_outQueue.reset(filter); + NotifyAttachmentChange(); +} + +// ************************************************************* + +FilterWithBufferedInput::BlockQueue::BlockQueue(unsigned int blockSize, unsigned int maxBlocks) + : m_buffer(blockSize * maxBlocks) +{ + ResetQueue(blockSize, maxBlocks); +} + +void FilterWithBufferedInput::BlockQueue::ResetQueue(unsigned int blockSize, unsigned int maxBlocks) +{ + m_buffer.Resize(blockSize * maxBlocks); + m_blockSize = blockSize; + m_maxBlocks = maxBlocks; + m_size = 0; + m_begin = m_buffer; +} + +const byte *FilterWithBufferedInput::BlockQueue::GetBlock() +{ + if (m_size >= m_blockSize) + { + const byte *ptr = m_begin; + if ((m_begin+=m_blockSize) == m_buffer.End()) + m_begin = m_buffer; + m_size -= m_blockSize; + return ptr; + } + else + return NULL; +} + +const byte *FilterWithBufferedInput::BlockQueue::GetContigousBlocks(unsigned int &numberOfBlocks) +{ + numberOfBlocks = STDMIN(numberOfBlocks, STDMIN((unsigned int)(m_buffer.End()-m_begin), m_size)/m_blockSize); + const byte *ptr = m_begin; + if ((m_begin+=m_blockSize*numberOfBlocks) == m_buffer.End()) + m_begin = m_buffer; + m_size -= m_blockSize*numberOfBlocks; + return ptr; +} + +unsigned int FilterWithBufferedInput::BlockQueue::GetAll(byte *outString) +{ + unsigned int size = m_size; + unsigned int numberOfBlocks = m_maxBlocks; + const byte *ptr = GetContigousBlocks(numberOfBlocks); + memcpy(outString, ptr, numberOfBlocks*m_blockSize); + memcpy(outString+numberOfBlocks*m_blockSize, m_begin, m_size); + m_size = 0; + return size; +} + +void FilterWithBufferedInput::BlockQueue::Put(const byte *inString, unsigned int length) +{ + assert(m_size + length <= m_buffer.size); + byte *end = (m_size < (unsigned)(m_buffer+m_buffer.size-m_begin)) ? m_begin + m_size : m_begin + m_size - m_buffer.size; + unsigned int len = STDMIN(length, (unsigned int)(m_buffer+m_buffer.size-end)); + memcpy(end, inString, len); + if (len < length) + memcpy(m_buffer, inString+len, length-len); + m_size += length; +} + +FilterWithBufferedInput::FilterWithBufferedInput(unsigned int firstSize, unsigned int blockSize, unsigned int lastSize, BufferedTransformation *outQ) + : Filter(outQ), m_firstSize(firstSize), m_blockSize(blockSize), m_lastSize(lastSize) + , m_firstInputDone(false) + , m_queue(1, m_firstSize) +{ +} + +void FilterWithBufferedInput::Put(byte inByte) +{ + Put(&inByte, 1); +} + +void FilterWithBufferedInput::Put(const byte *inString, unsigned int length) +{ + if (length == 0) + return; + + unsigned int newLength = m_queue.CurrentSize() + length; + + if (!m_firstInputDone && newLength >= m_firstSize) + { + unsigned int len = m_firstSize - m_queue.CurrentSize(); + m_queue.Put(inString, len); + FirstPut(m_queue.GetContigousBlocks(m_firstSize)); + assert(m_queue.CurrentSize() == 0); + m_queue.ResetQueue(m_blockSize, (2*m_blockSize+m_lastSize-2)/m_blockSize); + + inString += len; + newLength -= m_firstSize; + m_firstInputDone = true; + } + + if (m_firstInputDone) + { + if (m_blockSize == 1) + { + while (newLength > m_lastSize && m_queue.CurrentSize() > 0) + { + unsigned int len = newLength - m_lastSize; + const byte *ptr = m_queue.GetContigousBlocks(len); + NextPut(ptr, len); + newLength -= len; + } + + if (newLength > m_lastSize) + { + unsigned int len = newLength - m_lastSize; + NextPut(inString, len); + inString += len; + newLength -= len; + } + } + else + { + while (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() >= m_blockSize) + { + NextPut(m_queue.GetBlock(), m_blockSize); + newLength -= m_blockSize; + } + + if (newLength >= m_blockSize + m_lastSize && m_queue.CurrentSize() > 0) + { + assert(m_queue.CurrentSize() < m_blockSize); + unsigned int len = m_blockSize - m_queue.CurrentSize(); + m_queue.Put(inString, len); + inString += len; + NextPut(m_queue.GetBlock(), m_blockSize); + newLength -= m_blockSize; + } + + while (newLength >= m_blockSize + m_lastSize) + { + NextPut(inString, m_blockSize); + inString += m_blockSize; + newLength -= m_blockSize; + } + } + } + + m_queue.Put(inString, newLength - m_queue.CurrentSize()); +} + +void FilterWithBufferedInput::MessageEnd(int propagation) +{ + if (!m_firstInputDone && m_firstSize==0) + FirstPut(NULL); + + SecByteBlock temp(m_queue.CurrentSize()); + m_queue.GetAll(temp); + LastPut(temp, temp.size); + + m_firstInputDone = false; + m_queue.ResetQueue(1, m_firstSize); + + Filter::MessageEnd(propagation); +} + +void FilterWithBufferedInput::ForceNextPut() +{ + if (m_firstInputDone && m_queue.CurrentSize() >= m_blockSize) + NextPut(m_queue.GetBlock(), m_blockSize); +} + +// ************************************************************* + + + +// ************************************************************* + +ProxyFilter::ProxyFilter(Filter *filter, unsigned int firstSize, unsigned int lastSize, BufferedTransformation *outQ) + : FilterWithBufferedInput(firstSize, 1, lastSize, outQ), m_filter(filter), m_proxy(NULL) +{ + if (m_filter.get()) + m_filter->Attach(m_proxy = new OutputProxy(*this, false)); +} + +void ProxyFilter::Flush(bool completeFlush, int propagation) +{ + if (m_filter.get()) + { + bool passSignal = m_proxy->GetPassSignal(); + m_proxy->SetPassSignal(false); + m_filter->Flush(completeFlush, -1); + m_proxy->SetPassSignal(passSignal); + } + Filter::Flush(completeFlush, propagation); +} + +void ProxyFilter::SetFilter(Filter *filter) +{ + bool passSignal = m_proxy ? m_proxy->GetPassSignal() : false; + m_filter.reset(filter); + if (filter) + { + std::unique_ptr temp(m_proxy = new OutputProxy(*this, passSignal)); + m_filter->TransferAllTo(*m_proxy); + m_filter->Attach(temp.release()); + } + else + m_proxy=NULL; +} + +void ProxyFilter::NextPut(const byte *s, unsigned int len) +{ + if (m_filter.get()) + m_filter->Put(s, len); +} + +// ************************************************************* + +void StreamCipherFilter::Put(const byte *inString, unsigned int length) +{ + SecByteBlock temp(length); + cipher.ProcessString(temp, inString, length); + AttachedTransformation()->Put(temp, length); +} + +void HashFilter::Put(byte inByte) +{ + m_hashModule.Update(&inByte, 1); + if (m_putMessage) + AttachedTransformation()->Put(inByte); +} + +void HashFilter::Put(const byte *inString, unsigned int length) +{ + m_hashModule.Update(inString, length); + if (m_putMessage) + AttachedTransformation()->Put(inString, length); +} + +void HashFilter::MessageEnd(int propagation) +{ + SecByteBlock buf(m_hashModule.DigestSize()); + m_hashModule.Final(buf); + AttachedTransformation()->Put(buf, buf.size); + Filter::MessageEnd(propagation); +} + +// ************************************************************* + +HashVerifier::HashVerifier(HashModule &hm, BufferedTransformation *outQueue, word32 flags) + : FilterWithBufferedInput(flags & HASH_AT_BEGIN ? hm.DigestSize() : 0, 1, flags & HASH_AT_BEGIN ? 0 : hm.DigestSize(), outQueue) + , m_hashModule(hm), m_flags(flags) + , m_expectedHash(flags & HASH_AT_BEGIN ? hm.DigestSize() : 0), m_verified(false) +{ +} + +void HashVerifier::FirstPut(const byte *inString) +{ + if (m_flags & HASH_AT_BEGIN) + { + memcpy(m_expectedHash, inString, m_expectedHash.size); + if (m_flags & PUT_HASH) + AttachedTransformation()->Put(inString, m_expectedHash.size); + } +} + +void HashVerifier::NextPut(const byte *inString, unsigned int length) +{ + m_hashModule.Update(inString, length); + if (m_flags & PUT_MESSAGE) + AttachedTransformation()->Put(inString, length); +} + +void HashVerifier::LastPut(const byte *inString, unsigned int length) +{ + if (m_flags & HASH_AT_BEGIN) + { + assert(length == 0); + m_verified = m_hashModule.Verify(m_expectedHash); + } + else + { + m_verified = (length==m_hashModule.DigestSize() && m_hashModule.Verify(inString)); + if (m_flags & PUT_HASH) + AttachedTransformation()->Put(inString, length); + } + + if (m_flags & PUT_RESULT) + AttachedTransformation()->Put(m_verified); + + if ((m_flags & THROW_EXCEPTION) && !m_verified) + throw HashVerificationFailed(); +} + +// ************************************************************* + +void SignerFilter::MessageEnd(int propagation) +{ + SecByteBlock buf(m_signer.SignatureLength()); + m_signer.Sign(m_rng, m_messageAccumulator.release(), buf); + AttachedTransformation()->Put(buf, buf.size); + Filter::MessageEnd(propagation); + m_messageAccumulator.reset(m_signer.NewMessageAccumulator()); +} + +void VerifierFilter::PutSignature(const byte *sig) +{ + memcpy(m_signature.ptr, sig, m_signature.size); +} + +void VerifierFilter::MessageEnd(int propagation) +{ + AttachedTransformation()->Put((byte)m_verifier.Verify(m_messageAccumulator.release(), m_signature)); + Filter::MessageEnd(propagation); + m_messageAccumulator.reset(m_verifier.NewMessageAccumulator()); +} + +// ************************************************************* + +void Source::PumpAll() +{ + while (PumpMessages()) {} + while (Pump()) {} +} + +StringSource::StringSource(const char *string, bool pumpAll, BufferedTransformation *outQueue) + : Source(outQueue), m_store(string) +{ + if (pumpAll) + PumpAll(); +} + +StringSource::StringSource(const byte *string, unsigned int length, bool pumpAll, BufferedTransformation *outQueue) + : Source(outQueue), m_store(string, length) +{ + if (pumpAll) + PumpAll(); +} + +bool Store::GetNextMessage() +{ + if (!m_messageEnd && !AnyRetrievable()) + { + m_messageEnd=true; + return true; + } + else + return false; +} + +unsigned int Store::CopyMessagesTo(BufferedTransformation &target, unsigned int count) const +{ + if (m_messageEnd || count == 0) + return 0; + else + { + CopyTo(target); + if (GetAutoSignalPropagation()) + target.MessageEnd(GetAutoSignalPropagation()-1); + return 1; + } +} + +unsigned long StringStore::TransferTo(BufferedTransformation &target, unsigned long transferMax) +{ + unsigned long result = CopyTo(target, transferMax); + m_count += result; + return result; +} + +unsigned long StringStore::CopyTo(BufferedTransformation &target, unsigned long copyMax) const +{ + unsigned int len = (unsigned int)STDMIN((unsigned long)(m_length-m_count), copyMax); + target.Put(m_store+m_count, len); + return len; +} + +unsigned long RandomNumberStore::CopyTo(BufferedTransformation &target, unsigned long copyMax) const +{ + unsigned int len = (unsigned int)STDMIN((unsigned long)(m_length-m_count), copyMax); + for (unsigned int i=0; i void AutoDeltaPackedMap::pack(ByteStream & target, const std::string & buffer) { char temp[200]; - char valueBuffer[200]; Command c; Archive::put(target, countCharacter(buffer,':')); @@ -31,7 +30,6 @@ namespace Archive if (*i==':') { temp[tempPos]='\0'; - valueBuffer[0]='\0'; sscanf(temp,"%i",&c.key); char const * const valueStart = strchr(temp,' '); if (valueStart) diff --git a/src/game/server/application/SwgGameServer/src/shared/core/CSHandler.cpp b/src/game/server/application/SwgGameServer/src/shared/core/CSHandler.cpp index 622cd4434..6b1d615df 100644 --- a/src/game/server/application/SwgGameServer/src/shared/core/CSHandler.cpp +++ b/src/game/server/application/SwgGameServer/src/shared/core/CSHandler.cpp @@ -80,7 +80,7 @@ namespace CSHandlerNamespace return 0; } - std::string getOneArg( std::string input, unsigned &position ) + std::string getOneArg( std::string input, int position) { unsigned pos; // where we stop looking unsigned lastpos; // the last character in our argument. diff --git a/src/game/server/application/SwgGameServer/src/win32/WinMain.cpp b/src/game/server/application/SwgGameServer/src/win32/WinMain.cpp index 2d70f3a47..ee1e3aa64 100644 --- a/src/game/server/application/SwgGameServer/src/win32/WinMain.cpp +++ b/src/game/server/application/SwgGameServer/src/win32/WinMain.cpp @@ -1,554 +1,554 @@ -#include "FirstSwgGameServer.h" -#include "serverGame/GameServer.h" - -#include "LocalizationManager.h" -#include "serverGame/SetupServerGame.h" -#include "serverGame/ServerWorld.h" -#include "serverGame/ServerObjectTemplate.h" -#include "ServerObjectLint.h" -#include "serverPathfinding/SetupServerPathfinding.h" -#include "serverScript/SetupScript.h" -#include "serverUtility/SetupServerUtility.h" -#include "sharedDebug/SetupSharedDebug.h" -#include "sharedFile/SetupSharedFile.h" -#include "sharedFile/TreeFile.h" -#include "sharedFoundation/ConfigFile.h" -#include "sharedFoundation/ExitChain.h" -#include "sharedFoundation/FormattedString.h" -#include "sharedFoundation/Os.h" -#include "sharedFoundation/SetupSharedFoundation.h" -#include "sharedGame/SetupSharedGame.h" -#include "sharedGame/SharedObjectTemplate.h" -#include "sharedImage/SetupSharedImage.h" -#include "sharedLog/LogManager.h" -#include "sharedLog/SetupSharedLog.h" -#include "sharedMath/SetupSharedMath.h" -#include "sharedNetwork/NetworkHandler.h" -#include "sharedNetwork/SetupSharedNetwork.h" -#include "sharedObject/SetupSharedObject.h" -#include "sharedObject/ObjectTemplateList.h" -#include "sharedRandom/SetupSharedRandom.h" -#include "sharedRegex/SetupSharedRegex.h" -#include "sharedRemoteDebugServer/SharedRemoteDebugServer.h" -#include "sharedTerrain/SetupSharedTerrain.h" -#include "sharedThread/SetupSharedThread.h" -#include "sharedUtility/SetupSharedUtility.h" -#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" -#include "SwgGameServer/SwgGameServer.h" -#include "SwgGameServer/WorldSnapshotParser.h" -#include "swgSharedNetworkMessages/SetupSwgSharedNetworkMessages.h" -#include "swgServerNetworkMessages/SetupSwgServerNetworkMessages.h" - -#include -#include -#include - -#include - -#ifdef _DEBUG -#include "sharedDebug/DataLint.h" -#include "sharedDebug/PerformanceTimer.h" -#include "sharedFoundation/Os.h" -#include "sharedObject/Object.h" -#include "sharedObject/ObjectTemplate.h" - -void runDataLint(char const *responsePath); -void verifyUpdateRanges (const char* filename); -#endif // _DEBUG - -//_____________________________________________________________________ -/* -int WINAPI WinMain( - HINSTANCE hInstance, // handle to current instance - HINSTANCE hPrevInstance, // handle to previous instance - LPSTR lpCmdLine, // pointer to command line - int nCmdShow // show state of window - ) -*/ -int main(int argc, char ** argv) -{ - int i = 0; - -// UNREF(hPrevInstance); -// UNREF(nCmdShow); -//-- setup foundation - SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game); - - // command line hack - std::string cmdLine; - for(i = 1; i < argc; ++i) - { - cmdLine += argv[i]; - if(i + 1 < argc) - { - cmdLine += " "; - } - } -// setupFoundationData.hInstance = hInstance; - setupFoundationData.commandLine = cmdLine.c_str(); - setupFoundationData.createWindow = false; - setupFoundationData.clockUsesSleep = true; - - SetupSharedThread::install(); - SetupSharedDebug::install(1024); - - SetupSharedFoundation::install (setupFoundationData); - - SetupServerUtility::install(); - - SetupSharedRegex::install(); - - SetupSharedFile::install(false); - - SetupSharedNetwork::SetupData networkSetupData; - SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); - SetupSharedNetwork::install(networkSetupData); - - SetupSharedMath::install(); - - SetupSharedUtility::Data setupUtilityData; - SetupSharedUtility::setupGameData (setupUtilityData); - SetupSharedUtility::install (setupUtilityData); - - SetupSharedRandom::install(int(time(NULL))); - { - SetupSharedObject::Data data; - SetupSharedObject::setupDefaultGameData(data); - // we want the SlotIdManager initialized, but we don't need the associated hardpoint names on the server. - SetupSharedObject::addSlotIdManagerData(data, false); - // we want movement table information on this server - SetupSharedObject::addMovementTableData(data); - // we want CustomizationData support on this server. - SetupSharedObject::addCustomizationSupportData(data); - // we want POB ejection point override support. - SetupSharedObject::addPobEjectionTransformData(data); - // objects should not automatically alter their children and contents - data.objectsAlterChildrenAndContents = false; - SetupSharedObject::install(data); - } - - SetupSharedLog::install(FormattedString<92>().sprintf("SwgGameServer:%d", Os::getProcessId())); - - TreeFile::addSearchAbsolute(0); - TreeFile::addSearchPath(".",0); - - SetupSharedNetworkMessages::install(); - SetupSwgServerNetworkMessages::install(); - SetupSwgSharedNetworkMessages::install(); - - SetupSharedImage::Data setupImageData; - SetupSharedImage::setupDefaultData (setupImageData); - SetupSharedImage::install (setupImageData); - - SetupSharedGame::Data setupSharedGameData; - setupSharedGameData.setUseMountValidScaleRangeTable(true); - setupSharedGameData.setUseClientCombatManagerSupport(true); - SetupSharedGame::install (setupSharedGameData); - - SetupSharedTerrain::Data setupSharedTerrainData; - SetupSharedTerrain::setupGameData (setupSharedTerrainData); - SetupSharedTerrain::install (setupSharedTerrainData); - - SetupScript::Data setupScriptData; - SetupScript::setupDefaultGameData(setupScriptData); - SetupScript::install(); - - SetupServerPathfinding::install(); - - //-- setup game server - SetupServerGame::install(); - - SharedRemoteDebugServer::install(); - - //-- setup game server - cmdLine = ""; - // now, the real command line - for(i = 0; i < argc; ++i) - { - cmdLine += argv[i]; - if(i + 1 < argc) - { - cmdLine += " "; - } - } - - - Archive::ByteStream bs; - UNREF(bs); - - NetworkHandler::install(); - SwgGameServer::install(); - GameServer::getInstance().setCommandLine(cmdLine); - -#ifdef _DEBUG - //-- see if the game server is being run in a mode to parse the database dump to create planetary snapshot files - const char* const createWorldSnapshots = ConfigFile::getKeyString("WorldSnapshot", "createWorldSnapshots", 0); - if (createWorldSnapshots) - { - WorldSnapshotParser::createWorldSnapshots (createWorldSnapshots); - } - else - //-- see if the gameserver is to be run in a mode to scan update ranges - if (ConfigFile::getKeyBool ("SwgGameServer", "verifyUpdateRanges", false)) - { - ServerWorld::install (); - verifyUpdateRanges ("../../exe/win32/serverobjecttemplates.txt"); - ServerWorld::remove (); - } - else - if (!ConfigFile::getKeyBool("SwgGameServer/DataLint", "disable", true)) - { - runDataLint("../../exe/win32/DataLintServer.rsp"); - } - else -#endif // _DEBUG - { - //-- run game - SetupSharedFoundation::callbackWithExceptionHandling(GameServer::run); - } - - NetworkHandler::remove(); - SetupServerGame::remove(); - - SharedRemoteDebugServer::remove(); - SetupSharedLog::remove(); - SetupSharedFoundation::remove(); - SetupSharedThread::remove (); - - return 0; -} - -#ifdef _DEBUG - -void verifyUpdateRanges (const char* const filename) -{ - FILE* const infile = fopen (filename, "rt"); - if (!infile) - { - DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: response file %s could not be opened\n", filename)); - return; - } - - char serverObjectTemplateName [1024]; - while (fscanf (infile, "%s", serverObjectTemplateName) != EOF) - { - //-- does the name contain test? - if (strstr (serverObjectTemplateName, "test") != 0) - { - DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: skipping test object template %s\n", serverObjectTemplateName)); - continue; - } - - if (strstr (serverObjectTemplateName, "e3_") != 0) - { - DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: skipping test object template %s\n", serverObjectTemplateName)); - continue; - } - - //-- get the object template - const ObjectTemplate* const objectTemplate = ObjectTemplateList::fetch (serverObjectTemplateName); - if (!objectTemplate) - { - DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: %s is not a valid object template\n", serverObjectTemplateName)); - continue; - } - - //-- make sure its a server object template - const ServerObjectTemplate* const serverObjectTemplate = dynamic_cast (objectTemplate); - if (!serverObjectTemplate) - { - objectTemplate->releaseReference (); - DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: %s is not a valid server object template\n", serverObjectTemplateName)); - continue; - } - - //-- make sure it has a shared object template - const std::string& sharedObjectTemplateName = serverObjectTemplate->getSharedTemplate (); - if (sharedObjectTemplateName.empty ()) - { - objectTemplate->releaseReference (); - continue; - } - - //-- make sure the shared template exists - const SharedObjectTemplate* const sharedObjectTemplate = safe_cast (ObjectTemplateList::fetch (sharedObjectTemplateName.c_str ())); - if (!sharedObjectTemplate) - { - DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: %s is not a valid shared object template for server object template %s\n", sharedObjectTemplateName.c_str (), serverObjectTemplateName)); - objectTemplate->releaseReference (); - continue; - } - - const float farUpdateRange = serverObjectTemplate->getUpdateRanges (ServerObjectTemplate::UR_far); - DEBUG_REPORT_LOG (true, ("OK:\t%s\t%s\t%1.1f\n", serverObjectTemplateName, sharedObjectTemplateName.c_str (), farUpdateRange)); - objectTemplate->releaseReference (); - } - fclose(infile); -} - -static std::string currentLintedAsset; -static int m_startIndex = 0; -static int m_numberOfFilesToLint = -1; - -//----------------------------------------------------------------------------- -static int ExceptionHandler(LPEXCEPTION_POINTERS exceptionPointers) -{ - UNREF(exceptionPointers); - - static bool entered = false; - - // make the routine safe from re-entrance - - if (entered) - { - return EXCEPTION_CONTINUE_SEARCH; - } - - entered = true; - - // tell the Os not to abort so we can rethrow the exception - - Os::returnFromAbort(); - - // Let the ExitChain do its job - - DataLint::pushAsset(currentLintedAsset.c_str()); - FATAL(true, ("ExceptionHandler invoked - A crash just occured. The asset is bad or it is constructed improperly with DataLint.")); - DataLint::popAsset(); - - // rethrow the exception so that the debugger can catch it - - return EXCEPTION_CONTINUE_SEARCH; //lint !e527 // Unreachable -} - -//----------------------------------------------------------------------------- -static void lintType(char const *filePath, DataLint::AssetType const assetType, bool const skip) -{ - DataLint::setCurrentAssetType(assetType); - - static int assetNumber = 0; - - if (!skip) - { - DEBUG_REPORT_LOG (true, ("%5i Linting file %s... ", assetNumber, filePath)); - - bool failed = false; - - try - { - switch (assetType) - { - case DataLint::AT_objectTemplate: - { - const ObjectTemplate *objectTemplate = ObjectTemplateList::fetch(filePath); - if (objectTemplate) - { - objectTemplate->testValues(); - - // if file has the directory "base" in it's path, don't - // create an object - if (strstr(filePath, "/base/") == NULL) - { - Object* const object = objectTemplate->createObject (); - if (object != NULL) - delete object; - } - - objectTemplate->releaseReference(); - } - else - { - failed = true; - } - } - break; - case DataLint::AT_unSupported: - { - } - break; - - } - - if (failed) - { - DEBUG_REPORT_LOG (true, ("failed\n")); - } - else - { - DEBUG_REPORT_LOG (true, ("ok\n")); - } - } - catch (FatalException const &e) - { - DEBUG_REPORT_LOG (true, ("failed\n")); - - DataLint::logWarning(e.getMessage()); - } - } - - ++assetNumber; -} - -//----------------------------------------------------------------------------- -static void makeMicrosoftHappyAboutObjectUnWinding(char const *filePath, DataLint::AssetType const assetType, bool const skip) -{ - __try - { - lintType(filePath, assetType, skip); - } - __except (ExceptionHandler(GetExceptionInformation())) - { - } -} - -//----------------------------------------------------------------------------- -static void lint(char const *dataTypeString, DataLint::AssetType const assetType) -{ - DataLint::StringPairList stringPairList(DataLint::getList(assetType)); - DataLint::StringPairList::const_iterator dataLintStringListIter = stringPairList.begin(); - - DEBUG_REPORT_LOG_PRINT(1, ("Linting %d %s assets\n", stringPairList.size(), dataTypeString)); - - int currentIndex = 0; - for (; dataLintStringListIter != stringPairList.end(); ++dataLintStringListIter) - { - { - if ((currentIndex % 10) == 0) - { - //-- see if a file exists to abort - - FILE *file = fopen("stoplint.dat", "rt"); - - if (file) - { - fclose(file); - DEBUG_REPORT_LOG_PRINT(1, ("Stopping all DataLint processing for %s.\n", dataTypeString)); - DataLint::logWarning("Forced DataLint stop. Delete \"stoplint.dat\" to DataLint all the assets."); - break; - } - } - } - - char const *filePath = dataLintStringListIter->first.c_str(); - currentLintedAsset = dataLintStringListIter->second.c_str(); - - //DataLint::pushAsset(filePath); - makeMicrosoftHappyAboutObjectUnWinding(filePath, assetType, (currentIndex < m_startIndex)); - //DataLint::popAsset(); - - DataLint::clearAssetStack(); - ++currentIndex; - - if ((m_numberOfFilesToLint != -1) && (currentIndex >= (m_startIndex + m_numberOfFilesToLint))) - { - break; - } - } -} - -//----------------------------------------------------------------------------- -void runDataLint(char const *responsePath) -{ - ServerObjectLint::install(); - ServerWorld::install(); - DataLint::setServerMode(); - - PerformanceTimer performanceTimer; - performanceTimer.start(); - - FILE *fp = fopen(responsePath, "r"); - - if (fp) - { - // Default to start with the first asset - - m_startIndex = ConfigFile::getKeyInt("SwgGameServer/DataLint", "startIndex", 0); - - // Default to lint all assets - - m_numberOfFilesToLint = ConfigFile::getKeyInt("SwgGameServer/DataLint", "numberOfFilesToLint", -1); - - // Verify this is a valid resonse file - - char text[4096]; - fgets(text, sizeof(text), fp); - - if (strstr(text, "Valid DataLint Rsp") == NULL) - { - DEBUG_REPORT_LOG_PRINT(1, ("DataLint: Invalid Rsp file: %s\n", responsePath)); - -#ifdef WIN32 - char text[4096]; - sprintf(text, "Invalid Rsp file specified: %s. Make sure to run DataLintRspBuilder before running DataLint.", responsePath); - MessageBox(NULL, text, "DataLint Error!", MB_OK | MB_ICONERROR); -#endif // WIN32 - } - else - { - DataLint::install(); - - typedef std::vector StringList; - StringList stringList; - stringList.reserve(32768); - - DEBUG_REPORT_LOG_PRINT(1, ("Loading assets to lint from: %s\n", responsePath)); - - while (fgets(text, sizeof(text), fp)) - { - // Remove the newline character - - char *newLineTest = strchr(text, '\n'); - - if (newLineTest) - { - *newLineTest = '\0'; - } - - // Add the files to the master file list - - stringList.push_back(text); - } - - fclose(fp); - - // Add files to data lint - - DEBUG_REPORT_LOG_PRINT(1, ("Adding %d assets to DataLint to be categorized\n", stringList.size())); - - StringList::iterator stringListIter = stringList.begin(); - - for (; stringListIter != stringList.end(); ++stringListIter) - { - DataLint::addFilePath((*stringListIter).c_str()); - } - - if (ConfigFile::getKeyBool("SwgGameServer/DataLint", "objectTemplate", true)) - { - lint("Objects Template", DataLint::AT_objectTemplate); - } - - DataLint::report(); - } - } - else - { - DEBUG_REPORT_LOG_PRINT(1, ("Bad response path specified: %s", responsePath)); - -#ifdef WIN32 - char text[4096]; - sprintf(text, "Bad response file specified: %s. Make sure to run DataLintRspBuilder before running DataLint.", responsePath); - MessageBox(NULL, text, "DataLint Error!", MB_OK | MB_ICONERROR); -#endif // WIN32 - } - - // Dump the time required to data lint - - performanceTimer.stop(); - float const dataLintTime = performanceTimer.getElapsedTime(); - int const seconds = static_cast(dataLintTime) % 60; - int const minutes = (static_cast(dataLintTime) - seconds) / 60; - DEBUG_REPORT_LOG_PRINT(1, ("DateLint took: %dm %ds\n", minutes, seconds)); -} -#endif // _DEBUG - -//_____________________________________________________________________ +#include "FirstSwgGameServer.h" +#include "serverGame/GameServer.h" + +#include "LocalizationManager.h" +#include "serverGame/SetupServerGame.h" +#include "serverGame/ServerWorld.h" +#include "serverGame/ServerObjectTemplate.h" +#include "ServerObjectLint.h" +#include "serverPathfinding/SetupServerPathfinding.h" +#include "serverScript/SetupScript.h" +#include "serverUtility/SetupServerUtility.h" +#include "sharedDebug/SetupSharedDebug.h" +#include "sharedFile/SetupSharedFile.h" +#include "sharedFile/TreeFile.h" +#include "sharedFoundation/ConfigFile.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFoundation/FormattedString.h" +#include "sharedFoundation/Os.h" +#include "sharedFoundation/SetupSharedFoundation.h" +#include "sharedGame/SetupSharedGame.h" +#include "sharedGame/SharedObjectTemplate.h" +#include "sharedImage/SetupSharedImage.h" +#include "sharedLog/LogManager.h" +#include "sharedLog/SetupSharedLog.h" +#include "sharedMath/SetupSharedMath.h" +#include "sharedNetwork/NetworkHandler.h" +#include "sharedNetwork/SetupSharedNetwork.h" +#include "sharedObject/SetupSharedObject.h" +#include "sharedObject/ObjectTemplateList.h" +#include "sharedRandom/SetupSharedRandom.h" +#include "sharedRegex/SetupSharedRegex.h" +#include "sharedRemoteDebugServer/SharedRemoteDebugServer.h" +#include "sharedTerrain/SetupSharedTerrain.h" +#include "sharedThread/SetupSharedThread.h" +#include "sharedUtility/SetupSharedUtility.h" +#include "sharedNetworkMessages/SetupSharedNetworkMessages.h" +#include "SwgGameServer/SwgGameServer.h" +#include "SwgGameServer/WorldSnapshotParser.h" +#include "swgSharedNetworkMessages/SetupSwgSharedNetworkMessages.h" +#include "swgServerNetworkMessages/SetupSwgServerNetworkMessages.h" + +#include +#include +#include + +#include + +#ifdef _DEBUG +#include "sharedDebug/DataLint.h" +#include "sharedDebug/PerformanceTimer.h" +#include "sharedFoundation/Os.h" +#include "sharedObject/Object.h" +#include "sharedObject/ObjectTemplate.h" + +void runDataLint(char const *responsePath); +void verifyUpdateRanges (const char* filename); +#endif // _DEBUG + +//_____________________________________________________________________ +/* +int WINAPI WinMain( + HINSTANCE hInstance, // handle to current instance + HINSTANCE hPrevInstance, // handle to previous instance + LPSTR lpCmdLine, // pointer to command line + int nCmdShow // show state of window + ) +*/ +int main(int argc, char ** argv) +{ + int i = 0; + +// UNREF(hPrevInstance); +// UNREF(nCmdShow); +//-- setup foundation + SetupSharedFoundation::Data setupFoundationData(SetupSharedFoundation::Data::D_game); + + // command line hack + std::string cmdLine; + for(i = 1; i < argc; ++i) + { + cmdLine += argv[i]; + if(i + 1 < argc) + { + cmdLine += " "; + } + } +// setupFoundationData.hInstance = hInstance; + setupFoundationData.commandLine = cmdLine.c_str(); + setupFoundationData.createWindow = false; + setupFoundationData.clockUsesSleep = true; + + SetupSharedThread::install(); + SetupSharedDebug::install(1024); + + SetupSharedFoundation::install (setupFoundationData); + + SetupServerUtility::install(); + + SetupSharedRegex::install(); + + SetupSharedFile::install(false); + + SetupSharedNetwork::SetupData networkSetupData; + SetupSharedNetwork::getDefaultServerSetupData(networkSetupData); + SetupSharedNetwork::install(networkSetupData); + + SetupSharedMath::install(); + + SetupSharedUtility::Data setupUtilityData; + SetupSharedUtility::setupGameData (setupUtilityData); + SetupSharedUtility::install (setupUtilityData); + + SetupSharedRandom::install(int(time(NULL))); + { + SetupSharedObject::Data data; + SetupSharedObject::setupDefaultGameData(data); + // we want the SlotIdManager initialized, but we don't need the associated hardpoint names on the server. + SetupSharedObject::addSlotIdManagerData(data, false); + // we want movement table information on this server + SetupSharedObject::addMovementTableData(data); + // we want CustomizationData support on this server. + SetupSharedObject::addCustomizationSupportData(data); + // we want POB ejection point override support. + SetupSharedObject::addPobEjectionTransformData(data); + // objects should not automatically alter their children and contents + data.objectsAlterChildrenAndContents = false; + SetupSharedObject::install(data); + } + + SetupSharedLog::install(FormattedString<92>().sprintf("SwgGameServer:%d", Os::getProcessId())); + + TreeFile::addSearchAbsolute(0); + TreeFile::addSearchPath(".",0); + + SetupSharedNetworkMessages::install(); + SetupSwgServerNetworkMessages::install(); + SetupSwgSharedNetworkMessages::install(); + + SetupSharedImage::Data setupImageData; + SetupSharedImage::setupDefaultData (setupImageData); + SetupSharedImage::install (setupImageData); + + SetupSharedGame::Data setupSharedGameData; + setupSharedGameData.setUseMountValidScaleRangeTable(true); + setupSharedGameData.setUseClientCombatManagerSupport(true); + SetupSharedGame::install (setupSharedGameData); + + SetupSharedTerrain::Data setupSharedTerrainData; + SetupSharedTerrain::setupGameData (setupSharedTerrainData); + SetupSharedTerrain::install (setupSharedTerrainData); + + SetupScript::Data setupScriptData; + SetupScript::setupDefaultGameData(setupScriptData); + SetupScript::install(); + + SetupServerPathfinding::install(); + + //-- setup game server + SetupServerGame::install(); + + SharedRemoteDebugServer::install(); + + //-- setup game server + cmdLine = ""; + // now, the real command line + for(i = 0; i < argc; ++i) + { + cmdLine += argv[i]; + if(i + 1 < argc) + { + cmdLine += " "; + } + } + + + Archive::ByteStream bs; + UNREF(bs); + + NetworkHandler::install(); + SwgGameServer::install(); + GameServer::getInstance().setCommandLine(cmdLine); + +#ifdef _DEBUG + //-- see if the game server is being run in a mode to parse the database dump to create planetary snapshot files + const char* const createWorldSnapshots = ConfigFile::getKeyString("WorldSnapshot", "createWorldSnapshots", 0); + if (createWorldSnapshots) + { + WorldSnapshotParser::createWorldSnapshots (createWorldSnapshots); + } + else + //-- see if the gameserver is to be run in a mode to scan update ranges + if (ConfigFile::getKeyBool ("SwgGameServer", "verifyUpdateRanges", false)) + { + ServerWorld::install (); + verifyUpdateRanges ("../../exe/win32/serverobjecttemplates.txt"); + ServerWorld::remove (); + } + else + if (!ConfigFile::getKeyBool("SwgGameServer/DataLint", "disable", true)) + { + runDataLint("../../exe/win32/DataLintServer.rsp"); + } + else +#endif // _DEBUG + { + //-- run game + SetupSharedFoundation::callbackWithExceptionHandling(GameServer::run); + } + + NetworkHandler::remove(); + SetupServerGame::remove(); + + SharedRemoteDebugServer::remove(); + SetupSharedLog::remove(); + SetupSharedFoundation::remove(); + SetupSharedThread::remove (); + + return 0; +} + +#ifdef _DEBUG + +void verifyUpdateRanges (const char* const filename) +{ + FILE* const infile = fopen (filename, "rt"); + if (!infile) + { + DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: response file %s could not be opened\n", filename)); + return; + } + + char serverObjectTemplateName [1024]; + while (fscanf (infile, "%s", serverObjectTemplateName) != EOF) + { + //-- does the name contain test? + if (strstr (serverObjectTemplateName, "test") != 0) + { + DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: skipping test object template %s\n", serverObjectTemplateName)); + continue; + } + + if (strstr (serverObjectTemplateName, "e3_") != 0) + { + DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: skipping test object template %s\n", serverObjectTemplateName)); + continue; + } + + //-- get the object template + const ObjectTemplate* const objectTemplate = ObjectTemplateList::fetch (serverObjectTemplateName); + if (!objectTemplate) + { + DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: %s is not a valid object template\n", serverObjectTemplateName)); + continue; + } + + //-- make sure its a server object template + const ServerObjectTemplate* const serverObjectTemplate = dynamic_cast (objectTemplate); + if (!serverObjectTemplate) + { + objectTemplate->releaseReference (); + DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: %s is not a valid server object template\n", serverObjectTemplateName)); + continue; + } + + //-- make sure it has a shared object template + const std::string& sharedObjectTemplateName = serverObjectTemplate->getSharedTemplate (); + if (sharedObjectTemplateName.empty ()) + { + objectTemplate->releaseReference (); + continue; + } + + //-- make sure the shared template exists + const SharedObjectTemplate* const sharedObjectTemplate = safe_cast (ObjectTemplateList::fetch (sharedObjectTemplateName.c_str ())); + if (!sharedObjectTemplate) + { + DEBUG_REPORT_LOG (true, ("verifyUpdateRanges: %s is not a valid shared object template for server object template %s\n", sharedObjectTemplateName.c_str (), serverObjectTemplateName)); + objectTemplate->releaseReference (); + continue; + } + + const float farUpdateRange = serverObjectTemplate->getUpdateRanges (ServerObjectTemplate::UR_far); + DEBUG_REPORT_LOG (true, ("OK:\t%s\t%s\t%1.1f\n", serverObjectTemplateName, sharedObjectTemplateName.c_str (), farUpdateRange)); + objectTemplate->releaseReference (); + } + fclose(infile); +} + +static std::string currentLintedAsset; +static int m_startIndex = 0; +static int m_numberOfFilesToLint = -1; + +//----------------------------------------------------------------------------- +static int ExceptionHandler(LPEXCEPTION_POINTERS exceptionPointers) +{ + UNREF(exceptionPointers); + + static bool entered = false; + + // make the routine safe from re-entrance + + if (entered) + { + return EXCEPTION_CONTINUE_SEARCH; + } + + entered = true; + + // tell the Os not to abort so we can rethrow the exception + + Os::returnFromAbort(); + + // Let the ExitChain do its job + + DataLint::pushAsset(currentLintedAsset.c_str()); + FATAL(true, ("ExceptionHandler invoked - A crash just occured. The asset is bad or it is constructed improperly with DataLint.")); + DataLint::popAsset(); + + // rethrow the exception so that the debugger can catch it + + return EXCEPTION_CONTINUE_SEARCH; //lint !e527 // Unreachable +} + +//----------------------------------------------------------------------------- +static void lintType(char const *filePath, DataLint::AssetType const assetType, bool const skip) +{ + DataLint::setCurrentAssetType(assetType); + + static int assetNumber = 0; + + if (!skip) + { + DEBUG_REPORT_LOG (true, ("%5i Linting file %s... ", assetNumber, filePath)); + + bool failed = false; + + try + { + switch (assetType) + { + case DataLint::AT_objectTemplate: + { + const ObjectTemplate *objectTemplate = ObjectTemplateList::fetch(filePath); + if (objectTemplate) + { + objectTemplate->testValues(); + + // if file has the directory "base" in it's path, don't + // create an object + if (strstr(filePath, "/base/") == NULL) + { + Object* const object = objectTemplate->createObject (); + if (object != NULL) + delete object; + } + + objectTemplate->releaseReference(); + } + else + { + failed = true; + } + } + break; + case DataLint::AT_unSupported: + { + } + break; + + } + + if (failed) + { + DEBUG_REPORT_LOG (true, ("failed\n")); + } + else + { + DEBUG_REPORT_LOG (true, ("ok\n")); + } + } + catch (FatalException const &e) + { + DEBUG_REPORT_LOG (true, ("failed\n")); + + DataLint::logWarning(e.getMessage()); + } + } + + ++assetNumber; +} + +//----------------------------------------------------------------------------- +static void makeMicrosoftHappyAboutObjectUnWinding(char const *filePath, DataLint::AssetType const assetType, bool const skip) +{ + __try + { + lintType(filePath, assetType, skip); + } + __except (ExceptionHandler(GetExceptionInformation())) + { + } +} + +//----------------------------------------------------------------------------- +static void lint(char const *dataTypeString, DataLint::AssetType const assetType) +{ + DataLint::StringPairList stringPairList(DataLint::getList(assetType)); + DataLint::StringPairList::const_iterator dataLintStringListIter = stringPairList.begin(); + + DEBUG_REPORT_LOG_PRINT(1, ("Linting %d %s assets\n", stringPairList.size(), dataTypeString)); + + int currentIndex = 0; + for (; dataLintStringListIter != stringPairList.end(); ++dataLintStringListIter) + { + { + if ((currentIndex % 10) == 0) + { + //-- see if a file exists to abort + + FILE *file = fopen("stoplint.dat", "rt"); + + if (file) + { + fclose(file); + DEBUG_REPORT_LOG_PRINT(1, ("Stopping all DataLint processing for %s.\n", dataTypeString)); + DataLint::logWarning("Forced DataLint stop. Delete \"stoplint.dat\" to DataLint all the assets."); + break; + } + } + } + + char const *filePath = dataLintStringListIter->first.c_str(); + currentLintedAsset = dataLintStringListIter->second.c_str(); + + //DataLint::pushAsset(filePath); + makeMicrosoftHappyAboutObjectUnWinding(filePath, assetType, (currentIndex < m_startIndex)); + //DataLint::popAsset(); + + DataLint::clearAssetStack(); + ++currentIndex; + + if ((m_numberOfFilesToLint != -1) && (currentIndex >= (m_startIndex + m_numberOfFilesToLint))) + { + break; + } + } +} + +//----------------------------------------------------------------------------- +void runDataLint(char const *responsePath) +{ + ServerObjectLint::install(); + ServerWorld::install(); + DataLint::setServerMode(); + + PerformanceTimer performanceTimer; + performanceTimer.start(); + + FILE *fp = fopen(responsePath, "r"); + + if (fp) + { + // Default to start with the first asset + + m_startIndex = ConfigFile::getKeyInt("SwgGameServer/DataLint", "startIndex", 0); + + // Default to lint all assets + + m_numberOfFilesToLint = ConfigFile::getKeyInt("SwgGameServer/DataLint", "numberOfFilesToLint", -1); + + // Verify this is a valid resonse file + + char text[4096]; + fgets(text, sizeof(text), fp); + + if (strstr(text, "Valid DataLint Rsp") == NULL) + { + DEBUG_REPORT_LOG_PRINT(1, ("DataLint: Invalid Rsp file: %s\n", responsePath)); + +#ifdef WIN32 + char text[4096]; + sprintf(text, "Invalid Rsp file specified: %s. Make sure to run DataLintRspBuilder before running DataLint.", responsePath); + MessageBox(NULL, text, "DataLint Error!", MB_OK | MB_ICONERROR); +#endif // WIN32 + } + else + { + DataLint::install(); + + typedef std::vector StringList; + StringList stringList; + stringList.reserve(32768); + + DEBUG_REPORT_LOG_PRINT(1, ("Loading assets to lint from: %s\n", responsePath)); + + while (fgets(text, sizeof(text), fp)) + { + // Remove the newline character + + char *newLineTest = strchr(text, '\n'); + + if (newLineTest) + { + *newLineTest = '\0'; + } + + // Add the files to the master file list + + stringList.push_back(text); + } + + fclose(fp); + + // Add files to data lint + + DEBUG_REPORT_LOG_PRINT(1, ("Adding %d assets to DataLint to be categorized\n", stringList.size())); + + StringList::iterator stringListIter = stringList.begin(); + + for (; stringListIter != stringList.end(); ++stringListIter) + { + DataLint::addFilePath((*stringListIter).c_str()); + } + + if (ConfigFile::getKeyBool("SwgGameServer/DataLint", "objectTemplate", true)) + { + lint("Objects Template", DataLint::AT_objectTemplate); + } + + DataLint::report(); + } + } + else + { + DEBUG_REPORT_LOG_PRINT(1, ("Bad response path specified: %s", responsePath)); + +#ifdef WIN32 + char text[4096]; + sprintf(text, "Bad response file specified: %s. Make sure to run DataLintRspBuilder before running DataLint.", responsePath); + MessageBox(NULL, text, "DataLint Error!", MB_OK | MB_ICONERROR); +#endif // WIN32 + } + + // Dump the time required to data lint + + performanceTimer.stop(); + float const dataLintTime = performanceTimer.getElapsedTime(); + int const seconds = static_cast(dataLintTime) % 60; + int const minutes = (static_cast(dataLintTime) - seconds) / 60; + DEBUG_REPORT_LOG_PRINT(1, ("DateLint took: %dm %ds\n", minutes, seconds)); +} +#endif // _DEBUG + +//_____________________________________________________________________ diff --git a/src/swg.doxygen b/src/swg.doxygen new file mode 100644 index 000000000..33daf53fc --- /dev/null +++ b/src/swg.doxygen @@ -0,0 +1,2381 @@ +# Doxyfile 1.8.9.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Star Wars Galaxies" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 5 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = YES + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = YES + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = NO + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank the +# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, +# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, +# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, +# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, +# *.qsf, *.as and *.js. + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = */cmake/* */CMakeLists/* */alienbrain110/* */alienbrain122/* */alienbrain123/* */atiDxtc/* */atlmfc/* */bink/* */boost/* */debugHelp/* */dimm/* */directx9/* */dpvs/* */java/* */lcdui/* */lcdui_src/* */libiconv/* */libjpeg/* */libMozilla/* */libxml/* */libxml2/* */libxml2-2.6.7.win32/* */ms_unicode/* */nvtristrip/* */OCI/* */oracle/* */oracle_win32/* */pcre/* */perforce/* */qt/* */stlport453/* */tinyxml/* */vtune/* */zlib/* */zlib-1.2.3/* */CSAssist/utils/AES/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the +# cost of reduced performance. This can be particularly helpful with template +# rich C++ code for which doxygen's built-in parser lacks the necessary type +# information. +# Note: The availability of this option depends on whether or not doxygen was +# compiled with the --with-libclang option. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /